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