Разработка и Конфигурация · 11 мин
Как программно создать новый документ в 1С
Как программно создать документ в 1С: Документы.Менеджер, СоздатьДокумент, заполнение табличных частей, запись и проведение. Примеры кода и типичные ошибки.
Программное создание документов — базовая операция при разработке на платформе 1С:Предприятие. Она нужна при обмене данными, загрузке выписок, генерации первички из внешних систем и автоматизации рутинных операций. Вся работа строится вокруг менеджера документа, метода СоздатьДокумент(), заполнения реквизитов и последующей записи объекта.
Главное, что нужно понять сразу: пока вы не вызвали метод Записать(), документа в базе не существует. Объект живёт только в памяти, и любая ошибка на этапе заполнения не оставляет «мусора» в данных. Это даёт безопасную зону для экспериментов — но требует аккуратности на этапе записи и проведения.
Ниже разобран полный цикл: от получения объекта до проведения, включая заполнение табличных частей, работу в транзакциях, поиск дублей и типичные ошибки, которые приводят к битым данным.
Базовый код создания документа
Минимальный рабочий пример выглядит так: получаем объект через менеджер документа, заполняем обязательные реквизиты и записываем.
НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДатаСеанса();
НовыйДок.Организация = Организация;
НовыйДок.Контрагент = Контрагент;
НовыйДок.Договор = Договор;
НовыйДок.Записать(РежимЗаписиДокумента.Запись);
Метод СоздатьДокумент() возвращает объект типа ДокументОбъект — это полноценный объект со всеми реквизитами, табличными частями и обработчиками событий. Дата документа по умолчанию обычно пустая или равна текущей в зависимости от настроек, поэтому её лучше задавать явно. Номер присваивается автоматически при записи, если у документа включена автонумерация.
Обратите внимание: присваивать реквизитам нужно ссылки на существующие объекты, а не строки с наименованиями. Если контрагент или организация ещё не созданы, их нужно сначала создать или найти в базе.
Заполнение табличной части
Большинство документов бесполезны без строк. Табличная часть у объекта документа — это коллекция, в которую строки добавляются методом Добавить().
Для Каждого Позиция Из ДанныеТоваров Цикл
НоваяСтрока = НовыйДок.Товары.Добавить();
НоваяСтрока.Номенклатура = Позиция.Номенклатура;
НоваяСтрока.Количество = Позиция.Количество;
НоваяСтрока.Цена = Позиция.Цена;
НоваяСтрока.Сумма = Позиция.Количество * Позиция.Цена;
КонецЦикла;
Если в конфигурации есть обработчики вида «ПриИзменении» на полях табличной части, при программном заполнении они отрабатывают не всегда так, как при ручном вводе. Например, автоматический пересчёт суммы, подбор ставки НДС или подстановка счетов учёта могут не сработать. Поэтому расчётные поля надёжнее заполнять явно в коде или вызывать экспортные процедуры пересчёта, если они предусмотрены конфигурацией.
Перед записью имеет смысл проверить, что табличная часть не пуста, если документ без строк не имеет смысла: Если НовыйДок.Товары.Количество() = 0 Тогда .... Это простая защита от создания пустых документов при сбоях во входных данных.
Запись и проведение: выбор режима
Метод Записать() принимает параметр — режим записи. От него зависит, попадёт ли документ в регистры и какие проверки выполнит система.
| Режим | Что происходит | Когда применять |
|---|---|---|
| РежимЗаписиДокумента.Запись | Документ сохраняется без проведения, движений нет | Черновики, документы для ручной проверки |
| РежимЗаписиДокумента.Проведение | Документ записывается и проводится, формируются движения | Автоматическая загрузка проверенных данных |
| РежимЗаписиДокумента.ОтменаПроведения | Снимает документ с проведения | Исправление ошибок, откат загрузки |
НовыйДок.Записать(РежимЗаписиДокумента.Проведение);
Проведение выполняет контроль остатков, корректности счетов и другие проверки, заложенные в конфигурации. Если проверка не пройдена, вызывается исключение, и документ либо не записывается, либо остаётся непроведённым — поведение зависит от того, обёрнут ли вызов в попытку. Поэтому программное проведение всегда стоит оборачивать в конструкцию Попытка ... Исключение с записью ошибки в журнал регистрации.
Работа в транзакции и обработка ошибок
При создании нескольких связанных документов (например, заказ и реализация на его основании) логично объединять запись в транзакцию: либо создаются все документы, либо ни одного.
НачатьТранзакцию();
Попытка
НовыйДок.Записать(РежимЗаписиДокумента.Проведение);
// создание связанных документов
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("Создание документов",
УровеньЖурналаРегистрации.Ошибка, , ,
ОписаниеОшибки());
ВызватьИсключение;
КонецПопытки;
Без транзакции сбой на середине цикла оставит часть документов записанными, а часть — нет, и восстановить картину будет сложно. Внутри транзакции избегайте длительных операций и интерактивных вызовов — они блокируют данные и мешают другим пользователям.
- 1Получите объект: Документы.ИмяДокумента.СоздатьДокумент()
- 2Установите дату и обязательные реквизиты ссылками на существующие объекты
- 3Заполните табличные части через Добавить() в цикле
- 4Проверьте заполненность критичных полей и строк
- 5Запишите с режимом Запись или Проведение внутри Попытка/Исключение
- 6Проверьте результат: откройте документ и его движения в копии базы
Как избежать дублей при повторном запуске
Классическая проблема загрузок: код запустили дважды — и в базе появились два одинаковых документа. Защита строится на поиске ранее созданного документа по уникальному признаку: номеру и дате входящего документа, внешнему идентификатору из системы-источника или специально добавленному реквизиту.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1 Док.Ссылка
|ИЗ Документ.ПоступлениеТоваровУслуг КАК Док
|ГДЕ Док.НомерВходящегоДокумента = &Номер
|И Док.ДатаВходящегоДокумента = &Дата";
Запрос.УстановитьПараметр("Номер", НомерВходящего);
Запрос.УстановитьПараметр("Дата", ДатаВходящего);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
Иначе
ДокОбъект = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
КонецЕсли;
Такой подход делает загрузку идемпотентной: повторный запуск обновляет существующий документ, а не плодит копии. Если перезаписывать найденный документ нельзя (он проведён и участвует в учёте), добавьте проверку ДокОбъект.Проведен и решите явно: пропустить, отменить проведение или зафиксировать конфликт.
Создание документа на основании другого
Если документ должен быть связан с исходным (реализация на основании заказа), используйте свойство Основание или специальные реквизиты связи, предусмотренные конфигурацией. В типовых решениях часто есть процедуры вида Заполнить(ДокументОснование) в модуле объекта — вызовите её после создания:
НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДатаСеанса();
НовыйДок.Заполнить(ЗаказСсылка);
НовыйДок.Записать(РежимЗаписиДокумента.Проведение);
Метод Заполнить() вызывает обработчик заполнения объекта, который в типовой конфигурации переносит реквизиты и табличные части из основания. Это надёжнее ручного копирования полей: при обновлении конфигурации логика заполнения обновится централизованно. Проверьте в модуле объекта, какие типы оснований поддерживает обработчик — передача неподдерживаемого типа может оставить документ пустым.
Сравнение вариантов
Полный контроль над каждым полем, подходит для загрузки из внешних источников. Минус — нужно самостоятельно следить за расчётными полями
Использует штатную логику конфигурации, быстро и устойчиво к обновлениям. Ограничение — работает только для поддерживаемых типов оснований
Создаёт объект-копию существующего документа. Подходит для шаблонных документов, но требует очистки специфичных полей
Проверка результата
После отработки кода убедитесь, что документ реально создан и корректен. Минимальный набор проверок: документ открывается в списке, реквизиты и табличные части заполнены, при проведении сформированы движения по ожидаемым регистрам (кнопка «Движения документа» в форме), суммы совпадают с исходными данными.
Для массовой загрузки полезно собрать статистику: сколько документов создано, сколько пропущено как дубли, сколько завершилось ошибкой. Выведите эти данные в сообщения или файл протокола — это позволит быстро оценить качество загрузки, не перебирая документы вручную.
Как проверить результат
Отображается с корректным номером и датой
Документа нет — вероятно, не был вызван Записать()
Есть записи по ожидаемым регистрам с правильными суммами
Движений нет при проведённом документе или суммы нулевые
Все строки на месте, итоги сходятся с источником
Часть строк потеряна или суммы не пересчитаны
Что важно запомнить
Создание документа — это цепочка СоздатьДокумент() → заполнение реквизитов и табличных частей → Записать() с нужным режимом. Проведение оборачивайте в Попытка/Исключение, массовые операции — в транзакцию, а повторные запуски защищайте поиском дублей. Сначала тестируйте на копии базы.
Частые вопросы
Как создать документ с заданным номером?
После вызова СоздатьДокумент() присвойте свойству Номер нужное значение до записи. Учтите, что при включённой автонумерации система может перезаписать номер при записи — в типовых конфигурациях ручной номер обычно сохраняется, но поведение зависит от настроек нумерации и префиксации. Проверяйте уникальность номера в пределах периода нумерации.
Можно ли создать документ на клиенте без вызова сервера?
Нет. СоздатьДокумент() и Записать() — серверные методы. В управляемом приложении создайте серверную процедуру с директивой &НаСервере в модуле формы или используйте общий серверный модуль, а с клиента только вызывайте её.
Почему документ записывается, но не проводится, и ошибки нет?
Чаще всего в обработчике проведения или контроле остатков срабатывает отказ, а исключение перехватывается вашей же конструкцией Попытка/Исключение без вывода текста. Временно выведите ОписаниеОшибки() в сообщение или журнал регистрации — там будет конкретная причина: нехватка остатков, незаполненный счёт учёта или закрытый период.
Как создать документ задним числом, если период закрыт?
При включённой дате запрета изменения данных запись вызовет ошибку. Варианты: временно изменить дату запрета для служебного пользователя, выполняющего загрузку, или использовать привилегированный режим (УстановитьПривилегированныйРежим(Истина)) — он обходит проверки прав, но не отменяет логику контроля в обработчиках проведения. Любой обход должен быть осознанным и задокументированным.
Чем СоздатьДокумент() отличается от Скопировать()?
СоздатьДокумент() возвращает пустой объект с пустыми реквизитами и табличными частями. Метод Скопировать() у существующего объекта создаёт новый документ с полностью скопированным содержимым — удобно для повторяющихся документов, но требует очистки полей, которые не должны дублироваться: даты, номеров входящих документов, ссылок на основания.
Как заполнить реквизит составного типа?
Присвойте ссылку конкретного допустимого типа — система сама определит тип значения. Если нужно ограничить выбор, проверяйте тип присваиваемого значения через ТипЗнч() до записи. Присвоение значения неподдерживаемого типа вызовет ошибку преобразования.