Adds the foundation for AI confidence scoring: - fusion.reconcile.pattern: per-(company, partner) aggregate profile (volume, cadence, preferred matching strategy, memo signature, write-off habits) — recomputed nightly from precedents. - fusion.reconcile.precedent: per-historical-decision memory holding full feature vector + outcome, used by precedent_lookup for KNN scoring of new bank lines. Includes ACL rows for fusion accounting user (read) and admin (CRUD) groups. Manifest bumped to 19.0.1.0.1. Note: switched the pattern uniqueness rule from the deprecated _sql_constraints attribute to models.Constraint (Odoo 19 native API) so the unique(company_id, partner_id) is actually enforced at the PG level — _sql_constraints is silently ignored in 19. Made-with: Cursor
56 lines
2.0 KiB
Python
56 lines
2.0 KiB
Python
"""Per-partner bank reconciliation pattern aggregate.
|
||
|
||
One row per (company_id, partner_id). Continuously summarises HOW this
|
||
partner gets reconciled. Recomputed nightly via cron from the precedent
|
||
table. Used as a feature input to confidence_scoring.
|
||
"""
|
||
|
||
from odoo import fields, models
|
||
|
||
|
||
class FusionReconcilePattern(models.Model):
|
||
_name = "fusion.reconcile.pattern"
|
||
_description = "Per-partner bank reconciliation pattern aggregate"
|
||
_rec_name = "partner_id"
|
||
|
||
company_id = fields.Many2one('res.company', required=True, index=True,
|
||
default=lambda self: self.env.company)
|
||
partner_id = fields.Many2one('res.partner', required=True, index=True)
|
||
|
||
# Volume + cadence
|
||
reconcile_count = fields.Integer(default=0,
|
||
help="Total past reconciles for this partner")
|
||
typical_amount_range = fields.Char(
|
||
help="e.g. '$1,200 – $2,400 (median $1,847.50)'")
|
||
typical_cadence_days = fields.Float(
|
||
help="Mean inter-reconcile days")
|
||
typical_day_of_month = fields.Char(
|
||
help="e.g. '1st, 15th'")
|
||
|
||
# Matching strategy used historically
|
||
pref_strategy = fields.Selection([
|
||
('exact_amount', 'Exact-amount-first'),
|
||
('fifo', 'FIFO oldest-due-first'),
|
||
('multi_invoice', 'Multi-invoice consolidation'),
|
||
('cherry_pick', 'Cherry-pick specific invoices'),
|
||
])
|
||
pref_account_id = fields.Many2one('account.account',
|
||
help="Most-used target account")
|
||
|
||
# Memo signature
|
||
common_memo_tokens = fields.Char(
|
||
help="Comma-separated tokens that appear in ≥30% of past reconciles")
|
||
|
||
# Tax + write-off habits
|
||
common_writeoff_account_id = fields.Many2one('account.account')
|
||
common_writeoff_tax_id = fields.Many2one('account.tax')
|
||
typical_writeoff_amount = fields.Float(
|
||
help="e.g. 0.05 for rounding diffs")
|
||
|
||
last_refreshed_at = fields.Datetime()
|
||
|
||
_uniq_company_partner = models.Constraint(
|
||
'unique(company_id, partner_id)',
|
||
'One pattern row per (company, partner) — already exists.',
|
||
)
|