# Directive Test
**name**: directive_test
**version**: 19.0.1.0.0
**author**: Mk.Lab
**depends:** `directive_layer`, `base_user_role`, `sale`, `mail`, `account`, `account_payment`, `mrp`, `project`, `stock`

## Назначение

Демонстрационный модуль интеграции `directive_layer` с базовыми моделями Odoo. Служит референсом для разработчиков при подключении директив к новым моделям.

---

## Паттерн интеграции

Каждая интегрируемая модель подключается к `directive.mixin` через `_inherit` и реализует два элемента:

```python
class SomeModel(models.Model):
    _name = 'some.model'
    _inherit = ['some.model', 'directive.mixin']

    def _directive_generation_spec(self) -> list[dict]:
        return [{ ...spec... }]

    def action_executor_response(self, payload: dict) -> bool:
        # вызывается при завершении директивы
        return True
```

### Структура спецификации `_directive_generation_spec()`

| Ключ | Описание |
|---|---|
| `event` | Тип события: `on_write` или `on_callback` |
| `key` | Уникальный ключ директивы (для режима `create_once`) |
| `field` | Имя поля (для `on_write`) |
| `from` | Значение поля до изменения |
| `to` | Значение поля после изменения |
| `callback` | Имя метода (для `on_callback`) |
| `when` | Момент вызова: `after` |
| `if_result` | Условие на результат метода |
| `use_record_template_group` | Брать группу шаблонов из поля записи |
| `mode` | `create_once` — создать директиву только один раз |
| `domain` | Дополнительный фильтр по записям модели |

---

## Интегрированные модели

### `project.task` + `directive.mixin`

**Файл:** `models/project_task.py`

| Параметр | Значение |
|---|---|
| Событие | `on_write` |
| Поле | `stage_id` |
| Переход | от ID 9 к ID 10 |
| Тип исполнителя | `human` |

**Callback `directive_on_done_post_message(payload)`** — публикует в чат задачи сообщение: «Директива выполнена: {directive_name}».

---

### `account.move` + `directive.mixin`

**Файл:** `models/account_move.py`

| Параметр | Значение |
|---|---|
| Событие | `on_write` |
| Поле | `state` |
| Переход | `draft` → `posted` |
| Domain | `move_type = 'in_invoice'` (только входящие счета) |
| Тип исполнителя | `software` (аудит-бот) |

**Callback `action_audit_response(payload)`** — публикует в чат счёта результат проверки с оценкой риска.

---

### `sale.order` + `directive.mixin`

**Файл:** `models/sale_order.py`

| Параметр | Значение |
|---|---|
| Событие | `on_write` |
| Поле | `state` |
| Переход | `draft` → `sale` |
| Тип исполнителя | `software` (WMS-агент) |

**Callback `action_wms_response(payload)`** — публикует в чат заказа информацию о резервировании товара с указанием ячейки.

---

### `account.payment` + `directive.mixin`

**Файл:** `models/account_payment.py`

| Параметр | Значение |
|---|---|
| Событие | `on_write` |
| Поле | `state` |
| Переход | `draft` → `in_process` |
| Domain | `payment_type = 'outbound'` (только исходящие) |
| Тип исполнителя | `software` (банковский шлюз) |

**Callback `action_bank_gateway_response(payload)`** — публикует в чат платежа банковский референс в формате `REF-{id}-X99`.

---

### `stock.picking` + `directive.mixin`

**Файл:** `models/stock_picking.py`

| Параметр | Значение |
|---|---|
| Событие | `on_callback` |
| Метод | `button_validate` |
| Когда | `after` |
| Условие | `if_result: True` |
| Тип исполнителя | `software` (AGV-робот) |

**Callback `action_agv_callback(payload)`** — публикует в чат перемещения информацию о доставке в зону производства.

---

### `mrp.workorder` + `directive.mixin`

**Файл:** `models/mrp_workorder.py`

| Параметр | Значение |
|---|---|
| Событие | `on_write` |
| Поле | `state` |
| Переход | `pending` → `ready` |
| Domain | `name ilike 'резка'` |
| Тип исполнителя | `machine` (IoT/CNC) |

**Callback `action_iot_signal(payload)`** — публикует в чат рабочей операции телеметрию оборудования (температура шпинделя, вибрация) и обновляет заголовок производственного заказа.

---

### `mrp.production` (расширение без mixin)

**Файл:** `models/mrp_workorder.py`

Добавляет метод `action_choose_directive_group()` в модель производственного заказа. Метод берёт первый рабочий центр из `workorder_ids` и открывает визард `directive.choose.group.wizard` с `active_model='mrp.workorder'`. При отсутствии рабочих центров выводит предупреждение.

---

## Имитация программных агентов (cron)

**Файл:** `models/directive_directive.py`  
**Метод:** `_cron_simulate_system_agents()`

Запускается планировщиком для автоматического продвижения директив программных и машинных исполнителей по стадиям:

| Текущая стадия | Действие |
|---|---|
| `planned` | `_set_stage('in_progress')` |
| `in_progress` | `action_done()` |

Фильтр: `executor_type in ['software', 'machine']`, `stage_code in ['draft', 'planned', 'in_progress']`.

---

## Представления

**Файл:** `views/project_task_views.xml`

Добавляет единообразный набор элементов в формы шести объектов: `project.task`, `sale.order`, `account.move`, `account.payment`, `stock.picking`, `mrp.production`.

| Элемент | Расположение | Описание |
|---|---|---|
| Кнопка «Выбрать тип» | `header` | Открывает визард выбора группы шаблонов |
| Кнопка «Директивы» | `oe_button_box` | Открывает список директив объекта |
| Поле `directive_execution_status` | `sheet` | Текущий статус исполнения (readonly) |

Для задачи (`project.task`) дополнительно добавляется кнопка «Demo: Callback» для ручного тестирования механизма callback.

---

## Демо-пользователи

**Файл:** `data/users.xml`

| XML ID | Логин | Имя |
|---|---|---|
| `user_directive_executor` | `directive_executor` | Directive Executor |
| `user_directive_requester` | `directive_requester` | Directive Requester |
| `user_directive_dispatcher` | `directive_dispatcher` | Directive Dispatcher |

Все пользователи получают только `base.group_user`. Роли директив назначаются через `base_user_role`.
