Как реализовать отчет по продажам за несколько периодов в 1С 7.7 и избежать ошибок в итогах?

Программист 1С v7.7 1С:Комплексная автоматизация Управленческий учет Торговля и дистрибуция
← На главную

Разработка отчетов в системе 1С:Предприятие 7.7 требует внимательного подхода к структуре запросов и алгоритмам обработки таблиц значений. Одной из часто встречающихся задач является построение «шахматки», где по строкам выводится номенклатура, а по столбцам — продажи за произвольные периоды. В процессе реализации программисты часто сталкиваются с дублированием строк, некорректными кодами позиций и потерей данных в последней строке отчета. Разберем, как правильно построить такой отчет и исправить типичные ошибки.

Анализ проблем с группировками в запросе

Рассмотрим ситуацию, когда при использовании группировки Товар упорядочить по Товар.Наименование без групп все начинают выводиться лишние строки или неверные коды. Выясним причину этого поведения. В 1С 7.7 группировка по реквизиту объекта (например, по коду или наименованию внутри запроса по документам) может привести к «размножению» строк, если один и тот же товар встречается в разных контекстах. Правильный подход — группировать данные только по объекту (ссылке), а дополнительные данные (код, артикул) получать непосредственно при выводе.

Проанализируем фрагмент текста запроса, который вызывает проблемы:


|Группировка Товар упорядочить по Товар.Наименование без групп все;
|Группировка Месяц все;
|Группировка Код; // Ошибка: лишняя группировка

Важный момент: Группировка по Код здесь избыточна, так как код является атрибутом товара. Если товар уже сгруппирован, повторная группировка по его коду ломает иерархию и может привести к выводу пустых значений. Вместо этого в коде вывода следует обращаться к Запрос.Товар.Код.

Реализация сбора данных за несколько периодов

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

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


Для й = 1 По КолПериодов Цикл
    НачДата = ТЗПериод.ПолучитьЗначение(й, "Период_С");
    КонДата = ТЗПериод.ПолучитьЗначение(й, "Период_По");
    
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = "//{{ЗАПРОС(Сформировать)
    |Период с НачДата по КонДата;
    |Товар = Документ.ОтчетККМ.Номенклатура.ТекущийЭлемент;
    |Количество = Документ.ОтчетККМ.Количество;
    |Функция КоличествоСумма = Сумма(Количество);
    |Группировка Товар упорядочить по Товар.Наименование без групп все;
    |Условие(Товар в СписокЭлементовМФ);
    |"//}}ЗАПРОС;
    
    Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
        // Выгружаем и добавляем в общую ТЗВспом с пометкой периода
    КонецЕсли;
КонецЦикла;

Решение проблемы «последней строки» и расчета итогов

Одной из самых коварных ошибок является алгоритм вывода данных при смене номенклатуры. Посмотрим на классический цикл обхода таблицы значений. В нем секция итогов по товару обычно выводится в момент, когда Номенклатура <> ПредыдущаяНоменклатура. Это приводит к тому, что когда цикл доходит до последней строки таблицы, условие смены номенклатуры больше не срабатывает, и данные по последней позиции не попадают в печатную форму или не закрываются итогом.

Чтобы этого избежать, проанализируем правильную структуру вывода:

  1. Сортируем общую таблицу значений по Товару и Периоду.
  2. В цикле отслеживаем изменение текущего товара.
  3. Обязательно после завершения основного цикла добавляем блок вывода итогов для последней обработанной позиции.

Пример корректного алгоритма вывода:


ТЗВспом.Сортировать("Товар, Период +");
Номен = "";
Для N = 1 По ТЗВспом.КоличествоСтрок() Цикл
    ТЗВспом.ПолучитьСтрокуПоНомеру(N);
    ТекущийТовар = ТЗВспом.Товар;
    
    Если Номен <> ТекущийТовар Тогда
        Если N > 1 Тогда
            // Выводим итоги по предыдущему товару (Период, Прирост и т.д.)
            Таб.ПрисоединитьСекцию("Сформировать|ИтогиПоСтроке");
        КонецЕсли;
        
        // Выводим начало строки для нового товара
        Код = ТекущийТовар.Код;
        Таб.ВывестиСекцию("Сформировать|Товар");
        ИтогПоСтроке = 0;
        Номен = ТекущийТовар;
    КонецЕсли;
    
    // Выводим данные за конкретный период (столбец)
    Кол = ТЗВспом.Количество;
    ИтогПоСтроке = ИтогПоСтроке + Кол;
    Таб.ПрисоединитьСекцию("Сформировать|СтолбецПериода");
КонецЦикла;

// ВАЖНО: Довывод итогов для самого последнего товара
Таб.ПрисоединитьСекцию("Сформировать|ИтогиПоСтроке");

Как убрать строки с полностью нулевыми продажами?

Если в отчет попало много товаров, у которых продажи за все выбранные периоды равны нулю, их стоит отсечь перед выводом. Для этого удобно использовать метод Свернуть или предварительный цикл по таблице значений. Рассмотрим способ с предварительной очисткой:

Проанализируем таблицу перед печатью. Мы можем создать вспомогательную колонку ОбщийИтог, свернуть таблицу по товару, просуммировав продажи, и удалить те строки, где ОбщийИтог <= 0. После этого выводим только те позиции, которые остались в списке. Еще один вариант — проверять сумму итогов непосредственно в цикле вывода и использовать метод УдалитьСтроку(), двигаясь по таблице с конца в начало, чтобы не нарушить индексацию строк.

Оптимизация производительности

Выясним, как ускорить формирование отчета. Выполнение запроса внутри цикла (особенно если периодов много) — это серьезная нагрузка на базу данных. Профессиональный подход заключается в получении всех данных одним запросом за весь интервал (от самой первой даты до самой последней). В таком запросе используется группировка Месяц или Период. После выполнения запроса данные выгружаются в ТЗ, которая затем разворачивается в горизонтальный отчет программными средствами. Это сокращает количество обращений к SQL-серверу или файловой базе до минимума.

← На главную