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

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

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

Как программно записать документ из формы в 1С: методы Записать(), РежимЗаписиДокумента, проведение, типичные ошибки и проверка результата.

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

Главная сложность в том, что у формы документа есть собственный механизм записи, а у объекта документа — свой. Неправильный выбор метода приводит к конфликтам версий, потере введённых данных или записи «мимо» открытой формы. Поэтому важно понимать разницу между методами формы и методами объекта.

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

Как устроена запись документа из формы

Когда документ открыт в форме, существуют два связанных, но разных уровня данных. Первый — реквизит формы Объект, который содержит редактируемые пользователем данные. Второй — сам объект базы данных, который изменится только после записи.

Метод формы Записать() выполняет полный цикл: вызывает обработчики ПередЗаписью, ПриЗаписи на клиенте и сервере, записывает объект в базу, обновляет форму и оповещения. Именно этот метод используется стандартными кнопками «Записать» и «Провести».

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

Запись документа методом формы

Стандартный и безопасный способ — вызвать метод формы Записать() с передачей структуры параметров. Минимальный вариант в модуле формы выглядит так:

&НаКлиенте

Процедура ЗаписатьДокумент(Команда)

ПараметрыЗаписи = Новый Структура;

ПараметрыЗаписи.Вставить("РежимЗаписи", РежимЗаписиДокумента.Запись);

Если Записать(ПараметрыЗаписи) Тогда

ПоказатьОповещениеПользователя("Документ записан");

КонецЕсли;

КонецПроцедуры

Метод возвращает Истина, если запись прошла успешно, и Ложь — если пользователь отказался от действия или проверки не пройдены. На результат всегда стоит реагировать, а не считать запись выполненной по умолчанию.

В структуру параметров можно добавить РежимПроведения (оперативный или неоперативный), ПропуститьПроверкуЗапретаИзменения и другие ключи, поддерживаемые платформой. Состав параметров зависит от версии платформы, поэтому при сомнениях сверяйтесь с синтакс-помощником.

Порядок действий при записи из формы
  1. 1
    Сформируйте структуру параметров записи с нужным РежимЗаписи
  2. 2
    Вызовите метод формы Записать(ПараметрыЗаписи)
  3. 3
    Проверьте возвращаемое значение (Истина/Ложь)
  4. 4
    При успехе выполните дополнительные действия: оповещение, закрытие, обновление связанных данных
  5. 5
    При неудаче покажите пользователю сообщения об ошибках

Проведение и отмена проведения из формы

Для проведения документа укажите режим записи Проведение. Если документ ещё не записан, платформа сначала сохранит его, а затем выполнит проведение:

ПараметрыЗаписи = Новый Структура;

ПараметрыЗаписи.Вставить("РежимЗаписи", РежимЗаписиДокумента.Проведение);

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

Если Не Записать(ПараметрыЗаписи) Тогда

Возврат; // проведение не выполнено, сообщения уже показаны

КонецЕсли;

Оперативное проведение доступно только если у документа включён оперативный режим и дата документа соответствует текущему периоду. Иначе платформа выдаст ошибку, и документ не проведётся. Для «задним числом» используйте неоперативное проведение.

Отмена проведения выполняется аналогично — режимом ОтменаПроведения. Учтите, что отменить проведение можно только у проведённого документа, иначе метод вернёт Ложь или вызовет исключение в зависимости от контекста.

Сравнение способов записи

Записать() методом формы

Штатный способ из формы документа: выполняет все обработчики, обновляет форму, безопасен. Подходит почти всегда.

Объект.Записать() из формы

Записывает объект напрямую, форма не узнает о записи. Риск конфликта версий и рассинхронизации данных. Из формы документа почти не применяется.

Запись через Документы.Менеджер

Создание и запись объекта на сервере вне формы. Подходит для фоновых и пакетных операций, а не для работы с открытой формой.

Запись через объект: когда это допустимо

Иногда требуется записать не текущий документ формы, а другой объект — например, связанный документ, созданный на основании. Здесь корректно работать через объект:

&НаСервере

Процедура СоздатьСвязанныйДокумент()

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

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

НовыйДок.Заполнить(Объект.Ссылка);

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

КонецПроцедуры

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

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

Обработка ошибок и проверка результата

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

Метод формы Записать() в большинстве таких случаев не вызывает исключение, а просто возвращает Ложь, показывая сообщения пользователю. Поэтому логику после записи всегда помещайте внутрь проверки результата.

При записи через объект ошибки приводят к исключению, которое стоит перехватывать:

Попытка

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

Исключение

ИнформацияОбОшибке = ИнформацияОбОшибке();

ЗаписьЖурналаРегистрации("ЗаписьДокумента",

УровеньЖурналаРегистрации.Ошибка, , ,

ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));

ВызватьИсключение КраткоеПредставлениеОшибки(ИнформацияОбОшибке);

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

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

Дополнительные сценарии и тонкости

Запись и закрытие формы

Если после записи форму нужно закрыть, добавьте в параметры ключ Закрыть со значением Истина либо вызовите Закрыть() после успешной записи. Закрытие без записи у изменённого документа вызовет вопрос пользователю о сохранении.

Запись нового документа без открытия формы

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

Проверка модифицированности

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

Как проверить, что документ записан корректно

После записи убедитесь, что результат соответствует ожиданиям. Минимальный набор проверок: документ имеет ссылку (не пустую), признак проведения соответствует выбранному режиму, движения по регистрам сформированы.

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

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

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

Ссылка документа
Норма

Ссылка не пустая, документ открывается из списка

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

Ссылка пустая — запись не выполнена

Признак проведения
Норма

Проведен = Истина после режима Проведение

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

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

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

Записи в регистрах соответствуют табличным частям

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

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

Состояние формы
Норма

Модифицированность снята, заголовок обновлён

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

Форма по-прежнему показывает несохранённые изменения

Частые вопросы

Чем Записать() формы отличается от Объект.Записать()?

Метод формы выполняет полный цикл записи с обработчиками формы, обновляет интерфейс и снимает модифицированность. Метод объекта пишет данные напрямую в базу, форма об этом не узнаёт. Из формы документа корректен первый вариант.

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

Вызовите Записать() с режимом Проведение. Интерактивные вопросы возникают только если они зашиты в обработчиках формы — их нужно убрать или обойти через дополнительные свойства объекта с проверкой в обработчике.

Почему возникает ошибка «конфликт блокировок» или «версия данных изменилась»?

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

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

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

Что делать, если Записать() возвращает Ложь без сообщений?

Проверьте обработчики ПередЗаписью — там может стоять Отказ = Истина без пояснения. Также проверьте журнал регистрации и права пользователя на запись и проведение документа.

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

Получите объект по выделенной ссылке на сервере: ДокОбъект = Ссылка.ПолучитьОбъект(), затем ДокОбъект.Записать() с нужным режимом. После записи вызовите ОповеститьОбИзменении(Ссылка), чтобы список обновился.

Итог

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

Из формы документа записывайте методом формы Записать() с параметром РежимЗаписи. Проверяйте возвращаемое значение, не используйте Объект.Записать() для текущего документа формы, а запись через объект оставляйте для сторонних и пакетных операций.