Сложный запрос к УТ 11.5 с помощью ИИ: остатки, резервы, себестоимость и продажи одним пакетом
Задача, которую в Управлении торговлей не решить одним отчетом: по каждому товару на каждом складе показать, сколько лежит, сколько уже обещано клиентам, сколько свободно, во что обходится остаток и как товар продавался за период. Четыре регистра, аналитика учета ключами, виртуальные таблицы и соединения. Разбираем, как агент через Жёлтый мост дошел от первой ошибки до пакета запросов, который выполняется за две с половиной секунды, и что в этом пакете важно, включая ловушку, в которую легко попасть: наличие на складе и количество в учете себестоимости в УТ не обязаны совпадать.
Задача
Руководитель склада спрашивает: "Что у нас лежит без движения и сколько в этом денег?". Чтобы ответить, нужны сразу четыре источника. Физический остаток лежит в регистре ТоварыНаСкладах. Резервы под заказы клиентов в регистре ТоварыКОтгрузке. Стоимость остатка в регистре СебестоимостьТоваров. Продажи за период в регистре ВыручкаИСебестоимостьПродаж. Свободный остаток нигде не хранится, это разность первых двух.
Сложность не в объеме кода, а в устройстве конфигурации. Регистры себестоимости и продаж не хранят номенклатуру и склад напрямую: у них одно измерение АналитикаУчетаНоменклатуры, ссылка на служебный справочник ключей аналитики, в котором уже лежат Номенклатура, Характеристика, МестоХранения и еще десяток реквизитов. Кто пишет запросы к УТ 10.3 или Бухгалтерии, об этом не знает, и первые попытки заканчиваются ошибками.
Как шел агент
- Первая попытка по памяти. Модель пишет запрос к регистру СвободныеОстатки, как в старых редакциях УТ 11. Платформа отвечает через мост: "Таблица не найдена РегистрНакопления.СвободныеОстатки.Остатки", с позицией в тексте. Модель идет в справку по структуре базы и находит, что в 11.5 наличие и резервы разнесены по двум регистрам.
- Вторая ошибка, полезнее первой. Запрос к остаткам себестоимости с полем Себестоимость.Номенклатура падает: "Поле не найдено". В справке по регистру измерения Номенклатура нет, есть АналитикаУчетаНоменклатуры. Модель читает состав справочника ключей аналитики и понимает, что номенклатура и склад достаются оттуда.
- Первая рабочая версия. Пять временных таблиц, полное соединение остатков и резервов, разыменование аналитики через точку. На демо-базе пакет отработал за 4,6 секунды и вернул 342 строки. Ответ есть, но проверка синтаксиса выдала два замечания и девять предупреждений: соединения с виртуальными таблицами, разыменование ссылочных полей внутри запроса, полное внешнее соединение.
- Доводка по замечаниям. Виртуальные таблицы себестоимости и продаж сначала кладутся во временные таблицы и только потом соединяются со справочником ключей. Полное соединение заменено объединением ключей остатков и резервов с последующими левыми соединениями. Наименования подтягиваются соединением со справочниками, а не через точку. Тот же результат, 2,5 секунды, одно информационное сообщение анализатора, и оно оставлено сознательно.
Весь путь занял около десяти минут. Человек прошел бы его так же, только между шагами были бы переключения между конфигуратором, консолью запросов и синтакс-помощником.
Пакет запросов
Восемь запросов в одном пакете. Первые два собирают наличие и резервы по паре товар плюс склад. Третий и четвертый берут остатки себестоимости и раскрывают аналитику через справочник ключей. Пятый и шестой делают то же с продажами за период. Седьмой собирает список пар товар плюс склад из остатков и резервов. Восьмой сводит все левыми соединениями и считает свободный остаток и себестоимость единицы. В итоге одиннадцать колонок: наличие, резерв, свободно, количество и стоимость по учету себестоимости без НДС, себестоимость единицы без НДС, списано без расчета себестоимости, продано и выручка без НДС за период.
ВЫБРАТЬ Остатки.Номенклатура КАК Номенклатура, Остатки.Склад КАК Склад, СУММА(Остатки.ВНаличииОстаток) КАК ВНаличии ПОМЕСТИТЬ втОстатки ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата) КАК Остатки СГРУППИРОВАТЬ ПО Остатки.Номенклатура, Остатки.Склад ИНДЕКСИРОВАТЬ ПО Номенклатура, Склад ; ВЫБРАТЬ Резервы.Номенклатура КАК Номенклатура, Резервы.Склад КАК Склад, СУММА(Резервы.ВРезервеОстаток) КАК ВРезерве ПОМЕСТИТЬ втРезервы ИЗ РегистрНакопления.ТоварыКОтгрузке.Остатки(&Дата) КАК Резервы СГРУППИРОВАТЬ ПО Резервы.Номенклатура, Резервы.Склад ИНДЕКСИРОВАТЬ ПО Номенклатура, Склад ; // Партия выбирается намеренно, хотя дальше не нужна: виртуальная таблица // остатков сворачивает измерения, которых нет в списке полей, и списания без // партии (отрицательные остатки) схлопнулись бы с приходами еще до проверки знака. ВЫБРАТЬ Себестоимость.АналитикаУчетаНоменклатуры КАК АналитикаУчетаНоменклатуры, Себестоимость.Партия КАК Партия, Себестоимость.КоличествоОстаток КАК Количество, Себестоимость.СтоимостьБезНДСОстаток КАК Стоимость, ВЫБОР КОГДА Себестоимость.КоличествоОстаток < 0 ТОГДА -Себестоимость.КоличествоОстаток ИНАЧЕ 0 КОНЕЦ КАК СписаноБезРасчета ПОМЕСТИТЬ втСебестоимостьПоАналитике ИЗ РегистрНакопления.СебестоимостьТоваров.Остатки( &Дата, РазделУчета = ЗНАЧЕНИЕ(Перечисление.РазделыУчетаСебестоимостиТоваров.ТоварыНаСкладах)) КАК Себестоимость ; ВЫБРАТЬ Аналитика.Номенклатура КАК Номенклатура, Аналитика.МестоХранения КАК Склад, СУММА(Себестоимость.Количество) КАК Количество, СУММА(Себестоимость.Стоимость) КАК Стоимость, СУММА(Себестоимость.СписаноБезРасчета) КАК СписаноБезРасчета ПОМЕСТИТЬ втСебестоимость ИЗ втСебестоимостьПоАналитике КАК Себестоимость ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК Аналитика ПО Себестоимость.АналитикаУчетаНоменклатуры = Аналитика.Ссылка СГРУППИРОВАТЬ ПО Аналитика.Номенклатура, Аналитика.МестоХранения ИНДЕКСИРОВАТЬ ПО Номенклатура, Склад ; ВЫБРАТЬ Продажи.АналитикаУчетаНоменклатуры КАК АналитикаУчетаНоменклатуры, Продажи.Склад КАК Склад, Продажи.КоличествоОборот КАК Продано, Продажи.СуммаВыручкиБезНДСОборот КАК Выручка ПОМЕСТИТЬ втПродажиПоАналитике ИЗ РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&Начало, &Конец) КАК Продажи ; ВЫБРАТЬ Аналитика.Номенклатура КАК Номенклатура, Продажи.Склад КАК Склад, СУММА(Продажи.Продано) КАК Продано, СУММА(Продажи.Выручка) КАК Выручка ПОМЕСТИТЬ втПродажи ИЗ втПродажиПоАналитике КАК Продажи ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК Аналитика ПО Продажи.АналитикаУчетаНоменклатуры = Аналитика.Ссылка СГРУППИРОВАТЬ ПО Аналитика.Номенклатура, Продажи.Склад ИНДЕКСИРОВАТЬ ПО Номенклатура, Склад ; // ОБЪЕДИНИТЬ без ВСЕ намеренно: одна и та же пара товар + склад бывает // и в остатках, и в резервах, а нужна она один раз. ВЫБРАТЬ Остатки.Номенклатура КАК Номенклатура, Остатки.Склад КАК Склад ПОМЕСТИТЬ втКлючи ИЗ втОстатки КАК Остатки ОБЪЕДИНИТЬ ВЫБРАТЬ Резервы.Номенклатура, Резервы.Склад ИЗ втРезервы КАК Резервы ; ВЫБРАТЬ СправочникНоменклатура.Наименование КАК Номенклатура, СправочникСклады.Наименование КАК Склад, ЕСТЬNULL(Остатки.ВНаличии, 0) КАК ВНаличии, ЕСТЬNULL(Резервы.ВРезерве, 0) КАК ВРезерве, ЕСТЬNULL(Остатки.ВНаличии, 0) - ЕСТЬNULL(Резервы.ВРезерве, 0) КАК Свободно, ЕСТЬNULL(Себестоимость.Количество, 0) КАК КоличествоПоУчетуСебестоимости, ЕСТЬNULL(Себестоимость.Стоимость, 0) КАК СтоимостьБезНДСПоУчету, ВЫБОР КОГДА ЕСТЬNULL(Себестоимость.Количество, 0) > 0 ТОГДА Себестоимость.Стоимость / Себестоимость.Количество ИНАЧЕ 0 КОНЕЦ КАК СебестоимостьЕдиницыБезНДС, ЕСТЬNULL(Себестоимость.СписаноБезРасчета, 0) КАК СписаноБезРасчетаСебестоимости, ЕСТЬNULL(Продажи.Продано, 0) КАК ПроданоЗаПериод, ЕСТЬNULL(Продажи.Выручка, 0) КАК ВыручкаБезНДСЗаПериод ИЗ втКлючи КАК Ключи ЛЕВОЕ СОЕДИНЕНИЕ втОстатки КАК Остатки ПО Ключи.Номенклатура = Остатки.Номенклатура И Ключи.Склад = Остатки.Склад ЛЕВОЕ СОЕДИНЕНИЕ втРезервы КАК Резервы ПО Ключи.Номенклатура = Резервы.Номенклатура И Ключи.Склад = Резервы.Склад ЛЕВОЕ СОЕДИНЕНИЕ втСебестоимость КАК Себестоимость ПО Ключи.Номенклатура = Себестоимость.Номенклатура И Ключи.Склад = Себестоимость.Склад ЛЕВОЕ СОЕДИНЕНИЕ втПродажи КАК Продажи ПО Ключи.Номенклатура = Продажи.Номенклатура И Ключи.Склад = Продажи.Склад ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СправочникНоменклатура ПО Ключи.Номенклатура = СправочникНоменклатура.Ссылка ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Склады КАК СправочникСклады ПО Ключи.Склад = СправочникСклады.Ссылка УПОРЯДОЧИТЬ ПО СтоимостьБезНДСПоУчету УБЫВ, Номенклатура, Склад ; УНИЧТОЖИТЬ втОстатки ; УНИЧТОЖИТЬ втРезервы ; УНИЧТОЖИТЬ втСебестоимостьПоАналитике ; УНИЧТОЖИТЬ втСебестоимость ; УНИЧТОЖИТЬ втПродажиПоАналитике ; УНИЧТОЖИТЬ втПродажи ; УНИЧТОЖИТЬ втКлючи
На что обратить внимание в этом тексте.
- Раздел учета в параметрах виртуальной таблицы. Регистр СебестоимостьТоваров хранит не только товары на складах, но и товары в пути, у комиссионеров, материалы в переработке. Без отбора по разделу учета стоимость остатка завысится.
- Индексы временных таблиц по полям соединения. На демо-базе разница не видна, на базе с десятками тысяч позиций она решает, займет запрос секунды или минуты.
- Наличие и количество по учету себестоимости это разные цифры. Складской учет ведется в регистре ТоварыНаСкладах, финансовый учет себестоимости в регистре СебестоимостьТоваров, и сходятся они только после расчета себестоимости и при проведении всех движений по обоим контурам. На демо-базе расхождения заметные: по одному складу в наличии 475 штук, а в учете себестоимости 512, по другому 545 против 65. Поэтому количество по учету себестоимости выведено отдельной колонкой, а себестоимость единицы считается от него, а не от наличия. Первая версия запроса этого не показывала, и стоимость остатка читалась как стоимость того, что лежит на складе. Это было бы неверно.
- Себестоимость единицы верна только после расчета себестоимости. Пока расчет за период не выполнен, списания лежат в регистре без партии: количество ушло, а стоимость нет. На демо-базе по одному складу таких списаний 121 штука, и себестоимость единицы получалась вдвое выше реальной. Поэтому в пакете есть колонка "списано без расчета себестоимости": если она не ноль, себестоимости в этой строке верить нельзя, сначала закрытие месяца.
- Виртуальная таблица остатков сворачивает невыбранные измерения. Первая версия колонки "списано без расчета" всегда давала ноль: в запросе к остаткам себестоимости не была выбрана партия, и платформа сложила приходы по партиям с списаниями без партии еще до проверки знака. Стоило добавить партию в список полей, и по тому же товару появились 121 штука списаний. Это свойство любой виртуальной таблицы Остатки: она группирует по тем измерениям, которые вы попросили, и никакими другими.
- Стоимость и выручка без НДС. В регистрах есть оба варианта. Сравнивать себестоимость с выручкой можно только в одинаковой базе, иначе маржа врет на ставку налога.
- Свободный остаток может быть отрицательным. На демо-базе есть одна позиция, где резерв больше наличия. Это не ошибка запроса, а сигнал: клиенту обещали то, чего на складе нет. Такие строки стоит показывать первыми.
- ОБЪЕДИНИТЬ без ВСЕ оставлено намеренно. Пара товар плюс склад часто есть и в остатках, и в резервах, а в списке ключей она нужна один раз. Комментарий в тексте запроса об этом говорит, чтобы следующий читатель не "исправил" его на ОБЪЕДИНИТЬ ВСЕ.
Функция для обработки
Тот же пакет, обернутый в серверную функцию с параметрами дат. Именно в таком виде код попадает во внешнюю обработку: форма передает даты, функция возвращает таблицу значений, дальше ее можно вывести в табличный документ или в поле HTML.
// Остатки товаров по складам на дату с резервами, свободным остатком,
// себестоимостью остатка и продажами за период.
//
// Четыре регистра сведены одним пакетом запросов:
// - ТоварыНаСкладах: что физически лежит на складе (ВНаличии);
// - ТоварыКОтгрузке: что уже обещано клиентам (ВРезерве);
// - СебестоимостьТоваров: стоимость остатка по разделу учета "Товары на складах";
// - ВыручкаИСебестоимостьПродаж: сколько продано и на какую сумму за период.
// Ключ соединения везде пара Номенклатура + Склад. Характеристики и серии
// свернуты: если они нужны, добавьте их в группировки всех временных таблиц.
// Складской учет (ТоварыНаСкладах) и финансовый учет себестоимости
// (СебестоимостьТоваров) это разные контуры: количество в них расходится,
// пока не выполнен расчет себестоимости или движения проведены не по всем
// регистрам. Поэтому количество по учету себестоимости выводится отдельной
// колонкой, а себестоимость единицы считается от него, а не от наличия.
// Стоимость и выручка берутся без НДС, чтобы их можно было сравнивать между собой.
// Колонка СписаноБезРасчетаСебестоимости показывает количество, списанное без
// партии (отрицательные остатки по партиям): пока оно не ноль, расчет
// себестоимости за период не выполнен и себестоимость единицы завышена.
// Аналитика учета в регистрах себестоимости и продаж хранится ключом
// (справочник КлючиАналитикиУчетаНоменклатуры). Виртуальные таблицы этих
// регистров сначала кладутся во временные таблицы и только потом соединяются
// со справочником ключей: соединение напрямую с виртуальной таблицей платформа
// выполняет плохо. Строки итога собираются от объединения ключей остатков и
// резервов, полное соединение не используется.
//
// Параметры:
// Дата - Дата - момент остатков, берется конец этого дня;
// Начало - Дата - начало периода продаж;
// Конец - Дата - конец периода продаж, берется конец дня.
//
// Возвращаемое значение:
// ТаблицаЗначений - Номенклатура, Склад, ВНаличии, ВРезерве, Свободно,
// КоличествоПоУчетуСебестоимости, СтоимостьБезНДСПоУчету,
// СебестоимостьЕдиницыБезНДС, СписаноБезРасчетаСебестоимости,
// ПроданоЗаПериод, ВыручкаБезНДСЗаПериод.
&НаСервереБезКонтекста
Функция ОстаткиСРезервамиИПродажами(Знач Дата, Знач Начало, Знач Конец)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.Склад КАК Склад,
| СУММА(Остатки.ВНаличииОстаток) КАК ВНаличии
|ПОМЕСТИТЬ втОстатки
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата) КАК Остатки
|СГРУППИРОВАТЬ ПО
| Остатки.Номенклатура,
| Остатки.Склад
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура,
| Склад
|;
|ВЫБРАТЬ
| Резервы.Номенклатура КАК Номенклатура,
| Резервы.Склад КАК Склад,
| СУММА(Резервы.ВРезервеОстаток) КАК ВРезерве
|ПОМЕСТИТЬ втРезервы
|ИЗ
| РегистрНакопления.ТоварыКОтгрузке.Остатки(&Дата) КАК Резервы
|СГРУППИРОВАТЬ ПО
| Резервы.Номенклатура,
| Резервы.Склад
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура,
| Склад
|;
|// Партия выбирается намеренно, хотя дальше не нужна: виртуальная таблица
|// остатков сворачивает измерения, которых нет в списке полей, и списания без
|// партии (отрицательные остатки) схлопнулись бы с приходами еще до проверки знака.
|ВЫБРАТЬ
| Себестоимость.АналитикаУчетаНоменклатуры КАК АналитикаУчетаНоменклатуры,
| Себестоимость.Партия КАК Партия,
| Себестоимость.КоличествоОстаток КАК Количество,
| Себестоимость.СтоимостьБезНДСОстаток КАК Стоимость,
| ВЫБОР
| КОГДА Себестоимость.КоличествоОстаток < 0
| ТОГДА -Себестоимость.КоличествоОстаток
| ИНАЧЕ 0
| КОНЕЦ КАК СписаноБезРасчета
|ПОМЕСТИТЬ втСебестоимостьПоАналитике
|ИЗ
| РегистрНакопления.СебестоимостьТоваров.Остатки(
| &Дата,
| РазделУчета = ЗНАЧЕНИЕ(Перечисление.РазделыУчетаСебестоимостиТоваров.ТоварыНаСкладах)) КАК Себестоимость
|;
|ВЫБРАТЬ
| Аналитика.Номенклатура КАК Номенклатура,
| Аналитика.МестоХранения КАК Склад,
| СУММА(Себестоимость.Количество) КАК Количество,
| СУММА(Себестоимость.Стоимость) КАК Стоимость,
| СУММА(Себестоимость.СписаноБезРасчета) КАК СписаноБезРасчета
|ПОМЕСТИТЬ втСебестоимость
|ИЗ
| втСебестоимостьПоАналитике КАК Себестоимость
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК Аналитика
| ПО Себестоимость.АналитикаУчетаНоменклатуры = Аналитика.Ссылка
|СГРУППИРОВАТЬ ПО
| Аналитика.Номенклатура,
| Аналитика.МестоХранения
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура,
| Склад
|;
|ВЫБРАТЬ
| Продажи.АналитикаУчетаНоменклатуры КАК АналитикаУчетаНоменклатуры,
| Продажи.Склад КАК Склад,
| Продажи.КоличествоОборот КАК Продано,
| Продажи.СуммаВыручкиБезНДСОборот КАК Выручка
|ПОМЕСТИТЬ втПродажиПоАналитике
|ИЗ
| РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&Начало, &Конец) КАК Продажи
|;
|ВЫБРАТЬ
| Аналитика.Номенклатура КАК Номенклатура,
| Продажи.Склад КАК Склад,
| СУММА(Продажи.Продано) КАК Продано,
| СУММА(Продажи.Выручка) КАК Выручка
|ПОМЕСТИТЬ втПродажи
|ИЗ
| втПродажиПоАналитике КАК Продажи
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК Аналитика
| ПО Продажи.АналитикаУчетаНоменклатуры = Аналитика.Ссылка
|СГРУППИРОВАТЬ ПО
| Аналитика.Номенклатура,
| Продажи.Склад
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура,
| Склад
|;
|// ОБЪЕДИНИТЬ без ВСЕ намеренно: одна и та же пара товар + склад бывает
|// и в остатках, и в резервах, а нужна она один раз.
|ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.Склад КАК Склад
|ПОМЕСТИТЬ втКлючи
|ИЗ
| втОстатки КАК Остатки
|
|ОБЪЕДИНИТЬ
|
|ВЫБРАТЬ
| Резервы.Номенклатура,
| Резервы.Склад
|ИЗ
| втРезервы КАК Резервы
|;
|ВЫБРАТЬ
| СправочникНоменклатура.Наименование КАК Номенклатура,
| СправочникСклады.Наименование КАК Склад,
| ЕСТЬNULL(Остатки.ВНаличии, 0) КАК ВНаличии,
| ЕСТЬNULL(Резервы.ВРезерве, 0) КАК ВРезерве,
| ЕСТЬNULL(Остатки.ВНаличии, 0) - ЕСТЬNULL(Резервы.ВРезерве, 0) КАК Свободно,
| ЕСТЬNULL(Себестоимость.Количество, 0) КАК КоличествоПоУчетуСебестоимости,
| ЕСТЬNULL(Себестоимость.Стоимость, 0) КАК СтоимостьБезНДСПоУчету,
| ВЫБОР
| КОГДА ЕСТЬNULL(Себестоимость.Количество, 0) > 0
| ТОГДА Себестоимость.Стоимость / Себестоимость.Количество
| ИНАЧЕ 0
| КОНЕЦ КАК СебестоимостьЕдиницыБезНДС,
| ЕСТЬNULL(Себестоимость.СписаноБезРасчета, 0) КАК СписаноБезРасчетаСебестоимости,
| ЕСТЬNULL(Продажи.Продано, 0) КАК ПроданоЗаПериод,
| ЕСТЬNULL(Продажи.Выручка, 0) КАК ВыручкаБезНДСЗаПериод
|ИЗ
| втКлючи КАК Ключи
| ЛЕВОЕ СОЕДИНЕНИЕ втОстатки КАК Остатки
| ПО Ключи.Номенклатура = Остатки.Номенклатура
| И Ключи.Склад = Остатки.Склад
| ЛЕВОЕ СОЕДИНЕНИЕ втРезервы КАК Резервы
| ПО Ключи.Номенклатура = Резервы.Номенклатура
| И Ключи.Склад = Резервы.Склад
| ЛЕВОЕ СОЕДИНЕНИЕ втСебестоимость КАК Себестоимость
| ПО Ключи.Номенклатура = Себестоимость.Номенклатура
| И Ключи.Склад = Себестоимость.Склад
| ЛЕВОЕ СОЕДИНЕНИЕ втПродажи КАК Продажи
| ПО Ключи.Номенклатура = Продажи.Номенклатура
| И Ключи.Склад = Продажи.Склад
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СправочникНоменклатура
| ПО Ключи.Номенклатура = СправочникНоменклатура.Ссылка
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Склады КАК СправочникСклады
| ПО Ключи.Склад = СправочникСклады.Ссылка
|УПОРЯДОЧИТЬ ПО
| СтоимостьБезНДСПоУчету УБЫВ,
| Номенклатура,
| Склад
|;
|УНИЧТОЖИТЬ втОстатки
|;
|УНИЧТОЖИТЬ втРезервы
|;
|УНИЧТОЖИТЬ втСебестоимостьПоАналитике
|;
|УНИЧТОЖИТЬ втСебестоимость
|;
|УНИЧТОЖИТЬ втПродажиПоАналитике
|;
|УНИЧТОЖИТЬ втПродажи
|;
|УНИЧТОЖИТЬ втКлючи";
// Остатки на конец дня: иначе движения за сам день в остаток не попадут.
Запрос.УстановитьПараметр("Дата", КонецДня(Дата));
Запрос.УстановитьПараметр("Начало", НачалоДня(Начало));
Запрос.УстановитьПараметр("Конец", КонецДня(Конец));
// Нужен результат восьмого запроса пакета (индекс 7): временные таблицы
// и УНИЧТОЖИТЬ строк не возвращают.
Результаты = Запрос.ВыполнитьПакет();
Возврат Результаты[7].Выгрузить();
КонецФункции
Комментарии в шапке объясняют не что делает код, а почему он сделан так: откуда берется аналитика, зачем виртуальные таблицы сначала кладутся во временные, почему нет полного соединения. Это тот минимум, который экономит час следующему разработчику.
Как приспособить под себя
- Нужны характеристики или серии: добавьте их в поля и группировки первых шести запросов и в ключи объединения. Ключ соединения станет длиннее, логика не изменится.
- Нужен один склад: добавьте параметр в условия виртуальных таблиц остатков и резервов и в отбор продаж по складу. Не фильтруйте итоговую таблицу, это дороже.
- Нужны дни запаса: разделите свободный остаток на среднюю дневную продажу за период. Деление на ноль закройте конструкцией ВЫБОР, как сделано с себестоимостью единицы.
- В Комплексной автоматизации 2 и ERP 2 регистры называются так же. Код не проверялся на них в рамках этой статьи, поэтому перед использованием прогоните его на своей базе.
Как устроен цикл "запрос, ошибка платформы, справка по структуре, исправление" и почему он делает ИИ полезным для разработчика, в статье Разработка кода 1С с ИИ через Жёлтый мост. Подключить свою базу и повторить: кабинет, первые дни бесплатно.