Работа со складскими остатками — одна из самых частых задач при разработке отчетов в платформе 1С:Предприятие 8. Часто бухгалтерия или отдел продаж требует не просто показать текущее состояние склада, а предоставить динамику изменения запасов за определенный период. Это необходимо для анализа оборачиваемости, выявления дефицита или планирования закупок.

Сложность задачи заключается в том, что в базе данных физически хранятся только документы движения (приход и расход), а не ежедневные "снимки" остатков. Чтобы получить цифры на каждый день, программисту приходится использовать специальные механизмы платформы. В этой статье мы разберем, как с помощью языка запросов 1С сформировать таблицу, где в строках будут даты, а в колонках — актуальное количество товаров.

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

Использование виртуальных таблиц среза остатков

Самый производительный и правильный способ получения данных в типовых конфигурациях — обращение к виртуальным таблицам регистров накопления. Платформа 1С автоматически оптимизирует такие запросы, выбирая данные из таблиц итогов, если они есть, или рассчитывая их "на лету" оптимальным образом. Для получения остатков на конкретную дату используется таблица Остатки с параметром периода.

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

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

⚠️ Внимание: Виртуальные таблицы Остатки работают только с регистрами накопления, у которых включено ведение итогов. Если в вашем регистре снята галочка "Итоги", запрос будет выполняться медленнее, так как потребуется полный пересчет движений за весь период существования базы.

Рассмотрим базовый пример запроса к регистру ТоварыНаСкладах. Мы хотим получить остатки на конкретную дату отсечения. Синтаксис выглядит следующим образом:

ВЫБРАТЬ

ТоварыНаСкладахОстатки.Номенклатура,

ТоварыНаСкладахОстатки.Склад,

ТоварыНаСкладахОстатки.КоличествоОстаток

ИЗ

РегистрНакопления.ТоварыНаСкладах.Остатки(&КонецПериода) КАК ТоварыНаСкладахОстатки

Здесь &КонецПериода — это параметр, в который передается дата и время конца дня. Обратите внимание, что для корректной работы важно передавать именно конец дня (23:59:59), чтобы все документы, проведенные в этот день, были учтены в остатке.

💡

Всегда используйте конец дня (23:59:59) в качестве параметра периода для виртуальных таблиц остатков, чтобы избежать ситуации, когда документ, проведенный вечером, не попадет в выборку.

Генерация календаря дат для периодического отчета

Чтобы получить остатки не на одну дату, а на каждый день выбранного интервала, нам необходимо создать набор данных, содержащий все даты этого периода. В языке запросов 1С нет встроенной функции "генератор последовательности", поэтому мы используем хитрый прием с таблицей значений или временной таблицей.

Сначала формируется таблица с датами. Это можно сделать программно в коде 1С, создав объект ТаблицаЗначений, заполнить её датами цикла и передать в запрос как параметр. Либо, если период небольшой, можно использовать конструкцию с объединением (ОБЪЕДИНИТЬ ВСЕ) константных значений дат прямо в тексте запроса, хотя это менее гибко.

Далее полученный набор дат соединяется с данными об остатках. Здесь важно понимать логику: остаток на 5-е число — это состояние склада после всех операций 5-го числа. Поэтому при соединении таблицы дат с виртуальной таблицей остатков, мы используем дату из календаря как параметр периода.

  • 📅 Создайте таблицу значений с полями "Дата" и заполните её каждым днем выбранного периода.
  • 🔗 Передайте эту таблицу в запрос как параметр (например, &ТаблицаДат).
  • ⚙️ Используйте вложенный запрос или соединение, где для каждой строки даты вызывается виртуальная таблица остатков.

Такой подход позволяет получить детализированную картину. Вы увидите, как менялся остаток день ото дня. Это особенно полезно для выявления дней, когда товар отсутствовал на складе, но заявки от клиентов поступали.

📊 Какой метод генерации дат вы используете чаще?
Таблица значений в коде
Временная таблица в запросе
Регистр сведений "Календарь"
Цикл с отдельными запросами

Альтернативный метод: Расчет через движения регистра

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

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

Начальный остаток рассчитывается на дату, предшествующую началу периода. Затем к нему последовательно прибавляются приходы и вычитаются расходы каждого дня. В запросе это реализуется через временные таблицы и операцию СУММА ЕЩЁ или через соединение с накопленной суммой.

// Псевдокод логики расчета

