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