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