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

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

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

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

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

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

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

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

Когда пользователь нажимает «Создать на основании», платформа создаёт новый объект документа и вызывает его обработчик ОбработкаЗаполнения, передавая туда ссылку на документ-основание в параметре ДанныеЗаполнения. Тот же обработчик вызывается и при программном создании, если основание передать явно. Это значит, что дублировать логику в форме и в модуле объекта не нужно — достаточно одного обработчика.

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

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

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

ЗаполнитьНаОснованииЗаказа(ДанныеЗаполнения);

КонецЕсли;

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

Пример: обработчик ОбработкаЗаполнения в модуле объекта

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

Процедура ЗаполнитьНаОснованииЗаказа(Основание) Экспорт

// Реквизиты шапки

Контрагент = Основание.Контрагент;

Договор = Основание.Договор;

Склад = Основание.Склад;

Организация = Основание.Организация;

ДокументОснование = Основание;

// Табличная часть

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

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

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

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

НоваяСтрока.Цена = СтрокаЗаказа.Цена;

НоваяСтрока.Сумма = СтрокаЗаказа.Сумма;

КонецЦикла;

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

Если реквизитов много и их состав периодически меняется, вместо построчного присваивания используют ЗаполнитьЗначенияСвойств(ЭтотОбъект, Основание) — метод переносит все одноимённые реквизиты автоматически. Но применять его нужно осторожно: перенесутся и служебные поля, которые в новом документе должны отличаться, поэтому после вызова обычно переопределяют дату, номер и статус.

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

Программное создание и заполнение документа из кода

Когда документ создаётся не пользователем, а кодом — например, в регламентном задании или обработке — последовательность такая: создать объект, вызвать у него метод Заполнить() с основанием, при необходимости дозаполнить реквизиты и записать. Метод Заполнить() внутри себя вызывает тот же обработчик ОбработкаЗаполнения, поэтому логика не дублируется:

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

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

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

// Дозаполнение специфичных реквизитов

НовыйДокумент.Комментарий = "Создано автоматически";

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

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

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

Заполнение через структуру параметров

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

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

Если ДанныеЗаполнения.Свойство("Контрагент") Тогда

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

КонецЕсли;

Если ДанныеЗаполнения.Свойство("МассивЗаказов") Тогда

Для Каждого Заказ Из ДанныеЗаполнения.МассивЗаказов Цикл

// перенос строк из каждого заказа

КонецЦикла;

КонецЕсли;

КонецЕсли;

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

Маршрут решения

Как выбрать подход

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

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

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

Попытка

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

Исключение

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

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

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

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

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

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

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

Метод Записать() отработал, ссылка получена

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

Исключение при записи, запись в журнале регистрации

Реквизиты шапки
Норма

Контрагент, договор, склад совпадают с основанием

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

Пустые или отличающиеся значения

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

Количество строк и итоговая сумма равны основанию

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

Строки потеряны или удвоены при повторном вызове Заполнить()

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

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

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

Документ записан, но не проведён из-за ошибок контроля

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

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

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

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

Часто задаваемые вопросы

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

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

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

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

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

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

Как доработать заполнение в типовой конфигурации без снятия с поддержки?

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

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

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

Итог

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

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