Public release from ruodoo-project: 19.0 - 2026-07-26 21:17:35 UTC
This commit is contained in:
70
directive_test/README.md
Normal file
70
directive_test/README.md
Normal file
@ -0,0 +1,70 @@
|
||||
# Слой директив — Демонстрационная интеграция
|
||||
**name:** directive_test
|
||||
**version:** 19.0.1.0.0
|
||||
**author:** RuOdoo
|
||||
|
||||
|
||||
### 1. Общее описание
|
||||
|
||||
Модуль демонстрирует работу директив в реальных бизнес-объектах Odoo: задачах, заказах, счетах, складе и производстве. Служит рабочим примером для разработчиков, которые хотят подключить директивы к своим объектам, и позволяет оценить возможности базового модуля `directive_layer` на практике.
|
||||
|
||||
|
||||
### 2. Установка
|
||||
|
||||
1. Убедитесь, что установлен модуль `directive_layer`
|
||||
|
||||
2. Скопируйте папку `directive_test` в директорию `addons`
|
||||
|
||||
3. Перезапустите сервер Odoo
|
||||
|
||||
4. Обновите список приложений: **Настройки → Приложения → Обновить список**
|
||||
|
||||
5. Найдите **«Directive Test»** и установите
|
||||
|
||||
### 3. Функциональность
|
||||
|
||||
3.1 К каким объектам подключены директивы:
|
||||
|
||||
| Объект | Когда создаётся задание | Кто исполняет |
|
||||
|---|---|---|
|
||||
| Задача проекта | При переходе задачи в определённую стадию | Человек |
|
||||
| Заказ на продажу | При подтверждении заказа | WMS-агент (автоматически) |
|
||||
| Входящий счёт | При подтверждении счёта от поставщика | Аудит-бот (автоматически) |
|
||||
| Исходящий платёж | При переходе платежа в обработку | Банковский шлюз (автоматически) |
|
||||
| Перемещение склада | После подтверждения перемещения | AGV-робот (автоматически) |
|
||||
| Рабочий центр | Когда операция резки готова к запуску | IoT-оборудование (автоматически) |
|
||||
|
||||
3.2 Элементы на форме объекта:
|
||||
|
||||
На форме каждого из перечисленных объектов появляются три элемента:
|
||||
|
||||
- **Кнопка «Выбрать тип»** в шапке — назначает группу заданий для записи
|
||||
- **Кнопка «Директивы»** — показывает количество заданий, открывает список
|
||||
- **Поле «Исполнение»** — текущий сводный статус всех заданий по записи
|
||||
|
||||

|
||||
|
||||
После выполнения задания в чат записи автоматически поступает сообщение от исполнителя.
|
||||
|
||||
### Пример использования
|
||||
|
||||
### Открыть объект и назначить группу заданий
|
||||
|
||||
Перейдите в любой поддерживаемый объект, например **Продажи → Заказы**. Нажмите кнопку **«Выбрать тип»** в шапке формы и выберите группу шаблонов заданий.
|
||||
|
||||

|
||||
|
||||
### Выполнить бизнес-действие
|
||||
|
||||
Подтвердите заказ, переведите задачу в нужную стадию, проведите платёж и т.д. Задание создастся автоматически и появится в кнопке **«Директивы»**.
|
||||
|
||||
### Посмотреть список заданий
|
||||
|
||||
Нажмите кнопку **«Директивы»** на форме объекта — откроется список всех заданий с текущими стадиями, дедлайнами и исполнителями.
|
||||
|
||||

