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