Как получить список товаров, поступивших при нулевом остатке, и определить их цену

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

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

Анализ проблемы: почему стандартные отчеты не подходят

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

Шаг 1: Определение момента времени и выборка поступлений

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

Рассмотрим структуру первого этапа запроса. Мы создаем временную таблицу, в которую помещаем данные о закупках:


ВЫБРАТЬ
    Закупки.Номенклатура КАК Номенклатура,
    Закупки.Регистратор КАК ДокументПоступления,
    Закупки.Период КАК Период,
    Закупки.Регистратор.МоментВремени КАК МоментПоступления
ПОМЕСТИТЬ ВТ_Поступления
ИЗ
    РегистрНакопления.Закупки КАК Закупки
ГДЕ
    Закупки.Период МЕЖДУ &ДатаНачала И &ДатаКонца
;

Шаг 2: Расчет остатка на момент поступления

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

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


ВЫБРАТЬ
    ВТ_Поступления.Номенклатура,
    ВТ_Поступления.ДокументПоступления,
    СУММА(ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоПриход, 0) - ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоРасход, 0)) КАК ОстатокПередПоступлением
ПОМЕСТИТЬ ВТ_ОстаткиНаМомент
ИЗ
    ВТ_Поступления КАК ВТ_Поступления
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладахОстатки
        ПО ВТ_Поступления.Номенклатура = ТоварыНаСкладахОстатки.Номенклатура
            И ВТ_Поступления.МоментПоступления > ТоварыНаСкладахОстатки.МоментВремени
СГРУППИРОВАТЬ ПО
    ВТ_Поступления.Номенклатура,
    ВТ_Поступления.ДокументПоступления
;

Важный нюанс: условие ВТ_Поступления.МоментПоступления > ТоварыНаСкладахОстатки.МоментВремени гарантирует, что мы берем все записи строго до текущего документа. Если остаток товара на этот момент равен 0, значит, это именно то поступление, которое мы ищем.

Шаг 3: Фильтрация по нулевому остатку и поиск цены

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

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


ВЫБРАТЬ
    МаксимальныеДаты.Номенклатура,
    МАКСИМУМ(МаксимальныеДаты.МоментПоступления) КАК ПоследнийМоментНулевогоПрихода
ПОМЕСТИТЬ ВТ_ПоследниеПоступления
ИЗ
    ВТ_ОстаткиНаМомент КАК МаксимальныеДаты
ГДЕ
    МаксимальныеДаты.ОстатокПередПоступлением = 0
СГРУППИРОВАТЬ ПО
    МаксимальныеДаты.Номенклатура
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_ПоследниеПоступления.Номенклатура,
    Закупки.Цена КАК ЦенаПоследнегоПрихода,
    Закупки.Регистратор КАК Документ
ИЗ
    ВТ_ПоследниеПоступления КАК ВТ_ПоследниеПоступления
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.Закупки КАК Закупки
        ПО ВТ_ПоследниеПоступления.Номенклатура = Закупки.Номенклатура
            И ВТ_ПоследниеПоступления.ПоследнийМоментНулевогоПрихода = Закупки.Регистратор.МоментВремени

Особенности учета «типов нуля»

Проанализируем ситуацию более глубоко. В системах 1С нулевой остаток может трактоваться по-разному:

  1. Физический ноль: на складе реально нет коробок (смотрим регистр ТоварыНаСкладах).
  2. Свободный остаток: товар есть, но он весь зарезервирован под заказы покупателей (нужно анализировать регистр ТоварыВРезерве или СвободныеОстатки).
  3. Логический ноль: товар никогда не вводился в систему. Как отметили эксперты в обсуждении, если товара никогда не было и это первая закупка в истории — считать ли это «приходом на остаток 0»? Обычно для целей анализа цен такие случаи исключаются, поэтому в запросе можно добавить условие на наличие хотя бы одного движения в прошлом.

Оптимизация для больших баз данных

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

Подводя итог, можно сказать, что ключевым инструментом программиста здесь выступает МоментВремени. Правильное использование этого объекта в соединениях позволяет с точностью до секунды восстановить картину складских остатков и найти искомую цену «первого» поступления.

← На главную