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

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

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

Как программно записать документ в 1С 8.3: метод Записать(), режимы проведения, обход ошибок, примеры кода, работа с транзакциями и типичные ошибки разработчика.

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

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

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

Получение объекта документа: создание нового и открытие существующего

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

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

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

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

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

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

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

ДокОбъект.Записать(РежимЗаписиДокумента.Запись);

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

Режимы записи: Запись, Проведение и ОтменаПроведения

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

РежимЧто делаетКогда применять
ЗаписьСохраняет документ без проведения, движения не формируютсяЧерновая загрузка, изменение реквизитов без перепроведения
ПроведениеСохраняет и проводит документ, выполняется обработчик ОбработкаПроведенияДокумент должен отразиться в учёте сразу
ОтменаПроведенияУдаляет движения, документ остаётся в базе непроведённымИсправление ошибочно проведённых документов

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

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

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

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

Как выбрать режим записи

Документ загружается из внешнего источника и должен сразу попасть в учётРежимЗаписиДокумента.Проведение с РежимПроведенияДокумента.Неоперативный
Нужно только изменить реквизиты непроведённого документаРежимЗаписиДокумента.Запись
Документ уже проведён и требуется исправить данныеСначала ОтменаПроведения, затем изменение и повторное Проведение
Дата документа равна текущей дате и включено оперативное проведениеМожно использовать Оперативный режим для контроля остатков на текущий момент

Заполнение реквизитов и табличных частей

Реквизиты шапки заполняются прямым присваиванием. Ссылочные реквизиты (контрагент, договор, склад) должны получать именно ссылки, а не строки или коды — иначе при записи получите ошибку несоответствия типов или «пустые» значения.

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

ДокОбъект.Дата = ТекущаяДатаСеанса();

ДокОбъект.Организация = Справочники.Организации.НайтиПоНаименованию("ООО Ромашка");

ДокОбъект.Контрагент = НайденныйКонтрагент;

ДокОбъект.Склад = СкладСсылка;

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

ДокОбъект.Товары.Очистить();

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

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

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

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

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

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

КонецЦикла;

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

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

Перед записью полезно вызвать метод ПроверитьЗаполнение() — он выполняет те же проверки обязательных реквизитов, что и интерактивная запись, и возвращает Истина или Ложь:

Если Не ДокОбъект.ПроверитьЗаполнение() Тогда

ВызватьИсключение "Документ не заполнен корректно";

КонецЕсли;

Сама запись оборачивается в Попытка/Исключение, чтобы обработка не прерывалась на первом проблемном документе. Текст ошибки получают через ОписаниеОшибки() или ИнформацияОбОшибке():

Попытка

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

Исключение

Сообщить("Не удалось провести документ " + ДокОбъект.Номер + ": " + ОписаниеОшибки());

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

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

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

Запись в транзакции и массовая обработка

Если по логике задачи документы должны записываться «все или ни одного», используйте явную транзакцию:

НачатьТранзакцию();

Попытка

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

ДокОбъект = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();

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

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

КонецЦикла;

ЗафиксироватьТранзакцию();

Исключение

ОтменитьТранзакцию();

ВызватьИсключение ОписаниеОшибки();

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

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

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

ОбменДанными.Загрузка: когда проверки нужно отключить

При загрузке данных из других систем иногда требуется записать документ «как есть», минуя бизнес-проверки и подписки на события. Для этого служит свойство ОбменДанными.Загрузка:

ДокОбъект.ОбменДанными.Загрузка = Истина;

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

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

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

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

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

Документ появился в базе
Норма

Поиск по номеру или ссылке возвращает документ, реквизиты совпадают с загруженными

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

Документ отсутствует или реквизиты пустые — запись не выполнилась или откатилась транзакция

Состояние проведения
Норма

Свойство Проведен = Истина, движения видны в регистрах

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

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

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

Количество и суммы движений соответствуют табличной части

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

Движений нет или суммы не сходятся — проверяйте обработку проведения и заполнение

Журнал регистрации
Норма

Нет ошибок по сеансу загрузки

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

Ошибки блокировок, даты запрета или прав — корректируйте условия выполнения

Частые вопросы о программной записи документов

Итог

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

Записывается всегда объект документа, а не ссылка. Режим записи выбирается осознанно: Запись — без движений, Проведение — с движениями, для прошлых дат — только неоперативный режим. Ошибки обрабатывайте через Попытка/Исключение, массовые загрузки тестируйте на копии базы.

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

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

Как программно отменить проведение документа?

Получите объект через ПолучитьОбъект() и вызовите Записать(РежимЗаписиДокумента.ОтменаПроведения). Движения документа будут удалены, сам документ останется в базе с признаком «не проведён». Проверить успешность можно по свойству Проведен = Ложь.

Почему возникает ошибка «Оперативное проведение невозможно»?

Оперативное проведение допустимо только для документов с текущей датой и только если оно разрешено в свойствах документа в конфигураторе. При загрузке документов прошлыми датами передавайте второй параметр: РежимПроведенияДокумента.Неоперативный.

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

Да, весь описанный код работает без формы — на сервере, в фоновом задании, внешнем соединении или COM-подключении. Форма нужна только для интерактивной работы пользователя; программная запись опирается на объектную модель.

Как записать документ через COM-соединение из другой базы 1С?

Через COMConnector подключитесь к базе-источнику или приёмнику, затем используйте тот же объектный интерфейс: Соединение.Документы.ИмяДокумента.СоздатьДокумент(), заполнение реквизитов (ссылки передавайте через COM-объекты соединения, а не из текущей базы) и Записать() с нужным режимом. Ссылки разных баз несовместимы напрямую.

Что делать, если при проведении не хватает остатков на складе?

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