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