Skip to content

40. Manufacture KPI: Веса метрик и тип оплаты «Оклад + KPI»

Date: 2026-03-17

Status

Proposed

Context

Требуется:

  1. Веса KPI — в adjust_to_desired_salary уже используется getattr(m, 'weight', 1), но поле weight в модели KPIMetric отсутствует. Веса задают доли при распределении KPI-суммы по метрикам.

  2. Тип оплаты «Оклад + KPI» — новый тип Salary (type=5): фиксированный оклад (80 000 ₽) + переменная KPI-часть (20 000 ₽), распределяемая по сменам по весам метрик (например, 40% план, 40% брак, 20% отчёт). Итоговая ЗП формируется из начислений по каждой смене.

Decision

Часть 1: Веса в KPIMetric

  • Добавить в KPIMetric поле weight (DecimalField, default=1).
  • При расчёте KPI: kpi_payment = base_amount * weight.
  • В apply_kpi_corrections — обратная формула с учётом weight.
  • Хранение веса в KPIMetric (разный вес у разных сотрудников для одного типа KPI).

Часть 2: Тип «Оклад + KPI» (type=5)

  • Добавить Salary.type = 5 «Оклад + KPI».
  • Добавить поле Salary.kpi_monthly_amount (месячный KPI-пул в рублях).
  • Оклад — monthly_salary.
  • Расчёт на смену:
    • base_per_shift = monthly_salary / work_days
    • kpi_pool_per_shift = kpi_monthly_amount / shifts_count (смены берутся из фактического графика сотрудника — ActualWorkSchedule со статусами work, in_plan; при отсутствии смен — fallback на производственный календарь РФ).
    • По каждой выполненной метрике: kpi_payment_i = weight_i * kpi_pool_per_shift
  • Ограничение: сумма KPI за месяц не превышает kpi_monthly_amount (при превышении — пропорциональное уменьшение KPIRecord).
  • Итоговая ЗП за месяц = сумма mast_pay_plus_over_time_pay_flat по сменам (агрегация в отчётах уже есть).

Consequences

  • Требуется миграция для KPIMetric.weight и Salary (type, kpi_monthly_amount).
  • Расширение salary_calendar_service и actual_work_shedule.calculate_kpi().
  • Совместимость: старые KPIMetric получают weight=1, поведение не меняется.

Сценарии использования

Веса KPI (типы 1, 3, 4)

СценарийОжидаемый результат
1.1Назначение метрик с разным весомПри расчёте смены каждая метрика умножается на свой вес
1.2Массовое назначение с весамиPOST /kpi-metric/bulk_create с weight
1.3Корректировка суммы бригадиромОбратная формула пересчитывает KPIMetric.value с учётом weight
1.4adjust_to_desired_salaryЦелевая KPI-сумма распределяется по весам
1.5Существующие сотрудникиweight=1 (default) — поведение без изменений

Тип «Оклад + KPI» (type=5)

СценарийОжидаемый результат
2.1Перевод на Оклад+KPItype=5, monthly_salary=80000, kpi_monthly_amount=20000
2.2Все KPI выполненыbase≈3809₽, kpi_pool≈952₽, KPI=952₽, итого≈4761₽/смена
2.3Частичное выполнениеKPI = sum(weight_i) * pool только по достигнутым метрикам
2.4Формирование ЗП за месяцСумма смен = итоговая ЗП (при 21 смене и полном KPI ≈ 100 000₽)
2.5Ручные метрикиБригадир выставляет сумму вручную, вес учитывается при отображении

Кросс-сценарии

СценарийОжидаемый результат
3.1Смешанный состав (type=4 и type=5)Каждый считается по своему типу
3.2Deferred-метрики у type=5Начисление через bulk_accrue

Revision (2026-03-17)

Переход KPI type=5 на почасовую модель: kpi_pool_shift = kpi_rate_per_hour × kpi_hours, где kpi_rate_per_hour = kpi_monthly_amount / monthly_norm_hours, kpi_hours = min(actual_hours, shift_duration). При shift=Nonekpi_hours = actual_hours. Лимит за месяц — apply_kpi_monthly_cap.

См. также