Files
Odoo-Modules/fusion_accounting/models/accounting_rule.py
gsinghpal 4cd7357aa0 changes
2026-04-02 23:40:34 -04:00

121 lines
4.2 KiB
Python

import logging
from odoo import models, fields, api
_logger = logging.getLogger(__name__)
class FusionAccountingRule(models.Model):
_name = 'fusion.accounting.rule'
_description = 'Fusion Accounting Rule'
_order = 'sequence, id'
_inherit = ['mail.thread']
name = fields.Char(string='Name', required=True, tracking=True)
rule_type = fields.Selection(
selection=[
('match', 'Match'),
('classify', 'Classify'),
('audit', 'Audit'),
('fee', 'Fee'),
('routing', 'Routing'),
('followup', 'Follow-Up'),
],
string='Type',
required=True,
tracking=True,
)
description = fields.Text(
string='Description',
help='Natural language description read by the AI.',
)
trigger_domain = fields.Text(
string='Trigger Domain (JSON)',
help='Odoo domain filter for matching records.',
)
match_logic = fields.Text(
string='Match Logic',
help='Natural language matching instructions for the AI.',
)
match_code = fields.Text(
string='Match Code (Python)',
help='Optional deterministic Python matching code.',
)
fee_account_id = fields.Many2one(
'account.account', string='Fee Account',
)
write_off_account_id = fields.Many2one(
'account.account', string='Write-Off Account',
)
approval_tier = fields.Selection(
selection=[('auto', 'Auto-Approved'), ('needs_approval', 'Needs Approval')],
string='Approval Tier',
default='needs_approval',
tracking=True,
)
created_by = fields.Selection(
selection=[('admin', 'Admin'), ('ai', 'AI')],
string='Created By',
default='admin',
)
confidence_score = fields.Float(
string='Confidence Score', digits=(3, 2), default=0.0,
)
total_uses = fields.Integer(string='Total Uses', default=0)
total_approved = fields.Integer(string='Total Approved', default=0)
total_rejected = fields.Integer(string='Total Rejected', default=0)
promotion_threshold = fields.Float(
string='Promotion Threshold', default=0.95,
)
min_sample_size = fields.Integer(string='Min Sample Size', default=30)
active = fields.Boolean(string='Active', default=True, tracking=True)
version = fields.Integer(string='Version', default=1)
parent_rule_id = fields.Many2one(
'fusion.accounting.rule', string='Previous Version',
ondelete='set null',
)
journal_ids = fields.Many2many(
'account.journal', string='Journals',
)
company_id = fields.Many2one(
'res.company', string='Company',
default=lambda self: self.env.company,
)
sequence = fields.Integer(string='Sequence', default=10)
notes = fields.Text(string='Notes')
def _record_decision(self, approved=True):
for rec in self:
self.env.cr.execute("""
UPDATE fusion_accounting_rule
SET total_uses = total_uses + 1,
total_approved = total_approved + %s,
total_rejected = total_rejected + %s
WHERE id = %s
RETURNING total_uses, total_approved
""", (int(approved), int(not approved), rec.id))
row = self.env.cr.fetchone()
rec.invalidate_recordset(['total_uses', 'total_approved', 'total_rejected'])
if row and row[0] > 0:
rec.confidence_score = row[1] / row[0]
rec._check_promotion()
def _check_promotion(self):
for rec in self:
if (rec.approval_tier == 'needs_approval'
and rec.total_uses >= rec.min_sample_size
and rec.confidence_score >= rec.promotion_threshold):
rec.approval_tier = 'auto'
_logger.info(
"Rule '%s' promoted to auto-approved (confidence=%.2f, uses=%d)",
rec.name, rec.confidence_score, rec.total_uses,
)
def action_demote(self):
self.write({'approval_tier': 'needs_approval'})
def action_rollback(self):
for rec in self:
if rec.parent_rule_id:
rec.active = False
rec.parent_rule_id.active = True