Как реализовать сложное условное оформление в табличной части документа 1С на основе реквизитов ссылок

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке на платформе 1С:Предприятие 8.3 (Управляемые формы) программисты часто сталкиваются со стандартным ограничением механизма «Условного оформления». Если нам нужно раскрасить строку табличной части на основе простого реквизита (например, Количество > 10), проблем не возникает. Однако, как только задача усложняется и требует обращения к свойствам объектов через точку (например, сравнить срок хранения из карточки номенклатуры с датой из серии), стандартный конструктор в конфигураторе оказывается бессилен. Платформа не позволяет выбирать «реквизиты реквизитов» для условий оформления в реальном времени, так как это вызвало бы серьезные проблемы с производительностью из-за неявных запросов к базе данных при отрисовке каждой строки.

В этой статье мы подробно разберем, как обойти это ограничение, реализовать сложную логику проверки и при этом сохранить высокую скорость работы интерфейса. Мы рассмотрим наиболее эффективный метод — использование вспомогательного реквизита формы.

Суть проблемы: почему нельзя обратиться «через точку»?

Рассмотрим ситуацию: в документе «Заказ покупателя» есть табличная часть Товары. В строке указана Номенклатура (ссылка) и Серия (ссылка). У номенклатуры есть реквизит СрокХранения (число в месяцах), а у серии — ГоденДо (дата). Нам нужно подсветить строки, где текущая дата плюс срок хранения номенклатуры превышает срок годности серии.

Прямое условие в условном оформлении вида Объект.Товары.Номенклатура.СрокХранения + ТекущаяДата > Объект.Товары.Серия.ГоденДо невозможно, так как в коллекции ДанныеФормыКоллекция, с которой работает оформление, физически нет этих вложенных данных. Они находятся в таблицах справочников, а не в самой табличной части документа.

Решение: Использование служебного реквизита формы

Разберем самый надежный и производительный алгоритм решения этой задачи по шагам.

Шаг 1. Добавление колонки-флага в данные формы

Нам необходимо создать место, где будет храниться результат нашего сложного расчета. Для этого мы добавим реквизит не в сам объект (документ), а именно в Реквизиты формы.

  1. Откроем форму документа в конфигураторе.
  2. Перейдем на закладку «Реквизиты».
  3. Найдем в составе Объект нашу табличную часть (например, Товары).
  4. Нажмем правую кнопку мыши на табличной части и выберем «Добавить реквизит колонки».
  5. Назовем его СрокКритичен, тип — Булево.

Важно: этот реквизит не будет записываться в базу данных, он существует только «в памяти» открытой формы. Это именно то, что нам нужно для оформления.

Шаг 2. Настройка условного оформления

Теперь, когда у нас есть булево поле в каждой строке, настроить раскраску становится элементарно. Мы можем сделать это программно в процедуре ПриСозданииНаСервере или через диалог «Условное оформление» в свойствах формы.

Рассмотрим программный способ, так как он более гибкий:


&НаСервере
Процедура УстановитьУсловноеОформлениеНаФорме()
    
    ЭлементОформления = УсловноеОформление.Элементы.Добавить();
    
    // Указываем условие: наш флаг равен Истина
    ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.СрокКритичен");
    ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
    ЭлементУсловия.ПравоеЗначение = Истина;
    
    // Указываем оформление: красный цвет текста
    ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветТекста", WebЦвета.Красный);
    
    // Указываем поля, которые будем красить (например, Номенклатура и Серия)
    ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
    ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ТоварыНоменклатура");
    
    ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
    ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ТоварыСерия");
    
КонецПроцедуры

Шаг 3. Реализация логики расчета

Проанализируем, в какие моменты нам нужно пересчитывать значение СрокКритичен. Это должно происходить:

Для оптимизации вынесем логику расчета в отдельную процедуру. Поскольку нам нужно обращаться к реквизитам ссылок, расчет должен происходить на сервере.


