Как рассчитать и сохранить общий объем и вес номенклатуры на основе шаблонов упаковки в 1С:ERP?

Программист 1С v8.3 (Обычные формы) 1С:ERP Управление предприятием Управленческий учет Торговля и дистрибуция
← На главную

В процессе доработки систем на базе 1С:ERP Управление предприятием часто возникает задача автоматизации расчета логистических параметров, таких как общий вес и объем. Рассмотрим ситуацию, когда в системе реализован справочник ШаблоныСхемПакования, в табличной части которого указаны пакеты с конкретными физическими характеристиками. Наша цель — суммировать эти показатели и записывать результат в карточку соответствующей номенклатуры.

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

Анализ структуры данных и проектирование запроса

Первым шагом проанализируем структуру метаданных. У нас есть справочник ШаблоныСхемПакования, владельцем которого является справочник Номенклатура. Внутри шаблона есть табличная часть (ТЧ) Состав, где хранятся ссылки на упаковки, обладающие свойствами Длина, Ширина, Высота, Вес и Объем.

Для получения итоговых сумм нам необходимо использовать агрегатные функции языка запросов 1С. Важно помнить, что группировку следует выполнять по ссылке на владельца (номенклатуру), а не по его наименованию, чтобы избежать ошибок при наличии дублей или изменении названий.

Рассмотрим оптимальный текст запроса:


ВЫБРАТЬ
    СУММА(ШаблоныТЧ.ШаблонУпаковки.Вес) КАК ИтоговыйВес,
    СУММА(ШаблоныТЧ.ШаблонУпаковки.Объем) КАК ИтоговыйОбъем,
    Шаблоны.Владелец КАК СсылкаНаНоменклатуру
ИЗ
    Справочник.ШаблоныСхемПакования.ТЧСостав КАК ШаблоныТЧ
ЛЕВОЕ СОЕДИНЕНИЕ 
    Справочник.ШаблоныСхемПакования КАК Шаблоны
    ПО ШаблоныТЧ.Ссылка = Шаблоны.Ссылка
ГДЕ
    Шаблоны.Владелец = &НоменклатураСсылка
СГРУППИРОВАТЬ ПО
    Шаблоны.Владелец

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

Программная реализация расчета и записи данных

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

Проанализируем ключевой момент: для изменения данных в базе данных нам необходимо получить объект от ссылки, изменить его реквизиты и вызвать метод Записать(). Если мы работаем внутри формы элемента, нужно быть осторожными, чтобы не вызвать конфликт блокировок.


Процедура ОбновитьДанныеВесаИОбъема(НоменклатураСсылка)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |   СУММА(ТЧ.ШаблонУпаковки.Вес) КАК Вес,
    |   СУММА(ТЧ.ШаблонУпаковки.Объем) КАК Объем
    |ИЗ
    |   Справочник.ШаблоныСхемПакования.ТЧСостав КАК ТЧ
    |ГДЕ
    |   ТЧ.Ссылка.Владелец = &Ссылка";
    
    Запрос.УстановитьПараметр("Ссылка", НоменклатураСсылка);
    
    Результат = Запрос.Выполнить();
    Если Не Результат.Пустой() Тогда
        Выборка = Результат.Выбрать();
        Выборка.Следующий();
        
        // Получаем объект для записи в базу данных
        ОбъектНоменклатура = НоменклатураСсылка.ПолучитьОбъект();
        ОбъектНоменклатура.Вес = Выборка.Вес;
        ОбъектНоменклатура.Объем = Выборка.Объем;
        
        Попытка
            ОбъектНоменклатура.Записать();
        Исключение
            Сообщить("Не удалось записать данные номенклатуры: " + ОписаниеОшибки());
        КонецПопытки;
    КонецЕсли;
    
КонецПроцедуры

Решение проблемы обновления данных в интерфейсе (Обычные формы)

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

В обычных формах 1С при выполнении кода в событии ПередОткрытием или ПриОткрытии, объект формы уже может быть инициализирован старыми данными из БД. Если вы меняете данные через ПолучитьОбъект().Записать(), вы меняете запись в таблице СУБД, но не текущие данные в оперативной памяти формы.

Для решения этой проблемы существует два подхода:

  1. Обновление реквизитов формы напрямую: Вместо (или вместе с) записи в базу, необходимо присвоить значения элементам формы. Например: ЭтаФорма.Объем = Выборка.Объем;.
  2. Принудительное перечитывание: Использование метода ЭтаФорма.Прочитать() после записи объекта. Это заставит форму заново подтянуть актуальные данные из базы.

Пример интеграции в событие ПередОткрытием:


Процедура ПередОткрытием(Отказ, СтандартнаяОбработка)
    // Выполняем расчет
    ОбновитьДанныеВесаИОбъема(Ссылка);
    
    // Если форма уже открыта, данные могут не обновиться визуально.
    // В обычных формах иногда требуется явно обновить значения полей формы:
    // Объем = Ссылка.Объем; 
    // Вес = Ссылка.Вес;
КонецПроцедуры

Важные нюансы при работе в 1С:ERP

Работая в такой сложной конфигурации как ERP, нельзя забывать о нескольких критических аспектах:

  1. Единицы измерения: В запросе выше мы просто суммируем числа. Однако в шаблонах упаковки данные могут быть указаны в разных единицах (например, граммы и килограммы). Проанализируем необходимость приведения к единой базовой единице хранения. Перед суммированием обязательно умножайте значение на коэффициент из справочника единиц измерения, если они различаются.
  2. Подписки на события: Выполнение тяжелых запросов при каждом открытии формы — не самое оптимальное решение. Рассмотрим более правильный архитектурный подход: создать Подписку на событие ПриЗаписи для справочника ШаблоныСхемПакования. Тогда пересчет будет происходить только в момент изменения самих шаблонов, а в номенклатуре всегда будут лежать актуальные данные. Это существенно повысит скорость открытия карточек товаров.
  3. Группировка и вложенные запросы: Если у одной номенклатуры может быть несколько активных шаблонов пакования, убедитесь, что логика суммирования не дублирует данные. Возможно, стоит добавить фильтр по флагу ОсновнойШаблон или аналогичному признаку, принятому в вашей организации.

Использование стандартных механизмов

Прежде чем приступать к написанию кода, проверьте, не решается ли ваша задача стандартным функционалом ERP. В типовой конфигурации существуют УпаковкиЕдиницыИзмерения, где для каждой упаковки можно задать габариты и вес. Система автоматически рассчитывает весо-объемные характеристики в заказах и накладных. Если ваша «дописанная» часть дублирует этот функционал, рассмотрите возможность миграции данных в типовые регистры и справочники для сохранения поддержки конфигурации и использования встроенных отчетов.

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

← На главную