205 lines
10 KiB
Markdown
205 lines
10 KiB
Markdown
# Слои показателей - Базовый модуль
|
||
**name**: mklab_base_indicators
|
||
**version**: 19.0.2025.11.17
|
||
**author**: MK.Lab
|
||
**depends:** `base`
|
||
|
||
## Архитектура
|
||
|
||
Модуль реализует структуру данных **направленного гиперграфа** для аналитики KPI.
|
||
|
||
```
|
||
mklab_base_indicators
|
||
├── hg.node — вершина графа (generic: res_model + res_id)
|
||
├── hg.index — показатель (метрика), привязан к вершине
|
||
├── hg.index.code — классификатор показателей
|
||
├── hg.value — значение показателя (план/факт/дата/формула)
|
||
├── hg.link — направленная связь: source_node к [target_nodes]
|
||
└── hg.hg_mixin — AbstractModel: подключает любую модель к графу
|
||
```
|
||
|
||
---
|
||
|
||
## Модели
|
||
|
||
### `hg.node` — Вершина графа
|
||
|
||
**Файл:** `models/hg_node.py`
|
||
|
||
Вершина представляет конкретный объект Odoo в структуре гиперграфа. Хранит generic-ссылку на запись через пару `(res_model, res_id)`. При подключении модели через `hg.hg_mixin` вершина создаётся автоматически при создании записи.
|
||
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| `name` | Char | Название вершины |
|
||
| `res_id` | Integer | ID записи в Odoo |
|
||
| `res_model` | Char | Техническое имя модели (`project.task`, `sale.order` и др.) |
|
||
|
||
#### Методы
|
||
|
||
**`goto_related()`** — возвращает действие `ir.actions.act_window` для открытия связанной записи в диалоге. Используется для навигации из графа к исходному объекту.
|
||
|
||
---
|
||
|
||
### `hg.index` — Показатель
|
||
|
||
**Файл:** `models/hg_index.py`
|
||
|
||
Показатель — именованная KPI-метрика, привязанная к конкретной вершине графа. Хранит историю значений через связанные записи `hg.value` и вычисляет актуальное значение на текущую дату.
|
||
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| `name` | Char | Название показателя |
|
||
| `node_id` | Many2one → `hg.node` | Вершина-владелец показателя |
|
||
| `internal_code_id` | Many2one → `hg.index.code` | Внутренний классификатор |
|
||
| `external_code` | Char | Внешний код для интеграций |
|
||
| `public` | Boolean | Признак публичного показателя |
|
||
| `value_ids` | One2many → `hg.value` | История значений показателя |
|
||
| `current_value` | Float | Текущее значение на сегодня |
|
||
|
||
#### Методы
|
||
|
||
**`_compute_current_value()`** — вычисляет `current_value` на основе `value_ids`. Из всех значений отбираются те, у которых `date_due <= сегодня`. Среди отобранных берётся запись с наибольшей датой — её `value_float_actual` становится текущим значением. Если подходящих значений нет — возвращается `0`.
|
||
|
||
**`calc()`** — метод вычисления значения показателя по формуле или связанным вершинам. Вызывается явно при необходимости пересчёта.
|
||
|
||
---
|
||
|
||
### `hg.index.code` — Классификатор показателей
|
||
|
||
**Файл:** `models/hg_index_code.py`
|
||
|
||
Справочник внутренних кодов для группировки показателей. Позволяет объединять показатели разных вершин в один срез при аналитике (например, «Выручка» по всем задачам проекта).
|
||
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| `name` | Char | Название кода |
|
||
| `index_ids` | One2many → `hg.index` | Показатели с данным кодом |
|
||
|
||
---
|
||
|
||
### `hg.value` — Значение показателя
|
||
|
||
**Файл:** `models/hg_value.py`
|
||
|
||
Хранит конкретное числовое значение (плановое и фактическое) для показателя на определённую дату. Поддерживает два режима: простое значение и вычисление по формуле.
|
||
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| `name` | Char | Название значения |
|
||
| `index_id` | Many2one → `hg.index` | Родительский показатель |
|
||
| `date_due` | Date (required) | Дата значения |
|
||
| `value_float_plan` | Float | Плановое значение |
|
||
| `value_float_actual` | Float | Фактическое значение |
|
||
| `type` | Selection | `alone` — простое значение; `formula` — вычисляется по формуле |
|
||
| `formula` | Char | Python-выражение для вычисления (используется при `type='formula'`) |
|
||
|
||
#### Методы
|
||
|
||
**`calc()`** — вычисляет `value_float_actual` для значений с `type='formula'`. Вычисление выполняется через `safe_eval` с контекстом:
|
||
|
||
| Переменная | Значение |
|
||
|---|---|
|
||
| `node_value` | текущая запись `hg.value` |
|
||
| `node_index` | родительский показатель `hg.index` |
|
||
| `datatime` | текущая дата `fields.Date.today()` |
|
||
|
||
---
|
||
|
||
### `hg.link` — Матрица связности
|
||
|
||
**Файл:** `models/hg_link.py`
|
||
|
||
Представляет направленное гиперребро графа: один источник и множество вершин-приёмников. Используется для построения отчётов по связанным объектам и визуализации зависимостей.
|
||
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| `name` | Char | Название строки связи |
|
||
| `source_id` | Many2one → `hg.node` | Вершина-источник |
|
||
| `target_ids` | Many2many → `hg.node` | Множество вершин-приёмников |
|
||
|
||
---
|
||
|
||
### `hg.hg_mixin` — Миксин для моделей
|
||
|
||
**Файл:** `models/hg_mixin.py`
|
||
**Тип:** `models.AbstractModel`
|
||
|
||
Абстрактная модель, подключаемая через `_inherit` к любой модели Odoo. После подключения модель автоматически становится участником гиперграфа: при создании записи создаётся соответствующая вершина `hg.node`.
|
||
|
||
#### Подключение к модели
|
||
|
||
```python
|
||
class ProjectTask(models.Model):
|
||
_name = 'project.task'
|
||
_inherit = ['project.task', 'hg.hg_mixin']
|
||
```
|
||
|
||
#### Поля, добавляемые в модель
|
||
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| `node_id` | Many2one → `hg.node` | Вершина графа для данной записи |
|
||
| `index_ids` | Many2many → `hg.index` | Показатели, привязанные к вершине записи |
|
||
| `related_ids` | Many2many → `hg.node` | Вершины-приёмники из матрицы связности |
|
||
|
||
#### Методы
|
||
|
||
**`create()`** — переопределён: после создания записи автоматически создаёт `hg.node` с `res_model` и `res_id` текущей записи, устанавливает `node_id`.
|
||
|
||
**`_compute_indexes()`** — ищет все `hg.index` с `node_id` равным вершине записи, заполняет `index_ids`.
|
||
|
||
**`_compute_related()`** — ищет все `hg.link` где `source_id` равен вершине записи, собирает все `target_ids` из найденных связей, заполняет `related_ids`.
|
||
|
||
---
|
||
|
||
## Представления и меню
|
||
|
||
**Файл:** `views/views.xml`
|
||
|
||
Создаёт корневое меню **«Слои показателей»** со следующей структурой:
|
||
|
||
```
|
||
Слои показателей
|
||
├── Граф
|
||
│ ├── Вершины графа → hg.node (list / form)
|
||
│ └── Матрица связности → hg.link (list / form)
|
||
└── Показатели
|
||
├── Показатели → hg.index (list / form)
|
||
├── Значения показателей → hg.value (list / form)
|
||
└── Внутренний код → hg.index.code (list / form)
|
||
```
|
||
|
||
---
|
||
|
||
## Безопасность
|
||
|
||
**Файл:** `security/res_groups.xml`
|
||
|
||
Группа `group_indicators_admin` — **«Администратор Слоёв показателей»**. Полный CRUD-доступ ко всем моделям модуля.
|
||
|
||
**Файл:** `security/ir.model.access.csv`
|
||
|
||
| Модель | Группа | Права |
|
||
|---|---|---|
|
||
| `hg.node` | `group_indicators_admin` | CRUD |
|
||
| `hg.index` | `group_indicators_admin` | CRUD |
|
||
| `hg.index.code` | `group_indicators_admin` | CRUD |
|
||
| `hg.value` | `group_indicators_admin` | CRUD |
|
||
| `hg.link` | `group_indicators_admin` | CRUD |
|
||
| `hg.hg_mixin` | `group_indicators_admin` | CRUD |
|
||
|
||
---
|
||
|
||
## Тесты
|
||
|
||
**Файл:** `tests/`
|
||
|
||
| Файл | Что покрывает |
|
||
|---|---|
|
||
| `test_hg_node.py` | Создание вершины, метод `goto_related()` |
|
||
| `test_hg_index.py` | Создание показателя, вычисление `current_value` в различных сценариях |
|
||
| `test_hg_value.py` | Создание значения, вызов `calc()` для типов `alone` и `formula` |
|
||
| `test_hg_link.py` | Создание связи с вершинами-приёмниками и без них |
|
||
| `test_indicators.py` | Интеграционный тест цепочки модулей |
|
||
|
||
--- |