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