В типовых конфигурациях, таких как Управление торговлей 11.4, часто возникает задача анализа оборачиваемости или спроса на товары. Одной из классических задач является создание отчета, который показывает не только текущие остатки, но и активность покупателей за определенные промежутки времени: например, сколько раз товар заказывали за последние 30, 60 и 90 дней. Разберем подробно, как реализовать такой функционал правильно, используя современные инструменты 1С.
Начинающие программисты часто пытаются решить задачу "в лоб": создать массив или таблицу значений, в цикле обходить номенклатуру и для каждой позиции выполнять запрос. Как справедливо отмечено в обсуждении, за такие планы "отправляли на галеры". И вот почему: выполнение запроса в цикле — это критическая ошибка производительности. При наличии в справочнике 10 000 позиций программа выполнит 10 000 отдельных обращений к базе данных, что приведет к зависанию системы.
Правильный путь — использование Системы компоновки данных (СКД). Мы напишем один комплексный запрос, который за один проход соберет все необходимые данные. СКД сама позаботится о выводе, группировках по иерархии номенклатуры и оформлении отчета.
Для реализации задачи в УТ 11.4 нам понадобятся два основных источника данных:
ТоварыНаСкладах — из него мы возьмем остатки. Используем виртуальную таблицу Остатки.ЗаказыКлиентов — из него мы получим данные о количестве заказов. Нам понадобится виртуальная таблица Обороты.Важный нюанс: если мы просто выберем данные из регистра заказов, то в отчет попадут только те товары, которые заказывали. Чтобы увидеть "мертвые" позиции (у которых есть остаток, но нет заказов), основным источником в запросе должен выступать справочник Номенклатура.
Вместо того чтобы делать три разных запроса для каждого периода, мы воспользуемся конструкцией ВЫБОР внутри одного запроса к оборотам. Проанализируем, как это реализовать. Нам нужно посчитать именно количество уникальных заказов (документов-регистраторов), а не количество заказанного товара.
Рассмотрим пример запроса, который собирает статистику заказов:
ВЫБРАТЬ
ЗаказыОбороты.Номенклатура КАК Номенклатура,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВЫБОР
КОГДА ЗаказыОбороты.Период >= &ДатаНачала30
ТОГДА ЗаказыОбороты.Регистратор
ИНАЧЕ NULL
КОНЕЦ) КАК ЗаказовЗа30Дней,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВЫБОР
КОГДА ЗаказыОбороты.Период >= &ДатаНачала60
ТОГДА ЗаказыОбороты.Регистратор
ИНАЧЕ NULL
КОНЕЦ) КАК ЗаказовЗа60Дней,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказыОбороты.Регистратор) КАК ЗаказовЗа90Дней
ИЗ
РегистрНакопления.ЗаказыКлиентов.Обороты(&ДатаНачала90, &КонецПериода, День, ) КАК ЗаказыОбороты
СГРУППИРОВАТЬ ПО
ЗаказыОбороты.Номенклатура
В данном фрагменте мы используем функцию КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...). Это критически важно, так как одна позиция номенклатуры может присутствовать в нескольких строках одного заказа или по ней могут быть корректировки. Нам же нужно посчитать именно число уникальных сделок.
Теперь объединим справочник номенклатуры, текущие остатки и нашу статистику заказов с помощью левого соединения. Это позволит нам не потерять ни одну позицию товара. Проанализируем итоговую структуру запроса:
ВЫБРАТЬ
СпрНоменклатура.Ссылка КАК Номенклатура,
СпрНоменклатура.Артикул КАК Артикул,
ЕСТЬNULL(ТоварыОстатки.ВНаличииОстаток, 0) КАК ОстатокНаСегодня,
ЕСТЬNULL(СтатистикаЗаказов.ЗаказовЗа30Дней, 0) КАК Заказов30,
ЕСТЬNULL(СтатистикаЗаказов.ЗаказовЗа60Дней, 0) КАК Заказов60,
ЕСТЬNULL(СтатистикаЗаказов.ЗаказовЗа90Дней, 0) КАК Заказов90
ИЗ
Справочник.Номенклатура КАК СпрНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(&ПериодОстатков, ) КАК ТоварыОстатки
ПО СпрНоменклатура.Ссылка = ТоварыОстатки.Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ
Заказы.Номенклатура КАК Номенклатура,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВЫБОР
КОГДА Заказы.Период >= &Дата30
ТОГДА Заказы.Регистратор
КОНЕЦ) КАК ЗаказовЗа30Дней,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВЫБОР
КОГДА Заказы.Период >= &Дата60
ТОГДА Заказы.Регистратор
КОНЕЦ) КАК ЗаказовЗа60Дней,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Заказы.Регистратор) КАК ЗаказовЗа90Дней
ИЗ
РегистрНакопления.ЗаказыКлиентов.Обороты(&Дата90, &ТекущаяДата, День, ) КАК Заказы
СГРУППИРОВАТЬ ПО
Заказы.Номенклатура
) КАК СтатистикаЗаказов
ПО СпрНоменклатура.Ссылка = СтатистикаЗаказов.Номенклатура
ГДЕ
НЕ СпрНоменклатура.ЭтоГруппа
Разберем важные моменты этого запроса:
NULL. Функция ЕСТЬNULL заменяет его на 0, что делает отчет читаемым.ЭтоГруппа: Мы исключаем папки из выборки, так как остатки и заказы хранятся только по конкретным элементам.При работе с регистром ЗаказыКлиентов в УТ 11.4 нужно учитывать специфику бизнес-процессов. Заказ может быть создан, но позже отменен. В регистре накопления отмена строки заказа обычно отражается сторнирующим движением. Если мы просто считаем обороты, мы можем учесть отмененные заказы.
Чтобы отчет был максимально точным, рекомендуется добавить в виртуальную таблицу оборотов условие на статус заказа или анализировать только те заказы, которые перешли в статус "К выполнению" или "Закрыт". Также стоит обращать внимание на реквизит Отменено в строках заказа, если вы решите делать запрос к физической таблице (чего лучше избегать ради производительности).
Для того чтобы запрос заработал, необходимо правильно настроить параметры в схеме компоновки данных. На вкладке "Параметры" мы создаем:
&Дата90, &Дата60, &Дата30 — даты начала соответствующих периодов.&ПериодОстатков — текущий момент времени.Чтобы пользователю не приходилось вводить эти даты вручную, в выражениях параметров СКД можно прописать функции языка запросов. Например, для &Дата90 выражение будет: ДобавитьКДате(ТекущаяДата(), "День", -90). Это автоматизирует отчет, и он всегда будет показывать актуальную статистику относительно "сегодня".
Мы проанализировали задачу создания аналитического отчета в УТ 11.4. Использование СКД в сочетании с механизмом виртуальных таблиц оборотов и грамотным применением левых соединений позволяет создать быстрый и надежный инструмент для бизнеса. Такой подход не только экономит ресурсы сервера, но и предоставляет гибкие возможности для дальнейшей настройки отчета пользователем: добавления отборов по складам, артикулам или характеристикам товаров без изменения программного кода.