- New standalone module to collect fixes for default Odoo behavior - Fix #1: account_followup never clears followup_next_action_date when invoices are paid, causing collection emails to fully-paid clients. Hooks into _invoice_paid_hook to auto-clear stale data. - Harden Fusion Accounting followup queries with amount_residual > 0 filter and add balance check before sending emails Co-authored-by: Cursor <cursoragent@cursor.com>
55 lines
2.0 KiB
Python
55 lines
2.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2025-2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
#
|
|
# FIX: account_followup never clears followup_next_action_date
|
|
# ------------------------------------------------------------
|
|
# Odoo's account_followup module sets followup_next_action_date on
|
|
# res.partner when overdue invoices are detected, but never clears it
|
|
# when those invoices are paid. The daily cron re-evaluates status
|
|
# via SQL so it *usually* skips zero-balance partners, but the stale
|
|
# field causes partners to appear in follow-up lists and manual sends
|
|
# can still fire emails to fully-paid clients.
|
|
#
|
|
# This override hooks into _invoice_paid_hook (called by the core
|
|
# reconciliation engine) and clears the follow-up date when the
|
|
# partner has no remaining receivable balance.
|
|
|
|
import logging
|
|
|
|
from odoo import models
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class AccountMove(models.Model):
|
|
_inherit = 'account.move'
|
|
|
|
def _invoice_paid_hook(self):
|
|
super()._invoice_paid_hook()
|
|
|
|
partner_model = self.env['res.partner']
|
|
if 'followup_next_action_date' not in partner_model._fields:
|
|
return
|
|
|
|
partners = self.mapped('partner_id.commercial_partner_id').filtered(
|
|
'followup_next_action_date'
|
|
)
|
|
if not partners:
|
|
return
|
|
|
|
for partner in partners:
|
|
has_balance = self.env['account.move.line'].search_count([
|
|
('partner_id', '=', partner.id),
|
|
('account_id.account_type', '=', 'asset_receivable'),
|
|
('parent_state', '=', 'posted'),
|
|
('reconciled', '=', False),
|
|
('amount_residual', '>', 0),
|
|
], limit=1)
|
|
if not has_balance:
|
|
partner.write({'followup_next_action_date': False})
|
|
_logger.info(
|
|
"Cleared follow-up for partner %s (ID %s) -- no outstanding balance",
|
|
partner.name, partner.id,
|
|
)
|