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

Программист Финансы и профессиональные услуги
← На главную

При разработке в 1С часто возникает задача синхронизации состояния нескольких взаимосвязанных документов. Например, создается документ-заявка (или залоговый билет), на основании которого формируется и проводится кассовый ордер. Логичное желание разработчика: если форма заявки закрывается без проведения документа, связанный кассовый ордер также должен автоматически распровестись. Разберем эту задачу по шагам, проанализируем возможные ошибки и найдем правильные архитектурные решения.

Почему привязка бизнес-логики к интерфейсу (закрытию формы) — плохая практика?

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

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

  1. Аварийное завершение работы: Если приложение 1С зависнет или связь с сервером прервется (упадет клиент), форма закроется аварийно без вызова обработчиков.
  2. Действия пользователя: Пользователь может принудительно завершить процесс через Диспетчер задач. В этом случае код закрытия формы также не отработает.
  3. Тайм-аут сеанса: Системный администратор может завершить зависший сеанс со стороны консоли сервера 1С.

В результате возникнет рассинхронизация и нарушение целостности данных: заявка останется непроведенной (или вовсе не будет записана), а кассовый ордер не распроведется, так как команда из интерфейса не поступила на сервер.

Как программно отследить закрытие формы (если это нужно для интерфейса)?

Если задача заключается только во взаимодействии окон (например, обновить список на рабочем столе), отследить закрытие формы можно. Рассмотрим подробнее, как это реализовать с помощью клиентских событий.

В 1С предусмотрены два основных события для этих целей:

  1. ПередЗакрытием — здесь можно узнать о факте попытки закрытия и даже отменить его, установив параметр Отказ = Истина. Также можно проанализировать параметр ЗавершениеРаботы, чтобы понять, закрывается ли только текущая форма или пользователь полностью выходит из программы.
  2. ПриЗакрытии — окно уже закрывается, отменить действие нельзя.

Для передачи сигнала от одной формы к другой посмотрим на механизм оповещений. В закрывающейся форме мы можем послать сигнал:


&НаКлиенте
Процедура ПриЗакрытии()
    Если Не Объект.Проведен Тогда
        Оповестить("ЗакрытаНепроведеннаяЗаявка", Объект.Ссылка);
    КонецЕсли;
КонецПроцедуры

В другой открытой форме (например, в форме списка или на рабочем столе) перехватим это оповещение в событии ОбработкаОповещения:


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

Важно: этот способ работает только в рамках запущенного клиентского сеанса и требует наличия открытой формы-приемника. Он по-прежнему уязвим к аварийным завершениям работы.

Правильные архитектурные решения задачи

Вместо отслеживания действий пользователя с окнами, контроль состояний нужно переносить на уровень модуля объекта базы данных (выполнение на сервере). Выясним причину изначальной задачи: зачем вообще проводить ордер до проведения заявки? Часто это делается ради печати кассового документа (типовые решения иногда запрещают печать непроведенных ордеров). Разберем надежные варианты обхода.

Решение 1. Изменение логики печати

Самый простой и логичный выход — разрешить печать непроведенных документов. Как отметили специалисты, галочка "Печатать только проведенные" — это настраиваемое ограничение. Достаточно снять это ограничение (или изменить одну строчку в модуле печати), чтобы пользователь мог распечатать черновик приходного или расходного ордера, не проводя его. Тогда проблема рассинхронизации отпадает сама собой.

Решение 2. Использование статусов и отложенных движений

Если ордер все-таки должен быть проведен системой (например, для нужд подсистемы печати), можно использовать механизм отложенных движений. Кассовый ордер проводится, но не делает реальных движений по регистрам и не влияет на баланс, пока основная заявка (залоговый билет) не перейдет в нужный статус или не будет проведена.

Для этого в модуле объекта кассового ордера в обработчике ОбработкаПроведения мы проверяем состояние заявки-основания:


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

Решение 3. Жесткая связь через подписки на события или модули объектов

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

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

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

← На главную