Как реализовать автоматическое копирование данных из одного документа в другой в 1С 8.3

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

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача автоматизации бизнес-процессов, когда на основании одного документа должен создаваться другой, заполненный данными из первого. Рассмотрим классический пример: в медицинском учреждении данные из документа Приемный покой должны автоматически попадать в документ Стационар при его проведении. Это позволяет избежать двойного ввода данных и минимизировать ошибки персонала.

В данной статье мы разберем несколько способов реализации этой задачи: от стандартных механизмов платформы до написания универсальных процедур на языке 1С.

Метод 1: Использование стандартного механизма «Ввод на основании»

Прежде чем приступать к написанию кода «с нуля», проанализируем штатные возможности платформы. Механизм «Ввод на основании» — это самый правильный и архитектурно чистый путь. Он позволяет связать документы в дерево подчиненности и автоматически генерирует обработчик заполнения.

Для реализации этого метода выполним следующие шаги:

  1. В конфигураторе откроем документ-приемник (например, Стационар).
  2. Перейдем на вкладку «Ввод на основании».
  3. В списке документов выберем документ-источник (ПриемныйПокой).
  4. Нажмем кнопку «Конструктор копирования». Платформа предложит сопоставить реквизиты. Если имена реквизитов совпадают, они подставятся автоматически.

После использования конструктора в модуле объекта документа-приемника появится предопределенная процедура ОбработкаЗаполнения. Рассмотрим, как она выглядит:


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

Метод 2: Универсальная процедура копирования через Метаданные

Бывают ситуации, когда количество реквизитов огромно или документы часто меняются. В этом случае писать вручную заполнение каждого поля неудобно. Проанализируем универсальный подход, который использует встроенную функцию ЗаполнитьЗначенияСвойств и обход коллекции Метаданные.

Этот код позволяет скопировать все совпадающие по именам реквизиты шапки и все строки табличных частей, если их имена в обоих документах идентичны:


Процедура КопироватьДанныеИзОдногоДокументаВДругой(ДокументИсточник, ДокументПриемник)
    // Копируем реквизиты шапки, исключая системные поля
    ЗаполнитьЗначенияСвойств(ДокументПриемник, ДокументИсточник, , "Номер, Дата, Проведен, ПометкаУдаления");
    
    МетаданныеИсточника = ДокументИсточник.Метаданные();
    МетаданныеПриемника = ДокументПриемник.Метаданные();
    
    // Перебираем все табличные части источника
    Для Каждого ТЧ Из МетаданныеИсточника.ТабличныеЧасти Цикл
        // Проверяем, есть ли ТЧ с таким же именем в приемнике
        Если МетаданныеПриемника.ТабличныеЧасти.Найти(ТЧ.Имя) <> Неопределено Тогда
            Для Каждого Стр Из ДокументИсточник[ТЧ.Имя] Цикл
                НоваяСтрока = ДокументПриемник[ТЧ.Имя].Добавить();
                ЗаполнитьЗначенияСвойств(НоваяСтрока, Стр);
            КонецЦикла;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Важный нюанс: при использовании ЗаполнитьЗначенияСвойств крайне важно помнить о типах данных. Если в одном документе Врач — это ссылка на справочник Сотрудники, а во втором — на справочник ФизическиеЛица, прямое копирование не произойдет, так как типы не совпадают.

Метод 3: Автоматическое создание документа при проведении

Теперь выясним, как сделать так, чтобы при нажатии кнопки «Провести и закрыть» в Приемном покое документ Стационар создавался сам. Для этого нам понадобится обработчик события ОбработкаПроведения или Подписка на событие.

Рассмотрим пример кода в модуле документа-источника:


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

Рекомендации и лучшие практики

Проанализируем несколько важных моментов, которые помогут сделать ваш код более надежным:

Выяснив причину сложности копирования, мы понимаем, что универсального кода на 100% не существует из-за различий в структуре метаданных, но комбинация метода ЗаполнитьЗначенияСвойств и ручной доработки исключений дает наилучший результат.

← На главную