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