Как программно создать документ «Оплата платежной картой» и открыть форму без потери данных табличной части?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При разработке внешних обработок и интеграционных механизмов в среде 1С:Предприятие 8.3 часто возникает задача: программно сформировать документ, заполнить его реквизиты и табличные части, а затем открыть интерактивную форму, чтобы пользователь мог проверить данные перед проведением. Однако при работе с типовыми документами конфигурации «Бухгалтерия предприятия» (например, ОплатаПлатежнойКартой) разработчики нередко сталкиваются с тем, что строки табличной части РасшифровкаПлатежа или счета учета расчетов очищаются сразу после вызова метода Открыть().

Разберем причины такого поведения типовой конфигурации и рассмотрим надежные способы решения этой задачи.

Почему форма очищает табличную часть и счета учета?

Проанализируем логику работы типовой управляемой формы документа. Потеря данных происходит по следующим причинам:

  1. Инициализация нового документа: в типовых формах документов на базе БСП при открытии нового (еще не записанного в базу) объекта срабатывают алгоритмы синхронизации реквизитов шапки и табличной части. Форма определяет режим отображения (например, «Один платеж» или «Список платежей») и принудительно очищает коллекцию Объект.РасшифровкаПлатежа, пересобирая ее по полям шапки.
  2. Автоматическое переопределение счетов учета: счета расчетов с контрагентами и авансов заполняются специализированными процедурами на основе данных регистра сведений СчетаУчетаРасчетовСКонтрагентами. При формировании нового объекта типовой код перезаписывает переданные в строку счета стандартными настройками.
  3. Особенности передачи данных формы: связка методов ПолучитьФорму, ЗначениеВДанныеФормы и КопироватьДанныеФормы для несохраненных объектов часто конфликтует с внутренними событиями формы ПриСозданииНаСервере и ПриЧтенииСозданииНаСервере.

Способ 1. Создание и запись объекта в базу перед открытием (Рекомендуемый)

Рассмотрим наиболее надежный и архитектурно правильный подход: создадим объект документа на сервере, заполним все необходимые реквизиты и табличную часть, запишем его в режиме РежимЗаписиДокумента.Запись (без проведения), после чего откроем форму уже существующего документа по ссылке.

Посмотрим на пример серверной и клиентской части кода:


&НаСервере
Функция СоздатьИЗаписатьОплатуКартойНаСервере(СтруктураДанных)
    
    ДокументОбъект = Документы.ОплатаПлатежнойКартой.СоздатьДокумент();
    ДокументОбъект.Дата = СтруктураДанных.Дата;
    ДокументОбъект.Организация = СтруктураДанных.Организация;
    ДокументОбъект.Контрагент = СтруктураДанных.Контрагент;
    ДокументОбъект.ДоговорКонтрагента = СтруктураДанных.ДоговорКонтрагента;
    ДокументОбъект.СуммаДокумента = СтруктураДанных.Сумма;
    
    // Заполняем табличную часть
    ДокументОбъект.РасшифровкаПлатежа.Очистить();
    НоваяСтрока = ДокументОбъект.РасшифровкаПлатежа.Добавить();
    НоваяСтрока.ДоговорКонтрагента = СтруктураДанных.ДоговорКонтрагента;
    НоваяСтрока.СуммаВзаиморасчетов = СтруктураДанных.Сумма;
    НоваяСтрока.СуммаПлатежа = СтруктураДанных.Сумма;
    НоваяСтрока.СчетУчетаРасчетовСКонтрагентом = СтруктураДанных.СчетУчетаРасчетов;
    НоваяСтрока.СчетУчетаРасчетовПоАвансам = СтруктураДанных.СчетУчетаАвансов;
    
    // Записываем документ без проведения
    ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
    
    Возврат ДокументОбъект.Ссылка;
    
КонецФункции

&НаКлиенте
Процедура ОткрытьСозданныйДокумент(СтруктураДанных)
    
    СсылкаНаДокумент = СоздатьИЗаписатьОплатуКартойНаСервере(СтруктураДанных);
    
    Если ЗначениеЗаполнено(СсылкаНаДокумент) Тогда
        ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
        ОткрытьФорму("Документ.ОплатаПлатежнойКартой.ФормаОбъекта", ПараметрыФормы);
    КонецЕсли;
    
КонецПроцедуры

Преимущество данного способа: для уже записанного объекта форма не запускает алгоритмы инициализации нового документа. Все строки табличной части и указанные вручную счета учета считываются напрямую из базы данных и гарантированно отображаются на форме.

Способ 2. Открытие формы с параметром «ЗначенияЗаполнения»

Если создание несохраненных «пустышек» в базе данных нежелательно, воспользуемся штатным механизмом платформы 8.3 — передачей структуры ЗначенияЗаполнения в процедуру ОткрытьФорму.

Разберем по шагам, как передать параметры для автозаполнения:


&НаКлиенте
Процедура ОткрытьФормуНовогоДокумента(ПараметрыДокумента)
    
    ПараметрыЗаполнения = Новый Структура;
    ПараметрыЗаполнения.Вставить("Организация", ПараметрыДокумента.Организация);
    ПараметрыЗаполнения.Вставить("Контрагент", ПараметрыДокумента.Контрагент);
    ПараметрыЗаполнения.Вставить("ДоговорКонтрагента", ПараметрыДокумента.ДоговорКонтрагента);
    ПараметрыЗаполнения.Вставить("СуммаДокумента", ПараметрыДокумента.Сумма);
    
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("ЗначенияЗаполнения", ПараметрыЗаполнения);
    
    ОткрытьФорму("Документ.ОплатаПлатежнойКартой.ФормаОбъекта", ПараметрыОткрытия);
    
КонецПроцедуры

При таком вызове срабатывает стандартный обработчик ОбработкаЗаполнения объекта, и форма инициализируется штатными средствами конфигурации. Счета учета подставятся автоматически в соответствии с регистром сведений СчетаУчетаРасчетовСКонтрагентами.

Способ 3. Заполнение строк после открытия формы на клиенте

В ситуациях, когда требуется не записывать документ в базу, но при этом передать нестандартные счета учета, которые отличаются от данных регистра, можно применить постобработку данных формы сразу после вызова Открыть().

Посмотрим на реализацию:


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

Важное предостережение: прямой обход коллекции на клиенте после вызова Открыть() не запускает связанные серверные валидации и обработчики пересчета. Кроме того, если пользователь интерактивно изменит реквизиты шапки (контрагента или договор), типовой алгоритм формы может снова перезаполнить счета учета по регистру.

Итоги

Выясним главные правила программного создания документов:

  1. Для сложных документов со специфическими строками табличных частей и нестандартными счетами всегда предпочтительнее использовать предварительную запись объекта (РежимЗаписиДокумента.Запись) с последующим открытием через параметр Ключ.
  2. Для типового заполнения без предварительной записи используйте параметр формы ЗначенияЗаполнения, настроив правила подстановки счетов в регистре СчетаУчетаРасчетовСКонтрагентами.
← На главную