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