Как добавить остатки на период (день, неделя, месяц) в отчет по выручке в 1С

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

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

В этой статье мы подробно разберем три проверенных и надежных способа реализации этой задачи. Мы пройдем путь от самого быстрого и технологичного метода средствами Системы компоновки данных (СКД) до классического программного метода с использованием нарастающего итога в запросе.

Решение 1. Использование встроенных механизмов СКД (Рекомендуемый способ)

Платформа 1С содержит мощный встроенный функционал расчета остатков и дополнения периодов в СКД. Этот метод работает быстрее всего, так как расчет и сопоставление данных происходят на уровне платформы в оперативной памяти, минуя избыточные тяжелые запросы к базе данных СУБД.

Рассмотрим по шагам, как настроить СКД для автоматического расчета остатков по периодам:

  1. Создание запроса к виртуальной таблице:

    Для реализации этого метода нам понадобится обратиться к виртуальной таблице ОстаткиИОбороты соответствующего регистра накопления (например, ТоварыНаСкладах.ОстаткиИОбороты). В параметрах виртуальной таблицы обязательно укажем периодичность Авто.

    Пример структуры запроса:

    
    ВЫБРАТЬ РАЗРЕШЕННЫЕ
        Таблица.Номенклатура КАК Номенклатура,
        Таблица.Регистратор КАК Регистратор,
        Таблица.ПериодСекунда КАК ПериодСекунда,
        Таблица.ПериодДень КАК ПериодДень,
        Таблица.ПериодНеделя КАК ПериодНеделя,
        Таблица.ПериодМесяц КАК ПериодМесяц,
        Таблица.В выручкаОборот КАК Выручка,
        Таблица.КоличествоКонечныйОстаток КАК КонечныйОстаток
    ИЗ
        РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Авто, , ) КАК Таблица
    
  2. Настройка ролей полей на вкладке «Наборы данных»:

    Это ключевой шаг, без которого СКД не сможет корректно рассчитать остатки при группировке. Нам необходимо явно указать роли для всех полей периодов:

    • Для поля Номенклатура устанавливаем роль Измерение.
    • Для поля КонечныйОстаток задаем роль Остаток, указываем тип остатка «Конечный» и имя группы (например, «Количество»).
    • Для полей периодов настраиваем роль Период и задаем им порядковые номера от младшего к старшему. Это укажет системе иерархию дат:
      • Регистратор — роль Период, Номер 1.
      • ПериодСекунда — роль Период, Номер 2.
      • ПериодДень — роль Период, Номер 3.
      • ПериодНеделя — роль Период, Номер 4.
      • ПериодМесяц — роль Период, Номер 5.
  3. Настройка дополнения периодов в структуре отчета:

    Если в какой-то из дней продаж не было, стандартный отчет не выведет эту строку. Но остаток товара на складе в этот день все равно существовал! Чтобы СКД автоматически добавила «пустые» дни и показала на них актуальный остаток, настроим дополнение периодов.

    Вкладка «Настройки» -> Нажимаем на группировку по периоду (например, ПериодДень) -> В свойствах группировки находим параметр Тип дополнения и устанавливаем значение День. Также указываем начальную и конечную даты.

Используя этот подход, мы перекладываем всю сложную математику расчета остатков на платформу 1С. Отчет будет формироваться быстро и не перегрузит сервер СУБД.

Решение 2. Связь двух наборов данных в СКД (Параметрический метод)

Бывают ситуации, когда данные о выручке и остатках физически находятся в абсолютно разных регистрах (например, выручка — в оборотном регистре ВыручкаИСебестоимостьПродаж, а остатки — в регистре остатков ТоварыНаСкладах). Напрямую соединить их в одном запросе с периодичностью крайне трудно. В этом случае на помощь приходит механизм связей наборов данных в СКД.

