При разработке и кастомизации документов в решениях на платформе 1С:Предприятие 8.3 (например, в «1С:Управление торговлей 11», «1С:ERP» или «1С:Комплексная автоматизация») часто возникает задача динамического расчета логистических параметров. Пользователям крайне важно видеть общие весогабаритные характеристики отгружаемых или принимаемых товаров прямо в форме документа — в его подвале или на специальной панели.
В этой статье мы подробно разберем, как правильно реализовать расчет суммарного веса и объема товаров в табличной части управляемой формы, избежав типичных ошибок начинающих разработчиков, связанных с падением производительности системы. Мы изучим несколько альтернативных способов решения этой задачи, посмотрим на конкретные примеры кода и настроим автоматическую подсветку ячеек с незаполненными значениями.
Начинающие разработчики часто пытаются перенести логику из обычных форм (например, из конфигураций «УТ 10.3» или «УПП 1.3») в управляемые формы «1С 8.3». Типичный пример такой ошибки — использование события таблицы ОформлениеСтроки или попытка напрямую в цикле на клиенте обходить строки табличной части и обращаться через точку к свойствам ссылочных данных, например: Строка.Номенклатура.Вес.
В управляемом приложении такое обращение приводит к крайне неприятным последствиям:
Номенклатура), платформа выполняет скрытый синхронный запрос к серверу и базе данных. Если в документе содержится 100 строк, система сделает 100 отдельных запросов к серверу при каждом изменении количества. Интерфейс пользователя при этом начнет сильно зависать.Чтобы расчет происходил мгновенно и без лишней нагрузки на сервер, мы применим классический паттерн разработки в 1С: кэширование характеристик номенклатуры в строках табличной части. Мы будем получать вес и объем один раз при выборе номенклатуры в строке (на сервере), а все последующие расчеты при изменении количества выполнять мгновенно на клиенте.
Проанализируем пошагово, как это реализовать:
Товары нашего документа четыре новых реквизита: ВесЕдиницы (Число 15,3), ОбъемЕдиницы (Число 15,3), Вес (Число 15,3 — здесь будет храниться общий вес строки) и Объем (Число 15,3 — общий объем строки).ИтогВес (Число 15,3) и ИтогОбъем (Число 15,3). Перетащим их в дерево элементов формы в область подвала (или создадим отдельную группу внизу формы) и установим им вид Поле надписи.Теперь перейдем к написанию кода в модуле управляемой формы.
При изменении номенклатуры в строке табличной части нам необходимо обратиться к базе данных на сервере, получить вес и объем одной единицы товара и записать их в строку. Создадим обработчик события ТоварыНоменклатураПриИзменении:
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
Если СтрокаТаблицы <> Неопределено Тогда
// Вызываем серверную процедуру для заполнения данных единицы измерения
ЗаполнитьВесИОбъемНоменклатурыНаСервере(СтрокаТаблицы);
// Пересчитываем итоги по строке и по всему документу
РассчитатьСтрокуИИтоги(СтрокаТаблицы);
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ЗаполнитьВесИОбъемНоменклатурыНаСервере(СтрокаТаблицы)
// Получаем вес и объем непосредственно из справочника Номенклатура за один запрос к БД
ДанныеНоменклатуры = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(СтрокаТаблицы.Номенклатура, "ВесЧислитель, ОбъемЧислитель");
СтрокаТаблицы.ВесЕдиницы = ДанныеНоменклатуры.ВесЧислитель;
СтрокаТаблицы.ОбъемЕдиницы = ДанныеНоменклатуры.ОбъемЧислитель;
КонецПроцедуры
Обратите внимание на использование директивы &НаСервереБезКонтекста. Это позволяет избежать передачи контекста всей формы на сервер, что существенно экономит сетевой трафик и ускоряет работу программы.
Когда пользователь меняет количество товара в строке, расчет общего веса этой строки и пересчет итогов по документу должен происходить мгновенно на клиенте, без каких-либо обращений к серверу. Напишем универсальную процедуру расчета и привяжем ее к событию ТоварыКоличествоПриИзменении:
&НаКлиенте
Процедура ТоварыКоличествоПриИзменении(Элемент)
СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
Если СтрокаТаблицы <> Неопределено Тогда
РассчитатьСтрокуИИтоги(СтрокаТаблицы);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура РассчитатьСтрокуИИтоги(СтрокаТаблицы)
// Рассчитываем вес и объем для текущей строки
СтрокаТаблицы.Вес = СтрокаТаблицы.Количество * СтрокаТаблицы.ВесЕдиницы;
СтрокаТаблицы.Объем = СтрокаТаблицы.Количество * СтрокаТаблицы.ОбъемЕдиницы;
// Пересчитываем общие итоги по всей табличной части на клиенте (быстрый цикл)
ВсегоВес = 0;
ВсегоОбъем = 0;
Для Каждого ТекСтрока Из Объект.Товары Цикл
ВсегоВес = ВсегоВес + ТекСтрока.Вес;
ВсегоОбъем = ВсегоОбъем + ТекСтрока.Объем;
КонецЦикла;
// Записываем результат в реквизиты формы для отображения на экране
ИтогВес = ВсегоВес;
ИтогОбъем = ВсегоОбъем;
КонецПроцедуры
Важно помнить, что когда пользователь открывает уже созданный и сохраненный документ, реквизиты формы ИтогВес и ИтогОбъем изначально будут равны нулю, так как они не хранятся в базе данных, а существуют только в контексте формы. Нам необходимо рассчитать их при инициализации. Лучше всего сделать это в обработчике события формы ПриЧтенииНаСервере:
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Рассчитываем итоги при открытии существующего документа
ИтогВес = Объект.Товары.Итог("Вес");
ИтогОбъем = Объект.Товары.Итог("Объем");
КонецПроцедуры
Метод Итог() является встроенным методом табличных частей и таблиц значений в 1С. Он работает на уровне платформы чрезвычайно быстро, суммируя числовые значения по указанной колонке.
Если вам не принципиально выводить суммарный вес и объем в отдельные реквизиты внизу формы, можно воспользоваться стандартным и очень удобным механизмом платформы — отображением итогов прямо в подвале таблицы формы.
Давайте разберем по шагам, как настроить этот функционал через свойства элементов в конфигураторе:
Товары).Истина. Это активирует отображение дополнительной строки итогов под самой таблицей.ТоварыВес).Объект.Товары.ИтогВес (или выберите через диалоговое окно автовычисляемый итог: Объект.Товары.Итог("Вес")).ТоварыОбъем), указав в свойстве ПутьКДаннымПодвала путь: Объект.Товары.ИтогОбъем.При использовании этого способа платформа 1С будет самостоятельно и автоматически суммировать значения в колонках и выводить их в подвал при любом изменении строк таблицы на клиенте. Вам больше не потребуется писать код для обхода строк в цикле и вручную заполнять реквизиты формы.
Вернемся ко второму вопросу автора темы: как подсвечивать ячейку или всю строку цветом, если у товара в справочнике не задан вес (равен нулю). Как мы выяснили ранее, использовать программный код в цикле для этого категорически нельзя. Для этого в управляемом приложении предназначен механизм Условного оформления формы.
Разберем, как настроить автоподсветку без написания программного кода через конфигуратор:
Цвет фона (например, нежно-розовый цвет с RGB-кодом 255, 200, 200) или Цвет текста. Нажмите ОК.Объект.Товары.ВесЕдиницыРавно0ТоварыВесЕдиницы (и ТоварыВес при необходимости). Если нужно подсветить всю строку целиком, оставьте список оформляемых полей пустым.Платформа 1С берет на себя всю работу по отрисовке интерфейса. Как только в табличную часть будет добавлен товар с нулевым весом, ячейка мгновенно окрасится в заданный цвет прямо на клиенте.
Проанализируем частые ошибки, с которыми сталкиваются разработчики при написании кода:
Таблица на фактическое имя вашей табличной части на форме (в большинстве стандартных конфигураций это Объект.Товары или Элементы.Товары).ПриИзменении конкретных колонок. Чтобы этого избежать, обязательно привяжите вызов вашей процедуры РассчитатьСтрокуИИтоги() к событию самой таблицы ТоварыПриИзменении (оно срабатывает при добавлении, удалении или копировании строк).Используя предложенные методики кэширования данных в строках и декларативного условного оформления, вы получите быстрое, надежное и отказоустойчивое решение, которое будет соответствовать всем стандартам разработки фирмы «1С».