Как получить ежедневные данные по резервам, наличию и доступности товаров за период в 1С:УТ 11.5?

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

Добрый день, уважаемые коллеги и пользователи 1С! В процессе работы с конфигурациями 1С:Управление торговлей 11.5, 1С:Комплексная автоматизация 2.5 или 1С:ERP Управление предприятием 2.5, часто возникает необходимость в получении детализированных данных по остаткам товаров не только на конкретную дату, но и за определенный период с разбивкой по дням. Стандартные отчеты, такие как "Остатки и доступность товаров" или расширенный анализ продаж, остатков и резервов, как правило, показывают данные на выбранную дату, что бывает недостаточно для глубокого исторического анализа, интеграции с внешними системами или построения аналитических отчетов по продажам, учитывающих последние закупки и доступность, с привязкой к ежедневным запасам и резервам.

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

Ключевой регистр накопления для работы с запасами: "Запасы и потребности"

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

Рассмотрим подробнее, как различные показатели, которые нам требуются, хранятся и могут быть получены из этого регистра:

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

  2. В резерве: Резервирование товаров — это процесс закрепления определенного количества товарных позиций под конкретные потребности или заказы, чтобы гарантировать их наличие к моменту отгрузки. Регистр ЗапасыИПотребности предоставляет нам детальную информацию о резервах через следующие ресурсы:

    • РезервироватьНаСкладе: Этот ресурс показывает количество товаров, которые уже есть на складе и которые были фактически зарезервированы под определенный заказ (например, "Заказ клиента"). Это количество недоступно для свободной продажи или других заказов.

    • РезервироватьПоМереПоступления: Данный ресурс фиксирует количество товаров, которое должно быть зарезервировано из будущих поступлений. Это означает, что товара еще нет на складе, но он уже запланирован к поступлению и будет зарезервирован сразу после прихода, чтобы удовлетворить будущий заказ.

    Важно понимать, что резервы, по сути, являются разновидностью остатков, но с особым статусом использования. Форумчане совершенно верно подметили, что "резервы – это тоже остатки", и поэтому они логично хранятся в том же регистре накопления, что и основные остатки, позволяя системе эффективно управлять доступностью товаров. Практический пример работы с этими данными — отчет по движениям товаров с резервами, использующий возможности СКД.

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

    СвободныйОстаток = ВНаличии - СуммаВсехРезервов

    В 1С:УТ 11.5 "свободный остаток" определяется как запас за вычетом количества, требуемого для обеспечения текущих потребностей, зафиксированных заказами. Обратите внимание, что различные действия в строках документов ("Отгрузить", "Резервировать", "К обеспечению", "Не обеспечивать") напрямую влияют на расчет доступного количества, что необходимо учитывать при формировании отчетности.

Методика получения ежедневных данных за период

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

  1. Шаг 1: Используем виртуальную таблицу "ОстаткиИОбороты"

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

    При построении запроса к этой виртуальной таблице, критически важно правильно настроить параметры:

    • НачалоПериода и КонецПериода: Указываем желаемый диапазон дат.

    • Периодичность: Это самый важный параметр для нашей задачи. Устанавливаем его значение в День. Это гарантирует, что мы получим записи за каждый день, в который были какие-либо движения (приходы, расходы, резервирования) по товарам, или изменились остатки/резервы.

    • Условия: Мы можем наложить дополнительные фильтры по измерениям регистра, таким как Склад, Номенклатура, Характеристика и т.д., чтобы ограничить выборку и повысить производительность.

    Давайте посмотрим на пример структуры запроса к виртуальной таблице ОстаткиИОбороты:

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

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

  2. Шаг 2: Генерация таблицы дат для обеспечения непрерывности данных

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

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

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

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

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

  3. Шаг 3: Соединение данных и заполнение пробелов (перенос остатков)

    Теперь, когда у нас есть две ключевые временные таблицы — одна с календарными датами (ДатыПериода) и другая с данными об остатках и оборотах по дням, когда были движения (из ОстаткиИОбороты) — нам необходимо объединить их. Мы используем Левое соединение (ЛЕВОЕ СОЕДИНЕНИЕ) таблицы ДатыПериода с результатом запроса к ЗапасыИПотребности.ОстаткиИОбороты. Это позволит нам сохранить все календарные даты и прикрепить к ним существующие данные по остаткам.

    Самая сложная часть — это корректно перенести остатки для тех дней, когда в ОстаткиИОбороты не было записей (то есть, не было движений). В таких случаях нам нужно взять конечный остаток за последний день, когда были движения. Это требует более сложной логики в запросе, которая может быть реализована с использованием пакета запросов и вложенных запросов.

    Рассмотрим продвинутый способ заполнения "пробелов" в данных, чтобы получить непрерывную ленту остатков и резервов на каждый день:

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

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

    
    ВЫБРАТЬ
        КонечныеДанные.Дата,
        КонечныеДанные.Номенклатура,
        КонечныеДанные.Характеристика,
        КонечныеДанные.Склад,
        КонечныеДанные.ВНаличииНаКонецДня,
        КонечныеДанные.РезервНаСкладеНаКонецДня + КонечныеДанные.РезервПоМереПоступленияНаКонецДня КАК ВсегоВРезервеНаКонецДня,
        КонечныеДанные.ВНаличииНаКонецДня - (КонечныеДанные.РезервНаСкладеНаКонецДня + КонечныеДанные.РезервПоМереПоступленияНаКонецДня) КАК ДоступноНаКонецДня
    ИЗ
        &КонечныеДанные КАК КонечныеДанные // Результат предыдущего запроса
    УПОРЯДОЧИТЬ ПО
        КонечныеДанные.Номенклатура,
        КонечныеДанные.Характеристика,
        КонечныеДанные.Склад,
        КонечныеДанные.Дата
    ;
    

Важные нюансы и рекомендации

Заключение

Получение ежедневных исторических данных по резервам, наличию и доступности товаров в 1С:УТ 11.5 — это вполне реализуемая, хоть и требующая внимательности, задача. Мы видим, что она решается через глубокое понимание структуры регистра накопления ЗапасыИПотребности, умение работать с виртуальной таблицей ОстаткиИОбороты и построение комплексной логики запросов для генерации таблицы дат и корректного переноса остатков через "пробелы" в днях без движений. При правильном применении этих знаний вы сможете создать мощный аналитический инструмент для мониторинга товарных запасов и оптимизации бизнес-процессов.

← На главную