При формировании сводных печатных форм и отчетов (например, сводной накладной или сводного требования по документам питания за смену или день) часто требуется указать в шапке документа перечень всех первичных документов, вошедших в выборку. Разберем практическую реализацию этой задачи: от оптимизации запроса до склейки номеров в одну строку и корректного вывода в табличный документ с учетом совместимости платформ.
Проанализируем типовую ошибку при попытке получить номер документа. Если запрос строится к табличной части (например, Документ.МенюРаскладка_Л.Накладная), поле номера не хранится напрямую в строках табличной части. Поле Номер относится к шапке документа, поэтому обращаться к нему следует через реквизит ссылки: МенюРаскладка_Л.Ссылка.Номер.
Однако объединять выборку номенклатуры и номеров в один запрос к табличной части не всегда оптимально: если в документе 100 строк, номер повторится 100 раз, создавая лишнюю нагрузку на передачу данных. Более того, если документ был проведен с пустой табличной частью, он вовсе не попадет в выборку. Рассмотрим два способа выборки номеров.
Способ А. Выборка номеров в общем запросе с последующей сверткой
Добавим обращение к номеру через реквизит Ссылка:
ВЫБРАТЬ
МенюРаскладка_Л.Количество КАК КОЛИЧЕСТВО,
МенюРаскладка_Л.Сумма КАК СУММА,
МенюРаскладка_Л.Номенклатура КАК НОМЕНКЛАТУРА,
МенюРаскладка_Л.Ссылка.Номер КАК НОМЕР
ИЗ
Документ.МенюРаскладка_Л.Накладная КАК МенюРаскладка_Л
ГДЕ
МенюРаскладка_Л.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода
И МенюРаскладка_Л.Ссылка.ПометкаУдаления = ЛОЖЬ
И МенюРаскладка_Л.Ссылка.Организация = &Организация
И МенюРаскладка_Л.Ссылка.Склад = &Склад
Способ Б. Использование пакетного запроса (рекомендуемый)
Более чистое решение — получить агрегированные данные по товарам и отдельный список номеров документов в одном пакетном запросе. Это исключит лишнее копирование таблиц в оперативной памяти:
// Пакетный запрос
ТекстЗапроса =
"ВЫБРАТЬ
| Меню.Номенклатура КАК Номенклатура,
| СУММА(Меню.Количество) КАК Количество,
| СУММА(Меню.Сумма) КАК Сумма
|ИЗ
| Документ.МенюРаскладка_Л.Накладная КАК Меню
|ГДЕ
| Меню.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И Меню.Ссылка.ПометкаУдаления = ЛОЖЬ
| И Меню.Ссылка.Организация = &Организация
| И Меню.Ссылка.Склад = &Склад
|СГРУППИРОВАТЬ ПО
| Меню.Номенклатура;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| Док.Номер КАК Номер,
| Док.Ссылка КАК Ссылка
|ИЗ
| Документ.МенюРаскладка_Л КАК Док
|ГДЕ
| Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И Док.ПометкаУдаления = ЛОЖЬ
| И Док.Организация = &Организация
| И Док.Склад = &Склад
|УПОРЯДОЧИТЬ ПО
| Номер";
Запрос.Текст = ТекстЗапроса;
ПакетРезультатов = Запрос.ВыполнитьПакет();
ТабНоменклатура = ПакетРезультатов[0].Выгрузить();
ТабНомеров = ПакетРезультатов[1].Выгрузить();
Выясним причину, почему встроенная функция СтрСоединить() может вызывать ошибку. Функция СтрСоединить() появилась только в платформе 8.3.6. Если отчет выполняется в конфигурации «1С:Бухгалтерия предприятия 2.0» или любой другой конфигурации с установленным режимом совместимости «Версия 8.2» (или ниже 8.3.6), эта функция будет недоступна. Разберем универсальные варианты реализации.
Вариант 1. Универсальный цикл обхода таблицы значений
Обратите внимание на синтаксис: при обращении по индексу ТабНомеров[х] возвращается объект типа СтрокаТаблицыЗначений, поэтому необходимо явно указывать обращение к колонке .НОМЕР:
// Если запрос был единым, предварительно свернем номера
ТабНомеров = РезультатЗапроса.Выгрузить();
ТабНомеров.Свернуть("НОМЕР");
ТабНомеров.Сортировать("НОМЕР");
СтрокаНомеров = "";
Для Индекс = 0 По ТабНомеров.Количество() - 1 Цикл
НомерДокумента = СокрЛП(ТабНомеров[Индекс].НОМЕР);
// Добавляем запятую перед каждым элементом, кроме первого
СтрокаНомеров = СтрокаНомеров + ?(Индекс = 0, "", ", ") + НомерДокумента;
КонецЦикла;
Вариант 2. Использование функций Библиотеки Стандартных Подсистем (БСП)
Если в конфигурации используется БСП, можно выгрузить колонку номеров в массив и использовать встроенную процедуру общего модуля:
МассивНомеров = ТабНомеров.ВыгрузитьКолонку("НОМЕР");
СтрокаНомеров = СтроковыеФункцииКлиентСервер.СтрокаИзМассиваПодстрок(МассивНомеров, ", ");
Вариант 3. Использование СтрСоединить (для конфигураций без режима совместимости 8.2)
Если режим совместимости отключен или равен 8.3.6 и выше:
МассивНомеров = ТабНомеров.ВыгрузитьКолонку("НОМЕР");
СтрокаНомеров = СтрСоединить(МассивНомеров, ", ");
В номерах документов 1С содержатся служебные лидирующие нули и префиксы узлов информационной базы (например, 00БП-000124). Для красивого вывода в печатную форму имеет смысл удалять префиксы с помощью типовых функций БСП:
НомерНаПечать = ПрефиксацияОбъектовКлиентСервер.НомерНаПечать(ТекСтрока.НОМЕР, Истина, Истина);
Разберем типичную ошибку: вызов Область.Параметры.СтрокаНомеров.Заполнить() неверен, поскольку у свойства параметра примитивного типа (строка) нет метода Заполнить(). Значение присваивается напрямую свойству параметра области:
НомераДокументов.
Область = Макет.ПолучитьОбласть("Заголовок");
Область.Параметры.ТекстЗаголовка = "Требование-накладная";
Область.Параметры.НачалоПериода = Формат(НачалоПериода, "ДФ=dd.MM.yyyy");
Область.Параметры.КонецПериода = Формат(КонецПериода, "ДФ=dd.MM.yyyy");
Область.Параметры.НомераДокументов = "Составлен на основании документов: " + СтрокаНомеров;
ТабДокумент.Вывести(Область);
Такой подход гарантирует корректную работу печатной формы как на старых редакциях конфигураций (1С:Бухгалтерия 2.0), так и на современных версиях платформы без ошибок переполнения ячеек или несовместимости строковых функций.