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