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