К статье
Практический материал

Разработка и Конфигурация · 14 мин

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

Как программно создать документ на основании другого в 1С: метод ВвестиНаОсновании, процедура ОбработкаЗаполнения, параметры основания, примеры кода и типичные ошибки.

Ввод документа на основании — один из базовых механизмов 1С: счёт превращается в реализацию, заказ покупателя — в отгрузку, а накладная поставщика — в приходный ордер. Когда цепочка документов создаётся вручную, платформа делает всё сама, но в обработках, обменах и фоновых заданиях документ приходится создавать программно. Для этого есть два пути: типовой механизм «ВвестиНаОсновании» с процедурой «ОбработкаЗаполнения» и ручное заполнение реквизитов нового объекта.

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

В статье разобраны оба подхода, приведены рабочие примеры кода для управляемого приложения, показано, как проверить результат записи, и перечислены ошибки, из-за которых документ либо не создаётся, либо создаётся с некорректными данными.

Как устроен механизм ввода на основании в 1С

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

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

Дополнительно в конфигураторе у документа настраиваются свойства «Вводится на основании» и «Является основанием для». Эти настройки влияют на интерфейс (команды ввода на основании в формах) и на построение структуры подчинённости, но программное создание документа возможно и без них — связь фиксируется реквизитом основания, если он предусмотрен в метаданных.

Способ 1. Создание через Заполнить() — типовой механизм

Это основной и рекомендуемый способ, когда основание и создаваемый документ связаны типовой логикой. Последовательность такая: создаётся новый объект документа, вызывается метод «Заполнить» с передачей ссылки на основание, затем объект записывается.

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

НовыйДокумент.Дата = ТекущаяДатаСеанса();

НовыйДокумент.Заполнить(СчетНаОплатуСсылка);

НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение,

РежимПроведенияДокумента.Оперативный);

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

Обратите внимание на дату документа: её лучше установить до вызова «Заполнить», потому что логика заполнения может зависеть от даты — например, курс валюты, действующий договор или цены подбираются на дату документа. Если дату установить после заполнения, часть реквизитов может оказаться рассчитанной на неверный момент времени.

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

Способ 2. Ручное заполнение реквизитов нового документа

Ручное заполнение применяется, когда типовая связь между документами отсутствует, когда документ создаётся из нескольких оснований либо когда данные приходят из внешнего источника — файла, HTTP-сервиса, очереди сообщений. В этом случае разработчик сам переносит каждое поле.

НовыйДокумент = Документы.ПеремещениеТоваров.СоздатьДокумент();

НовыйДокумент.Дата = ТекущаяДатаСеанса();

НовыйДокумент.Организация = Основание.Организация;

НовыйДокумент.СкладОтправитель = Основание.Склад;

Для Каждого СтрокаТовара Из Основание.Товары Цикл

НоваяСтрока = НовыйДокумент.Товары.Добавить();

НоваяСтрока.Номенклатура = СтрокаТовара.Номенклатура;

НоваяСтрока.Количество = СтрокаТовара.Количество;

КонецЦикла;

НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение);

Главный риск этого подхода — пропустить обязательные реквизиты, которые при интерактивном вводе заполняются автоматически: ответственный, валюта, вид цен, ставки НДС, признаки учёта. При записи такой документ может не пройти проверку заполнения, а при проведении — сформировать неполные движения. Поэтому после ручного переноса основных полей полезно вызывать типовые процедуры заполнения значений по умолчанию, если они вынесены в общие модули конфигурации.

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

Сравнение подходов

Заполнить(Основание)

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

Ручное заполнение

Подходит для нестандартных связей, нескольких оснований и внешних данных. Полный контроль, но вся ответственность за обязательные реквизиты и корректность сумм лежит на разработчике.

Запись, проведение и работа в транзакции

Метод «Записать» принимает режим записи: простая запись, проведение или отмена проведения. Для документов, формирующих движения, обычно сразу выполняется проведение, но безопаснее сначала записать документ, проверить корректность, и только потом проводить — особенно при массовом создании документов в обработках.

Если документ создаётся в цикле по множеству оснований, каждую итерацию стоит оборачивать в попытку с обработкой исключения: ошибка в одном документе не должна прерывать всю обработку. А если бизнес-логика требует, чтобы связка «основание — подчинённый документ» существовала только целиком, обе записи помещаются в транзакцию через «НачатьТранзакцию» и «ЗафиксироватьТранзакцию».

Попытка

НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение);

Исключение

ЗаписьЖурналаРегистрации("СозданиеДокументов",

УровеньЖурналаРегистрации.Ошибка,,,

ОписаниеОшибки());

КонецПопытки;

Как проверить, что документ создан корректно

Первый признак успеха — метод «Записать» отработал без исключения, а у объекта появилась ссылка: «НовыйДокумент.Ссылка» перестала быть пустой. Но отсутствие ошибки не гарантирует корректность данных, поэтому результат нужно проверять содержательно.

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

