Как правильно определить статус отгрузки заказа в запросе 1С

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В процессе разработки отчетов или доработки логики в конфигурациях на базе 1С:Предприятие 8 часто возникает задача: определить, насколько отгружен товар по конкретному заказу клиента. Типичная ситуация — когда программист пытается сравнить количество в документе с остатками по регистру ЗаказыКлиентов, но сталкивается с тем, что запрос возвращает неверные результаты (например, всегда «0» или неверно определяет полностью отгруженные позиции).

В этой статье мы подробно разберем, как построить надежный запрос, который будет безошибочно возвращать три статуса: «Товар полностью не отгружен», «Отгружена часть товара» и «Товар полностью отгружен».

Разбор типичной ошибки в логике условий

Проанализируем ситуацию, с которой часто сталкиваются начинающие разработчики. Рассмотрим фрагмент кода, который не работает корректно:


ВЫБОР 
    КОГДА ЕСТЬNULL(ОстаткиЗаказовКлиента.ЗаказаноОстаток, 0) <> 0 
    ТОГДА 
        ВЫБОР 
            КОГДА ОстаткиЗаказовКлиента.ЗаказаноОстаток = КоличествоТоваровИтог.Количество ТОГДА 1 
            КОГДА ЕСТЬNULL(ОстаткиЗаказовКлиента.ЗаказаноОстаток, 0) = 0 ТОГДА -1 
            ИНАЧЕ 0 
        КОНЕЦ 
КОНЕЦ

Выясним причину ошибки: в данном примере используется вложенная конструкция ВЫБОР. Внешнее условие сразу отсекает все записи, где остаток равен нулю (или NULL), проверяя <> 0. Следовательно, внутреннее условие КОГДА ЕСТЬNULL(ОстаткиЗаказовКлиента.ЗаказаноОстаток, 0) = 0 никогда не будет выполнено, так как программа до него просто не дойдет. Именно поэтому для всех полностью отгруженных заказов результат будет неопределенным или нулевым.

Пошаговый алгоритм правильного определения статуса

Чтобы запрос работал правильно, нам нужно сопоставить данные из двух источников: табличной части документа (сколько заказано изначально) и виртуальной таблицы остатков регистра накопления (сколько осталось отгрузить). Рассмотрим основные шаги.

Шаг 1. Получение итогового количества по заказу. Нам необходимо сгруппировать строки табличной части Товары документа ЗаказКлиента, чтобы получить общую сумму по каждой позиции или по документу в целом.

Шаг 2. Получение текущих остатков. Обращаемся к таблице РегистрНакопления.ЗаказыКлиентов.Остатки. Важно помнить, что когда товар полностью отгружен, запись в этой таблице пропадает, и при левом соединении мы получим NULL.

Шаг 3. Сопоставление данных. Теперь мы можем применить правильную логику условий. Проанализируем последовательность проверки:

  1. Если остаток в регистре равен нулю (или запись отсутствует, т.е. NULL) — значит, товар полностью отгружен.
  2. Если остаток в регистре равен количеству в заказе — значит, к отгрузке еще не приступали, товар полностью не отгружен.
  3. Во всех остальных случаях (когда остаток больше нуля, но меньше исходного количества) — товар отгружен частично.

Оптимальный вариант реализации запроса

Посмотрим на пример кода, который реализует эту логику наиболее эффективно:


ВЫБОР 
    КОГДА ЕСТЬNULL(ОстаткиЗаказовКлиента.ЗаказаноОстаток, 0) = 0 
        ТОГДА 3 // Полностью отгружен
    КОГДА ОстаткиЗаказовКлиента.ЗаказаноОстаток = КоличествоТоваровИтог.Количество 
        ТОГДА 1 // Вообще не отгружен
    ИНАЧЕ 2 // Отгружен частично
КОНЕЦ КАК СтатусОтгрузки

Этот вариант лишен вложенности и корректно обрабатывает ситуацию с NULL через функцию ЕСТЬNULL. Порядок условий здесь критически важен: сначала проверяем крайние состояния (полная отгрузка или ее отсутствие), а промежуточное состояние «частично» оставляем в секции ИНАЧЕ.

Повышение надежности запроса: временные таблицы

Использование подзапросов в секции ЛЕВОЕ СОЕДИНЕНИЕ (как часто делают начинающие) может привести к существенному замедлению работы системы. Проанализируем ситуацию: СУБД сложнее оптимизировать такой запрос. Рассмотрим правильный архитектурный подход с использованием временных таблиц:

  1. Создаем временную таблицу ВТ_КоличествоЗаказ, где суммируем количество из документа.
  2. Создаем временную таблицу ВТ_ОстаткиРегистра, куда выбираем данные из виртуальной таблицы остатков.
  3. В финальном запросе соединяем эти таблицы по ссылке на заказ.

Пример структуры финального запроса:


ВЫБРАТЬ
    Заказ.Ссылка КАК Ссылка,
    ВЫБОР
        КОГДА ЕСТЬNULL(ВТ_Остатки.ЗаказаноОстаток, 0) = 0 ТОГДА "Полностью отгружен"
        КОГДА ЕСТЬNULL(ВТ_Остатки.ЗаказаноОстаток, 0) >= ВТ_Заказано.КоличествоИтог ТОГДА "Не отгружен"
        ИНАЧЕ "Частично отгружен"
    КОНЕЦ КАК Статус
ИЗ
    Документ.ЗаказКлиента КАК Заказ
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Заказано КАК ВТ_Заказано ПО Заказ.Ссылка = ВТ_Заказано.Заказ
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Остатки КАК ВТ_Остатки ПО Заказ.Ссылка = ВТ_Остатки.Заказ

Важные нюансы и рекомендации

Рассмотрим дополнительные факторы, которые могут повлиять на результат:

1. Закрытые заказы. В типовых конфигурациях (УТ 11, ERP) при установке статуса «Закрыт» остатки по регистру ЗаказыКлиентов могут обнуляться принудительно. Если вы видите, что статус отгрузки «Полностью отгружен», но реализации не было — проверьте, не закрыт ли заказ менеджером вручную.

2. Проблема точности. Тип данных Число(15, 3) может преподносить сюрпризы при сравнении. Если вы сталкиваетесь с тем, что визуально числа равны, но условие = не срабатывает, попробуйте использовать округление: ОКРУГЛИТЬ(Остаток, 3) = ОКРУГЛИТЬ(Количество, 3).

3. Склады и характеристики. Если ваш отчет строится в разрезе складов или характеристик, убедитесь, что группировка в обеих временных таблицах совпадает. Если в документе один склад, а отгрузка произошла с другого (при включенном ордерном складе или перемещениях), простым сравнением остатков по заказу без учета аналитики можно получить некорректные данные.

Используя приведенную выше логику и структуру с временными таблицами, вы сможете создавать производительные и точные отчеты, которые всегда будут показывать актуальное состояние заказов ваших клиентов.

← На главную