Как получить срез последних цен поставщиков на дату документа поступления в 1С?

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

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

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

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

Способ 1. Получение среза последних цен через пакетный запрос

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

  1. Подготовка исходных данных документов: во временную таблицу выбираются уникальные комбинации даты прихода, номенклатуры и контрагента из регистра партий.
  2. Поиск максимальной даты установки цены: выполняется соединение с реальной таблицей цен по условию Период <= ДатаПрихода и группировкой находится МАКСИМУМ(Период).
  3. Получение ресурсов на найденную дату: соединяем полученные максимальные даты с таблицей цен для выборки числовых показателей (цена, пошлина, транспортные расходы).
  4. Итоговая выборка: связываем партии с рассчитанными ценами.

Посмотрим на пример текста запроса:


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

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

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

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Партии.Контрагент КАК Контрагент,
    ВТ_Партии.Номенклатура КАК Номенклатура,
    ВТ_Партии.ДокументЗакупки КАК ДокументЗакупки,
    ВТ_Партии.Склад КАК Склад,
    ВТ_Партии.ДатаПрихода КАК ДатаПрихода,
    ВТ_Партии.КоличествоОборот КАК КоличествоОборот,
    ВТ_Партии.СтоимостьОборот КАК СтоимостьОборот,
    ЕСТЬNULL(ВТ_ЦеныНаДату.ЦенаПоставщика, 0) КАК ЦенаПоставщика,
    ЕСТЬNULL(ВТ_ЦеныНаДату.КонтрольныеЗнаки, 0) КАК КонтрольныеЗнаки,
    ЕСТЬNULL(ВТ_ЦеныНаДату.ПошлинаСумма, 0) КАК ПошлинаСумма,
    ЕСТЬNULL(ВТ_ЦеныНаДату.ТранспортСумма, 0) КАК ТранспортСумма,
    ЕСТЬNULL(ВТ_ЦеныНаДату.ОптоваяНадбавкаСумма, 0) КАК ОптоваяНадбавкаСумма,
    ЕСТЬNULL(ВТ_ЦеныНаДату.Себестоимость, 0) КАК Себестоимость,
    ЕСТЬNULL(ВТ_ЦеныНаДату.СебестоимостьВал, 0) КАК СебестоимостьВал
ИЗ
    ВТ_Партии КАК ВТ_Партии
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ЦеныНаДату КАК ВТ_ЦеныНаДату
        ПО ВТ_Партии.Номенклатура = ВТ_ЦеныНаДату.Номенклатура
            И ВТ_Партии.Контрагент = ВТ_ЦеныНаДату.Контрагент
            И ВТ_Партии.ДатаПрихода = ВТ_ЦеныНаДату.ДатаПрихода

Способ 2. Реализация через связи наборов данных в СКД

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

Разберем по шагам настройку схемы компоновки данных:

  1. Создаем первый набор данных — запрос (НаборДанныхПартии):

    
    ВЫБРАТЬ
        Партии.Номенклатура КАК Номенклатура,
        Партии.ДокументОприходования.Контрагент КАК Контрагент,
        Партии.ДокументОприходования КАК ДокументЗакупки,
        Партии.Склад КАК Склад,
        Партии.ДокументОприходования.Дата КАК ДатаПрихода,
        Партии.КоличествоПриход КАК КоличествоОборот,
        Партии.СтоимостьПриход КАК СтоимостьОборот
    ИЗ
        РегистрНакопления.ПартииТоваровНаСкладах.Обороты(&ДатаНачала, &ДатаКонца, Авто, ) КАК Партии
    
  2. Создаем второй набор данных — запрос (НаборДанныхЦены):

    
    ВЫБРАТЬ
        Цены.Номенклатура КАК Номенклатура,
        Цены.Контрагент КАК Контрагент,
        Цены.ЦенаПоставщика КАК ЦенаПоставщика,
        Цены.КонтрольныеЗнаки КАК КонтрольныеЗнаки,
        Цены.ПошлинаСумма КАК ПошлинаСумма,
        Цены.ТранспортСумма КАК ТранспортСумма,
        Цены.ОптоваяНадбавкаСумма КАК ОптоваяНадбавкаСумма,
        Цены.Себестоимость КАК Себестоимость,
        Цены.СебестоимостьВал КАК СебестоимостьВал
    ИЗ
        РегистрСведений.ЦеныПоставщиков.СрезПоследних(&ПериодСреза, Номенклатура = &Номенклатура И Контрагент = &Контрагент) КАК Цены
    
  3. Настраиваем вкладку «Связи наборов данных»:

    Указываем источник связи НаборДанныхПартии и приемник связи НаборДанныхЦены.

    В условиях связи связываем поля Номенклатура и Контрагент.

    В колонке Параметры настраиваем передачу значений в параметры приемника:

    1. Для параметра ПериодСреза указываем выражение источника ДатаПрихода;
    2. Для параметра Номенклатура указываем выражение источника Номенклатура;
    3. Для параметра Контрагент указываем выражение источника Контрагент.

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

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

Обратим внимание на ключевые особенности при работе с периодическими регистрами:

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