При разработке интерфейсов на платформе 1С:Предприятие 8.3 программисты и продвинутые пользователи часто сталкиваются с задачей визуального выделения документов в списке на основании данных, содержащихся в их табличных частях. Типичный пример: выделить цветом все «Заказы клиентов», в которых есть хотя бы одна позиция номенклатуры с определенным кодом ТН ВЭД. Однако при попытке реализовать это через стандартное Условное оформление формы списка многие замечают странное поведение: оформление срабатывает только в том случае, если искомое значение находится в самой первой строке табличной части. Если же условие выполняется для второй, третьей или десятой строки, документ в списке остается неоформленным.
В этой статье мы подробно разберем, почему платформа ведет себя именно так, проанализируем технические ограничения динамических списков и рассмотрим несколько эффективных способов решения этой задачи, от простых настроек до программной доработки запросов.
Давайте проанализируем ситуацию с точки зрения работы базы данных. Когда мы добавляем в динамический список поле из табличной части (например, Товары.Номенклатура.КодТНВЭД), платформа 1С вынуждена при выполнении SQL-запроса соединять основную таблицу документов с таблицей их составных частей (используя оператор LEFT JOIN).
Основное правило динамического списка в 1С заключается в том, что одна строка в списке должна соответствовать одному объекту (документу). Если у документа в табличной части «Товары» содержится 20 строк, система не может вывести 20 строк в списке документов — это нарушит логику интерфейса. Чтобы сохранить уникальность строк, платформа при простом соединении таблиц зачастую ограничивает выборку данных из связанной таблицы. В результате для целей условного оформления анализируется только та запись, которая физически оказалась первой в выборке СУБД для данного документа. Именно поэтому оформление «подхватывается» только по первой строке и игнорирует остальные.
Рассмотрим, как мы можем обойти это ограничение и заставить систему проверять все строки документа.
Самый правильный и производительный метод — это модификация самого текста запроса, который питает динамический список. Вместо того чтобы полагаться на автоматические связи платформы, мы сами подготовим поле-признак.
Разберем по шагам, как это сделать:
Истина, если в документе есть хотя бы одна подходящая строка. Для этого идеально подходит оператор ГДЕ СУЩЕСТВУЕТ (EXISTS).Посмотрим на пример текста запроса:
ВЫБРАТЬ
ДокументЗаказКлиента.Ссылка КАК Ссылка,
ДокументЗаказКлиента.Дата КАК Дата,
ДокументЗаказКлиента.Номер КАК Номер,
ВЫБОР
КОГДА ЕСТЬNULL((ВЫБРАТЬ ТОП 1 1
ИЗ Документ.ЗаказКлиента.Товары КАК Т
ГДЕ Т.Ссылка = ДокументЗаказКлиента.Ссылка
И Т.Номенклатура.КодТНВЭД ПОДОБНО "2710%"), 0) = 1
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ КАК СодержитЦелевойТНВЭД
ИЗ
Документ.ЗаказКлиента КАК ДокументЗаказКлиента
В данном примере мы создали вычисляемое поле СодержитЦелевойТНВЭД. Подзапрос ищет хотя бы одну запись в табличной части, соответствующую условию. Если запись найдена, поле получает значение Истина. Теперь в настройках Условного оформления на закладке «Условие» нам достаточно указать: СодержитЦелевойТНВЭД Равно Истина. Это решение будет работать безупречно для любой строки документа.
Если структура вашего динамического списка позволяет использовать группировки, можно применить агрегатные функции для вычисления признака. Рассмотрим этот вариант подробнее.
Мы можем соединить таблицу документов с таблицей товаров и сгруппировать результат по ссылке документа. Для определения наличия нужного кода можно использовать функцию МАКСИМУМ для булевого поля или КОЛИЧЕСТВО.
ВЫБРАТЬ
Заказ.Ссылка КАК Ссылка,
МАКСИМУМ(ВЫБОР
КОГДА Товары.Номенклатура.КодТНВЭД ПОДОБНО "2710%"
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ) КАК ЕстьПроблемныйТНВЭД
ИЗ
Документ.ЗаказКлиента КАК Заказ
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента.Товары КАК Товары
ПО Заказ.Ссылка = Товары.Ссылка
СГРУППИРОВАТЬ ПО
Заказ.Ссылка
Важно: При использовании этого метода нужно быть осторожным с производительностью. Если в таблице сотни тысяч документов и миллионы строк товаров, группировка «на лету» в динамическом списке может замедлить прокрутку и открытие формы.
Проанализируем ситуацию: что если список документов открывается сотни раз в день разными пользователями, а база данных очень объемная? В этом случае постоянные вложенные запросы к табличным частям могут создать избыточную нагрузку на SQL-сервер.
Для оптимизации применяется метод денормализации. Мы добавляем реальный реквизит СодержитСпецифическийТНВЭД (тип Булево) непосредственно в шапку документа. Далее, в модуле объекта документа в процедуре ПередЗаписью, мы прописываем логику проверки табличной части:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Проверяем наличие кода ТН ВЭД в строках
НайденныйКод = Ложь;
Для Каждого СтрокаТовара Из Товары Цикл
Если Лев(СтрокаТовара.Номенклатура.КодТНВЭД, 4) = "2710" Тогда
НайденныйКод = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
СодержитСпецифическийТНВЭД = НайденныйКод;
КонецПроцедуры
Теперь условное оформление настраивается по реквизиту шапки. Это работает мгновенно, так как системе не нужно обращаться к другим таблицам. Минус этого способа — необходимость обновления этого реквизита в уже существующих документах (например, через групповую обработку).
Если вы все же пытаетесь решить задачу без изменения кода, обратите внимание на параметр Вид сравнения в настройках оформления. Часто пользователи выбирают «Равно» или «В списке», что не совсем корректно для поиска по маске.
Разберем правильные варианты:
Однако помните: без программной правки запроса (Способ 1), даже с правильным видом сравнения, 1С продолжит анализировать преимущественно первую физическую строку табличной части, попавшую в выборку.
Мы рассмотрели проблему, когда условное оформление динамического списка 1С «не видит» строки табличной части дальше первой. Подводя итог, можно сказать: наиболее сбалансированным решением является использование произвольного запроса с вложенным подзапросом ВЫБРАТЬ ТОП 1. Это обеспечивает точность данных и приемлемую скорость работы системы. Если же скорость критична — используйте скрытый реквизит в шапке документа.
Используя эти методы, вы сможете создавать действительно удобные и информативные интерфейсы для пользователей, помогая им оперативно ориентироваться в больших массивах документов.