# -*- coding: utf-8 -*- # Copyright 2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) # Part of the Fusion Plating product family. from odoo import api, fields, models class FpRisk(models.Model): """Risk register entry. Implements the operational risk management requirement from AS9100 Rev D §8.1.1. Each risk gets scored on a 1–5 likelihood and 1–5 impact scale; the multiplicative score drives the level classification (low / medium / high / critical) used for escalation and reporting. """ _name = 'fusion.plating.risk' _description = 'Fusion Plating — Risk Register Entry' _inherit = ['mail.thread', 'mail.activity.mixin'] _order = 'risk_score desc, id desc' name = fields.Char( string='Reference', required=True, copy=False, readonly=True, default=lambda self: self._default_name(), tracking=True, ) title = fields.Char( string='Title', required=True, tracking=True, ) description = fields.Html( string='Description', ) category = fields.Selection( [ ('operational', 'Operational'), ('supply_chain', 'Supply Chain'), ('quality', 'Quality'), ('safety', 'Safety'), ('environmental', 'Environmental'), ('financial', 'Financial'), ('customer', 'Customer'), ('regulatory', 'Regulatory'), ], string='Category', default='operational', required=True, tracking=True, ) likelihood = fields.Selection( [ ('1', '1 — Very Low'), ('2', '2 — Low'), ('3', '3 — Medium'), ('4', '4 — High'), ('5', '5 — Very High'), ], string='Likelihood', default='3', required=True, tracking=True, ) impact = fields.Selection( [ ('1', '1 — Very Low'), ('2', '2 — Low'), ('3', '3 — Medium'), ('4', '4 — High'), ('5', '5 — Very High'), ], string='Impact', default='3', required=True, tracking=True, ) risk_score = fields.Integer( string='Score', compute='_compute_risk_score', store=True, help='Likelihood × Impact (1–25).', ) risk_level = fields.Selection( [ ('low', 'Low'), ('medium', 'Medium'), ('high', 'High'), ('critical', 'Critical'), ], string='Level', compute='_compute_risk_level', store=True, tracking=True, ) mitigation_plan = fields.Html( string='Mitigation Plan', ) owner_id = fields.Many2one( 'res.users', string='Owner', default=lambda self: self.env.user, tracking=True, ) review_date = fields.Date( string='Next Review', tracking=True, ) state = fields.Selection( [ ('identified', 'Identified'), ('assessed', 'Assessed'), ('treated', 'Treated'), ('monitored', 'Monitored'), ('closed', 'Closed'), ], string='Status', default='identified', required=True, tracking=True, ) company_id = fields.Many2one( 'res.company', string='Company', default=lambda self: self.env.company, ) active = fields.Boolean(default=True) @api.model def _default_name(self): seq = self.env['ir.sequence'].next_by_code('fusion.plating.risk') return seq or '/' @api.model_create_multi def create(self, vals_list): for vals in vals_list: if not vals.get('name') or vals.get('name') == '/': vals['name'] = self._default_name() return super().create(vals_list) @api.depends('likelihood', 'impact') def _compute_risk_score(self): for rec in self: try: likely = int(rec.likelihood or 0) impact = int(rec.impact or 0) except (TypeError, ValueError): likely, impact = 0, 0 rec.risk_score = likely * impact @api.depends('risk_score') def _compute_risk_level(self): for rec in self: score = rec.risk_score or 0 if score >= 20: rec.risk_level = 'critical' elif score >= 12: rec.risk_level = 'high' elif score >= 6: rec.risk_level = 'medium' else: rec.risk_level = 'low' def action_assess(self): self.write({'state': 'assessed'}) def action_treat(self): self.write({'state': 'treated'}) def action_monitor(self): self.write({'state': 'monitored'}) def action_close(self): self.write({'state': 'closed'})