При разработке на платформе 1С:Предприятие 8.3 (Управляемые формы) программисты часто сталкиваются со стандартным ограничением механизма «Условного оформления». Если нам нужно раскрасить строку табличной части на основе простого реквизита (например, Количество > 10), проблем не возникает. Однако, как только задача усложняется и требует обращения к свойствам объектов через точку (например, сравнить срок хранения из карточки номенклатуры с датой из серии), стандартный конструктор в конфигураторе оказывается бессилен. Платформа не позволяет выбирать «реквизиты реквизитов» для условий оформления в реальном времени, так как это вызвало бы серьезные проблемы с производительностью из-за неявных запросов к базе данных при отрисовке каждой строки.
В этой статье мы подробно разберем, как обойти это ограничение, реализовать сложную логику проверки и при этом сохранить высокую скорость работы интерфейса. Мы рассмотрим наиболее эффективный метод — использование вспомогательного реквизита формы.
Рассмотрим ситуацию: в документе «Заказ покупателя» есть табличная часть Товары. В строке указана Номенклатура (ссылка) и Серия (ссылка). У номенклатуры есть реквизит СрокХранения (число в месяцах), а у серии — ГоденДо (дата). Нам нужно подсветить строки, где текущая дата плюс срок хранения номенклатуры превышает срок годности серии.
Прямое условие в условном оформлении вида Объект.Товары.Номенклатура.СрокХранения + ТекущаяДата > Объект.Товары.Серия.ГоденДо невозможно, так как в коллекции ДанныеФормыКоллекция, с которой работает оформление, физически нет этих вложенных данных. Они находятся в таблицах справочников, а не в самой табличной части документа.
Разберем самый надежный и производительный алгоритм решения этой задачи по шагам.
Нам необходимо создать место, где будет храниться результат нашего сложного расчета. Для этого мы добавим реквизит не в сам объект (документ), а именно в Реквизиты формы.
Объект нашу табличную часть (например, Товары).СрокКритичен, тип — Булево.Важно: этот реквизит не будет записываться в базу данных, он существует только «в памяти» открытой формы. Это именно то, что нам нужно для оформления.
Теперь, когда у нас есть булево поле в каждой строке, настроить раскраску становится элементарно. Мы можем сделать это программно в процедуре ПриСозданииНаСервере или через диалог «Условное оформление» в свойствах формы.
Рассмотрим программный способ, так как он более гибкий:
&НаСервере
Процедура УстановитьУсловноеОформлениеНаФорме()
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
// Указываем условие: наш флаг равен Истина
ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.СрокКритичен");
ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементУсловия.ПравоеЗначение = Истина;
// Указываем оформление: красный цвет текста
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветТекста", WebЦвета.Красный);
// Указываем поля, которые будем красить (например, Номенклатура и Серия)
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ТоварыНоменклатура");
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ТоварыСерия");
КонецПроцедуры
Проанализируем, в какие моменты нам нужно пересчитывать значение СрокКритичен. Это должно происходить:
Для оптимизации вынесем логику расчета в отдельную процедуру. Поскольку нам нужно обращаться к реквизитам ссылок, расчет должен происходить на сервере.
&НаСервере
Процедура РассчитатьСрокКритиченДляСтроки(СтрокаТЧ)
// Если данные не заполнены, сбрасываем флаг
Если Не ЗначениеЗаполнено(СтрокаТЧ.Номенклатура) Или Не ЗначениеЗаполнено(СтрокаТЧ.Серия) Тогда
СтрокаТЧ.СрокКритичен = Ложь;
Возврат;
КонецЕсли;
// Получаем данные одним запросом или через обращение к объекту (зависит от контекста)
// В данном случае для наглядности используем обращение через точку
СрокХраненияМес = СтрокаТЧ.Номенклатура.СрокХранения;
ДатаГодности = СтрокаТЧ.Серия.ГоденДо;
// Проверка логики
Если ЗначениеЗаполнено(ДатаГодности) Тогда
РасчетнаяДата = ДобавитьМесяц(ТекущаяДатаСеанса(), СрокХраненияМес);
СтрокаТЧ.SrokKritichen = (РасчетнаяДата > ДатаГодности);
Иначе
СтрокаТЧ.СрокКритичен = Ложь;
КонецЕсли;
КонецПроцедуры
Выясним, как правильно вызывать расчет при взаимодействии пользователя с формой. Разберем основные обработчики.
1. При чтении на сервере. Это событие срабатывает при открытии уже записанного документа. Здесь мы должны пройтись циклом по всей табличной части и заполнить наши флаги.
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
Для Каждого Стр Из Объект.Товары Цикл
РассчитатьСрокКритиченДляСтроки(Стр);
КонецЦикла;
КонецПроцедуры
2. Изменение реквизитов. Для полей Номенклатура и Серия в табличной части создадим клиентские обработчики ПриИзменении, которые будут вызывать серверный расчет для конкретной строки.
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
Если ТекущаяСтрока <> Неопределено Тогда
РассчитатьСрокКритиченНаСервереДляОднойСтроки(ТекущаяСтрока.ПолучитьИдентификатор());
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура РассчитатьСрокКритиченНаСервереДляОднойСтроки(ИдентификаторСтроки)
Стр = Объект.Товары.НайтиПоИдентификатору(ИдентификаторСтроки);
РассчитатьСрокКритиченДляСтроки(Стр);
КонецПроцедуры
3. Обработка подбора. Если товары добавляются через форму подбора, необходимо вызвать полный или частичный пересчет в процедуре ОбработкаВыбора или в обработчике события, которое генерирует форма подбора.
Если в вашем документе тысячи строк, расчет «через точку» в цикле может замедлить открытие формы. В этом случае проанализируем ситуацию и применим Запрос в процедуре ПриЧтенииНаСервере. Мы можем одним запросом получить все необходимые сроки хранения и даты годности для всех уникальных товаров и серий документа, а затем быстро распределить их по строкам таблицы.
Рассмотрим случай, когда таблица в документе предназначена в основном для просмотра. В такой ситуации можно заменить стандартную таблицу на Динамический список с произвольным запросом. В запросе динамического списка мы можем свободно соединять таблицы (например, ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура) и вычислять любые поля прямо на уровне SQL. В этом случае условное оформление будет работать максимально быстро и без написания кода в обработчиках событий, так как все поля будут доступны в схеме компоновки данных списка.
Мы выяснили, что для решения задачи раскраски по «сложным» условиям в 1С лучше всего использовать связку «скрытый реквизит формы + расчет в событиях + условное оформление по этому реквизиту». Это решение является стандартным для платформы 1С и обеспечивает отличный баланс между сложностью реализации и производительностью системы.
Помните, что использование расширений (для версий платформы 8.3.15 и выше) позволяет добавлять подобные служебные реквизиты даже в типовые конфигурации, не снимая их с поддержки, что делает этот метод еще более универсальным и безопасным.