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