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