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