В процессе разработки в среде «1С:Предприятие» одной из самых частых задач является контроль заполнения обязательных полей перед записью объекта. Для этого платформа предоставляет удобный встроенный механизм и обработчик ОбработкаПроверкиЗаполнения. Однако начинающие (и даже опытные) разработчики часто сталкиваются с непониманием: почему на разных этапах проверки состав массива ПроверяемыеРеквизиты выглядит совершенно по-разному? Почему в форме мы видим только один элемент "Объект", а в модуле объекта — целый список конкретных полей?
В этой статье мы подробно разберем, по каким правилам платформа формирует этот массив, как работает двухуровневая проверка и как мы можем программно влиять на этот процесс.
Процесс проверки заполнения, если он инициирован интерактивно (например, пользователь нажал кнопку «Записать и закрыть» в форме элемента справочника или документа), выполняется платформой последовательно в два этапа:
ОбработкаПроверкиЗаполненияНаСервере(Отказ, ПроверяемыеРеквизиты). В этот момент массив ПроверяемыеРеквизиты содержит реквизиты самой формы, для которых установлено свойство «Проверка заполнения — Выдавать ошибку», а также строку "Объект". Строка "Объект" здесь выступает в роли собирательного контейнера. Она указывает платформе, что после завершения проверки на уровне формы необходимо передать управление в модуль объекта.Отказ остался равен Ложь) и в массиве присутствовал элемент "Объект", платформа переходит к выполнению процедуры ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты) в модуле объекта. В этот момент платформа производит «декомпозицию» (разворачивание) элемента "Объект". Вместо одной строки "Объект" в массив помещаются имена всех конкретных реквизитов объекта метаданных, у которых в конфигураторе взведен флаг проверки заполнения.Именно эту разницу и наблюдал автор вопроса на форуме: в форме он видел лишь один элемент-указатель, а в модуле объекта — детальный список полей.
Основным источником, из которого платформа черпает информацию для первоначального заполнения массива ПроверяемыеРеквизиты, являются свойства метаданных в конфигураторе. Проанализируем эти настройки:
Для реквизитов формы действует аналогичное правило: если элемент управления связан с реквизитом формы (не путать с реквизитами объекта) и у него настроена проверка заполнения, он попадет в массив на уровне формы.
Разработчику важно знать, что платформа «1С:Предприятие» обладает встроенной «умной» логикой. Она может самостоятельно исключать некоторые реквизиты из массива ПроверяемыеРеквизиты, даже если в конфигураторе для них жестко задано «Выдавать ошибку». Рассмотрим эти ситуации подробнее:
Доступность = Ложь) или скрыто с формы (Видимость = Ложь), платформа автоматически удаляет этот реквизит из списка проверяемых. Это логично: глупо требовать от пользователя заполнения поля, которое он физически не может увидеть или изменить.ЭтотОбъект.ПроверитьЗаполнение() вне контекста формы, то анализ видимости и доступности не производится. В массив попадут абсолютно все реквизиты со свойством «Выдавать ошибку».Массив ПроверяемыеРеквизиты передается в процедуры-обработчики по ссылке. Это означает, что мы имеем полное право изменять его состав «на лету» прямо во время выполнения кода. Это стандартный и наиболее правильный способ реализации условной обязательности полей.
Рассмотрим по шагам, как мы можем управлять составом массива.
Представим ситуацию: у нас есть справочник «Контрагенты». В конфигураторе для реквизитов ИНН и КПП установлено свойство «Выдавать ошибку». Однако, если контрагент является физическим лицом, заполнение КПП не требуется. Реализуем эту логику в модуле объекта:
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
// Если контрагент — физлицо, КПП проверять не нужно
Если ЮрФизЛицо = Перечисления.ЮрФизЛицо.ФизЛицо Тогда
// Находим индекс элемента в массиве
ИндексКПП = ПроверяемыеРеквизиты.Найти("КПП");
// Если элемент найден, удаляем его из массива проверки
Если ИндексКПП <> Неопределено Тогда
ПроверяемыеРеквизиты.Удалить(ИндексКПП);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Бывает обратная ситуация: в конфигураторе у реквизита Договор стоит значение «Не проверять», так как он нужен не всегда. Но если сумма документа превышает 100 000 рублей, договор становится строго обязательным. Реализуем такое поведение:
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
// Проверяем условие обязательности договора
Если СуммаДокумента > 100000 Тогда
// Проверяем, нет ли его уже в массиве, чтобы избежать дублирования
Если ПроверяемыеРеквизиты.Найти("Договор") = Неопределено Тогда
ПроверяемыеРеквизиты.Добавить("Договор");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Работа с табличными частями в контексте проверки заполнения имеет свои нюансы, которые необходимо учитывать:
ПроверяемыеРеквизиты просто имя табличной части (например, "Товары"), то система проверит только одно: наличие хотя бы одной строки в этой табличной части. Если таблица пустая — будет выдана ошибка."Товары.Номенклатура" или "Товары.Количество".Проанализируем пример условной проверки колонки табличной части. Допустим, колонку Спецификация в табличной части Товары нужно проверять только для услуг:
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
// По умолчанию колонка "Товары.Спецификация" настроена как обязательная в конфигураторе.
// Если в табличной части есть товары, которые не являются услугами, снимем для них обязательность.
ЕстьТоварыНЕУслуги = Ложь;
Для Каждого СтрокаТЧ Из Товары Цикл
Если СтрокаТЧ.Номенклатура.ТипНоменклатуры <> Перечисления.ТипыНоменклатуры.Услуга Тогда
ЕстьТоварыНЕУслуги = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
// Если найдены обычные товары, убираем жесткую автоматическую проверку колонки для всей ТЧ
Если ЕстьТоварыНЕУслуги Тогда
ИндексКолонки = ПроверяемыеРеквизиты.Найти("Товары.Спецификация");
Если ИндексКолонки <> Неопределено Тогда
ПроверяемыеРеквизиты.Удалить(ИндексКолонки);
КонецЕсли;
// Теперь мы должны вручную проверить только те строки, где действительно услуга
Для Каждого СтрокаТЧ Из Товары Цикл
Если СтрокаТЧ.Номенклатура.ТипНоменклатуры = Перечисления.ТипыНоменклатуры.Услуга
И Не ЗначениеЗаполнено(СтрокаТЧ.Спецификация) Тогда
// Выводим сообщение об ошибке пользователю напрямую
ТекстСообщения = ШаблонОбщегоНазначенияКлиентСервер.ПолучитьШаблонСообщенияОбОшибкеЗаполненияРеквизита("Спецификация");
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
НСтр("ru = 'Не заполнена спецификация для услуги!'"),
ЭтотОбъект,
"Товары[" + Формат(Товары.Индекс(СтрокаТЧ), "ЧГ=0") + "].Спецификация",
,
Отказ
);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Не забывайте про существование стандартного механизма прерывания проверок. Если в модуле формы в процедуре ОбработкаПроверкиЗаполненияНаСервере вы установите параметр СтандартнаяОбработка = Ложь, то платформа полностью откажется от автоматического вызова проверки в модуле объекта. В этом случае массив ПроверяемыеРеквизиты в модуле объекта не будет формироваться автоматически на основе метаданных, пока вы сами явно не вызовете метод ПроверитьЗаполнение() для объекта.
Использование этого параметра позволяет разработчику полностью взять под контроль весь сценарий валидации данных формы и объекта, подменяя стандартные системные сообщения собственными алгоритмами.