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