Files
public/directive_layer/models/directive_policy.py

153 lines
5.8 KiB
Python
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.
from odoo import fields, models
from odoo.tools.safe_eval import safe_eval
import logging
_logger = logging.getLogger(__name__)
class DirectivePolicy(models.Model):
_name = "directive.policy"
_description = "Directive Policy"
_order = "sequence, id"
name = fields.Char(required=True)
active = fields.Boolean(default=True)
sequence = fields.Integer(default=10)
origin_model = fields.Char(
string="Origin model",
required=True,
index=True,
help="Техническое имя модели источника, например 'project.task'",
)
event = fields.Selection(
[
("manual", "Manual"),
("on_create", "On Create"),
("on_write", "On Write"),
("on_stage", "On Stage Change"),
("on_cron", "On Cron"),
("on_callback", "При вызове метода (on_callback)"),
],
required=True,
index=True,
default="manual",
)
mode = fields.Selection(
[
("create_once", "Create once"),
("create_each_time", "Create each time"),
],
required=True,
default="create_once",
)
use_record_template_group = fields.Boolean(
default=True,
help="Если включено, группа берётся из поля записи-источника directive_template_group_id.",
)
template_group_id = fields.Many2one(
"directive.template.group",
string="Fixed template group",
help="Если указано и use_record_template_group=False — будет использоваться эта группа.",
)
trigger_field = fields.Char(
help="Имя поля источника, например 'stage_id'."
)
trigger_value_int = fields.Integer(
help="Для Many2one/Integer: ожидаемое значение (например ID стадии)."
)
trigger_value_char = fields.Char(
help="Для Char/Selection-полей (например mrp.workorder.state='progress'): "
"ожидаемое строковое значение. Для Many2one/Integer использовать trigger_value_int.",
)
domain_filter = fields.Char(
string="Доменный фильтр источника",
help="Odoo-домен (строка), применяется к записи-источнику перед генерацией. "
"Пусто — без фильтра.",
)
def _policy_should_fire(self, record, payload: dict | None = None) -> bool:
self.ensure_one()
# (1) Доменный фильтр источника применяется ко ВСЕМ событиям (вкл. on_callback).
if self.domain_filter:
try:
domain = safe_eval(self.domain_filter) or []
except Exception as e:
_logger.error("[directive.policy %s] bad domain_filter: %s", self.name, e)
return False
if domain and not record.filtered_domain(domain):
return False
# (2) Для on_callback факт вызова метода - это уже триггер (домен уже отфильтровал).
if self.event == 'on_callback':
return True
if not self.trigger_field:
return True
value = getattr(record, self.trigger_field, False)
# (3a) Many2one: сравнение по id с trigger_value_int.
if hasattr(value, "id"):
return bool(value and value.id == self.trigger_value_int)
# (3b) Char/Selection: сравнение с trigger_value_char. ПРАВИЛО fail-loud:
# если trigger_value_char пуст, НЕ проваливаемся в целочисленную ветку
# (сравнение 'progress' == 0 всегда False) — логируем и возвращаем False.
if isinstance(value, str):
if self.trigger_value_char:
return value == self.trigger_value_char
_logger.warning(
"[directive.policy %s] trigger_field '%s' вернул строку '%s', но "
"trigger_value_char не задан — политика не срабатывает.",
self.name, self.trigger_field, value,
)
return False
# (3c) Integer/число: сравнение с trigger_value_int (как сейчас — test_01 'color').
try:
return value == self.trigger_value_int
except Exception as e:
_logger.error("[directive.policy] Error comparing values: %s", e)
return False
def _resolve_template_group(self, record):
self.ensure_one()
if self.use_record_template_group:
return record.directive_template_group_id
return self.template_group_id
def apply_to_records(self, records, payload: dict | None = None):
self.ensure_one()
if not records:
return 0
created_total = 0
for rec in records:
if rec._name != self.origin_model:
continue
if not self._policy_should_fire(rec, payload=payload):
continue
group = self._resolve_template_group(rec)
if not group:
continue
if self.mode == "create_once":
existing = rec.env["directive.directive"].search_count([
("origin_id", "=", rec.directive_origin_id.id),
("policy_id", "=", self.id),
])
if existing:
continue
rec._directive_create_from_group(group, policy=self)
created_total += 1
return created_total