Как в 1С:Управление торговлей 10.3 получить срез последних цен на дату каждого документа в отчете?

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

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

Выясним причину сложности задачи

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

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

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

Разберем по шагам классический алгоритм эмуляции среза последних на произвольные даты с использованием временных таблиц (ВТ). Данный подход универсален и применим как в коде обработок, так и в отчетах без СКД.

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

Посмотрим на пример текста запроса, реализующего данный механизм:


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

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

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

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	Продажи.Регистратор КАК ДокументПродажи,
	Продажи.Период КАК Период,
	Продажи.Номенклатура КАК Номенклатура,
	Продажи.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
	Продажи.Количество КАК Количество,
	ЕСТЬNULL(ВТ_АктуальныеЦены.Цена, 0) КАК Цена,
	ЕСТЬNULL(ВТ_АктуальныеЦены.Цена, 0) * Продажи.Количество КАК СтоимостьРасчетная
ИЗ
	РегистрНакопления.Продажи КАК Продажи
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_АктуальныеЦены КАК ВТ_АктуальныеЦены
		ПО Продажи.Номенклатура = ВТ_АктуальныеЦены.Номенклатура
			И Продажи.ХарактеристикаНоменклатуры = ВТ_АктуальныеЦены.ХарактеристикаНоменклатуры
			И Продажи.Период = ВТ_АктуальныеЦены.ПериодДокумента
ГДЕ
	Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода

Обратите внимание на производительность: использование конструкции ИНДЕКСИРОВАТЬ ПО для временных таблиц по всем ключевым полям связи является критически важным. Отсутствие индексов на реальных объемах данных базы может привести к зависанию запроса из-за неоптимального соединения СУБД.

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

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

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

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

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

Особенности структуры данных конфигурации «Управление торговлей 10.3»

При соединении с регистром ЦеныНоменклатуры в типовой УТ 10.3 важно учитывать несколько прикладных нюансов:

  1. Учет по характеристикам: регистр цен содержит измерение ХарактеристикаНоменклатуры. Если в информационной базе включен учет по характеристикам, неучет этого поля приведет к дублированию строк в отчете или получению неверной стоимости.
  2. Коэффициенты упаковок и единиц: цена в регистре задается для конкретной единицы (реквизит ЕдиницаИзмерения). Если продажи зафиксированы в базовых единицах (например, в штуках), а прайс-лист ведется в упаковках, полученную цену необходимо умножать или делить на коэффициент единицы измерения (ЕдиницаИзмерения.Коэффициент).
  3. Валюта цен: реквизит Валюта в регистре цен может не совпадать с валютой управленческого учета. В таком случае в запрос потребуется включить дополнительное соединение с регистром сведений КурсыВалют на дату документа продажи для пересчета цены.
  4. Обработка отсутствия цены: если на дату продажи цена еще ни разу не устанавливалась, соединение вернет значение NULL. Для предотвращения ошибок в вычислениях поле цены обязательно оборачивается функцией ЕСТЬNULL(..., 0).
← На главную