&НаСервере
Процедура РассчитатьСрокКритиченДляСтроки(СтрокаТЧ)
    
    // Если данные не заполнены, сбрасываем флаг
    Если Не ЗначениеЗаполнено(СтрокаТЧ.Номенклатура) Или Не ЗначениеЗаполнено(СтрокаТЧ.Серия) Тогда
        СтрокаТЧ.СрокКритичен = Ложь;
        Возврат;
    КонецЕсли;
    
    // Получаем данные одним запросом или через обращение к объекту (зависит от контекста)
    // В данном случае для наглядности используем обращение через точку
    СрокХраненияМес = СтрокаТЧ.Номенклатура.СрокХранения;
    ДатаГодности = СтрокаТЧ.Серия.ГоденДо;
    
    // Проверка логики
    Если ЗначениеЗаполнено(ДатаГодности) Тогда
        РасчетнаяДата = ДобавитьМесяц(ТекущаяДатаСеанса(), СрокХраненияМес);
        СтрокаТЧ.SrokKritichen = (РасчетнаяДата > ДатаГодности);
    Иначе
        СтрокаТЧ.СрокКритичен = Ложь;
    КонецЕсли;
    
КонецПроцедуры

Шаг 4. Обработка событий формы

Выясним, как правильно вызывать расчет при взаимодействии пользователя с формой. Разберем основные обработчики.

1. При чтении на сервере. Это событие срабатывает при открытии уже записанного документа. Здесь мы должны пройтись циклом по всей табличной части и заполнить наши флаги.


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    Для Каждого Стр Из Объект.Товары Цикл
        РассчитатьСрокКритиченДляСтроки(Стр);
    КонецЦикла;
КонецПроцедуры

2. Изменение реквизитов. Для полей Номенклатура и Серия в табличной части создадим клиентские обработчики ПриИзменении, которые будут вызывать серверный расчет для конкретной строки.


&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
    ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
    Если ТекущаяСтрока <> Неопределено Тогда
        РассчитатьСрокКритиченНаСервереДляОднойСтроки(ТекущаяСтрока.ПолучитьИдентификатор());
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура РассчитатьСрокКритиченНаСервереДляОднойСтроки(ИдентификаторСтроки)
    Стр = Объект.Товары.НайтиПоИдентификатору(ИдентификаторСтроки);
    РассчитатьСрокКритиченДляСтроки(Стр);
КонецПроцедуры

3. Обработка подбора. Если товары добавляются через форму подбора, необходимо вызвать полный или частичный пересчет в процедуре ОбработкаВыбора или в обработчике события, которое генерирует форма подбора.

Оптимизация: когда строк очень много

Если в вашем документе тысячи строк, расчет «через точку» в цикле может замедлить открытие формы. В этом случае проанализируем ситуацию и применим Запрос в процедуре ПриЧтенииНаСервере. Мы можем одним запросом получить все необходимые сроки хранения и даты годности для всех уникальных товаров и серий документа, а затем быстро распределить их по строкам таблицы.

Альтернативный вариант: Динамический список

Рассмотрим случай, когда таблица в документе предназначена в основном для просмотра. В такой ситуации можно заменить стандартную таблицу на Динамический список с произвольным запросом. В запросе динамического списка мы можем свободно соединять таблицы (например, ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура) и вычислять любые поля прямо на уровне SQL. В этом случае условное оформление будет работать максимально быстро и без написания кода в обработчиках событий, так как все поля будут доступны в схеме компоновки данных списка.

Итоги

Мы выяснили, что для решения задачи раскраски по «сложным» условиям в 1С лучше всего использовать связку «скрытый реквизит формы + расчет в событиях + условное оформление по этому реквизиту». Это решение является стандартным для платформы 1С и обеспечивает отличный баланс между сложностью реализации и производительностью системы.

Помните, что использование расширений (для версий платформы 8.3.15 и выше) позволяет добавлять подобные служебные реквизиты даже в типовые конфигурации, не снимая их с поддержки, что делает этот метод еще более универсальным и безопасным.

← На главную