1. Получить ОстаткиНачальные на (ДатаНачала - 1 день)

2. Получить Обороты за период (Приход, Расход) с группировкой по Дню

3. Объединить Начальные Остатки и Обороты

4. Рассчитать Накопительный Итог по дням

При реализации такого алгоритма критически важно учитывать порядок следования документов внутри одного дня. Хотя для остатков на конец дня это не имеет значения, если вы планируете показывать остатки на начало дня, логика усложняется.

⚠️ Внимание: Расчет остатков через движения без использования итогов регистра может привести к значительному замедлению работы отчета на больших объемах данных (миллионы движений). Обязательно тестируйте производительность на реальной базе.

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

Получение остатков на каждый день — тяжелая операция для базы данных. Если период составляет год, а номенклатура насчитывает десятки тысяч позиций, количество вычисляемых ячеек может исчисляться миллионами. Без правильной оптимизации такой отчет может "положить" сервер 1С.

Первое правило оптимизации — отбор по измеряемым полям. Никогда не выбирайте все остатки по всей базе, если это не требуется. Всегда ограничивайте запрос конкретными складами, группами номенклатуры или ответственными лицами. Индексы в таблице итогов регистра помогут базе данных быстро найти нужные записи.

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

Метод оптимизации Влияние на скорость Сложность внедрения
Отбор по складам/товарам Высокое Низкая
Использование итогов регистра Критическое Низкая
Временные таблицы с индексами Среднее Средняя
Асинхронное выполнение Высокое (для пользователя) Высокая

Также стоит рассмотреть возможность выполнения отчета в фоновом задании. Если формирование занимает более 30-60 секунд, пользователю лучше предложить оставить заявку на формирование, а результат получить позже или по электронной почте. Это освободит ресурсы сервера для других пользователей.

☑️ Чек-лист оптимизации отчета

Выполнено: 0 / 4

Обработка нулевых остатков и пропущенных дней

Частая проблема при формировании таких отчетов — отсутствие строк в выборке для тех дней, когда движений по товару не было. Если вы используете метод с движениями, дни без операций просто не попадут в результат. Однако для анализа важно видеть, что остаток сохранялся неизменным несколько дней подряд.

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

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

Если же вы используете платформу 8.3.20 и выше, обратите внимание на новые возможности языка запросов, позволяющие делать СУММА ЕЩЁ с параметром УПОРЯДОЧИВАНИЕ, что позволяет рассчитывать нарастающий итог и заполнять пропуски более элегантно.

Как заполнить пропуски программно?

Создайте таблицу результатов. В цикле по датам проверяйте, есть ли запись для текущей даты. Если нет — возьмите значение остатка из переменной, хранящей остаток предыдущего дня, и добавьте новую строку в таблицу.

Сравнение итогов и оперативных остатков

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

В таких случаях помогает перепроведение документов или выполнение обработки "Перепроведение документов за период". Однако для отчета, который строится "здесь и сейчас", можно добавить проверку. Сравните данные, полученные через виртуальную таблицу, с данными, полученными прямым суммированием движений за период плюс начальный остаток.

Если разница существенна, это сигнал о проблемах с целостностью данных в регистре накопления. В типовой конфигурации 1С такие ситуации редки, но в сильно доработанных системах или после некорректного импорта данных они возможны.

⚠️ Внимание: Никогда не используйте таблицу итогов регистра напрямую (физическую таблицу _AccRegRst) в запросах. Всегда обращайтесь только через виртуальные таблицы. Прямое обращение лишено контекста безопасности и может вернуть некорректные данные в многопоточной среде.

FAQ: Часто задаваемые вопросы

Почему запрос к виртуальной таблице возвращает пустой результат?

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

Можно ли получить остатки на начало дня, а не на конец?

Да. Для этого в параметр виртуальной таблицы Остатки нужно передавать дату и время, соответствующие началу нужного дня (00:00:00). Либо передавать дату предыдущего дня с временем конца суток. Остаток на начало 5-го числа равен остатку на конец 4-го числа.

Как ускорить отчет, если период составляет несколько лет?

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

Влияют ли документы "Корректировка регистра" на остатки?

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

Что делать, если остатки "уходят в минус" в отчете?

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

💡

Использование виртуальных таблиц с параметром периода — единственный гарантированно верный способ получения остатков в 1С, обеспечивающий согласованность данных и высокую производительность.