При разработке крупных корпоративных систем на базе 1С:ERP Управление предприятием часто возникает задача динамического контроля ввода свойств или характеристик номенклатуры. Типичный сценарий: в зависимости от выбора одних свойств (например, вида материала или габаритов), необходимо накладывать жесткие ограничения на доступность, видимость или обязательность заполнения других свойств.
Сложность заключается в том, что условия взаимосвязи свойств редко бывают линейными. Они могут содержать сложные логические конструкции: «Если Свойство 1 заполнено И Свойство 3 НЕ равно Значению А, ТО Свойство 2 становится обязательным для заполнения, а из списка выбора Свойства 2 исключаются определенные значения».
В этой статье мы подробно разберем, как спроектировать архитектуру хранения таких условий, решить проблему контроля ссылочной целостности при удалении свойств, и как использовать мощь системы компоновки данных (СКД) для мгновенной проверки условий на форме без написания сложных парсеров на встроенном языке 1С.
Прежде чем переходить к алгоритмам проверки, необходимо определиться, как именно хранить условия отборов и правил в базе данных. Существует несколько подходов, рассмотрим их сильные и слабые стороны:
Этот способ кажется простым, так как позволяет напрямую сериализовать настройки компоновщика отбора. Однако у него есть критический недостаток — отсутствие контроля ссылочной целостности. Если пользователь решит удалить одно из свойств или конкретное значение свойства, система не сможет штатно отследить, что эта ссылка используется внутри сериализованного объекта в Хранилище Значения. В результате при проверке правил система начнет выдавать труднодиагностируемые ошибки («битые ссылки»).
Этот подход является наиболее надежным и используется в типовых конфигурациях 1С (например, в Библиотеке стандартных подсистем). Мы создаем специальный справочник (например, ПравилаСовместногоЗаполненияСвойств) с табличной частью, в которой каждая строка представляет собой элементарное условие: Свойство, Вид сравнения, Значение. Для сложных иерархических условий (И, ИЛИ, НЕ) можно использовать подчиненные справочники или рекурсивную структуру табличных частей.
Преимущество: Платформа 1С автоматически отслеживает ссылки во всех табличных частях. При попытке удаления свойства сработает стандартный механизм поиска ссылок, и система либо заблокирует удаление, либо позволит вам корректно очистить или скорректировать правила через подписку на событие ПередУдалением.
Когда структура хранения определена, возникает следующая сложная задача: как быстро и универсально проверить, удовлетворяют ли текущие значения свойств, выбранные пользователем на форме, настроенному правилу отбора?
Написание собственного парсера, который вручную обходил бы дерево условий, учитывал виды сравнения («В списке», «Не в списке», «Заполнено», «В группе» для иерархических справочников), крайне трудоемко и неэффективно. Вместо этого мы можем использовать штатный процессор СКД, заставив его работать с виртуальной таблицей значений.
Рассмотрим подробный алгоритм решения этой задачи:
Проанализируем программную реализацию этого алгоритма на встроенном языке 1С:
// Функция проверяет, соответствуют ли текущие значения свойств заданному отбору СКД
//
// Параметры:
// ТекущиеСвойства - Структура - Ключ: Свойство (ссылка), Значение: ВыбранноеЗначение
// НастройкиОтбора - НастройкиКомпоновкиДанных - сохраненные настройки отбора
//
// Возвращает:
// Булево - Истина, если свойства удовлетворяют условиям отбора
//
Функция ПроверитьСоответствиеСвойствОтбору(ТекущиеСвойства, НастройкиОтбора) Экспорт
// 1. Создаем таблицу значений с одной строкой
ТаблицаДанных = Новый ТаблицаЗначений;
НоваяСтрока = ТаблицаДанных.Добавить();
Для Каждого КлючИЗначение Из ТекущиеСвойства Цикл
// Имя колонки формируем уникальным образом на основе УИД свойства,
// чтобы избежать недопустимых символов в именах полей СКД
ИмяКолонки = "П_" + СтрЗаменить(Строка(КлючИЗначение.Ключ.УникальныйИдентификатор()), "-", "_");
ТаблицаДанных.Колонки.Добавить(ИмяКолонки);
НоваяСтрока[ИмяКолонки] = КлючИЗначение.Value;
КонецЦикла;
// 2. Программно создаем схему компоновки данных
СхемаСКД = Новый СхемаКомпоновкиДанных;
ИсточникДанных = СхемаСКД.ИсточникиДанных.Добавить("ИсточникДанных1");
ИсточникДанных.ТипИсточникаДанных = "Local";
НаборДанных = СхемаСКД.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
НаборДанных.Имя = "НаборДанных1";
НаборДанных.ИмяОбъекта = "ТаблицаДанных";
НаборДанных.ИсточникДанных = "ИсточникДанных1";
// Добавляем поля в набор данных схемы
Для Каждого Колонка Из ТаблицаДанных.Колонки Цикл
ПолеСхемы = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
ПолеСхемы.ПутьКДанным = Колонка.Имя;
ПолеСхемы.Поле = Колонка.Имя;
ПолеСхемы.Заголовок = Колонка.Имя;
КонецЦикла;
// 3. Инициализируем компоновщик настроек и загружаем в него отбор
КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаСКД));
// Загружаем сохраненный отбор в настройки компоновщика
КомпоновщикНастроек.ЗагрузитьНастройки(НастройкиОтбора);
// 4. Выполняем компоновку данных
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаСКД, КомпоновщикНастроек.ПолучитьНастройки(), , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ВнешниеНаборы = Новый Структура("ТаблицаДанных", ТаблицаДанных);
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборы);
РезультатТаблица = Новый ТаблицаЗначений;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(РезультатТаблица);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// 5. Если строка осталась после применения отбора - условия выполнены
Возврат РезультатТаблица.Количество() > 0;
КонецФункции
Предложенный подход крайне гибок и решает проблему сложных отборов любой вложенности, включая отборы по группам (иерархии) справочников. Однако программное создание СКД и выполнение процессора компоновки — достаточно ресурсоемкие операции для платформы 1С. Если на форме расположено множество свойств, и проверка должна выполняться интерактивно при каждом изменении, пользователь может заметить задержки (микрофризы) интерфейса.
Рассмотрим несколько приемов, которые позволят оптимизировать этот механизм и сделать его работу мгновенной:
Вместо того чтобы собирать объект СхемаКомпоновкиДанных заново при каждом изменении реквизита на форме, целесообразно инициализировать структуру схемы один раз при открытии формы (или при первом обращении к подсистеме контроля свойств). Сконструированную схему можно сохранить в реквизите формы или поместить во Временное хранилище. При изменении значений пользователю нужно будет лишь обновлять данные в таблице значений и передавать её в уже готовый процессор компоновки.
Далеко не все условия в вашей системе будут сложными. По статистике, около 80–90% условий представляют собой простые проверки вида «Свойство равно Значению» или «Свойство заполнено». Для таких простых правил запускать полноценный механизм СКД избыточно.
Мы рекомендуем разработать легкую функцию-препроцессор на встроенном языке 1С. Она будет обходить коллекцию элементов отбора и выполнять простые проверки (равенство, неравенство, проверка на заполненность) напрямую в коде. И только если препроцессор обнаружит сложные виды сравнения (например, «В группе», «В списке» или сложные логические группы «ИЛИ», «НЕ»), система передаст задачу тяжеловесному механизму СКД. Это снизит нагрузку на сервер в разы.
Если на форме действует множество независимых правил контроля, не стоит запускать процедуру проверки для каждого правила по отдельности. Вместо этого в таблицу значений, передаваемую в СКД, можно поместить не одну строку, а несколько (по строке на каждое проверяемое правило). Добавьте в таблицу значений служебную колонку ИдентификаторПравила. Процессор СКД наложит общий отбор на всю таблицу, и на выходе вы получите список только тех идентификаторов правил, условия которых успешно выполнились. Это позволит выполнить всего один цикл компоновки данных для всей формы.
Используя предложенную архитектуру хранения и гибридный метод проверки условий через виртуальные таблицы СКД, вы сможете построить отказоустойчивую, гибкую и быстродействующую подсистему контроля ввода свойств в 1С:ERP, которая будет легко масштабироваться под любые требования бизнеса.