Почему не работает обработчик «ОбработкаПроверкиЗаполненияНаСервере» и как правильно проверять заполнение реквизитов на форме 1С?

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

При разработке в среде «1С:Предприятие 8» (особенно на управляемых формах) программисты часто сталкиваются с ситуацией, когда стандартный платформенный механизм проверки заполнения ведет себя не так, как ожидается. Типичный сценарий: разработчик пытается программно добавить реквизит в массив ПроверяемыеРеквизиты внутри события формы ОбработкаПроверкиЗаполненияНаСервере, но система игнорирует это действие, и незаполненное поле преспокойно записывается в базу данных.

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

Выясняем причину: в чем разница между реквизитами формы и реквизитами объекта?

Основной источник ошибок и непонимания кроется в разделении контекста. Нам необходимо четко разграничивать понятия «реквизиты формы» и «реквизиты объекта»:

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

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

Единственное «объектное» значение, которое изначально присутствует в массиве ПроверяемыеРеквизиты на форме по умолчанию — это строка "Объект". Она указывает платформе на то, что после завершения проверки формы необходимо запустить стандартную проверку заполнения самого прикладного объекта.

Анализируем полный жизненный цикл проверки заполнения при записи

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

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

Решение 1: Красивая ручная проверка реквизитов объекта на уровне формы

Что делать, если вам нужно проверить заполнение реквизита объекта (например, Объект.Договор), но логика этой проверки жестко завязана на состояние интерфейса формы? Например, поле должно быть обязательным только в том случае, если на форме открыта определенная функциональная вкладка или пользователь установил локальный флажок формы, который не записывается в базу данных.

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

Рассмотрим пример реализации такой проверки:


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

Почему этот способ лучше, чем проверка в ПередЗаписью на клиенте?

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

Если логика проверки реквизитов объекта достаточно сложна, но зависит от параметров формы, хорошей практикой считается перенос всей логики проверки в модуль объекта. Но как передать значение интерактивного переключателя или настройки формы в модуль объекта?

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

Шаг первый — передаем параметры из формы в объект перед проверкой:


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

Шаг второй — анализируем переданный параметр в обработчике модуля объекта:


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

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

Решение 3: Как БСП использует этот обработчик для дополнительных реквизитов

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

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

Так как платформа ничего не знает о динамических реквизитах на уровне объекта базы данных, БСП выполняет их валидацию именно на уровне формы, перехватывая серверное событие проверки заполнения:


&НаСервере
Процедура ОбработкаПроверкиЗаполненияНаСервере(Отказ, ПроверяемыеРеквизиты)
    
    // Интеграция со стандартными механизмами БСП
    // Метод анализирует созданные свойства и динамически добавляет их пути в массив ПроверяемыеРеквизиты
    УправлениеСвойствами.ОбработкаПроверкиЗаполнения(ЭтотОбъект, Отказ, ПроверяемыеРеквизиты, Объект);
    
КонецПроцедуры

Внутри общего модуля БСП определяет, какие из динамических реквизитов формы помечены как обязательные для заполнения, и добавляет их строковые пути во входящий массив ПроверяемыеРеквизиты. Далее платформа берет этот модифицированный массив и автоматически подсвечивает незаполненные дополнительные поля на форме красным цветом.

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

Подведем итог нашему разбору. Чтобы проверки заполнения в ваших конфигурациях работали стабильно, надежно и красиво, придерживайтесь следующих простых правил:

← На главную