|
||||
|
||||
### Проверить результат в чате
|
||||
|
||||
После выполнения задания перейдите в чат записи — там появится сообщение от исполнителя с результатом работы.
|
||||
|
||||
194
directive_test/TECHNICAL.md
Normal file
194
directive_test/TECHNICAL.md
Normal file
@ -0,0 +1,194 @@
|
||||
# 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`.
|
||||
1
directive_test/__init__.py
Normal file
1
directive_test/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from . import models
|
||||
13
directive_test/__manifest__.py
Normal file
13
directive_test/__manifest__.py
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "Directive Test",
|
||||
"version": "19.0.1.0.0",
|
||||
"summary": "Тестовая интеграция слоя директив с project.task",
|
||||
"license": "LGPL-3",
|
||||
"depends": ["sale", "mail", "account", "account_payment", "mrp", "project", "directive_layer", "base_user_role", "stock"],
|
||||
"data": [
|
||||
"data/users.xml",
|
||||
"views/project_task_views.xml",
|
||||
],
|
||||
"installable": True,
|
||||
"application": False,
|
||||
}
|
||||
22
directive_test/data/users.xml
Normal file
22
directive_test/data/users.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<odoo>
|
||||
<record id="user_directive_executor" model="res.users">
|
||||
<field name="name">Directive Executor</field>
|
||||
<field name="login">directive_executor</field>
|
||||
<field name="email">directive_executor@example.com</field>
|
||||
<field name="group_ids" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="user_directive_requester" model="res.users">
|
||||
<field name="name">Directive Requester</field>
|
||||
<field name="login">directive_requester</field>
|
||||
<field name="email">directive_requester@example.com</field>
|
||||
<field name="group_ids" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="user_directive_dispatcher" model="res.users">
|
||||
<field name="name">Directive Dispatcher</field>
|
||||
<field name="login">directive_dispatcher</field>
|
||||
<field name="email">directive_dispatcher@example.com</field>
|
||||
<field name="group_ids" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
</odoo>
|
||||
BIN
directive_test/img_1.png
Normal file
BIN
directive_test/img_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
BIN
directive_test/img_2.png
Normal file
BIN
directive_test/img_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
BIN
directive_test/img_3.png
Normal file
BIN
directive_test/img_3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
7
directive_test/models/__init__.py
Normal file
7
directive_test/models/__init__.py
Normal file
@ -0,0 +1,7 @@
|
||||
from . import project_task
|
||||
from . import sale_order
|
||||
from . import directive_directive
|
||||
from . import account_move
|
||||
from . import account_payment
|
||||
from . import mrp_workorder
|
||||
from . import stock_picking
|
||||
32
directive_test/models/account_move.py
Normal file
32
directive_test/models/account_move.py
Normal file
@ -0,0 +1,32 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_name = "account.move"
|
||||
_inherit = ["account.move", "directive.mixin"]
|
||||
|
||||
|
||||
def _directive_generation_spec(self):
|
||||
return [
|
||||
{
|
||||
"event": "on_write",
|
||||
"key": "am_audit_trigger",
|
||||
"field": "state",
|
||||
"from": "draft",
|
||||
"to": "posted",
|
||||
"use_record_template_group": True,
|
||||
"mode": "create_once",
|
||||
# Генерируем только для входящих инвойсов от поставщиков
|
||||
"domain": [("move_type", "=", "in_invoice")],
|
||||
}
|
||||
]
|
||||
|
||||
def action_audit_response(self, payload: dict):
|
||||
"""
|
||||
Вызывается агентом-аудитором.
|
||||
"""
|
||||
for move in self:
|
||||
move.message_post(
|
||||
body=f"Audit Bot: Обнаружен риск, 30/100."
|
||||
f"Директива #{payload.get('directive_id')} завершена с предупреждением."
|
||||
)
|
||||
32
directive_test/models/account_payment.py
Normal file
32
directive_test/models/account_payment.py
Normal file
@ -0,0 +1,32 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class AccountPayment(models.Model):
|
||||
_name = 'account.payment'
|
||||
_inherit = ["account.payment", "directive.mixin"]
|
||||
|
||||
def _directive_generation_spec(self):
|
||||
return [
|
||||
{
|
||||
"event": "on_write",
|
||||
"key": "pay_bank_trigger",
|
||||
"field": "state",
|
||||
"from": "draft",
|
||||
"to": "in_process",
|
||||
"use_record_template_group": True,
|
||||
"mode": "create_once",
|
||||
# Только для исходящих платежей
|
||||
"domain": [("payment_type", "=", "outbound")],
|
||||
}
|
||||
]
|
||||
|
||||
def action_bank_gateway_response(self, payload: dict):
|
||||
for pay in self:
|
||||
bank_ref = f"REF-{pay.id}-X99"
|
||||
|
||||
pay.message_post(
|
||||
body=f"Bank Gateway: Платеж отправлен в банк."
|
||||
f"Bank Reference: {bank_ref}"
|
||||
f"Комиссия агента: 0.00 у.е."
|
||||
)
|
||||
return True
|
||||
27
directive_test/models/directive_directive.py
Normal file
27
directive_test/models/directive_directive.py
Normal file
@ -0,0 +1,27 @@
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class Directive(models.Model):
|
||||
_inherit = "directive.directive"
|
||||
|
||||
@api.model
|
||||
def _cron_simulate_system_agents(self):
|
||||
"""
|
||||
Этот метод имитирует работу внешних систем (WMS, Банк, AI).
|
||||
Запускается раз в минуту.
|
||||
"""
|
||||
system_directives = self.search([
|
||||
('executor_type', 'in', ['software', 'machine']),
|
||||
('stage_code', 'in', ['draft', 'planned', 'in_progress']),
|
||||
('stage_code', '!=', 'done')
|
||||
], limit=50)
|
||||
|
||||
for d in system_directives:
|
||||
|
||||
if d.stage_code == 'planned':
|
||||
d._set_stage('in_progress')
|
||||
print(f"Agent started directive {d.id}")
|
||||
|
||||
elif d.stage_code == 'in_progress':
|
||||
d.action_done()
|
||||
print(f"Agent finished directive {d.id}")
|
||||
77
directive_test/models/mrp_workorder.py
Normal file
77
directive_test/models/mrp_workorder.py
Normal file
@ -0,0 +1,77 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class MrpWorkorder(models.Model):
|
||||
_name = "mrp.workorder"
|
||||
_inherit = ["mrp.workorder", "directive.mixin"]
|
||||
|
||||
def _directive_generation_spec(self):
|
||||
return [
|
||||
{
|
||||
"event": "on_write",
|
||||
"key": "mrp_iot_trigger",
|
||||
"field": "state",
|
||||
"from": "pending",
|
||||
"to": "ready",
|
||||
"use_record_template_group": True,
|
||||
"mode": "create_once",
|
||||
"domain": [("name", "ilike", "резка")],
|
||||
}
|
||||
]
|
||||
|
||||
def action_iot_signal(self, payload: dict):
|
||||
"""
|
||||
Метод-обработчик завершения директивы оборудованием.
|
||||
Записывает телеметрию в саму операцию и в головной заказ (MO).
|
||||
"""
|
||||
for wo in self:
|
||||
telemetry = payload.get('telemetry', {})
|
||||
temp = telemetry.get('temperature', 59)
|
||||
vibro = telemetry.get('vibration', 'Норма')
|
||||
|
||||
message = (
|
||||
f"IoT CNC [{wo.name}]: Операция завершена.<br/>"
|
||||
f"Температура шпинделя: {temp}°C<br/>"
|
||||
f"Вибрация: {vibro}."
|
||||
)
|
||||
|
||||
if wo.production_id:
|
||||
wo.production_id.message_post(
|
||||
body=f"Отчет по операции {wo.name}: {message}"
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class MrpProduction(models.Model):
|
||||
_inherit = 'mrp.production'
|
||||
|
||||
def action_choose_directive_group(self):
|
||||
|
||||
self.ensure_one()
|
||||
|
||||
workorder = self.workorder_ids[:1]
|
||||
|
||||
if not workorder:
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': 'Внимание',
|
||||
'message': 'Сначала подтвердите заказ, чтобы появились операции (Work Orders)',
|
||||
'type': 'warning',
|
||||
'sticky': False,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"name": f"Назначить директивы для: {workorder.name}",
|
||||
"res_model": "directive.choose.group.wizard",
|
||||
"view_mode": "form",
|
||||
"target": "new",
|
||||
"context": {
|
||||
# КОСТЫЛЬ
|
||||
"active_model": "mrp.workorder",
|
||||
"active_id": workorder.id,
|
||||
},
|
||||
}
|
||||
44
directive_test/models/project_task.py
Normal file
44
directive_test/models/project_task.py
Normal file
@ -0,0 +1,44 @@
|
||||
from odoo import models
|
||||
|
||||
|
||||
class ProjectTask(models.Model):
|
||||
_name = 'project.task'
|
||||
_inherit = ["project.task", "directive.mixin"]
|
||||
|
||||
def directive_on_done_post_message(self, payload: dict):
|
||||
for task in self:
|
||||
task.message_post(
|
||||
body=f"Директива выполнена: {payload.get('directive_name')})"
|
||||
)
|
||||
return True
|
||||
|
||||
# def _directive_generation_spec(self):
|
||||
# return [
|
||||
# {
|
||||
# "event": "on_callback",
|
||||
# "callback": "action_demo_directive_callback",
|
||||
# "mode": "create_once",
|
||||
# "when": "after",
|
||||
# "if_result": True,
|
||||
# "use_record_template_group": True,
|
||||
# "key": "demo_callback_v1",
|
||||
# }
|
||||
# ]
|
||||
|
||||
def _directive_generation_spec(self):
|
||||
return [
|
||||
{
|
||||
"event": "on_write",
|
||||
"key": "stage_draft_to_progress",
|
||||
"field": "stage_id",
|
||||
"from": 9,
|
||||
"to": 10,
|
||||
"use_record_template_group": True,
|
||||
"mode": "create_once",
|
||||
}
|
||||
]
|
||||
|
||||
def action_demo_directive_callback(self):
|
||||
for task in self:
|
||||
task.message_post(body="Demo callback executed")
|
||||
return True
|
||||
31
directive_test/models/sale_order.py
Normal file
31
directive_test/models/sale_order.py
Normal file
@ -0,0 +1,31 @@
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_name = 'sale.order'
|
||||
_inherit = ["sale.order", "directive.mixin"]
|
||||
|
||||
def _directive_generation_spec(self):
|
||||
return [
|
||||
{
|
||||
"event": "on_write",
|
||||
"key": "so_trigger_wms",
|
||||
"field": "state",
|
||||
"from": "draft",
|
||||
"to": "sale",
|
||||
"use_record_template_group": True,
|
||||
"mode": "create_once",
|
||||
}
|
||||
]
|
||||
|
||||
def action_wms_response(self, payload: dict):
|
||||
for order in self:
|
||||
bin_location = "ZONE-A-ROW-5"
|
||||
|
||||
order.message_post(
|
||||
body=f"WMS Агент: Товар зарезервирован."
|
||||
f"Ячейка: {bin_location}<br/>"
|
||||
f"Директива #{payload.get('directive_id')} закрыта успешно."
|
||||
)
|
||||
|
||||
return True
|
||||
26
directive_test/models/stock_picking.py
Normal file
26
directive_test/models/stock_picking.py
Normal file
@ -0,0 +1,26 @@
|
||||
from odoo import models, fields
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_name = 'stock.picking'
|
||||
_inherit = ["stock.picking", "directive.mixin"]
|
||||
|
||||
def _directive_generation_spec(self):
|
||||
return [
|
||||
{
|
||||
"event": "on_callback",
|
||||
"callback": "button_validate",
|
||||
"mode": "create_once",
|
||||
"when": "after",
|
||||
"if_result": True,
|
||||
"use_record_template_group": True,
|
||||
"key": "picking_done_check_finance",
|
||||
}
|
||||
]
|
||||
|
||||
def action_agv_callback(self, payload: dict):
|
||||
for picking in self:
|
||||
picking.message_post(
|
||||
body=f"AGV Unit 01: Доставка в зону производства выполнена."
|
||||
f"Батарея: 84%."
|
||||
)
|
||||
return True
|
||||
198
directive_test/views/project_task_views.xml
Normal file
198
directive_test/views/project_task_views.xml
Normal file
@ -0,0 +1,198 @@
|
||||
<odoo>
|
||||
<record id="project_task_form_directives_inherit" model="ir.ui.view">
|
||||
<field name="name">project.task.form.directives.inherit</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="inherit_id" ref="project.view_task_form2"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<xpath expr="//form/header" position="inside">
|
||||
<button
|
||||
string="Выбрать тип"
|
||||
type="object"
|
||||
name="action_choose_directive_group"
|
||||
class="btn-primary"
|
||||
/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//form/sheet/div[@class='oe_button_box']" position="inside">
|
||||
<button
|
||||
type="object"
|
||||
name="action_open_directives"
|
||||
class="oe_stat_button"
|
||||
icon="fa-tasks"
|
||||
string="Директивы"
|
||||
/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet" position="inside">
|
||||
<group string="Исполнение">
|
||||
<field name="directive_execution_status" readonly="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sale_order_form_directives_inherit" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.directives.inherit</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<xpath expr="//form/header" position="inside">
|
||||
<button
|
||||
string="Выбрать тип"
|
||||
type="object"
|
||||
name="action_choose_directive_group"
|
||||
class="btn-primary"
|
||||
/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//form/sheet/div[@class='oe_button_box']" position="inside">
|
||||
<button
|
||||
type="object"
|
||||
name="action_open_directives"
|
||||
class="oe_stat_button"
|
||||
icon="fa-tasks"
|
||||
string="Директивы"
|
||||
/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet" position="inside">
|
||||
<group string="Исполнение">
|
||||
<field name="directive_execution_status" readonly="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_move_form_directives_inherit" model="ir.ui.view">
|
||||
<field name="name">account.move.form.directives.inherit</field>
|
||||
<field name="model">account.move</field>
|
||||
<field name="inherit_id" ref="account.view_move_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<xpath expr="//form/header" position="inside">
|
||||
<button
|
||||
string="Выбрать тип"
|
||||
type="object"
|
||||
name="action_choose_directive_group"
|
||||
class="btn-primary"
|
||||
/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//form/sheet/div[@class='oe_button_box']" position="inside">
|
||||
<button
|
||||
type="object"
|
||||
name="action_open_directives"
|
||||
class="oe_stat_button"
|
||||
icon="fa-tasks"
|
||||
string="Директивы"
|
||||
/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet" position="inside">
|
||||
<group string="Исполнение">
|
||||
<field name="directive_execution_status" readonly="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_payment_form_directives_inherit" model="ir.ui.view">
|
||||
<field name="name">account.payment.form.directives.inherit</field>
|
||||
<field name="model">account.payment</field>
|
||||
<field name="inherit_id" ref="account.view_account_payment_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<xpath expr="//form/header" position="inside">
|
||||
<button
|
||||
string="Выбрать тип"
|
||||
type="object"
|
||||
name="action_choose_directive_group"
|
||||
class="btn-primary"
|
||||
/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//form/sheet/div[@class='oe_button_box']" position="inside">
|
||||
<button
|
||||
type="object"
|
||||
name="action_open_directives"
|
||||
class="oe_stat_button"
|
||||
icon="fa-tasks"
|
||||
string="Директивы"
|
||||
/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet" position="inside">
|
||||
<group string="Исполнение">
|
||||
<field name="directive_execution_status" readonly="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="stock_picking_form_directives_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.picking.form.directives.inherit</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<xpath expr="//form/header" position="inside">
|
||||
<button
|
||||
string="Выбрать тип"
|
||||
type="object"
|
||||
name="action_choose_directive_group"
|
||||
class="btn-primary"
|
||||
/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//form/sheet/div[@class='oe_button_box']" position="inside">
|
||||
<button
|
||||
type="object"
|
||||
name="action_open_directives"
|
||||
class="oe_stat_button"
|
||||
icon="fa-tasks"
|
||||
string="Директивы"
|
||||
/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet" position="inside">
|
||||
<group string="Исполнение">
|
||||
<field name="directive_execution_status" readonly="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="mrp_production_form_directives_inherit" model="ir.ui.view">
|
||||
<field name="name">mrp.production.form.directives.inherit</field>
|
||||
<field name="model">mrp.production</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_production_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<button
|
||||
string="Выбрать тип"
|
||||
type="object"
|
||||
name="action_choose_directive_group"
|
||||
class="btn-primary"
|
||||
/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="project_task_form_directive_demo" model="ir.ui.view">
|
||||
<field name="name">project.task.form.directive.demo</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="inherit_id" ref="project.view_task_form2"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<button
|
||||
name="action_demo_directive_callback"
|
||||
type="object"
|
||||
string="Demo: Callback"
|
||||
class="btn-primary"
|
||||
/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user