Как программно создать документ на основании другого документа в 1С?

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

В процессе разработки в системе «1С:Предприятие 8» часто возникает необходимость автоматизировать создание одних документов на базе других. Это может быть создание «Списания с расчетного счета» на основании «Платежного поручения» или «Приходного кассового ордера» на основании «Реализации». Несмотря на кажущуюся простоту, начинающие разработчики часто сталкиваются с тем, что создаваемый документ остается пустым или механизмы автоматического заполнения не срабатывают. В этой статье мы подробно разберем, как правильно реализовать программный ввод на основании, проанализируем типичные ошибки и рассмотрим различные подходы в зависимости от контекста задачи. Для пакетного формирования документов можно использовать готовые инструменты, например для загрузки отчётов о продажах маркетплейсов в БП 3 из Excel.

Разбор основной проблемы: Объект против Ссылки

Рассмотрим стандартную ситуацию, с которой сталкиваются многие программисты. При попытке создать документ программно часто используется следующий код:


// Ошибочный или неполный подход
Док = Документы.ПлатежноеПоручение.СоздатьДокумент();
// ... заполнение и запись Док ...
НовыйДокументСписания = Документы.СписаниеСРасчетногоСчета.СоздатьДокумент();
НовыйДокументСписания.Заполнить(Док); 

Выясним причину, почему в данном случае НовыйДокументСписания может оказаться пустым. Основная ошибка заключается в передаче самого объекта (переменная Док), находящегося в оперативной памяти, в метод Заполнить(). Для корректной работы стандартного механизма 1С методу Заполнить() требуется именно ссылка на документ-основание.

Правильный алгоритм действий выглядит так: сначала мы записываем документ-источник, чтобы получить его ссылку в базе данных, а затем передаем эту ссылку в метод заполнения создаваемого объекта.


// Корректный программный ввод на основании
Док = Документы.ПлатежноеПоручение.СоздатьДокумент();
// Заполняем реквизиты...
Док.Записать(); // Теперь у документа есть Ссылка

НовыйДокументСписания = Документы.СписаниеСРасчетногоСчета.СоздатьДокумент();
// Передаем именно Ссылку!
НовыйДокументСписания.Заполнить(Док.Ссылка); 

Как работает обработчик «ОбработкаЗаполнения»

Когда мы вызываем метод Заполнить(Основание), платформа 1С неявно обращается к предопределенной процедуре ОбработкаЗаполнения, расположенной в модуле объекта создаваемого документа. Проанализируем структуру этого обработчика:


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

Важно понимать следующие моменты:

  1. Параметр ДанныеЗаполнения: Это именно то значение, которое вы передали в метод Заполнить(). Если вы передали объект, а обработчик ожидает ссылку (через проверку ТипЗнч), то код заполнения просто пропустится.
  2. СтандартнаяОбработка: Если в конфигураторе настроены связи «Ввод на основании», платформа может попытаться заполнить реквизиты автоматически по совпадающим именам. Установка СтандартнаяОбработка = Ложь отключает этот механизм, позволяя полностью контролировать процесс программно.
  3. Контекст: Метод Заполнить() и процедура ОбработкаЗаполнения всегда выполняются на стороне сервера.

Интерактивное создание: Открытие формы с заполнением

Часто бизнес-процесс требует, чтобы документ не просто создавался «тихо» в фоне, а открывался пользователю для проверки и дальнейшего редактирования. В современных управляемых формах 1С (платформа 8.3) это делается через передачу параметра Основание в форму документа.

Разберем, как это реализовать. Нам не нужно вручную создавать объект через СоздатьДокумент(), достаточно вызвать ОткрытьФорму():


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

В этом случае платформа сама создаст новый объект в памяти, вызовет для него ОбработкаЗаполнения, передав туда СсылкаНаИсточник, и покажет готовую форму пользователю. Этот способ считается более «чистым», так как пользователю не нужно искать только что созданный программно документ — он сразу видит его на экране.

Программное создание с немедленной записью

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


ПКО = Документы.ПриходныйКассовыйОрдер.СоздатьДокумент();
ПКО.Дата = ТекущаяДата();
// Заполняем на основании документа-источника
ПКО.Заполнить(ДокументОснование); 
// Сразу записываем и проводим
ПКО.Записать(РежимЗаписиДокумента.Проведение);

Важное примечание: Если вы создаете цепочку документов, убедитесь, что в новом документе заполняется реквизит, хранящий ссылку на документ-основание (например, реквизит ДокументОснование). Это необходимо для работы критериев отбора, таких как «Связанные документы». Платформа не заполняет эту связь автоматически при программном вызове, если это не прописано в ОбработкаЗаполнения.

Использование структур для гибкого заполнения

Иногда нужно заполнить новый документ данными, которые не хранятся в одном конкретном документе-основании, а собраны из разных мест. Метод Заполнить() позволяет передавать не только ссылку, но и Структуру.

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


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

НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Заполнить(ДанныеДляЗаполнения);

Чтобы это сработало, в модуле объекта «РеализацияТоваровУслуг» в процедуре ОбработкаЗаполнения должна быть предусмотрена обработка структуры:


Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") Тогда
    ЗаполнитьЗначенияСвойств(ЭтотОбъект, ДанныеЗаполнения);
КонецЕсли;

Различия между Заполнить() и ЗаполнитьЗначенияСвойств()

Часто возникает вопрос: в чем разница между ДокументОбъект.Заполнить(Источник) и функцией ЗаполнитьЗначенияСвойств(ДокументОбъект, Источник)? Разберем по шагам:

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

Резюме и рекомендации

Проанализировав различные подходы, можно составить итоговый чек-лист для правильного программного ввода на основании:

  1. Всегда записывайте документ-основание перед вызовом Заполнить(), чтобы получить валидную ссылку.
  2. Передавайте в метод Заполнить() ссылку (Источник.Ссылка), а не объект (Источник).
  3. Если нужно просто показать форму пользователю — используйте ОткрытьФорму с параметром «Основание».
  4. Помните, что логика заполнения табличных частей должна быть явно прописана в модуле объекта в процедуре ОбработкаЗаполнения.
  5. Проверяйте типы данных в обработчике заполнения, чтобы ваш код был универсальным и поддерживал ввод как на основании документов, так и на основании структур или справочников.

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

← На главную