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