- fusion.followup.cron AbstractModel with two handlers - cron_fusion_followup_daily_scan: walks every overdue partner and delegates to engine.send_followup_email - cron_fusion_followup_risk_refresh: weekly refresh of fusion_followup_risk_score / risk_band on res.partner - V19 ir.cron records (no numbercall field) - 2 smoke tests added (80 total) Made-with: Cursor
85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
"""Cron handlers for fusion_accounting_followup.
|
|
|
|
Two scheduled jobs:
|
|
- Daily scan: walk every partner with an open overdue receivable line and
|
|
call the engine to send/escalate where appropriate.
|
|
- Weekly risk refresh: recompute fusion_followup_risk_score on every
|
|
partner with overdue.
|
|
"""
|
|
|
|
import logging
|
|
from datetime import date
|
|
|
|
from odoo import api, models
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class FusionFollowupCron(models.AbstractModel):
|
|
_name = "fusion.followup.cron"
|
|
_description = "Fusion Follow-up Cron Handlers"
|
|
|
|
@api.model
|
|
def _cron_daily_scan(self):
|
|
"""Scan every partner with overdue and send follow-ups when due."""
|
|
engine = self.env['fusion.followup.engine']
|
|
Line = self.env['account.move.line'].sudo()
|
|
overdue_lines = Line.search([
|
|
('parent_state', '=', 'posted'),
|
|
('account_id.account_type', '=', 'asset_receivable'),
|
|
('reconciled', '=', False),
|
|
('amount_residual', '>', 0),
|
|
('date_maturity', '<', date.today()),
|
|
])
|
|
partner_ids = list(set(overdue_lines.mapped('partner_id').ids))
|
|
sent = 0
|
|
skipped = 0
|
|
for pid in partner_ids:
|
|
partner = self.env['res.partner'].sudo().browse(pid)
|
|
if not partner.exists():
|
|
continue
|
|
try:
|
|
with self.env.cr.savepoint():
|
|
result = engine.send_followup_email(partner)
|
|
if result.get('status') == 'sent':
|
|
sent += 1
|
|
else:
|
|
skipped += 1
|
|
except Exception as e:
|
|
_logger.warning(
|
|
"Cron daily_scan failed for partner %s: %s", pid, e,
|
|
)
|
|
skipped += 1
|
|
_logger.info(
|
|
"Cron: scanned %d partners, sent %d, skipped %d",
|
|
len(partner_ids), sent, skipped,
|
|
)
|
|
|
|
@api.model
|
|
def _cron_risk_refresh(self):
|
|
"""Refresh fusion_followup_risk_score on every partner with overdue."""
|
|
Partner = self.env['res.partner'].sudo()
|
|
engine = self.env['fusion.followup.engine']
|
|
Line = self.env['account.move.line'].sudo()
|
|
partner_ids = list(set(Line.search([
|
|
('parent_state', '=', 'posted'),
|
|
('account_id.account_type', '=', 'asset_receivable'),
|
|
('reconciled', '=', False),
|
|
('amount_residual', '>', 0),
|
|
]).mapped('partner_id').ids))
|
|
updated = 0
|
|
for pid in partner_ids:
|
|
partner = Partner.browse(pid)
|
|
try:
|
|
overdue = engine.get_overdue_for_partner(partner)
|
|
partner.write({
|
|
'fusion_followup_risk_score': overdue['risk']['score'],
|
|
'fusion_followup_risk_band': overdue['risk']['band'],
|
|
})
|
|
updated += 1
|
|
except Exception as e:
|
|
_logger.warning(
|
|
"Risk refresh failed for partner %s: %s", pid, e,
|
|
)
|
|
_logger.info("Cron: refreshed risk on %d partners", updated)
|