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

161 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Механизм назначения согласующих в заявках на закупку
## Как это работает
### 1. Определение требуемых ролей (модель `ProcurementRequest`)
Когда пользователь отправляет заявку на согласование (`submit` action), система определяет какие роли нужны:
```python
# в 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()`)
После определения ролей система ищет людей, занимающих эти должности:
```python
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. "Финансовый менеджер не найдена"
```python
# Причина: нет пользователя с правом change_budget
# Решение:
Django Admin → Users → выбрать пользователя → добавить permission change_budget
```
### 2. "Директор не найден"
```python
# Причина: нет суперпользователей в системе
# Решение:
Django Admin → Users → выбрать пользователя → поставить галочку is_superuser
```
### 3. Разные согласующие для разных отделов
```python
# Текущая реализация: один финменеджер и один директор на всю компанию
# Чтобы сделать разных:
# 1. Создать модель ApprovalChain или DepartmentApprovalPolicy
# 2. Связать со своими финменеджерами и директорами
# 3. Изменить логику поиска в submit action
```
## API для отладки
### Проверить какие роли требуются для заявки
```bash
GET /api/procurement/requests/{id}/
# Ответ содержит поле "required_approvals" если его добавить в сериализатор
```
### Узнать кто назначен согласующим
```bash
GET /api/procurement/requests/{id}/
# approvals: [
# { id, approver, role, status, comment }
# ]
```
## Параметры для настройки
```python
# backend/procurement/constants.py
APPROVAL_THRESHOLD_LOW = 10_000 # ← Можно менять
APPROVAL_THRESHOLD_HIGH = 50_000 # ← Можно менять
# Порог | Рол требующиеся
# < 10K | Руководитель отдела
# 10K - 50K | Руководитель + Финансы
# > 50K | Руководитель + Финансы + Директор
```