"""Per-historical-decision reconciliation memory. One row per past reconciliation. Holds the full feature vector + outcome, used by precedent_lookup for K-nearest-neighbour search when scoring a new bank line. """ from odoo import fields, models class FusionReconcilePrecedent(models.Model): _name = "fusion.reconcile.precedent" _description = "Historical bank reconciliation decision (memory)" _order = "reconciled_at desc, id desc" company_id = fields.Many2one('res.company', required=True, index=True, default=lambda self: self.env.company) partner_id = fields.Many2one('res.partner', index=True) # Bank line features (the "input") amount = fields.Monetary(currency_field='currency_id') currency_id = fields.Many2one('res.currency') date = fields.Date() memo_tokens = fields.Char( help="Comma-separated normalized memo tokens (output of memo_tokenizer)") journal_id = fields.Many2one('account.journal') # Outcome (the "decision made") matched_move_line_count = fields.Integer( help="1 = exact, 2-3 = consolidation, etc.") matched_account_ids = fields.Char( help="Comma-separated account.account IDs that were matched against") matched_invoice_ages_days = fields.Char( help="Comma-separated days-old at reconcile time, e.g. '12, 45, 78'") write_off_amount = fields.Float() write_off_account_id = fields.Many2one('account.account') exchange_diff = fields.Boolean() # Provenance reconciler_user_id = fields.Many2one('res.users') reconciled_at = fields.Datetime() source = fields.Selection([ ('historical_bootstrap', 'Imported from history'), ('backfill', 'Backfilled from account.partial.reconcile (migration)'), ('manual', 'Manual reconcile via fusion'), ('ai_accepted', 'AI suggestion accepted'), ('auto_rule', 'account.reconcile.model auto-fired'), ], required=True) # No uniqueness constraint — multiple reconciles can share features