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