В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача автоматизации ввода документов. Стандартный механизм "Создать на основании" предполагает связь "один к одному": из одного документа-источника создается один документ-приемник. Однако бизнес-логика иногда требует иного подхода. Например, когда на основании одной реализации с несколькими товарными позициями необходимо создать несколько отдельных документов (по одному на каждую строку), и при этом сразу открыть их формы для проверки пользователем. Рассмотрим подробнее, как реализовать такую задачу, не снимая типовую конфигурацию с поддержки.
Первое, с чем сталкивается разработчик — это попытка реализовать логику в стандартном обработчике ОбработкаЗаполнения в модуле объекта. Проанализируем, почему этот путь является тупиковым для нашей задачи:
ОбработкаЗаполнения выполняется строго на сервере. Согласно архитектуре управляемого приложения, серверный код не может управлять интерфейсом. Мы не можем вызвать команду ОткрытьФорму из серверного контекста модуля объекта.Документы.НужныйТип.СоздатьДокумент(), нам придется их записывать, чтобы не потерять.Выясним причину: для корректного решения нам нужно перенести инициализацию процесса на сторону клиента.
Так как изменять типовую "Бухгалтерию предприятия 3.0" нельзя, мы воспользуемся механизмом расширений. Это позволит нам добавить собственную команду в интерфейс, не затрагивая основной код конфигурации.
Разберем по шагам алгоритм создания команды:
РеализацияТоваровУслуг).ДокументСсылка.РеализацияТоваровУслуг.Командная панель формы.Создать на основании. Теперь наша кнопка появится в стандартном подменю.Теперь проанализируем код клиентского метода этой команды. Нам нужно получить данные из документа-основания и в цикле вызвать открытие форм новых документов.
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
// Получаем данные табличной части (нужен серверный вызов)
ДанныеДляЗаполнения = ПолучитьДанныеДокументаНаСервере(ПараметрКоманды);
Если ДанныеДляЗаполнения.Количество() > 10 Тогда
ОписаниеОповещения = Новый ОписаниеОповещения("ВыполнитьСозданиеПослеПодтверждения", ЭтотОбъект, ДанныеДляЗаполнения);
ПоказатьВопрос(ОписаниеОповещения, "Будет создано " + ДанныеДляЗаполнения.Количество() + " документов. Продолжить?", РежимДиалогаВопрос.ДаНет);
Иначе
ВыполнитьЦиклОткрытияФорм(ДанныеДляЗаполнения);
КонецЕсли;
КонецПроцедуры
Чтобы каждый новый документ "знал", какой именно строкой из основания он должен заполниться, мы будем использовать структуру ЗначенияЗаполнения. Рассмотрим, как правильно передать эти данные в функцию ОткрытьФорму.
В модуле команды (или формы) создадим процедуру открытия:
&НаКлиенте
Процедура ВыполнитьЦиклОткрытияФорм(ДанныеДляЗаполнения)
Для Каждого СтрокаДанных Из ДанныеДляЗаполнения Цикл
ПараметрыФормы = Новый Структура;
// Формируем структуру параметров заполнения
СтруктураЗаполнения = Новый Структура;
СтруктураЗаполнения.Вставить("Основание", СтрокаДанных.СсылкаНаОснование);
СтруктураЗаполнения.Вставить("НомерСтрокиОснования", СтрокаДанных.НомерСтроки);
СтруктураЗаполнения.Вставить("ОсобыйРежимЗаполнения", Истина);
ПараметрыФормы.Вставить("ЗначенияЗаполнения", СтруктураЗаполнения);
// Открываем форму нового документа
ОткрытьФорму("Документ.НашНовыйДокумент.ФормаОбъекта", ПараметрыФормы);
КонецЦикла;
КонецПроцедуры
Теперь нам необходимо доработать сам создаваемый документ (также через расширение), чтобы он умел обрабатывать эти специфические параметры. В модуле объекта нового документа перехватим процедуру ОбработкаЗаполнения.
&После("ОбработкаЗаполнения")
Процедура Расш_ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура")
И ДанныеЗаполнения.Свойство("ОсобыйРежимЗаполнения") Тогда
// Отключаем стандартное заполнение, если нужно, или очищаем ТЧ
ЭтотОбъект.Товары.Очистить();
// Получаем данные только по одной строке
ДокументОбъектОснование = ДанныеЗаполнения.Основание.ПолучитьОбъект();
СтрокаИсточника = ДокументОбъектОснование.Товары[ДанныеЗаполнения.НомерСтроки - 1];
// Заполняем реквизиты документа
ЗаполнитьЗначенияСвойств(ЭтотОбъект, ДокументОбъектОснование, "Организация, Контрагент, Склад");
// Добавляем только нашу одну строку
НоваяСтрока = ЭтотОбъект.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточника);
КонецЕсли;
КонецПроцедуры
Если по каким-то причинам использование расширений нежелательно, в конфигурациях на базе БСП (Библиотека стандартных подсистем), к которым относится и "Бухгалтерия предприятия 3.0", существует механизм "Дополнительных отчетов и обработок".
Посмотрим на преимущества этого метода:
Для реализации этого метода необходимо создать внешнюю обработку и в модуле объекта прописать функцию СведенияОВнешнейОбработке(). В таблице команд укажите вид ЗаполнениеОбъекта или СозданиеСвязанныхОбъектов. Важно указать использование ОткрытиеФормы, если вы хотите использовать клиентскую логику.
Проанализируем ситуацию, упомянутую в обсуждении: что если в исходном документе 50 или 100 строк номенклатуры? Программное открытие 100 окон мгновенно приведет к зависанию клиентского сеанса и сделает работу пользователя невозможной.
Рекомендации по оптимизации:
Таким образом, мы разобрали, что ключевым моментом решения является уход от стандартного серверного механизма заполнения в сторону клиентского управления формами. Использование Структуры в параметре ЗначенияЗаполнения позволяет гибко передавать контекст из одного документа в другой, обеспечивая корректное разделение данных табличной части.