При переходе на управляемые формы разработчики часто сталкиваются с трудностями при работе с динамическими таблицами. Типичные проблемы — созданная на сервере таблица значений не отображается на форме, данные запроса содержат ошибки соединения, а попытки раскрасить строки «по старинке» через обход в цикле ни к чему не приводят. В этой статье мы подробно разберем, как правильно спроектировать этот механизм, исправим ошибки в запросе и настроим автоматическое условное оформление.
В управляемом приложении 1С действует строгое разделение на клиент и сервер. Переменная, созданная конструктором Новый ТаблицаЗначений внутри серверной процедуры, существует только в оперативной памяти сервера во время выполнения этой процедуры. Как только код завершается, таблица уничтожается.
Для того чтобы данные отобразились в интерфейсе пользователя, необходимо связать их с контекстом формы. В 1С это реализуется через связку: Реквизит формы (Данные) -> Элемент формы (Отображение). Рассмотрим, как правильно выполнить эту связь.
Проанализируем три главные ошибки в исходном коде автора темы:
И (AND) при соединении по трем субконто одновременно приводит к тому, что запрос всегда будет возвращать пустые значения (или NULL) для номенклатуры. На счете учета номенклатура физически не может находиться одновременно в трех разрезах аналитики.УсловноеОформление, который работает декларативно.Разберем по шагам правильную реализацию задачи.
---
Перед тем как писать программный код, нам нужно подготовить структуру на самой форме в конфигураторе. Выполним следующие действия:
ТаблицаОстатков. Укажем тип данных — ТаблицаЗначений.ТаблицаОстатков и добавим в нее колонки:
Номенклатура (Тип: СправочникСсылка.Номенклатура)Остаток (Тип: Число, длина 15, точность 3)Себестоимость (Тип: Число, длина 15, точность 2)МинимальныйОстаток (Тип: Число, длина 15, точность 3)ПревышенМинимум (Тип: Булево) — эта скрытая колонка понадобится нам для упрощения настройки условного оформления.ТаблицаОстатков в левое окно Элементы. Платформа автоматически создаст элемент формы типа «Таблица» и подчиненные ему поля ввода для каждой колонки.---
Рассмотрим структуру запроса. Нам нужно получить остатки по счету товаров (например, счет 41 «Товары») и соединить их со справочником «Номенклатура», чтобы получить значение реквизита _МинимальныйОстаток.
Поскольку субконто на счетах учета имеют составной тип данных, для оптимизации работы СУБД крайне важно использовать оператор ВЫРАЗИТЬ. Соединение нужно делать только по тому субконто, на котором ведется учет номенклатуры (в типовых конфигурациях это обычно Субконто1).
Также мы сразу рассчитаем себестоимость на уровне запроса с защитой от деления на ноль и вычислим признак дефицита товара (ПревышенМинимум).
Посмотрим на пример правильного запроса:
&НаСервере
Процедура ЗаполнитьТаблицуНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(ТиповойОстатки.Субконто1 КАК Справочник.Номенклатура) КАК Номенклатура,
| ТиповойОстатки.КоличествоОстаток КАК Остаток,
| ВЫБОР
| КОГДА ТиповойОстатки.КоличествоОстаток = 0 ТОГДА 0
| ИНАЧЕ ТиповойОстатки.СуммаОстаток / ТиповойОстатки.КоличествоОстаток
| КОНЕЦ КАК Себестоимость,
| ЕСТЬNULL(Номенклатура._МинимальныйОстаток, 0) КАК МинимальныйОстаток,
| ВЫБОР
| КОГДА ТиповойОстатки.КоличествоОстаток <= ЕСТЬNULL(Номенклатура._МинимальныйОстаток, 0) ТОГДА ИСТИНА
| ИНАЧЕ ЛОЖЬ
| КОНЕЦ КАК ПревышенМинимум
|ИЗ
| РегистрБухгалтерии.Типовой.Остатки(, Счет.Код = ""41"", , ) КАК ТиповойОстатки
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
| ПО (ВЫРАЗИТЬ(ТиповойОстатки.Субконто1 КАК Справочник.Номенклатура)) = Номенклатура.Ссылка";
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Заполняем реквизит формы данными полученной таблицы значений
ЗначениеВРеквизитФормы(РезультатЗапроса, "ТаблицаОстатков");
КонецПроцедуры
Использование метода ЗначениеВРеквизитФормы позволяет мгновенно транслировать выгруженную таблицу из запроса в объект интерфейса без ручного перебора строк в цикле, что значительно повышает производительность системы.
---
Теперь разберем, как сделать так, чтобы строки, где реальный остаток меньше или равен минимальному, окрашивались в красный цвет.
Мы задействуем расчетную колонку ПревышенМинимум, значение которой рассчитали еще на этапе выполнения запроса. Это самый надежный и быстродействующий способ реализации условного оформления, так как системе не приходится «на лету» сравнивать два динамических поля для каждой строки при отрисовке интерфейса.
Настройку условного оформления выполним программно в обработчике события формы ПриСозданииНаСервере. Рассмотрим код настройки подробнее:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Заполняем таблицу данными
ЗаполнитьТаблицуНаСервере();
// Настраиваем правила оформления интерфейса
НастроитьУсловноеОформлениеТаблицы();
КонецПроцедуры
&НаСервере
Процедура НастроитьУсловноеОформлениеТаблицы()
// 1. Создаем новый элемент условного оформления
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
ЭлементОформления.Использование = Истина;
// 2. Указываем оформление (красный фон для привлечения внимания)
// Можно использовать WebЦвета или системные цвета стиля
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.СветлоРозовый);
// 3. Задаем условие срабатывания: ТаблицаОстатков.ПревышенМинимум Равно Истина
ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ТаблицаОстатков.ПревышенМинимум");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Истина;
ЭлементОтбора.Использование = Истина;
// 4. Указываем, какие именно поля (колонки) нужно раскрасить
// Если хотите красить только колонку "Остаток":
ПолеОформления = ЭлементОформления.Поля.Элементы.Добавить();
ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("ТаблицаОстатковОстаток");
ПолеОформления.Использование = Истина;
// Если требуется раскрасить всю строку целиком, добавьте аналогичным образом
// все остальные элементы-колонки таблицы на форме:
// ПолеНоменклатура = ЭлементОформления.Поля.Элементы.Добавить();
// ПолеНоменклатура.Поле = Новый ПолеКомпоновкиДанных("ТаблицаОстатковНоменклатура");
// ПолеНоменклатура.Использование = Истина;
КонецПроцедуры
Важное замечание по именам полей: Обратите внимание, что при заполнении ПолеКомпоновкиДанных для отбора используется имя реквизита через точку (ТаблицаОстатков.ПревышенМинимум), а для указания оформляемых полей используется имя элемента управления формы, которое обычно генерируется как слияние имени таблицы и имени колонки (ТаблицаОстатковОстаток).
---
Если по каким-то причинам вы не хотите добавлять вспомогательную булеву колонку в вашу таблицу значений, платформа 1С позволяет настроить условное оформление путем прямого сравнения значений двух полей. Для этого в качестве правого значения отбора передается не константа, а объект ПолеКомпоновкиДанных.
Проанализируем пример такой настройки отбора:
// Альтернативный вариант настройки отбора "Остаток <= МинимальныйОстаток"
ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ТаблицаОстатков.Остаток");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.МеньшеИлиРавно;
ЭлементОтбора.ПравоеЗначение = Новый ПолеКомпоновкиДанных("ТаблицаОстатков.МинимальныйОстаток");
ЭлементОтбора.Использование = Истина;
Этот способ более лаконичен в плане структуры данных, однако первый вариант (с использованием расчетной булевой колонки ПревышенМинимум) работает быстрее на больших объемах данных, так как избавляет клиентское приложение от необходимости производить вычисления при каждом скроллинге таблицы.
Мы успешно решили задачу: исправили логические ошибки соединения таблиц в запросе к регистру бухгалтерии, обеспечили правильную передачу данных в контекст управляемой формы и настроили производительное условное оформление для визуального контроля остатков.