В процессе кастомизации типовых конфигураций 1С (например, 1С:ERP, 1С:Управление торговлей или 1С:Комплексная автоматизация) разработчики часто сталкиваются с необходимостью создания альтернативных форм для стандартных документов. Представим ситуацию: для документа "Заявка на расходование денежных средств" создана новая, измененная форма. На эту форму выведены дополнительные реквизиты, которые обязательны к заполнению.
Однако если мы просто настроим стандартную проверку заполнения этих реквизитов в конфигураторе, система начнет требовать их заполнения везде, включая типовую форму документа. Это приведет к ошибкам у пользователей, работающих в стандартном интерфейсе. Как правильно разграничить логику проверки для разных форм? Разберем подробно несколько практических способов реализации этой задачи, проанализируем их плюсы и минусы, а также изучим подводные камни платформы 1С.
Это наиболее элегантное и архитектурно правильное решение в управляемом приложении. Оно позволяет изолировать логику проверки исключительно внутри вашей новой формы, вообще не затрагивая модуль объекта и не создавая лишних расширений для серверной логики.
Для реализации этого метода выполним следующие шаги:
ОбработкаПроверкиЗаполненияНаСервере.Рассмотрим пример кода, который необходимо поместить в модуль формы:
&НаСервере
Процедура ОбработкаПроверкиЗаполненияНаСервере(Отказ, ПроверяемыеРеквизиты)
// Добавляем реквизиты нашего объекта, которые обязательны ТОЛЬКО на этой форме
ПроверяемыеРеквизиты.Добавить("Объект.НовыйРеквизитДляПроверки");
ПроверяемыеРеквизиты.Добавить("Объект.ЕщеОдинВажныйРеквизит");
КонецПроцедуры
Выясним, почему данный метод считается идеальным с точки зрения архитектуры 1С:
Иногда требуется реализовать проверку в модуле объекта, например, когда состав проверяемых реквизитов зависит от сложных условий или определенных бизнес-правил самого объекта, а не только от интерфейса. Для этого используется предопределенная процедура модуля объекта ОбработкаПроверкиЗаполнения.
Если мы работаем в типовой конфигурации, лучшим решением будет использование расширения конфигурации. Мы можем перехватить обработку проверки заполнения и динамически управлять составом массива проверяемых реквизитов.
Посмотрим на пример реализации такого кода в модуле объекта через расширение:
&После("ОбработкаПроверкиЗаполнения")
Процедура Расш1_ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
// Выясним, нужно ли нам проверять реквизиты в зависимости от контекста.
// Например, если в объекте установлен определенный флаг или реквизит.
Если ЭтотОбъект.ИспользоватьНовуюЛогикуПроверки Тогда
// Добавляем реквизит в проверку, если его там еще нет
Если ПроверяемыеРеквизиты.Найти("НовыйРеквизит") = Неопределено Тогда
ПроверяемыеРеквизиты.Добавить("НовыйРеквизит");
КонецЕсли;
Иначе
// Если это стандартный режим, исключаем реквизит из проверки
Индекс = ПроверяемыеРеквизиты.Найти("НовыйРеквизит");
Если Индекс <> Неопределено Тогда
ПроверяемыеРеквизиты.Удалить(Индекс);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важное правило стандартов разработки 1С (БСП): Обратите внимание, что мы не выдаем здесь ошибки напрямую через функции типа Сообщить() и не прерываем выполнение жестко установкой Отказ = Истина. Стандарты 1С предписывают именно манипулировать массивом ПроверяемыеРеквизиты, чтобы платформа самостоятельно и корректно обработала вывод диагностических сообщений пользователю.
На форумах часто советуют передавать признак открытой формы в модуль объекта при записи через структуру ДополнительныеСвойства объекта (например, заполняя флаг "ИспользованаНоваяФорма" на клиенте перед записью). Будьте предельно осторожны: здесь кроется классическая ловушка, связанная с жесткой последовательностью выполнения платформенных событий при записи документа.
Давайте проанализируем цепочку вызовов при интерактивном нажатии кнопки "Записать" на форме:
ПередЗаписьюОбработкаПроверкиЗаполненияНаСервереОбработкаПроверкиЗаполненияПередЗаписьюНаСервере (именно здесь разработчики чаще всего пытаются инициализировать ДополнительныеСвойства объекта!)ПередЗаписьюПриЗаписи (старт транзакции базы данных)Вывод очевиден: проверка заполнения на уровне модуля объекта (шаг 3) выполняется раньше, чем срабатывает обработчик формы ПередЗаписьюНаСервере (шаг 4). Если вы попытаетесь передать флаг активной формы в ДополнительныеСвойства внутри события ПередЗаписьюНаСервере, то в момент проверки в модуле объекта эта структура гарантированно будет пустой, и проверка отработает некорректно!
Если вам все же критически необходимо передать параметры из формы в модуль объекта для проверки заполнения, выполнять это нужно строго в клиентском обработчике ПередЗаписью на форме перед вызовом стандартного механизма записи, либо использовать первый вариант с проверкой непосредственно в форме.
В старых конфигурациях на обычных формах часто использовался подход с ручной проверкой через функцию ЗначениеЗаполнено() непосредственно в обработчике ПередЗаписью модуля объекта или формы. Выглядит это примерно так:
Процедура ПередЗаписью(Отказ, РежимЗаписи)
Если Не ЗначениеЗаполнено(ЭтотОбъект.НовыйРеквизит) Тогда
Сообщить("Поле 'Новый реквизит' обязательно для заполнения!");
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Давайте разберем, почему данный подход крайне не рекомендуется использовать в современной разработке на платформе 1С:Предприятие 8.3:
Сообщить() просто выводит текстовое сообщение на экран. Пользователю придется вручную искать глазами, где на форме находится незаполненное поле. В то время как стандартный механизм платформы сразу подсветит поле красным маркером и сфокусирует на нем внимание при клике на ошибку.ПередЗаписью выполняется уже в рамках открытой транзакции СУБД. Если проверка не пройдена, транзакция аварийно откатывается. База данных тратит вычислительные ресурсы на открытие и откат транзакции. Стандартный метод ОбработкаПроверкиЗаполнения выполняется до начала транзакции, что существенно экономит ресурсы сервера и повышает общую производительность системы в условиях многопользовательской работы.При выборе места для размещения кода проверки заполнения всегда учитывайте важнейший аспект: как именно данный документ будет создаваться и записываться в систему?
Если запись происходит интерактивно (пользователь нажимает кнопку в интерфейсе), система последовательно выполняет события и формы, и объекта. В этом случае отлично работают как проверки в модуле формы, так и проверки в модуле объекта.
Если же запись происходит программно (документ загружается через API, веб-сервисы, файлы Excel, или создается регламентным заданием в фоне), то события формы не вызываются вообще. Будет задействован исключительно модуль объекта.
Если вы жестко пропишете обязательность заполнения новых полей в модуле объекта без дополнительных условий, то при любом программном обмене данными система начнет сыпать ошибками о незаполненных реквизитах, блокируя загрузку. Использование гибкого разделения проверок с помощью первого варианта (на уровне измененной формы) полностью защищает вас от этой проблемы: пользователи в новой форме обязаны заполнять поля, а внешние интеграции и стандартные формы продолжают стабильно функционировать без сбоев.