Как создать документ, заполнить его данными другого документа и открыть форму без записи

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

При разработке прикладных решений на платформе «1С:Предприятие 8» часто возникает задача: по нажатию кнопки создать новый документ, скопировать в него данные из текущего документа, внести определенные изменения и открыть пользователю готовую форму. При этом критически важным требованием является то, что новый документ не должен записываться в базу данных автоматически. Пользователь должен сам проверить заполненные реквизиты, при необходимости отредактировать их и самостоятельно нажать кнопку сохранения или проведения.

В обычном приложении для решения этой задачи разработчики нередко создавали объект в памяти и вызывали метод получения формы напрямую у объекта. Однако в парадигме клиент-серверного взаимодействия и управляемых форм логика работы существенно меняется: объект типа ДокументОбъект существует исключительно на сервере, а на клиенте отображаются ДанныеФормыСтруктура. Передать серверный объект напрямую на клиент нельзя, а для открытия существующего документа платформе требуется параметр Ключ со ссылкой на сохраненную запись. Разберем по шагам, как правильно открыть форму нового несохраненного документа с заполненными данными.

Способ 1. Использование стандартного параметра формы «ЗначениеКопирования»

Самый простой, быстрый и платформенно корректный способ скопировать текущий документ в новый без записи — использовать штатный механизм копирования платформы. Для этого при открытии формы нового документа передается параметр ЗначениеКопирования, в который помещается ссылка на исходный документ.

Посмотрим на пример клиентского кода:


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

Разберем подробнее, как работает этот механизм:

  1. Платформа открывает форму нового документа и автоматически копирует все реквизиты шапки и строки табличных частей из документа-источника точно так же, как при интерактивном нажатии клавиши F9 в списке документов.
  2. При этом новый документ не получает ссылку в базе данных и находится только в оперативной памяти клиентского сеанса.
  3. Если конфигурация типовая, в модуле формы автоматически отрабатывают стандартные алгоритмы инициализации нового документа, сформированного копированием.

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


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

Способ 2. Заполнение через механизм ввода на основании

Второй классический способ — использование логики ввода на основании. Для этого при открытии формы передается стандартный параметр Основание. В этом случае на сервере платформой автоматически вызывается процедура ОбработкаЗаполнения модуля объекта создаваемого документа.

Рассмотрим вызов формы на клиенте:


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

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


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
        // Заполняем документ по правилам ввода на основании
        ЗаполнитьПоДокументу(ДанныеЗаполнения);
    КонецЕсли;
КонецПроцедуры

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

Способ 3. Передача произвольных данных через «ЗначенияЗаполнения»

Если требуется передать не ссылку на документ, а произвольный набор значений, можно воспользоваться стандартным параметром формы ЗначенияЗаполнения. В него передается структура, ключи которой соответствуют именам реквизитов документа.

Посмотрим на пример вызова:


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

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

Проанализируем важные особенности работы со ЗначенияЗаполнения:

  1. Платформа автоматически заполняет реквизиты шапки из переданной структуры только в том случае, если в свойствах этих реквизитов в конфигураторе установлен признак «Заполнять из данных заполнения».
  2. Табличные части платформой автоматически из структуры не заполняются. Если в создаваемый документ необходимо перенести строки табличной части, потребуется обработать структуру ДанныеЗаполнения в процедуре ОбработкаЗаполнения модуля объекта.

Способ 4. Заполнение через получение формы и работу с данными формы

На форуме был предложен вариант ручной трансформации данных через методы ДанныеФормыВЗначение и ЗначениеВДанныеФормы. Разберем, как выглядит этот программный код и какие подводные камни он в себе таит.


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

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

Выясним причину, почему данный подход не рекомендуется использовать в современных конфигурациях:

  1. Метод ПолучитьФорму считается устаревшим в управляемом приложении. Основным методом открытия форм является ОткрытьФорму.
  2. Прямая перезапись реквизита Форма.Объект через КопироватьДанныеФормы не вызывает пользовательские события формы (например, ПриИзменении элементов). В типовых решениях из-за этого не пересчитываются суммы, ставки НДС, скидки и итоги по строкам.
  3. Событие формы ПриСозданииНаСервере срабатывает в момент выполнения ПолучитьФорму, когда табличные части еще пусты. Вся типовая логика инициализации элементов интерфейса отработает на пустом документе, что может привести к скрытым ошибкам интерфейса.

Реализация изменений в типовой конфигурации без снятия с поддержки

Если перед нами стоит задача доработать типовую конфигурацию (например, 1C:ERP, Комплексную автоматизацию или Управление торговлей) и объект нельзя менять в основной ветке конфигуратора, лучшим решением будет использование расширения конфигурации:

  1. Перехват события формы: добавляем форму документа в расширение и подключаем обработчик ПриСозданииНаСервере с аннотацией &После. В обработчике проверяем переданные параметры (например, Параметры.Свойство("ЗначениеКопирования")) и корректируем значения реквизитов.
  2. Перехват обработки заполнения: добавляем документ в расширение и переопределяем процедуру ОбработкаЗаполнения модуля объекта через директиву &После. В ней считываем дополнительно переданные параметры и модифицируем объект перед отображением формы.

Таким образом, для создания нового несохраненного документа наиболее правильным и чистым решением в 1С 8.3 является использование метода ОткрытьФорму с параметром ЗначениеКопирования или Основание, а любые дополнительные корректировки следует производить в серверных обработчиках открываемого объекта или его формы.

← На главную