Как в 1С изменить реквизит документа только при нажатии кнопки «ОК» (Провести и закрыть)

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача разделить логику поведения документа в зависимости от того, какое действие совершил пользователь: просто сохранил черновик (кнопка «Записать») или завершил работу с документом, инициировав его проведение и закрытие формы (кнопка «ОК» или «Провести и закрыть»).

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

Анализ проблемы: почему РежимЗаписи не всегда помогает?

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


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если РежимЗаписи = РежимЗаписиДокумента.Проведение И Не Отказ Тогда
        Ответственный = ПараметрыСеанса.ТекущийПользователь;
    КонецЕсли;
КонецПроцедуры

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

Способ 1: Использование коллекции ДополнительныеСвойства

Проанализируем наиболее гибкий и надежный метод — передачу флага из формы документа в модуль объекта через коллекцию ДополнительныеСвойства. Этот механизм позволяет «пробросить» информацию о намерениях пользователя непосредственно в транзакцию записи.

Разберем реализацию по шагам:

  1. В модуле формы документа перехватим событие ПередЗаписьюНаСервере. Здесь мы можем проверить параметры записи формы.
  2. Если пользователь нажал «Провести и закрыть», параметр ПараметрыЗаписи.ЗакрытьПослеЗаписи будет иметь значение Истина.
  3. Передадим этот признак в объект.

Пример кода в модуле формы:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    // Проверяем, было ли инициировано закрытие формы после записи (нажата кнопка ОК)
    Если ПараметрыЗаписи.Свойство("ЗакрытьПослеЗаписи") И ПараметрыЗаписи.ЗакрытьПослеЗаписи Тогда
        ТекущийОбъект.ДополнительныеСвойства.Вставить("ЭтоНажатиеОК", Истина);
    КонецЕсли;
КонецПроцедуры

Теперь в модуле объекта мы можем проверить наличие этого свойства:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если ДополнительныеСвойства.Свойство("ЭтоНажатиеОК") Тогда
        // Код выполняется только при нажатии "ОК" (Провести и закрыть)
        Ответственный = ПараметрыСеанса.ТекущийПользователь;
    КонецЕсли;
КонецПроцедуры

Способ 2: Использование расширения и перехват команд формы

Если мы работаем в современной конфигурации (например, Бухгалтерия предприятия 3.0), рассмотрим вариант с расширением. Мы можем создать расширение для формы документа и добавить обработчики («после» или «вместо») для стандартных команд Записать и ПровестиИЗакрыть.

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

Способ 3: Сравнение текущих данных с данными в базе данных

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


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    // Проверяем, не является ли объект новым
    Если Не ЭтоНовый() Тогда
        // Получаем значение из базы данных для сравнения
        СтарыйСтатусПроведения = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Проведен");
        
        // Если документ не был проведен, а сейчас проводится
        Если Не СтарыйСтатусПроведения И РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
            Ответственный = ПараметрыСеанса.ТекущийПользователь;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

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

Важное предостережение: избегайте рекурсивной записи!

Разберем критическую ошибку, упомянутую в обсуждении. Некоторые разработчики пытаются менять реквизиты в процедуре ОбработкаПроведения и вызывать метод Записать(). Так делать категорически нельзя.

Проанализируем причины:

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

Резюме и рекомендации

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

Пошаговый алгоритм действий для разработчика:

  1. Убедиться, что в конфигурации используются управляемые формы.
  2. В модуле формы в ПередЗаписьюНаСервере установить флаг в ТекущийОбъект.ДополнительныеСвойства, ориентируясь на параметр ЗакрытьПослеЗаписи.
  3. В модуле объекта в ПередЗаписью считать этот флаг и установить значение реквизита Ответственный.
  4. Протестировать поведение системы: при обычном сохранении (дискета или «Записать») ответственный меняться не должен, а при нажатии «Провести и закрыть» — должен обновляться.

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

← На главную