Как правильно получить последний документ прихода и его дату в 1С

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

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

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

Почему нельзя использовать конструкцию МАКСИМУМ(Регистратор)

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

Выясним причину некорректной работы функции МАКСИМУМ для составных полей. На уровне базы данных СУБД выполняет сравнение составных ссылок не по дате документа, а по следующим правилам:

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

Таким образом, выражение МАКСИМУМ(Регистратор) вернет документ того типа, чей код таблицы в структуре метаданных конфигурации оказался старше, а не тот, который был проведен позже по времени. Именно поэтому дата из МАКСИМУМ(Период) может указывать на вчерашний день, а полученный через МАКСИМУМ(Регистратор) документ будет датирован прошлым месяцем.

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

Решение 1. Двухэтапная выборка через временные таблицы в запросе

Классический и наиболее надежный способ получения последнего документа на уровне единого запроса — разделение задачи на поиск максимального момента движения и последующее получение самого документа.

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

  1. Во временную таблицу отбираем максимальный период движения (МАКСИМУМ(Период)) в разрезе необходимых измерений (Номенклатура, Склад) с отбором по виду движения Приход.
  2. Соединяем полученную таблицу максимальных дат обратно с исходной таблицей регистра по измерениям и периоду. Чтобы защититься от ситуации, когда в одну и ту же секунду проведено два разных приходных документа, группируем результат и берем МАКСИМУМ(Регистратор) — внутри одной и той же секунды это безопасно и исключит дублирование строк.
  3. Связываем полученную временную таблицу с основными данными отчета.

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


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

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

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_ПоследниеПриходы.Номенклатура КАК Номенклатура,
    ВТ_ПоследниеПриходы.Склад КАК Склад,
    ВТ_ПоследниеПриходы.ДатаПрихода КАК ДатаПрихода,
    ВТ_ПоследниеПриходы.ПоследнийДокумент КАК ДокументПрихода
ИЗ
    ВТ_ПоследниеПриходы КАК ВТ_ПоследниеПриходы

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

Решение 2. Использование связей наборов данных в СКД

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

Рассмотрим порядок настройки отчета:

  1. Создаем основной набор данных (например, НаборДанных1), где рассчитываем остатки, обороты и список товаров без привязки к последнему приходу.
  2. Создаем второй набор данных — запрос (НаборДанных2), возвращающий ровно один последний документ для конкретной связки номенклатуры и склада:

ВЫБРАТЬ ПЕРВЫЕ 1
    ПартииТоваров.Период КАК ДатаПрихода,
    ПартииТоваров.Регистратор КАК ДокументПрихода
ИЗ
    РегистрНакопления.ПартииТоваровНаСкладах КАК ПартииТоваров
ГДЕ
    ПартииТоваров.Номенклатура = &Номенклатура
    И ПартииТоваров.Склад = &Склад
    И ПартииТоваров.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
    И ПартииТоваров.Период <= &КонецПериода
УПОРЯДОЧИТЬ ПО
    ПартииТоваров.Период УБЫВ,
    ПартииТоваров.НомерСтроки УБЫВ
  1. Переходим на вкладку Связи наборов данных схемы компоновки.
  2. Указываем источник связи — НаборДанных1, приемник связи — НаборДанных2.
  3. В колонках условий связи сопоставляем поля Номенклатура и Склад.
  4. В колонке Параметры обязательно прописываем параметры &Номенклатура и &Склад.

При таком подходе СКД при выводе каждой строки номенклатуры передает ее значение в параметры подчиненного запроса и получает ровно одну актуальную запись за счет конструкции ВЫБРАТЬ ПЕРВЫЕ 1 и сортировки по убыванию периода.

Рекомендации по учету специфики документов

При реализации поиска документов поступления важно заранее согласовать бизнес-логику работы алгоритма:

  1. Корректировочные движения: Если в системе используются сторнирующие записи или возвраты с признаком Приход и отрицательным количеством, добавьте в условия отбора фильтр Партии.Количество > 0.
  2. Специфика видов документов: Если последним поступлением должна считаться исключительно поставка от поставщика, исключите внутренние перемещения и сборки с помощью условия на тип регистратора (например, Партии.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг) либо анализируйте реквизит КодОперации.
← На главную