При работе с системой 1С:Управление торговлей 11 (УТ 11) часто возникает потребность в анализе динамики цен на номенклатуру. Одной из таких задач является получение списка товаров, цена продажи которых изменялась за определенный период, с указанием их текущей актуальной цены и точной даты последнего изменения — для этого подойдёт отчёт для анализа истории изменения цен в 1С:УТ. В некоторых случаях полезно изучить готовая история (динамика) изменения цен номенклатуры, но в этой статье мы разберем, как самостоятельно решить эту задачу, используя гибкие возможности системы компоновки данных (СКД) и запросы к регистру сведений ЦеныНоменклатуры.
Давайте рассмотрим эту проблему по шагам и выясним, как построить корректный запрос, который учтет все нюансы, включая появление новой номенклатуры в анализируемом периоде.
Прежде чем приступать к формированию запроса, нам необходимо четко понять, какие данные хранятся в системе и как они структурированы. В 1С:Управление торговлей 11 информация о ценах номенклатуры хранится в регистре сведений ЦеныНоменклатуры. Этот регистр является периодическим и позволяет отслеживать изменения цен во времени. Если вам требуется максимально подробный анализ цен за период с детализацией по дням, важно помнить, что каждая запись регистра содержит Номенклатуру, ВидЦены, Период (дата, с которой начинает действовать цена) и саму Цену.
Наша задача состоит в следующем:
Простой срез последних цен (СрезПоследних) не подойдет, так как он покажет только актуальные цены, не давая информации об их изменении и датах этих изменений в прошлом. Нам потребуется более сложный запрос с использованием временных таблиц.
Для корректного решения данной задачи мы будем использовать подход с несколькими временными таблицами. Этот метод позволяет последовательно собирать нужные данные, фильтровать их и объединять, чтобы получить финальный результат. Такой подход часто применяется, когда требуется анализ динамики изменения цен номенклатуры за период.
Первым делом нам нужно определить, какие цены являются актуальными на конец нашего анализируемого периода. Для этого мы используем виртуальную таблицу СрезПоследних регистра сведений ЦеныНоменклатуры. Эта таблица позволяет получить последнюю запись регистра для каждого измерения (в нашем случае Номенклатура и ВидЦены) на указанный момент времени.
Мы создаем первую временную таблицу ВТ_ТекущиеЦены. В ней мы выберем Номенклатуру, Цену (которую назовем ТекущаяЦена для ясности) и ВидЦены на &КонецПериода. Параметр &ВидЦены позволит нам фильтровать данные по конкретному виду цен, если это необходимо (например, только цены продажи).
// 1. Получаем текущие цены на &КонецПериода
ВЫБРАТЬ
Срез.Номенклатура,
Срез.Цена КАК ТекущаяЦена,
Срез.ВидЦены
ПОМЕСТИТЬ ВТ_ТекущиеЦены
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
&КонецПериода,
ВидЦены = &ВидЦены
) КАК Срез
;
Чтобы понять, изменилась ли цена, нам нужно с чем-то ее сравнить. Логично сравнить текущую цену с ценой, которая действовала на начало анализируемого периода. Аналогично предыдущему шагу, мы используем СрезПоследних, но уже на &НачалоПериода. Это позволяет реализовать анализ и сравнение цен номенклатуры текущей с предыдущей.
Эта вторая временная таблица, ВТ_ЦеныНаНачалоПериода, будет содержать Номенклатуру, Цену (как ЦенаНаНачалоПериода) и ВидЦены, актуальные на &НачалоПериода. Если для какой-то номенклатуры не будет найдено цен на начало периода (например, номенклатура была введена в течение периода), соответствующая запись будет отсутствовать в этой таблице. Это важный момент, который мы учтем при финальной фильтрации.
// 2. Получаем цены на &НачалоПериода
ВЫБРАТЬ
Срез.Номенклатура,
Срез.Цена КАК ЦенаНаНачалоПериода,
Срез.ВидЦены
ПОМЕСТИТЬ ВТ_ЦеныНаНачалоПериода
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
&НачалоПериода,
ВидЦены = &ВидЦены
) КАК Срез
;
Следующий критически важный шаг — найти дату последнего изменения цены для каждой номенклатуры в пределах заданного периода. Для этого мы обращаемся непосредственно ко всему регистру сведений ЦеныНоменклатуры, а не к его виртуальным таблицам срезов.
Мы выбираем все записи регистра, которые попадают в диапазон между &НачалоПериода и &КонецПериода, и фильтруем по ВидуЦены. Затем мы группируем эти записи по Номенклатуре и ВидуЦены и используем агрегатную функцию МАКСИМУМ(История.Период), чтобы получить самую позднюю дату, когда для данной номенклатуры была зафиксирована цена в указанном периоде. Эта дата и будет считаться ДатаПоследнегоИзменения.
// 3. Получаем все записи регистра за период для определения даты последнего изменения
ВЫБРАТЬ
История.Номенклатура,
МАКСИМУМ(История.Период) КАК ДатаПоследнегоИзменения,
История.ВидЦены
ПОМЕСТИТЬ ВТ_ДатыИзменений
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК История
ГДЕ
История.Период МЕЖДУ &НачалоПеиода И &КонецПериода
И История.ВидЦены = &ВидЦены
СГРУППИРОВАТЬ ПО
История.Номенклатура,
История.ВидЦены
;
Важно отметить, что эта дата — это дата последней записи в регистре, которая попала в период. Она может не совпадать с датой, когда цена *фактически* изменилась по сравнению с предыдущей ценой, но для нашей задачи (показать дату последней *записи* цены в периоде для изменившейся номенклатуры) это подходит.
Наконец, мы объединяем все наши временные таблицы, чтобы сформировать итоговый результат. Мы начинаем с ВТ_ТекущиеЦены, так как нам нужна актуальная цена для каждой позиции.
Производим ЛЕВОЕ СОЕДИНЕНИЕ с ВТ_ЦеныНаНачалоПериода по Номенклатуре и ВидуЦены. ЛЕВОЕ СОЕДИНЕНИЕ здесь важно, чтобы сохранить номенклатуру, для которой не было цен на начало периода (что означает, что она появилась в течение периода, и ее цена, по сути, "изменилась" с "ничего" на текущую). Дополнительно можно внедрить анализ изменения цен товара с выводом штрихкодов и остатков для информативности.
Затем выполняем ВНУТРЕННЕЕ СОЕДИНЕНИЕ с ВТ_ДатыИзменений, чтобы привязать дату последнего изменения к каждой номенклатуре.
Ключевым моментом является условие в секции ГДЕ. Мы используем оператор ВЫБОР КОГДА ТОГДА ИНАЧЕ КОНЕЦ для обработки двух сценариев:
Номенклатура появилась в течение периода: Если ВТ_ЦеныНаНачалоПериода.ЦенаНаНачалоПериода ЕСТЬ NULL, это означает, что на начало периода этой номенклатуры не было или цены на нее не существовало. В таком случае мы считаем, что цена "изменилась" (появилась), и включаем эту номенклатуру в отчет.
Номенклатура существовала на начало периода: В этом случае мы сравниваем ВТ_ТекущиеЦены.ТекущаяЦена с ВТ_ЦеныНаНачалоПериода.ЦенаНаНачалоПериода. Если цены не равны (<>), значит, цена изменилась.
Таким образом, мы формируем итоговый набор данных, содержащий Номенклатуру, ее ТекущуюЦену и ДатуПоследнегоИзменения за указанный период.
// 4. Объединяем и фильтруем те, у кого цена изменилась
ВЫБРАТЬ
ВТ_ТекущиеЦены.Номенклатура,
ВТ_ТекущиеЦены.ТекущаяЦена,
ВТ_ДатыИзменений.ДатаПоследнегоИзменения
ИЗ
ВТ_ТекущиеЦены КАК ВТ_ТекущиеЦены
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ЦеныНаНачалоПериода КАК ВТ_ЦеныНаНачалоПериода
ПО ВТ_ТекущиеЦены.Номенклатура = ВТ_ЦеныНаНачалоПериода.Номенклатура
И ВТ_ТекущиеЦены.ВидЦены = ВТ_ЦеныНаНачалоПериода.ВидЦены
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ДатыИзменений КАК ВТ_ДатыИзменений
ПО ВТ_ТекущиеЦены.Номенклатура = ВТ_ДатыИзменений.Номенклатура
И ВТ_ТекущиеЦены.ВидЦены = ВТ_ДатыИзменений.ВидЦены
ГДЕ
ВЫБОР
КОГДА ВТ_ЦеныНаНачалоПериода.ЦенаНаНачалоПериода ЕСТЬ NULL
ТОГДА ИСТИНА // Новая номенклатура, цена точно "менялась" (появилась)
ИНАЧЕ ВТ_ТекущиеЦены.ТекущаяЦена <> ВТ_ЦеныНаНачалоПериода.ЦенаНаНачалоПериода
КОНЕЦ
;
Для корректной работы этого запроса в СКД вам потребуется определить следующие параметры:
&НачалоПериода: Дата начала анализируемого периода.&КонецПериода: Дата окончания анализируемого периода.&ВидЦены: Конкретный вид цены, по которому производится анализ (например, "Цена продажи"). Этот параметр должен быть типа СправочникСсылка.ВидыЦенНоменклатуры.В настройках СКД эти параметры следует вынести в пользовательские настройки для удобства работы пользователя.
После того как вы создали текст запроса в схеме компоновки данных, необходимо правильно настроить сам отчет.
Закладка "Наборы данных": Перейдите на закладку "Наборы данных", добавьте новый набор данных "Запрос" и вставьте наш итоговый запрос.
Закладка "Параметры": Убедитесь, что все параметры (НачалоПериода, КонецПериода, ВидЦены) корректно определились. Установите им соответствующие типы данных (Дата для периода, СправочникСсылка.ВидыЦенНоменклатуры для вида цены) и при необходимости задайте значения по умолчанию или установите флаг "Ограничение доступности" для пользователя.
Закладка "Ресурсы": Если вы хотите выполнять какие-либо агрегатные функции (например, подсчет количества изменившихся позиций), настройте соответствующие ресурсы.
Закладка "Настройки": Здесь вы определяете структуру отчета.
Добавьте новую группировку по Номенклатура.
В выбранные поля для этой группировки включите Номенклатура, ТекущаяЦена, ДатаПоследнегоИзменения.
Вы можете добавить другие поля из справочника Номенклатура, если это необходимо для более детального анализа.
Внешний вид: Настройте форматирование полей, если требуется, например, выделите цены или даты определенным цветом.
Рассмотренный нами подход является достаточно универсальным и надежным для большинства случаев. Однако, при работе со специфическими требованиями, могут возникнуть дополнительные соображения:
Производительность: Для очень больших баз данных с миллионами записей в регистре ЦеныНоменклатуры, многократное использование временных таблиц и сканирование полного регистра может сказаться на производительности — её ускоряет обработка очистки истории цен от дублей.
Определение "изменения": Наш текущий запрос определяет изменение как различие между ценой на начало и конец периода. Если же вам необходим анализ изменения цен продажи с учетом фактических скидок в документах и конкретных менеджеров, логику запроса придется существенно расширить.
Контекст видов цен: Убедитесь, что параметр &ВидЦены всегда передается корректно. Если требуется анализировать несколько видов цен одновременно, запрос можно модифицировать, убрав фильтр по ВидЦены и включив его в группировку и выбранные поля.
Детализация последнего изменения: Если требуется не просто дата последнего изменения, а, например, предыдущая цена до этого изменения, запрос можно усложнить, используя оконные функции или дополнительные временные таблицы для поиска "соседа" по периоду.
Мы подробно разобрали, как с помощью СКД и запросов к регистру сведений ЦеныНоменклатуры в 1С:Управление торговлей 11 сформировать отчет, который показывает номенклатуру, цена которой изменялась за заданный период. Предложенное решение использует несколько временных таблиц для последовательного сбора и анализа данных, что обеспечивает высокую точность и учитывает такие сценарии, как появление новой номенклатуры.
Используя этот подход, вы сможете предоставлять пользователям системы ценную аналитическую информацию о динамике цен, что поможет в принятии управленческих решений и контроле над ценовой политикой предприятия. Не забывайте о важности тестирования отчета на реальных данных и, при необходимости, оптимизации запросов для больших объемов информации.