Как получить ежедневную себестоимость по складам в 1С: решение проблемы пропадающих остатков

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

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

Проанализируем причину проблемы: механика работы виртуальных таблиц

Прежде чем приступать к написанию кода, выясним причину «странного» поведения системы. В 1С виртуальные таблицы ОстаткиИОбороты оптимизированы для производительности. Когда мы указываем периодичность День и выбираем измерение АналитикаУчетаНоменклатуры, платформа выдает записи остатков только на те моменты (даты), когда по данному конкретному ключу аналитики было движение.

Рассмотрим ситуацию: на складе лежит товар А (Ключ1) и товар Б (Ключ2).

Если мы просто сгруппируем данные по дням, то на 10-е число мы увидим остаток только товара А, а на 12-е — только товара Б. Общая сумма склада на каждый день будет некорректной, так как «неподвижные» товары просто выпадают из выборки конкретного дня. Чтобы этого избежать, нам нужно заставить систему «протянуть» остатки через те дни, где движений не было.

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

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

Рассмотрим по шагам, как это настроить:

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

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

Способ 2. Формирование «сетки» интервалов в запросе

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

Разберем пример кода, который реализует этот подход через использование функции АВТОНОМЕРЗАПИСИ() для связи соседних строк:


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

// Шаг 2: Создаем интервалы "Дата С" и "Дата По"
ВЫБРАТЬ
    ВТ.Аналитика КАК Аналитика,
    ВТ.Остаток КАК Остаток,
    ВТ.Период КАК ПериодС,
    ЕСТЬNULL(ДОБАВИТЬКДАТЕ(ВТ_След.Период, СЕКУНДА, -1), &ДатаКон) КАК ПериодПо
ПОМЕСТИТЬ ВТ_ПериодыДействия
ИЗ
    ВТ_ОстаткиДвижения КАК ВТ
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ОстаткиДвижения КАК ВТ_След
        ПО ВТ.Аналитика = ВТ_След.Аналитика
        И (ВТ.нпп + 1 = ВТ_След.нпп);

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

В данном примере мы сначала пронумеровали записи. Это позволило нам для каждой строки с остатком найти «следующую» дату изменения по этой же аналитике. Таким образом, мы получили отрезки времени. Соединив эти отрезки с полным списком дат из календаря, мы «заполнили» пустоты: на каждый день календаря теперь приходится актуальный на тот момент остаток.

Способ 3. Расчет нарастающим итогом

Еще один вариант — не использовать ОстаткиИОбороты для промежуточных дней, а взять остаток на начало периода и прибавлять к нему ежедневные обороты. В запросах 1С это реализуется через соединение таблицы оборотов самой с собой по условию Т1.Период >= Т2.Период.

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

Поэтому для расчета себестоимости за длительный период метод с интервалами (Способ 2) является более предпочтительным с точки зрения производительности.

Важные замечания по работе с ключами аналитики

В конфигурациях вроде 1С:ERP или 1С:Комплексная автоматизация склад и номенклатура часто «спрятаны» внутри ключа аналитики. Посмотрим на критическую ошибку, которую часто совершают новички: соединение с регистром сведений АналитикаУчетаНоменклатуры внутри виртуальной таблицы или в условии ГДЕ. Если вы накладываете условие на склад через ЛЕВОЕ СОЕДИНЕНИЕ с расшифровкой ключей после получения данных из ВТ, вы рискуете потерять те записи, где ключ по каким-то причинам не сопоставился (например, при битых ссылках). Всегда используйте Внутреннее соединение, если склад является обязательным разрезом, и проверяйте актуальность регистра АналитикаУчетаНоменклатуры — иногда он требует пересчета при обновлении базы.

Резюме

Чтобы получить корректную себестоимость по складам за каждый день:

  1. Помните, что ОстаткиИОбороты не возвращают строки для дней без движений по конкретной аналитике.
  2. Для отчетов используйте СКД с настройкой «Дополнение периодов» — это самый быстрый и надежный способ.
  3. Для сложных расчетов в коде используйте построение временной таблицы интервалов, соединяя её с календарным графиком.
  4. Всегда группируйте данные по складу только после того, как обеспечили наличие остатка по каждой аналитике на каждую дату.
← На главную