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