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