При разработке внешних обработок для создания связанных документов или ввода на основании часто возникает задача программного переноса данных из одного документа в другой. Например, требуется сформировать документ РеализацияТоваровУслуг на основании документа ОтчетПроизводстваЗаСмену. Простого копирования строк через ЗаполнитьЗначенияСвойств оказывается недостаточно: в созданном документе остаются незаполненными счета учета номенклатуры, счета учета НДС, цены, ставки и суммы налога.
Выясним причину такого поведения платформы и разберем правильные архитектурные подходы к автозаполнению и пересчету табличных частей типовых документов в конфигурации «1С:Бухгалтерия предприятия 3.0».
В управляемом интерфейсе 1С при программном добавлении строк в коллекцию формы события элементов формы (такие как ТоварыНоменклатураПриИзменении) намеренно не вызываются платформой. Попытка открыть форму через ПолучитьФорму, перенести туда данные через КопироватьДанныеФормы и вручную вызывать клиентские обработчики приводит к усложнению кода, переносу множества зависимых процедур во внешнюю обработку и нестабильной работе интерфейса.
Все типовые конфигурации на базе БСП (Библиотеки стандартных подсистем) содержат готовые серверные механизмы для инициализации, подстановки счетов учета и пересчета сумм. Рассмотрим подробнее, как их использовать.
Для внешних обработок с видом «Создание связанных объектов» стандартом разработки 1С является выполнение операции на стороне сервера с типом команды ВызовСерверногоМетода. В этом случае мы создаем документ в серверном контексте, заполняем его реквизиты, применяем специализированные методы конфигурации и записываем объект.
Разберем по шагам реализацию этого механизма в модуле объекта внешней обработки:
ВыполнитьКоманду создаем новый объект документа.СчетаУчетаВДокументах и ОбработкаТабличныхЧастейКлиентСервер для подстановки счетов и расчета суммовых показателей.СозданныеОбъекты, чтобы БСП выдала пользователю оповещение или открыла созданный документ.Посмотрим на пример кода серверной процедуры:
Процедура ВыполнитьКоманду(ИдентификаторКоманды, МассивОбъектов, СозданныеОбъекты) Экспорт
Для Каждого СсылкаОснование Из МассивОбъектов Цикл
НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДатаСеанса();
НовыйДокумент.Организация = СсылкаОснование.Организация;
НовыйДокумент.Склад = СсылкаОснование.Склад;
НовыйДокумент.ДокументОснование = СсылкаОснование;
// Переносим номенклатурный состав
Для Каждого СтрПродукция Из СсылкаОснование.Продукция Цикл
НоваяСтрока = НовыйДокумент.Товары.Добавить();
НоваяСтрока.Номенклатура = СтрПродукция.Номенклатура;
НоваяСтрока.Количество = СтрПродукция.Количество;
НоваяСтрока.Коэффициент = 1;
// Заполнение счетов учета номенклатуры и доходов/расходов по правилам БП 3.0
СчетаУчетаВДокументах.ЗаполнитьСчетаУчетаВСтрокеТабЧасти(НовыйДокумент, НоваяСтрока, "Товары");
// Расчет сумм и НДС при наличии цен
ОбработкаТабличныхЧастейКлиентСервер.РассчитатьСуммуТабЧасти(НоваяСтрока, НовыйДокумент);
ОбработкаТабличныхЧастейКлиентСервер.РассчитатьСуммуНДСТабЧасти(НоваяСтрока, НовыйДокумент);
КонецЦикла;
// Пакетное заполнение счетов учета для всей табличной части (альтернативный вызов)
СчетаУчетаВДокументах.ЗаполнитьСчетаУчетаВТабличнойЧасти(НовыйДокумент, "Товары");
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
СозданныеОбъекты.Добавить(НовыйДокумент.Ссылка);
КонецЦикла;
КонецПроцедуры
Если логика бизнес-процесса требует не сразу сохранять документ в базу, а открыть готовую, но незаписанную форму для ручной проверки и редактирования пользователем, используется метод ОткрытьФорму с параметром ЗначенияЗаполнения.
Проанализируем ситуацию: платформа 1С при передаче структуры в параметре ЗначенияЗаполнения автоматически запускает обработчик ОбработкаЗаполнения в модуле объекта и инициализирует форму по всем правилам конфигурации. Для этого не нужно использовать устаревший метод ПолучитьФорму.
Разберем пример реализации на клиенте:
&НаКлиенте
Процедура СоздатьРеализациюИнтерактивно(СсылкаОснование)
ДанныеЗаполнения = СформироватьДанныеЗаполненияНаСервере(СсылкаОснование);
ПараметрыОткрытия = Новый Структура;
ПараметрыОткрытия.Вставить("ЗначенияЗаполнения", ДанныеЗаполнения);
ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта", ПараметрыОткрытия);
КонецПроцедуры
&НаСервере
Функция СформироватьДанныеЗаполненияНаСервере(СсылкаОснование)
ДанныеЗаполнения = Новый Структура;
ДанныеЗаполнения.Вставить("Организация", СсылкаОснование.Организация);
ДанныеЗаполнения.Вставить("Склад", СсылкаОснование.Склад);
ДанныеЗаполнения.Вставить("ДокументОснование", СсылкаОснование);
// Формируем таблицу товаров для подстановки
ТаблицаТовары = Новый ТаблицаЗначений;
ТаблицаТовары.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТаблицаТовары.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
Для Каждого Стр Из СсылкаОснование.Продукция Цикл
СтрТовары = ТаблицаТовары.Добавить();
СтрТовары.Номенклатура = Стр.Номенклатура;
СтрТовары.Количество = Стр.Количество;
КонецЦикла;
ДанныеЗаполнения.Вставить("Товары", ТаблицаТовары);
Возврат ДанныеЗаполнения;
КонецФункции
Если есть возможность использовать механизм расширений, наиболее чистым решением будет добавление логики связки документов непосредственно в типовую процедуру ОбработкаЗаполнения модуля объекта документа РеализацияТоваровУслуг.
В этом случае типовой документ сам научится заполняться на основании ОтчетПроизводстваЗаСмену, команда создания станет доступна в стандартном подменю «Создать на основании», а все счета учета и суммы будут рассчитаны штатными процедурами конфигурации.
Пример кода метода в модуле объекта через аннотацию &Вместо или &После:
&После("ОбработкаЗаполнения")
Процедура Расш_ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ОтчетПроизводстваЗаСмену") Тогда
Организация = ДанныеЗаполнения.Организация;
Склад = ДанныеЗаполнения.Склад;
ДокументОснование = ДанныеЗаполнения;
Для Каждого Стр Из ДанныеЗаполнения.Продукция Цикл
НоваяСтрока = Товары.Добавить();
НоваяСтрока.Номенклатура = Стр.Номенклатура;
НоваяСтрока.Количество = Стр.Количество;
НоваяСтрока.Коэффициент = 1;
КонецЦикла;
// Вызов штатного заполнения счетов БП 3.0
СчетаУчетаВДокументах.ЗаполнитьСчетаУчетаВТабличнойЧасти(ЭтотОбъект, "Товары");
КонецЕсли;
КонецПроцедуры
ТоварыНоменклатураПриИзменении) во внешние обработки.СчетаУчетаВДокументах для автоматического определения счетов БУ (41, 43, 90.01, 90.02) по регистру сведений «Счета учета номенклатуры».ОбработкаТабличныхЧастейКлиентСервер.