changes
This commit is contained in:
120
fusion_accounting/models/accounting_rule.py
Normal file
120
fusion_accounting/models/accounting_rule.py
Normal file
@@ -0,0 +1,120 @@
|
||||
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
|
||||
Reference in New Issue
Block a user