Проанализируем этот алгоритм:

  1. Создаем НаборДанных1 (Продажи):

    Пишем простой запрос для получения выручки с детализацией по периодам.

    
    ВЫБРАТЬ
        Продажи.Номенклатура КАК Номенклатура,
        Продажи.ПериодДень КАК ПериодДень,
        Продажи.СуммаВыручкиОборот КАК Выручка
    ИЗ
        РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&НачалоПериода, &КонецПериода, День, ) КАК Продажи
    
  2. Создаем НаборДанных2 (Остатки):

    Этот набор данных будет отвечать исключительно за получение остатков товаров на конкретную дату. В параметрах виртуальной таблицы укажем параметр &П_ДатаОстатков.

    
    ВЫБРАТЬ
        Остатки.Номенклатура КАК Номенклатура,
        Остатки.В наличииОстаток КАК ОстатокНаДату
    ИЗ
        РегистрНакопления.ТоварыНаСкладах.Остатки(&П_ДатаОстатков, ) КАК Остатки
    
  3. Настраиваем связи наборов данных:

    Переходим на вкладку «Связи наборов данных» и добавляем новую связь:

    • Источник связи: НаборДанных1.
    • Приемник связи: НаборДанных2.
    • Условие связи: Номенклатура = Номенклатура.
    • Параметры: Имя параметра — П_ДатаОстатков, Выражение источника — ПериодДень (или ПериодНеделя/ПериодМесяц в зависимости от выбранной пользователем детализации).

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

Решение 3. Расчет остатка нарастающим итогом в запросе (Без СКД)

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

Разберем по шагам логику такого запроса:

  1. Получение начального остатка и всех движений:

    Сначала мы получаем остаток на самую начальную дату отчета, а также собираем все обороты (приходы и расходы) в разрезе дней.

  2. Соединение таблицы дат с таблицей движений:

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

Посмотрим на пример практической реализации такого запроса:


// Шаг 1: Получаем все уникальные даты, в которые были движения, или используем производственный календарь
ВЫБРАТЬ РАЗРЕШЕННЫЕ
    Продажи.Номенклатура КАК Номенклатура,
    Продажи.ПериодДень КАК ПериодДень,
    Продажи.КоличествоОборот КАК КоличествоПродаж
ПОМЕСТИТЬ ВТ_Продажи
ИЗ
    РегистрНакопления.КнигаПродаж.Обороты(&НачалоПериода, &КонецПериода, День, ) КАК Продажи
;

// Шаг 2: Получаем таблицу всех движений (приходов и расходов) для расчета нарастающего итога
ВЫБРАТЬ
    Движения.Номенклатура КАК Номенклатура,
    Движения.Период КАК ПериодДень,
    СУММА(ВЫБОР
            КОГДА Движения.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
                ТОГДА Движения.Количество
            ИНАЧЕ -Движения.Количество
        КОНЕЦ) КАК РасходПриходОборот
ПОМЕСТИТЬ ВТ_ВсеДвижения
ИЗ
    РегистрНакопления.ТоварыНаСкладах КАК Движения
ГДЕ
    Движения.Период МЕЖДУ &НачалоПериода И &КонецПериода
ГРУППИРОВАТЬ ПО
    Движения.Номенклатура,
    Движения.Период
;

// Шаг 3: Соединяем таблицы и рассчитываем нарастающий итог на каждую дату
ВЫБРАТЬ
    ВТ_Продажи.Номенклатура КАК Номенклатура,
    ВТ_Продажи.ПериодДень КАК ПериодДень,
    ВТ_Продажи.КоличествоПродаж КАК Продано,
    // Получаем остаток на начало отчета + сумму всех движений до текущей даты
    &НачальныйОстатокВсего + СУММА(ЕСТЬNULL(ВТ_ВсеДвиженияДубль.РасходПриходОборот, 0)) КАК ОстатокНаДень
ИЗ
    ВТ_Продажи КАК ВТ_Продажи
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ВсеДвижения КАК ВТ_ВсеДвиженияДубль
        ПО ВТ_Продажи.Номенклатура = ВТ_ВсеДвиженияДубль.Номенклатура
        И ВТ_Продажи.ПериодДень >= ВТ_ВсеДвиженияДубль.ПериодДень
ГРУППИРОВАТЬ ПО
    ВТ_Продажи.Номенклатура,
    ВТ_Продажи.ПериодДень,
    ВТ_Продажи.КоличествоПродаж

Анализ метода: Использование неявного соединения таблиц по условию >= (нарастающий итог) создает большую нагрузку на процессор сервера СУБД. Применять этот метод в «чистом» виде рекомендуется только при работе с относительно небольшими выборками товаров или когда построение отчета через СКД по каким-то причинам невозможно.

Резюме и рекомендации

Мы проанализировали три основных подхода к решению этой непростой архитектурной задачи. Какой же из них выбрать в реальной работе?

← На главную