Также полезно проверить структуру подчинённости: откройте основание в интерфейсе и убедитесь, что созданный документ виден в цепочке связанных документов. Если документ там не отображается, скорее всего, не заполнен реквизит основания в новом документе — типовая «ОбработкаЗаполнения» обычно заполняет его сама, а при ручном заполнении это нужно сделать явно.

Контрольные точки

Как проверить результат

Ссылка на новый документ
Норма

Ссылка не пустая, документ открывается в интерфейсе

Тревожный признак

Ссылка пустая — запись не выполнена, смотрите журнал регистрации

Суммы и количества
Норма

Совпадают с эталонным документом, введённым вручную из того же основания

Тревожный признак

Расхождения — не перенесена часть строк или не рассчитаны суммы/НДС

Движения по регистрам
Норма

Наборы записей совпадают с эталоном по составу и итогам

Тревожный признак

Движений нет или они неполные — не заполнены обязательные для проведения реквизиты

Структура подчинённости
Норма

Документ виден в цепочке от основания

Тревожный признак

Документа в цепочке нет — не заполнен реквизит основания

Типичные ошибки и ограничения

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

Вторая группа ошибок связана с правами и контекстом выполнения. Если код выполняется в фоновом задании или на сервере под другим пользователем, у учётной записи может не быть прав на создание документа данного вида — запись завершится ошибкой доступа. Также в фоновом задании недоступен ряд интерактивных механизмов: если «ОбработкаЗаполнения» вызывает диалоги или обращается к клиентскому контексту, код завершится с ошибкой.

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

Типичные ошибки
01
Вызов Заполнить() у существующего документа — табличные части задваиваются, потому что строки добавляются поверх имеющихся.
02
Установка даты после заполнения — курсы, цены и договор подбираются на неверную дату.
03
Игнорирование исключений при записи в цикле — часть документов не создаётся, а обработка отчитывается об успехе.
04
Ручное заполнение без реквизита основания — документ не попадает в структуру подчинённости, связь теряется.
05
Запуск массового создания на рабочей базе без теста на копии — массовые некорректные проводки, которые трудно откатить.

Создание документа из нескольких оснований и из внешних данных

Когда один документ должен объединить данные нескольких оснований, стандартный приём — передать в «Заполнить» структуру с массивом ссылок, предварительно доработав «ОбработкуЗаполнения» через расширение конфигурации. В обработчике проверяется тип «ДанныеЗаполнения»: если это структура с массивом, выполняется цикл по основаниям с агрегацией табличных частей и сворачиванием одинаковых позиций номенклатуры.

Для данных из внешних систем (файлы обмена, веб-сервисы, очереди брокеров сообщений) основания в базе может вообще не существовать. Тогда документ заполняется полностью вручную, а связь с внешним источником фиксируется в дополнительном реквизите или регистре соответствия — это позволит при повторной загрузке найти и обновить документ вместо создания дубля.

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

Что важно запомнить

Для типовых связей используйте СоздатьДокумент() + Заполнить(Основание) + Записать() — это задействует штатную ОбработкуЗаполнения. Для нестандартных сценариев заполняйте реквизиты вручную, не забывая обязательные поля и реквизит основания. Всегда обрабатывайте исключения при записи, тестируйте на копии базы и сверяйте результат с документом, введённым вручную.

Частые вопросы

Чем отличается Заполнить() от простого присваивания реквизитов?

Метод «Заполнить» вызывает процедуру «ОбработкаЗаполнения» в модуле объекта, то есть выполняет всю логику, заложенную разработчиками конфигурации: перенос шапки и табличных частей, подстановку значений по умолчанию, расчёт сумм. Ручное присваивание переносит только те поля, которые вы указали явно, и не запускает никаких дополнительных проверок и расчётов.

Можно ли создать документ на основании, если связь не настроена в конфигураторе?

Да, программно это возможно: создайте объект и заполните его реквизиты вручную. Но документ не появится в структуре подчинённости, если в метаданных не предусмотрен реквизит основания или не настроены свойства ввода на основании. Для полноценной связи потребуется доработка конфигурации или расширение.

Почему при записи возникает ошибка о незаполненных реквизитах?

При записи платформа вызывает обработку проверки заполнения, которая проверяет обязательные поля. Если типовая логика не заполнила какой-то реквизит (например, у основания он был пуст), запись отклоняется. Решение — заполнить недостающие поля в коде до вызова «Записать» или проанализировать текст исключения, где перечислены незаполненные поля.

Как создать документ в фоновом задании или на сервере?

Код создания документа тот же, но нужно учитывать контекст: на сервере и в фоновом задании недоступны интерактивные вызовы, а права могут отличаться от прав пользователя, запустившего обработку. Убедитесь, что у служебной учётной записи есть права на добавление и проведение документа, и что «ОбработкаЗаполнения» не содержит клиентских вызовов.

Как обновить ранее созданный документ при повторной загрузке данных?

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

Нужно ли проводить документ сразу при создании?

Не обязательно. Можно записать документ без проведения, а провести позже — отдельной обработкой или после проверки. Такой подход безопаснее при массовом создании: сначала вы контролируете корректность данных, и только затем документы формируют движения по регистрам.