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