feat(fusion_accounting_followup): inherit res.partner with follow-up state

Made-with: Cursor
This commit is contained in:
gsinghpal
2026-04-19 20:46:08 -04:00
parent 207c857e6b
commit 2ddc600d65
5 changed files with 82 additions and 1 deletions

View File

@@ -1,6 +1,6 @@
{
'name': 'Fusion Accounting Follow-up',
'version': '19.0.1.0.8',
'version': '19.0.1.0.9',
'category': 'Accounting/Accounting',
'summary': 'AI-augmented customer follow-ups (dunning) for unpaid invoices.',
'description': """

View File

@@ -1,3 +1,4 @@
from . import fusion_followup_level
from . import fusion_followup_run
from . import fusion_followup_text_cache
from . import res_partner

View File

@@ -0,0 +1,52 @@
"""Inherit res.partner: add follow-up state fields."""
from odoo import _, api, fields, models
FOLLOWUP_STATUS = [
('no_action', 'No Action Needed'),
('action_due', 'Action Due'),
('paused', 'Paused'),
('blocked', 'Blocked'),
('with_credit_team', 'With Credit Team'),
]
class ResPartner(models.Model):
_inherit = "res.partner"
fusion_followup_status = fields.Selection(
FOLLOWUP_STATUS, default='no_action', tracking=True,
help="Current follow-up status as computed by the engine.")
fusion_followup_paused_until = fields.Date(
tracking=True,
help="Pause follow-ups for this partner until this date.")
fusion_followup_last_level_id = fields.Many2one(
'fusion.followup.level',
help="The most-recent follow-up level this partner has been contacted at.")
fusion_followup_last_run_date = fields.Datetime(readonly=True)
fusion_followup_run_ids = fields.One2many(
'fusion.followup.run', 'partner_id', string='Follow-up History')
fusion_followup_run_count = fields.Integer(
compute='_compute_fusion_followup_run_count')
fusion_followup_risk_score = fields.Integer(
readonly=True, default=0,
help="Latest computed payment risk (0-100). Updated by cron.")
fusion_followup_risk_band = fields.Selection([
('low', 'Low'), ('medium', 'Medium'),
('high', 'High'), ('critical', 'Critical'),
], default='low', readonly=True)
def _compute_fusion_followup_run_count(self):
for partner in self:
partner.fusion_followup_run_count = len(partner.fusion_followup_run_ids)
def action_view_followup_history(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'res_model': 'fusion.followup.run',
'view_mode': 'list,form',
'domain': [('partner_id', '=', self.id)],
'context': {'default_partner_id': self.id},
}

View File

@@ -6,3 +6,4 @@ from . import test_followup_text_generator
from . import test_fusion_followup_level
from . import test_fusion_followup_run
from . import test_fusion_followup_text_cache
from . import test_res_partner_inherit

View File

@@ -0,0 +1,27 @@
from odoo.tests.common import TransactionCase
from odoo.tests import tagged
@tagged('post_install', '-at_install')
class TestResPartnerFollowup(TransactionCase):
def test_default_status_no_action(self):
partner = self.env['res.partner'].create({'name': 'Default Status'})
self.assertEqual(partner.fusion_followup_status, 'no_action')
self.assertEqual(partner.fusion_followup_risk_band, 'low')
self.assertEqual(partner.fusion_followup_risk_score, 0)
def test_run_count_reflects_history(self):
partner = self.env['res.partner'].create({'name': 'History Partner'})
self.assertEqual(partner.fusion_followup_run_count, 0)
for _ in range(3):
self.env['fusion.followup.run'].create({'partner_id': partner.id})
partner.invalidate_recordset(['fusion_followup_run_count', 'fusion_followup_run_ids'])
self.assertEqual(partner.fusion_followup_run_count, 3)
def test_action_view_followup_history_returns_action(self):
partner = self.env['res.partner'].create({'name': 'Action Partner'})
action = partner.action_view_followup_history()
self.assertEqual(action['res_model'], 'fusion.followup.run')
self.assertEqual(action['domain'], [('partner_id', '=', partner.id)])
self.assertEqual(action['context']['default_partner_id'], partner.id)