Как связать подразделение из регистров «Заказы поставщикам» и «Закупки» в УПП 1.3

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

При разработке отчетов в конфигурации «Управление производственным предприятием» (УПП) 1.3 часто возникает задача сопоставить данные о заказанных товарах и их фактическом поступлении. Одной из основных сложностей здесь является связывание данных по аналитическому разрезу «Подразделение», так как структура регистров накопления для этих операций существенно различается. В этой статье мы подробно разберем, как правильно построить запрос для связи этих регистров и на что обратить внимание при использовании Системы компоновки данных (СКД).

Анализ структуры метаданных

Прежде чем приступать к написанию кода, проанализируем, где хранится информация о подразделениях в типовой конфигурации:

  1. Регистр накопления «Закупки»: Это оборотный регистр. В нем измерение Подразделение присутствует в явном виде. Это позволяет нам напрямую получать данные о том, какое подразделение оформило поступление товаров.
  2. Регистр накопления «Заказы поставщикам»: Это регистр остатков. В его измерениях Подразделение отсутствует. Однако информация о подразделении содержится в самом документе-заказе, который является измерением этого регистра (поле ЗаказПоставщику).

Таким образом, наша задача сводится к тому, чтобы в запросе «достать» подразделение из реквизитов документа заказа и сопоставить его с измерением регистра закупок.

Проблема составного типа данных и функция ВЫРАЗИТЬ

Одной из критических ошибок при написании таких запросов является прямое обращение через точку к реквизитам заказа, например: ЗаказыПоставщикамОбороты.ЗаказПоставщику.Подразделение. В УПП поле ЗаказПоставщику имеет составной тип данных (оно может содержать ссылки на документы «Заказ поставщику», «Внутренний заказ» и другие).

Если мы не укажем платформе конкретный тип, SQL-запрос будет выполнять левое соединение со всеми возможными таблицами документов, входящими в этот тип. Это приводит к резкому падению производительности. Чтобы этого избежать, мы обязательно должны использовать конструкцию ВЫРАЗИТЬ.

Рассмотрим, как это выглядит в коде:


ВЫБРАТЬ
    ВЫРАЗИТЬ(ЗаказыПоставщикамОбороты.ЗаказПоставщику КАК Документ.ЗаказПоставщику).Подразделение КАК ПодразделениеЗаказа
...

Построение запроса для объединения регистров

Разберем структуру запроса, который позволит связать заказы и закупки по номенклатуре и подразделению. Мы будем использовать ЛЕВОЕ СОЕДИНЕНИЕ, чтобы видеть все заказы, даже те, по которым еще не было поступлений.


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    ЗаказыПоставщикамОбороты.Период КАК ДатаЗаказа,
    ЗаказыПоставщикамОбороты.Регистратор,
    ЗаказыПоставщикамОбороты.ЗаказПоставщику КАК Заказ,
    ЗаказыПоставщикамОбороты.Номенклатура КАК Номенклатура,
    СУММА(ЗаказыПоставщикамОбороты.СуммаУпрПриход) КАК СтоимостьЗаказа,
    ЗакупкиОбороты.ДокументЗакупки КАК Поступление,
    СУММА(ЗакупкиОбороты.КоличествоОборот) КАК КоличествоПоступление,
    СУММА(ЗакупкиОбороты.СтоимостьОборот) КАК СтоимостьПоступление,
    ВЫРАЗИТЬ(ЗаказыПоставщикамОбороты.ЗаказПоставщику КАК Документ.ЗаказПоставщику).Подразделение КАК Подразделение
