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

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

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

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

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

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

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

Создание нового документа через объектную модель

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

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

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

НовыйДок.Организация = Организация;

НовыйДок.Контрагент = Контрагент;

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

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

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

Заполнение реквизитов шапки

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

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

КонтрагентСсылка = Справочники.Контрагенты.НайтиПоНаименованию(ИмяКонтрагента);

Если КонтрагентСсылка.Пустая() Тогда

ВызватьИсключение "Контрагент не найден: " + ИмяКонтрагента;

КонецЕсли;

НовыйДок.Контрагент = КонтрагентСсылка;

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

Заполнение табличной части

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

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

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

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

НоваяСтрока.Количество = СтрокаДанных.Количество;

НоваяСтрока.Цена = СтрокаДанных.Цена;

НоваяСтрока.Сумма = СтрокаДанных.Количество * СтрокаДанных.Цена;

КонецЦикла;

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

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

bsl
НовыйДок = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДатаСеанса();
НовыйДок.Организация = Организация;
НовыйДок.Контрагент = Контрагент;
СтрокаТовара = НовыйДок.Товары.Добавить();
СтрокаТовара.Номенклатура = Номенклатура;
СтрокаТовара.Количество = 10;
СтрокаТовара.Цена = 500;
СтрокаТовара.Сумма = 5000;
НовыйДок.Записать(РежимЗаписиДокумента.Проведение);

Поиск и изменение существующего документа

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

ДокСсылка = Документы.ЗаказПокупателя.НайтиПоНомеру(Номер, Дата);

Если Не ДокСсылка.Пустая() Тогда

ДокОбъект = ДокСсылка.ПолучитьОбъект();

ДокОбъект.Комментарий = "Изменён загрузкой";

ДокОбъект.Записать();

КонецЕсли;

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

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

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

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

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

Попытка

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

Исключение

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

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

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

НовыйДок.Записать(); // сохранить хотя бы без проведения

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

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

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

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

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

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

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

Ссылка пустая — запись не выполнена

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

Проведен = Истина при режиме проведения

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

Документ записан, но не проведён — искать причину в сообщениях об ошибках

Сумма и итоги
Норма

Итог по табличной части совпадает с данными источника

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

Расхождение сумм — ошибка в расчёте цен или НДС

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

Движения присутствуют и корректны по счетам/складам

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

Движений нет или они по неверным счетам

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

Самая частая ошибка — забыть записать объект или записать его до заполнения табличной части, получив пустой документ. Вторая по частоте — присвоение в ссылочный реквизит строки вместо ссылки, что вызывает ошибку несоответствия типов либо молча оставляет поле пустым в зависимости от контекста.

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

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

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

FAQ

Чем программное заполнение отличается от метода ВводНаОсновании?

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

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

Работа с ДокументОбъектом доступна только на сервере. В управляемых формах серверный вызов делается через процедуру с директивой &НаСервере или через серверный общий модуль. Попытка создать объект документа в клиентском контексте завершится ошибкой.

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

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

Что делать, если проведение программно созданного документа падает с ошибкой, а вручную тот же документ проводится?

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

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

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

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

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

Итог

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

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