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