При решении тестовых заданий или реальных бизнес-задач разработчики часто сталкиваются с размытыми формулировками требований заказчика. Одной из таких классических задач является распределение премиального фонда проекта между его участниками на основе индивидуальных коэффициентов трудового участия (КТУ). В данной статье мы подробно разберем, как устроена математика этого расчета, спроектируем оптимальную архитектуру метаданных в системе «1С:Предприятие 8.3» и создадим надежный отчет на схеме компоновки данных (СКД), который не будет удваивать показатели при детализации.
Основная путаница у начинающих разработчиков возникает на стыке трех понятий: процент премии проекта, коэффициент участия сотрудника (КТУ) и итоговый процент начисления. Рассмотрим ситуацию на конкретном примере, который часто приводится в тестовых заданиях.
Допустим, у нас есть проект «Модернизация сети». За отчетный период прибыль по проекту составила 100 000 рублей. В настройках проекта указано:
Выясним по шагам, как рассчитываются показатели для итогового отчета:
100 000 * 5% = 5 000 рублей.8 + 2 = 10. Это наш общий знаменатель (база распределения).(8 / 10) * 100% = 80%.(2 / 10) * 100% = 20%.5% (премия проекта) * 80% (доля КТУ) = 4%.5% (премия проекта) * 20% (доля КТУ) = 1%.100 000 (прибыль) * 4% (эффективный процент) = 4 000 рублей.100 000 (прибыль) * 1% (эффективный процент) = 1 000 рублей.Таким образом, формула 4000 = 100000 / 100 * 4 из примера отчета становится абсолютно прозрачной. Число 4 в ней — это не базовый КТУ сотрудника, а его эффективный процент премии от общей прибыли проекта.
Для реализации этой бизнес-логики нам понадобится создать минимальный, но расширяемый набор объектов метаданных. Проанализируем структуру каждого из них.
1. Справочник «Проекты»
Этот объект служит аналитическим разрезом. В нем мы храним правила распределения прибыли.
Премия (Тип: Число, длина 5, точность 2, неотрицательное) — базовый процент премии.КТУ.
Сотрудник (Тип: СправочникСсылка.Сотрудники).Коэффициент (Тип: Число, длина 10, точность 2, неотрицательное) — индивидуальный коэффициент сотрудника.2. Регистр накопления «Прибыль»
Поскольку прибыль — это оборотный финансовый показатель за период, нам не нужно хранить остатки. Выбираем вид регистра Обороты. Это существенно повысит производительность системы.
Проект (Тип: СправочникСсылка.Проекты).Сумма (Тип: Число, длина 15, точность 2).3. Документы «Приходная накладная» и «Расходная накладная»
Добавим в шапку обоих документов реквизит Проект (Тип: СправочникСсылка.Проекты). При проведении документы должны делать записи в регистр накопления Прибыль.
Рассмотрим пример кода процедуры проведения для документа РасходнаяНакладная (формирует выручку, то есть положительное движение):
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.Прибыль.Записывать = Истина;
Движение = Движения.Прибыль.Добавить();
Движение.Период = Дата;
Движение.Проект = Проект;
Движение.Сумма = СуммаДокумента; // Записываем доход в плюс
КонецПроцедуры
Для документа ПриходнаяНакладная, который отражает затраты (себестоимость), движение записывается со знаком «минус»:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.Прибыль.Записывать = Истина;
Движение = Движения.Прибыль.Добавить();
Движение.Период = Дата;
Движение.Проект = Проект;
Движение.Сумма = -СуммаДокумента; // Расход уменьшает прибыль
КонецПроцедуры
Главная опасность при создании отчета по этой задаче — «декартово произведение» таблиц при соединении в запросе. Если мы просто свяжем обороты регистра Прибыль с табличной частью КТУ справочника Проекты по полю Проект, то при выводе детальных записей (например, по регистратору) сумма прибыли начнет дублироваться для каждого сотрудника. Из-за этого общие итоги по прибыли проекта в отчете окажутся завышенными.
Разберем правильный алгоритм построения запроса СКД с использованием временных таблиц. Нам необходимо предварительно рассчитать общий КТУ по каждому проекту, чтобы иметь базу для деления.
Шаг 1. Получаем общую сумму КТУ по каждому проекту:
ВЫБРАТЬ
ПроектыКТУ.Ссылка КАК Проект,
СУММА(ПроектыКТУ.Коэффициент) КАК ВсегоКТУ
ПОМЕСТИТЬ ВТ_ВсегоКТУ
ИЗ
Справочник.Проекты.КТУ КАК ПроектыКТУ
ГРУППИРОВАТЬ ПО
ПроектыКТУ.Ссылка
;
Шаг 2. Связываем прибыль проекта, участников и рассчитанные доли КТУ:
ВЫБРАТЬ
ПрибыльОбороты.Проект КАК Проект,
ПрибыльОбороты.Регистратор КАК Регистратор,
ПрибыльОбороты.СуммаОборот КАК СуммаПрибыли,
ПроектыКТУ.Сотрудник КАК Сотрудник,
ПроектыКТУ.Ссылка.Премия КАК ПроцентПремииПроекта,
ПроектыКТУ.Коэффициент КАК КоэффициентСотрудника,
ВТ_ВсегоКТУ.ВсегоКТУ КАК ВсегоКТУ
ИЗ
РегистрНакопления.Прибыль.Обороты КАК ПрибыльОбороты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Проекты.КТУ КАК ПроектыКТУ
ПО ПрибыльОбороты.Проект = ПроектыКТУ.Ссылка
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ВсегоКТУ КАК ВТ_ВсегоКТУ
ПО ПрибыльОбороты.Проект = ВТ_ВсегоКТУ.Проект
Шаг 3. Настройка вычисляемых полей в СКД:
Для того чтобы отчет выглядел профессионально и динамически реагировал на настройки группировок, формулы расчета долей лучше перенести в вычисляемые поля на вкладке «Вычисляемые поля» схемы компоновки данных:
ПроцентКТУ:Выбор Когда ВсегоКТУ = 0 Тогда 0 Иначе (КоэффициентСотрудника / ВсегоКТУ) * 100 КонецЭффективныйПроцент:Выбор Когда ВсегоКТУ = 0 Тогда 0 Иначе ПроцентПремииПроекта * (КоэффициентСотрудника / ВсегоКТУ) КонецНачисленнаяПремия:Выбор Когда ВсегоКТУ = 0 Тогда 0 Иначе СуммаПрибыли * (ПроцентПремииПроекта / 100) * (КоэффициентСотрудника / ВсегоКТУ) КонецШаг 4. Настройка ресурсов (Важнейший этап):
Перейдем на вкладку «Ресурсы» и укажем, как система должна агрегировать данные на уровнях группировок:
НачисленнаяПремия указываем стандартное выражение: Сумма(НачисленнаяПремия). Премии сотрудников должны суммироваться без ограничений.СуммаПрибыли нельзя писать обычную сумму, иначе при сложении строк по сотрудникам прибыль проекта увеличится в разы. Нам нужно применить агрегатную функцию среднего или максимума в контексте группировки по проекту. Напишем следующее выражение:Сумма(ВычислитьВыражениеСГруппировкойТаблицаЗначений("Максимум(СуммаПрибыли)", "Проект"))Применив данные архитектурные решения, мы получим гибкую и устойчивую к ошибкам систему распределения премий, которая корректно отображает финансовый результат компании на любых уровнях детализации отчета.