В процессе разработки на платформе 1С:Предприятие 8 часто возникает задача динамического управления обязательными полями. Типичный сценарий: в конфигураторе для реквизита табличной части установлено свойство «Проверка заполнения» в значение «Выдавать ошибку», но при определенных условиях (например, в зависимости от вида операции или роли пользователя) нам нужно разрешить запись документа с пустым значением этого реквизита.
Разберем детально, почему нельзя просто поменять свойство реквизита «в лоб» и какие инструменты предоставляет платформа для решения этой задачи.
Прежде всего, проанализируем фундаментальное ограничение системы. Свойства, которые мы задаем в окне «Свойства» объекта метаданных в конфигураторе, жестко фиксируются в структуре конфигурации. Платформа 1С не позволяет программно изменять метаданные во время работы сеанса пользователя. Это означает, что вы не сможете написать код вида Объект.Метаданные().ТабличныеЧасти.ТЧ1.Реквизиты.Реквизит1.ПроверкаЗаполнения = ПроверкаЗаполнения.НеПроверять.
Все «динамические изменения», о которых пойдет речь ниже, — это способы управления поведением стандартных механизмов платформы, а не модификация самих метаданных.
Наиболее правильным и стандартным методом является использование обработчика события ОбработкаПроверкиЗаполнения, который располагается в модуле объекта (документа, справочника и т.д.). Рассмотрим подробнее, как работает этот механизм.
Когда пользователь нажимает кнопку «Записать» или «Провести», платформа формирует массив ПроверяемыеРеквизиты. В него попадают имена всех реквизитов, у которых в конфигураторе стоит признак проверки. Наша задача — программно удалить ненужный реквизит из этого массива при выполнении определенного условия.
Посмотрим на пример кода в модуле документа:
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
// Проверяем условие, при котором проверку нужно отключить
Если ВидОперации = Перечисления.ВидыОпераций.Прочее Тогда
// Для удаления реквизита табличной части используется путь "ИмяТЧ.ИмяРеквизита"
Индекс = ПроверяемыеРеквизиты.Найти("ТЧ1.Реквизит1");
Если Индекс <> Неопределено Тогда
ПроверяемыеРеквизиты.Удалить(Индекс);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важные нюансы работы с массивом:
"ИмяТабличнойЧасти.ИмяРеквизита", платформа перестанет проверять этот реквизит во всех строках табличной части."ИмяТабличнойЧасти".Найти(). Если реквизита в массиве нет (например, он уже был удален другим кодом или не включен в метаданных), попытка удаления по значению Неопределено приведет к аварийному завершению работы программы.Иногда программисту нужно не просто отключить проверку, а управлять визуальной индикацией (красным пунктиром) на форме. Для этого существует свойство элемента формы АвтоОтметкаНезаполненного. Рассмотрим ситуацию: мы хотим, чтобы поле подсвечивалось только в том случае, если документ еще не утвержден.
Проанализируем пример кода в модуле формы:
&НаСервере
Процедура УстановитьВизуальнуюПроверку()
// Управляем визуальным отображением обязательности
НужноПроверять = (Объект.Статус = Перечисления.Статусы.Черновик);
Элементы.ТЧ1Реквизит1.АвтоОтметкаНезаполненного = НужноПроверять;
КонецПроцедуры
Внимание: Установка АвтоОтметкаНезаполненного = Ложь убирает только визуальную подсветку. Если в метаданных реквизита стоит «Выдавать ошибку», при записи объект все равно выдаст системную ошибку заполнения. Поэтому использование АвтоОтметкаНезаполненного должно идти в паре с ОбработкаПроверкиЗаполнения в модуле объекта.
В обсуждении на форуме упоминался флаг Загрузка = Истина. Выясним причину, почему этот способ часто используют, и в чем его опасность. Когда у объекта установлен признак ОбменДанными.Загрузка = Истина, платформа полностью игнорирует вызов ОбработкаПроверкиЗаполнения и не выполняет стандартные проверки метаданных.
Пример использования при программном создании документа:
НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
// Заполнение данных...
НовыйДок.ОбменДанными.Загрузка = Истина;
НовыйДок.Записать(РежимЗаписиДокумента.Запись);
Последствия использования этого режима:
ПередЗаписью / ПриЗаписи.Разберем ситуацию, когда вы создаете объект программно и хотите убедиться, что он заполнен корректно, прежде чем записывать его. По умолчанию метод Записать() в коде (не из формы) не инициирует проверку заполнения. Чтобы запустить механизм, нужно вызвать метод ПроверитьЗаполнение().
Если ЭтотОбъект.ПроверитьЗаполнение() Тогда
ЭтотОбъект.Записать();
Иначе
// Обработка ситуации, когда данные не валидны
КонецЕсли;
Этот метод внутри себя вызывает ту самую процедуру ОбработкаПроверкиЗаполнения, которую мы рассматривали в первом пункте. Это позволяет централизованно управлять логикой проверки и для интерактивной работы пользователя, и для программных обработок. Для наглядного анализа порядка срабатывания обработчиков при записи и валидации данных можно использовать разработку для изучения последовательности событий платформы 1С.
Для того чтобы ваша конфигурация была гибкой и удобной в поддержке, мы рекомендуем придерживаться следующей стратегии:
РольДоступна()) описывайте в ОбработкаПроверкиЗаполнения.АвтоОтметкаНезаполненного на форме, синхронизируя его с логикой в модуле объекта.Таким образом, хотя мы и не можем изменить свойство метаданных напрямую, платформа предоставляет мощный программный интерфейс для перехвата и модификации процесса проверки, что позволяет реализовать логику любой сложности.