Разработка и Конфигурация · 12 мин
Как создать документ из обработки в 1С
Как программно создать документ из внешней обработки в 1С: код на встроенном языке, заполнение табличных частей, проведение, типичные ошибки и проверка результата.
Создание документов из внешней обработки — одна из самых частых задач при автоматизации 1С: загрузка данных из Excel, массовое формирование реализаций, перенос документов между базами. Всё это делается программно через объектную модель встроенного языка, без ручного ввода данных пользователем.
Логика работы одинакова для любого вида документа: получить менеджер документа, создать новый объект, заполнить реквизиты и табличные части, записать. Различия возникают только в составе реквизитов конкретной конфигурации и в том, нужно ли проводить документ или достаточно простой записи.
Ниже разобран рабочий порядок действий для управляемых и обычных форм, приведён готовый код, показано, как заполнять табличные части, проводить документ, обрабатывать ошибки и проверять результат. Примеры ориентированы на типовые конфигурации (УТ, ERP, БП), но подход универсален.
Подготовка: где писать код и что нужно знать о конфигурации
Перед написанием обработки откройте конфигуратор и выясните точное имя документа в метаданных — оно не всегда совпадает с представлением в интерфейсе. Например, «Реализация (акты, накладные)» в БП 3.0 — это документ с именем РеализацияТоваровУслуг. Также выпишите имена ключевых реквизитов: Организация, Контрагент, Склад, Договор и состав табличных частей (Товары, Услуги).
Код создания документа должен выполняться на сервере. В управляемом приложении внешняя обработка по умолчанию работает на клиенте, поэтому процедуру создания документа размещают в модуле объекта обработки или вызывают через серверный метод общего модуля. Директива &НаСервере в модуле формы тоже подходит, если обработка открывается интерактивно.
Убедитесь, что у пользователя, под которым будет работать обработка, есть права на добавление и проведение нужного вида документов, а также на чтение связанных справочников (контрагенты, номенклатура, склады). Недостаток прав — одна из самых частых причин «неработающего» кода.
Базовый код создания документа
Минимальный сценарий состоит из четырёх шагов: создать объект, заполнить шапку, записать, проверить. Вот рабочий пример для документа «Реализация товаров и услуг»:
НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДатаСеанса();
НовыйДок.Организация = Организация;
НовыйДок.Контрагент = Контрагент;
НовыйДок.Склад = Склад;
НовыйДок.Валюта = ВалютаРегламентированногоУчета();
НовыйДок.Записать(РежимЗаписиДокумента.Запись);
Метод СоздатьДокумент() возвращает объект типа ДокументОбъект, который существует только в памяти до вызова Записать(). Если не вызвать запись — документ в базе не появится. Дату лучше устанавливать явно: иначе документ получит текущую дату сеанса, что при загрузке исторических данных приведёт к неправильным периодам.
Обратите внимание: присваивать реквизитам нужно ссылки на объекты базы, а не строки. Если исходные данные содержат только наименование контрагента или номенклатуры, сначала найдите ссылку запросом или методом НайтиПоНаименованию(), а при отсутствии — создайте элемент справочника.
НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДатаСеанса();
НовыйДок.Организация = Организация;
НовыйДок.Контрагент = Контрагент;
НовыйДок.Записать(РежимЗаписиДокумента.Запись);Заполнение табличных частей
Табличная часть заполняется в цикле: для каждой строки вызывается Добавить(), после чего заполняются поля строки. Пример для табличной части «Товары»:
Для Каждого СтрокаДанных Из ТаблицаЗагрузки Цикл
НоваяСтрока = НовыйДок.Товары.Добавить();
НоваяСтрока.Номенклатура = СтрокаДанных.Номенклатура;
НоваяСтрока.Количество = СтрокаДанных.Количество;
НоваяСтрока.Цена = СтрокаДанных.Цена;
НоваяСтрока.Сумма = СтрокаДанных.Количество * СтрокаДанных.Цена;
КонецЦикла;
В типовых конфигурациях табличные части содержат больше полей, чем видно в простом примере: ставка НДС, сумма НДС, счета учёта, единица измерения, коэффициент. Часть из них заполняется автоматически обработчиками при интерактивном вводе, но при программном создании эти обработчики не срабатывают. Поэтому либо заполняйте поля явно, либо вызывайте экспортные процедуры заполнения из модулей конфигурации, если они доступны.
Практичный приём: создайте один документ вручную в интерфейсе, заполнив все нужные поля, затем выгрузите его структуру (например, через консоль кода или отладчик) и посмотрите, какие значения реально записаны в реквизиты. Это покажет полный список полей, которые должна заполнить обработка.
Запись и проведение документа
Метод Записать() принимает режим записи. Основные варианты: РежимЗаписиДокумента.Запись — просто сохранить без движений; РежимЗаписиДокумента.Проведение — записать и провести; РежимЗаписиДокумента.ОтменаПроведения — распровести. Для проведения часто добавляют режим РежимПроведенияДокумента.Неоперативный, если документ создаётся «задним числом»:
НовыйДок.Записать(РежимЗаписиДокумента.Проведение,
РежимПроведенияДокумента.Неоперативный);
Если проведение не удалось (не хватает остатков, закрыт период, не заполнен обязательный реквизит), платформа вызовет исключение. Без обработки ошибок обработка прервётся, а пользователь увидит техническое сообщение. Поэтому массовое создание документов всегда оборачивают в попытку и транзакцию:
НачатьТранзакцию();
Попытка
// создание и проведение документов
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка: " + ОписаниеОшибки());
КонецПопытки;
Альтернативный подход при массовой загрузке — сначала записать все документы без проведения, вывести пользователю список, и только затем проводить пакетно с отчётом по каждому документу. Так проще локализовать проблемные строки.
Как выбрать режим записи
Заполнение на основании существующего документа
Часто из обработки нужно создать документ не «с нуля», а на основании другого — например, реализацию на основании заказа покупателя. Для этого у нового объекта вызывается метод Заполнить() с параметром-основанием:
НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДатаСеанса();
НовыйДок.Заполнить(ЗаказСсылка);
НовыйДок.Записать(РежимЗаписиДокумента.Проведение);
Метод Заполнить() вызывает обработчик ОбработкаЗаполнения модуля документа, который в типовых конфигурациях умеет копировать данные из документа-основания. Это надёжнее ручного переноса реквизитов: задействуется штатная логика конфигурации, включая заполнение договоров, соглашений и табличных частей.
Ограничение: заполнение сработает только если в конфигурации предусмотрен ввод на основании для этой пары документов. Проверить это можно в конфигураторе — свойство «Вводится на основании» у документа, либо просто попробовав создать документ на основании в интерфейсе.
Если обработка массово создаёт документы на основании заказов, проверяйте, не создан ли документ по этому основанию ранее — ищите существующие документы по реквизиту основания запросом. Иначе при повторном запуске получите дубли реализаций.
Особенности управляемого приложения и безопасного режима
В тонком клиенте внешняя обработка открывается на клиенте, а код СоздатьДокумент() доступен только на сервере. Типовая схема: на форме обработки кнопка вызывает клиентскую процедуру, которая обращается к серверной процедуре, а та уже создаёт документы. Данные для заполнения (например, таблица из Excel) передаются на сервер через параметры или временное хранилище.
Если конфигурация работает в модели сервиса или включён безопасный режим, выполнение внешних обработок может быть ограничено. В этом случае код создания документов переносят в расширение конфигурации или дополнительную обработку через механизм БСП «Дополнительные отчеты и обработки» — там доступ к объектам разрешён штатно.
Для фонового создания большого количества документов используйте длительные операции (в БСП — ДлительныеОперации.ВыполнитьВФоне) или фоновые задания. Это не заблокирует сеанс пользователя и позволит показать прогресс выполнения.
Проверка результата и поиск проблем
После выполнения обработки проверьте три вещи: документы физически появились в журнале, они проведены (если требовалось) и движения по регистрам корректны. Быстрый способ — открыть журнал документов с отбором по дате и автору, затем открыть несколько документов и посмотреть «Движения документа».
Полезно сразу в обработке формировать отчёт о результатах: для каждой строки исходных данных фиксировать ссылку на созданный документ, статус (создан / проведён / ошибка) и текст ошибки. Это избавляет от ручного сопоставления «что загрузилось, а что нет».
Как проверить результат
Присутствует, номер и дата корректны
Документа нет или дата отличается от исходных данных
Проведён, движения по регистрам сформированы
Не проведён или проведён с пустыми движениями
Контрагент, договор, склад заполнены ссылками
Поля пустые или содержат не те значения
Все строки загружены, суммы и НДС посчитаны
Часть строк потеряна, суммы не сходятся с исходными данными
Если документы созданы, но не проводятся, смотрите протокол ошибок проведения: чаще всего это незаполненные обязательные реквизиты, закрытый период, отрицательные остатки или отсутствие счетов учёта. Каждая из этих причин устраняется на этапе заполнения, а не после записи.
Частые вопросы
Можно ли создать документ из обработки, не открывая её форму?
Да. Код можно выполнить через консоль кода, внешнюю обработку с автозапуском на сервере, регламентное задание или фоновое задание. Для регламентного сценария логику лучше размещать в общем модуле или расширении, а не во внешней обработке.
Почему документ создаётся, но реквизиты пустые?
Чаще всего причина в несовпадении имён реквизитов — обращение к несуществующему реквизиту вызвало бы ошибку, но если вы присваиваете значение через структуру или ЗаполнитьЗначенияСвойств, лишние ключи просто игнорируются. Вторая причина — присвоение строки вместо ссылки: типизированный реквизит отбрасывает значение несовместимого типа.
Как создать документ с конкретным номером?
После создания объекта присвойте НовыйДок.Номер = "НужныйНомер" до записи и установите НовыйДок.УстановитьНовыйНомер() не вызывая его. Учтите, что при нарушении уникальности запись завершится ошибкой, а ручная нумерация может конфликтовать с автонумерацией при последующем интерактивном вводе.
Чем отличается СоздатьДокумент() от ПолучитьСсылку().ПолучитьОбъект()?
СоздатьДокумент() создаёт новый объект в памяти без ссылки. ПолучитьОбъект() загружает существующий документ из базы для изменения. Для перезаполнения уже созданного документа используйте второй вариант: найдите ссылку запросом, получите объект, измените, запишите.
Как массово создать тысячи документов без блокировок?
Разбейте загрузку на порции (например, по 100–500 документов в транзакции), выполняйте в фоновом задании в нерабочее время, отключите оперативное проведение для исторических дат. При конфликтах блокировок уменьшите размер порции и добавьте паузы между итерациями.
Нужно ли удалять ошибочно созданные документы вручную?
Если обработка работала в транзакции — при ошибке всё откатится автоматически. Если без транзакции, помечайте ошибочные документы на удаление программно (УстановитьПометкуУдаления) по списку созданных ссылок, а физическое удаление выполняйте штатной обработкой «Удаление помеченных объектов».
Что важно запомнить
Документ из обработки создаётся через СоздатьДокумент(), заполнение реквизитов ссылками и Записать() с нужным режимом. Весь код — только на сервере, массовые операции — в транзакции с обработкой ошибок, отладка — исключительно на копии базы. Перед заполнением сверяйте имена реквизитов с метаданными вашей конфигурации.