Corp/PROCUREMENT_APPROVERS.md
Игорь Надеин 46cb319903 fix: исправить ошибки в админке Budget
- Убрать remaining_amount и utilization_percentage из list_display (это @property)
- Добавить методы get_remaining_amount и get_utilization_percentage
- Защитить от None в allocated_amount
- Исправить prefetch_related в views_frontend
2025-12-10 07:16:00 +03:00

7.0 KiB
Raw Blame History

Механизм назначения согласующих в заявках на закупку

Как это работает

1. Определение требуемых ролей (модель ProcurementRequest)

Когда пользователь отправляет заявку на согласование (submit action), система определяет какие роли нужны:

# в procurement/models.py - метод get_required_approvals()

cost = estimated_cost  # Сумма заявки

if cost < 10,000₽:                    # НИЗКАЯ
    → [DEPARTMENT_HEAD]               # Только руководитель отдела

elif cost < 100,000₽:                 # СРЕДНЯЯ  
    → [DEPARTMENT_HEAD,               # Руководитель отдела +
       FINANCE_MANAGER]               # Финансовый менеджер

else:                                 # ВЫСОКАЯ (> 100K)
    → [DEPARTMENT_HEAD,               # Руководитель отдела +
       FINANCE_MANAGER,               # Финансовый менеджер +
       DIRECTOR]                      # Генеральный директор

2. Поиск конкретных людей (вьюсет ProcurementRequestViewSet.submit())

После определения ролей система ищет людей, занимающих эти должности:

for role in required_approvals:
    approver = None
    
    if role == DEPARTMENT_HEAD:
        # ✅ Берёт руководителя из department.head
        approver = procurement_request.department.head
    
    elif role == FINANCE_MANAGER:
        # ✅ Ищет пользователя с правом change_budget
        approver = Employee.objects.filter(
            is_active=True,
            groups__permissions__codename='change_budget'
        ).first()
    
    elif role == DIRECTOR:
        # ✅ Берёт первого суперпользователя
        approver = Employee.objects.filter(
            is_superuser=True
        ).first()
    
    # Создаём запись согласования
    Approval.objects.create(
        request=procurement_request,
        approver=approver,
        role=role,
        status=ApprovalStatus.PENDING
    )

Пример

Заявка на 50,000₽ от отдела IT

Сумма: 50,000₽
Отдел: IT (руководитель = Петр Петров)

┌─────────────────────────────────────────┐
│ Определение ролей (get_required_approvals)
│ 10,000 < 50,000 < 100,000  
│ → [DEPARTMENT_HEAD, FINANCE_MANAGER]
└─────────────────────────────────────────┘
          ↓
┌─────────────────────────────────────────┐
│ Поиск согласующих (submit action)       │
├─────────────────────────────────────────┤
│ DEPARTMENT_HEAD                         │
│ → IT.head = Петр Петров ✓              │
│                                         │
│ FINANCE_MANAGER                         │
│ → Permission(change_budget)             │
│ → Мария Сидорова ✓                      │
└─────────────────────────────────────────┘
          ↓
┌─────────────────────────────────────────┐
│ Создание записей согласования           │
├─────────────────────────────────────────┤
│ Approval #1: Петр Петров (PENDING)     │
│ Approval #2: Мария Сидорова (PENDING)  │
└─────────────────────────────────────────┘
          ↓
       Уведомления
       ↙         ↖
   Петр         Мария

Где это конфигурируется?

Компонент Где конфигурируется Как
Пороги сумм procurement/constants.py APPROVAL_THRESHOLD_LOW, APPROVAL_THRESHOLD_HIGH
Руководитель отдела Django Admin → Departments Выбрать head в модели Department
Финансовый менеджер Django Admin → Permissions Дать permission change_budget пользователю или группе
Директор Django Admin → Users Сделать пользователя суперпользователем (is_superuser=True)

Потенциальные проблемы и решения

1. "Финансовый менеджер не найдена"

# Причина: нет пользователя с правом change_budget
# Решение: 
Django Admin → Users → выбрать пользователя → добавить permission change_budget

2. "Директор не найден"

# Причина: нет суперпользователей в системе
# Решение:
Django Admin → Users → выбрать пользователя → поставить галочку is_superuser

3. Разные согласующие для разных отделов

# Текущая реализация: один финменеджер и один директор на всю компанию
# Чтобы сделать разных:
# 1. Создать модель ApprovalChain или DepartmentApprovalPolicy
# 2. Связать со своими финменеджерами и директорами
# 3. Изменить логику поиска в submit action

API для отладки

Проверить какие роли требуются для заявки

GET /api/procurement/requests/{id}/
# Ответ содержит поле "required_approvals" если его добавить в сериализатор

Узнать кто назначен согласующим

GET /api/procurement/requests/{id}/
# approvals: [
#   { id, approver, role, status, comment }
# ]

Параметры для настройки

# backend/procurement/constants.py

APPROVAL_THRESHOLD_LOW = 10_000    # ← Можно менять
APPROVAL_THRESHOLD_HIGH = 50_000   # ← Можно менять

# Порог         | Рол требующиеся
# < 10K         | Руководитель отдела
# 10K - 50K     | Руководитель + Финансы
# > 50K         | Руководитель + Финансы + Директор