ИЗ
    РегистрНакопления.ЗаказыПоставщикам.Обороты(&НачалоПериода, &КонецПериода, Запись, ) КАК ЗаказыПоставщикамОбороты
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Закупки.Обороты(&НачалоПериода, &КонецПериодаЗакупок, Запись, ) КАК ЗакупкиОбороты
        ПО ЗаказыПоставщикамОбороты.ЗаказПоставщику = ЗакупкиОбороты.ЗаказПоставщику
            И ЗаказыПоставщикамОбороты.Номенклатура = ЗакупкиОбороты.Номенклатура
            И ВЫРАЗИТЬ(ЗаказыПоставщикамОбороты.ЗаказПоставщику КАК Документ.ЗаказПоставщику).Подразделение = ЗакупкиОбороты.Подразделение

СГРУППИРОВАТЬ ПО
    ЗаказыПоставщикамОбороты.Период,
    ЗаказыПоставщикамОбороты.Регистратор,
    ЗаказыПоставщикамОбороты.ЗаказПоставщику,
    ЗаказыПоставщикамОбороты.Номенклатура,
    ЗакупкиОбороты.ДокументЗакупки,
    ВЫРАЗИТЬ(ЗаказыПоставщикамОбороты.ЗаказПоставщику КАК Документ.ЗаказПоставщику).Подразделение

Особенности бизнес-логики и возможные расхождения

Важно понимать, что жесткая связь по подразделению в условии ПО (как в примере выше) может скрыть часть данных. Выясним причину: в УПП возможна ситуация централизованных закупок. Например, подразделение «Отдел снабжения» делает заказ, а товар приходуется на «Склад основного производства» или другое подразделение-затратчик.

Если в вашем учете подразделения в заказе и поступлении могут различаться, рекомендуем следующий подход:

  1. Связывайте регистры только по Заказу и НоменклатуреХарактеристике, если она используется).
  2. Выводите оба подразделения в отчет: «Подразделение-заказчик» (из заказа) и «Подразделение-получатель» (из регистра закупок).
  3. Используйте подразделение из заказа как основную группировку.

Проанализируем пример изменения условия связи:


// Вместо жесткой связи в ПО, просто выбираем два поля
ВЫБРАТЬ
    ...
    ВЫРАЗИТЬ(ЗаказыПоставщикамОбороты.ЗаказПоставщику КАК Документ.ЗаказПоставщику).Подразделение КАК ПодразделениеЗаказа,
    ЗакупкиОбороты.Подразделение КАК ПодразделениеЗакупки
...
ПО ЗаказыПоставщикамОбороты.ЗаказПоставщику = ЗакупкиОбороты.ЗаказПоставщику
    И ЗаказыПоставщикамОбороты.Номенклатура = ЗакупкиОбороты.Номенклатура

Работа с СКД через внешний набор данных

Если вы используете программное формирование отчета (через ПриКомпоновкеРезультата в модуле объекта), как предлагал автор вопроса, помните о правильной передаче таблицы значений в СКД. Рассмотрим по шагам этот процесс:

1. Сначала сформируем таблицу значений в коде модуля, выполнив наш запрос.

2. Создадим структуру для внешних наборов данных.

3. Вызовем процессор компоновки.


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // ... Выполнение запроса и выгрузка в ТЗ ...
    РЗ = ЗапросЗаказов.Выполнить();
    ТаблицаДанных = РЗ.Выгрузить();
    
    ВнешниеНаборыДанных = Новый Структура;
    ВнешниеНаборыДанных.Вставить("тзЗакупкиПоЗаказам", ТаблицаДанных);
    
    СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

Важный нюанс: при использовании внешнего набора данных (Набор данных - объект) в самой схеме СКД (в конструкторе) необходимо вручную добавить все поля с теми же именами и типами, которые возвращает ваш запрос. Если вы добавили поле Подразделение в запрос, оно должно быть описано и в наборе данных СКД.

Рекомендации по оптимизации

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

Таким образом, мы разобрали основные аспекты связывания подразделений. Главное — помнить об отсутствии измерения в одном из регистров и использовать ВЫРАЗИТЬ для безопасного и быстрого обращения к реквизитам документов-заказов.

← На главную