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

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

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

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

Почему в форме в массиве ПроверяемыеРеквизиты виден только «Объект»?

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


&НаСервере
Процедура ОбработкаПроверкиЗаполненияНаСервере(Отказ, ПроверяемыеРеквизиты)
    // Попытка удалить конкретный реквизит объекта в форме
    ПроверяемыеРеквизиты.Удалить(ПроверяемыеРеквизиты.Найти("Объект.Подразделение")); 
КонецПроцедуры

Этот код вызывает ошибку выполнения. Если же попытаться просто удалить элемент "Объект", то проверка отключается вообще для всех реквизитов документа. Почему так происходит?

Дело в особенностях архитектуры платформы 1С:

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

Таким образом, пытаться найти и удалить строку "Подразделение" или "Объект.Подразделение" в модуле формы бессмысленно — платформа их там не хранит.

Главное заблуждение: «В модуле объекта тоже ничего не видно»

Часто разработчики ошибочно полагают, что в модуле объекта ситуация аналогична модулю формы, и в обработчике проверки тоже виден только весь «Объект» целиком. Это не так.

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

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

Рассмотрим три практических способа решения задачи динамической проверки реквизитов.

Способ А. Проверка в модуле объекта на основе реквизита (Рекомендуемый стандарт 1С)

Согласно стандартам разработки фирмы «1С» (требование #std463), бизнес-логика приложения должна быть максимально отделена от визуального интерфейса. Проверка корректности данных должна работать корректно даже при записи объекта программно (например, при обмене данными или загрузке из внешних файлов), когда формы вообще не создаются.

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

Рассмотрим пример реализации в модуле объекта:


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

Этот способ является наиболее чистым с точки зрения архитектуры. Объект сам контролирует целостность своих данных на основе своего внутреннего состояния.

Способ Б. Передача параметров из управляемой формы в модуль объекта

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

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

Проанализируем по шагам код в модуле формы:


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

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


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

Используя этот подход, мы сохраняем гибкость интерфейса и не нарушаем цепочку стандартных проверок платформы.

Способ В. Изменение логики: динамическое добавление проверки

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

Давайте разберем этот подход подробнее:

  1. В конфигураторе у реквизита Подразделение устанавливаем свойство Проверка заполнения в значение «Не проверять». Таким образом, по умолчанию платформа никогда не будет ругаться на пустое подразделение.
  2. Чтобы пользователь визуально видел необходимость заполнения поля, в свойствах элемента формы у поля ввода устанавливаем свойство АвтоОтметкаНезаполненного в значение Истина (или управляем им динамически через условное оформление формы).
  3. В модуле объекта мы динамически добавляем этот реквизит в массив проверок только тогда, когда выполняются наши условия:

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

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

Использование инструментов БСП (Библиотеки стандартных подсистем)

Если вы ведете разработку в современной конфигурации, построенной на базе БСП (например, 1С:ERP, Управление торговлей или Бухгалтерия предприятия), то вам доступен готовый сервисный инструментарий. В составе БСП есть общий модуль ОбщегоНазначения, который содержит полезный метод для быстрого удаления реквизитов из проверки.

Пример использования метода БСП в модуле объекта:


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

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

Подводя итог, помните: разделение логики интерфейса формы и бизнес-логики объекта — залог стабильной работы и легкого обновления любого решения на платформе 1С.

← На главную