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

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

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

Программное создание документа на основании в 1С: обработчики заполнения, заполнение по основанию, типовые механизмы БСП, примеры кода и типичные ошибки разработчиков.

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

Программное создание на основании нужно в обменах данными, обработках группового ввода документов, регламентных заданиях и интеграциях с внешними системами. Главная задача разработчика — не просто создать объект, а корректно перенести данные из документа-основания, заполнить обязательные реквизиты и не нарушить логику типовой конфигурации.

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

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

У каждого вида документа в конфигураторе есть свойство «Вводится на основании» — список документов, которые могут служить основанием. Это свойство влияет на интерфейс: именно по нему платформа формирует список в кнопке «Создать на основании» и проверяет допустимость вызова.

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

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

Базовый код: создание документа с вызовом Заполнить()

Минимальный сценарий создания реализации на основании заказа выглядит так:

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

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

НовыйДокумент.Заполнить(ЗаказСсылка); // ЗаказСсылка — ссылка на документ-основание

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

Метод Заполнить() серверный, поэтому код выполняется на сервере — в модуле менеджера, общем модуле с признаком «Сервер» или в серверной процедуре формы. Вызов с клиента потребует серверного вызова через &НаСервере-процедуру.

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

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

Обработчик ОбработкаЗаполнения: где описываются правила переноса

Правила переноса данных из основания описываются в модуле объекта документа, в обработчике ОбработкаЗаполнения. Типовая структура — ветвление по типу данных заполнения:

Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)

Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказКлиента") Тогда

Организация = ДанныеЗаполнения.Организация;

Контрагент = ДанныеЗаполнения.Контрагент;

Договор = ДанныеЗаполнения.Договор;

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

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

ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаЗаказа);

КонецЦикла;

КонецЕсли;

КонецПроцедуры

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

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

Ввод на основании в типовых конфигурациях на БСП

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

Чтобы документ появился в списке «Создать на основании», в модуле менеджера документа-основания описывается процедура вида:

Процедура ДобавитьКомандыСоздатьНаОсновании(КомандыСозданияНаОсновании, Параметры) Экспорт

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

КонецПроцедуры

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

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

Ручное заполнение без обработчика и заполнение структурой

Иногда обработчик использовать нельзя или нежелательно: например, обмен создаёт документ по данным внешней системы, а не по существующему документу базы. В этом случае реквизиты заполняются напрямую, а в Заполнить() передаётся структура:

Данные = Новый Структура;

Данные.Вставить("Организация", ОрганизацияСсылка);

Данные.Вставить("Контрагент", КонтрагентСсылка);

Данные.Вставить("Основание", ЗаказСсылка);

НовыйДокумент = Документы.СчетНаОплатуПокупателю.СоздатьДокумент();

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

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

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

В обработчике такая ветка проверяется через ТипЗнч(ДанныеЗаполнения) = Тип("Структура"). Это удобно, когда одному документу нужно несколько сценариев заполнения: по ссылке-основанию, по структуре параметров, по массиву оснований (например, одна реализация по нескольким заказам).

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

Сравнение вариантов

Заполнить(СсылкаОснования)

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

Заполнить(Структура)

Гибкий сценарий для обменов и нестандартных источников. Требует своей ветки в ОбработкаЗаполнения.

Ручное присваивание реквизитов

Полный контроль, но потеря типовой логики. Оправдано только в простых интеграциях с малым числом полей.

Копирование через Скопировать()

Создаёт копию того же вида документа. Не подходит для ввода другого вида документа на основании.

Проверка результата и типичные ошибки

После записи документа проверьте ключевые признаки корректности: заполнены ли обязательные реквизиты (организация, контрагент, договор, склад), перенеслась ли табличная часть целиком, сошлись ли суммы с основанием, провёлся ли документ без ошибок. Для программной проверки используйте метод ПроверитьЗаполнение() до записи — он вернёт Ложь и выведет сообщения, если обязательные поля пусты.

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

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

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

Обязательные реквизиты шапки
Норма

Организация, контрагент, договор заполнены

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

Поля пустые, при записи сообщения о незаполненности

Табличная часть
Норма

Число строк и суммы совпадают с основанием

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

Строк меньше, количество или цены обнулены

Проведение
Норма

Документ проведён, движения сформированы

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

Документ записан, но не проведён, движений нет

Связь с основанием
Норма

В документе есть ссылка на основание, он виден из основания по кнопке перехода

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

Связь не зафиксирована, критерий отбора не находит документ

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

Ограничения и когда привлекать разработчика

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

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

Итог

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

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

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

Почему документ создаётся пустым, хотя Заполнить(Основание) вызван?

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

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

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

Как создать документ на основании без проведения?

Вызовите Записать() с параметром РежимЗаписиДокумента.Запись вместо Проведение. Документ сохранится в базе без движений по регистрам, и пользователь сможет открыть его, проверить и провести вручную. Это безопасный вариант для обработок, где данные требуют визуального контроля.

Нужно ли заполнять реквизит «ДокументОснование» вручную?

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

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

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

Чем создание на основании отличается от копирования документа?

Копирование (метод Скопировать()) создаёт дубликат того же вида документа со всеми реквизитами. Ввод на основании создаёт документ другого вида и переносит только те данные, которые предусмотрены правилами заполнения. Для цепочки «заказ → реализация → счёт-фактура» используется именно ввод на основании.