Initial commit
This commit is contained in:
248
Fusion Accounting/wizard/followup_send_wizard.py
Normal file
248
Fusion Accounting/wizard/followup_send_wizard.py
Normal file
@@ -0,0 +1,248 @@
|
||||
# Part of Fusion Accounting. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class FusionFollowupSendWizard(models.TransientModel):
|
||||
"""Wizard for previewing and manually sending payment follow-ups.
|
||||
|
||||
Allows the user to review the email content, modify the message
|
||||
body, choose communication channels, and send the follow-up for
|
||||
one or more partners at once.
|
||||
"""
|
||||
|
||||
_name = 'fusion.followup.send.wizard'
|
||||
_description = "Fusion Follow-up Send Wizard"
|
||||
|
||||
# ---- Context Fields ----
|
||||
followup_line_id = fields.Many2one(
|
||||
comodel_name='fusion.followup.line',
|
||||
string="Follow-up Record",
|
||||
readonly=True,
|
||||
)
|
||||
partner_id = fields.Many2one(
|
||||
comodel_name='res.partner',
|
||||
string="Partner",
|
||||
related='followup_line_id.partner_id',
|
||||
readonly=True,
|
||||
)
|
||||
followup_level_id = fields.Many2one(
|
||||
comodel_name='fusion.followup.level',
|
||||
string="Follow-up Level",
|
||||
related='followup_line_id.followup_level_id',
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
# ---- Editable Content ----
|
||||
email_subject = fields.Char(
|
||||
string="Subject",
|
||||
compute='_compute_email_preview',
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
email_body = fields.Html(
|
||||
string="Email Body",
|
||||
compute='_compute_email_preview',
|
||||
store=True,
|
||||
readonly=False,
|
||||
help="Edit the email body before sending. Changes apply only to this send.",
|
||||
)
|
||||
|
||||
# ---- Channel Overrides ----
|
||||
do_send_email = fields.Boolean(
|
||||
string="Send Email",
|
||||
compute='_compute_channel_defaults',
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
do_send_sms = fields.Boolean(
|
||||
string="Send SMS",
|
||||
compute='_compute_channel_defaults',
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
do_print_letter = fields.Boolean(
|
||||
string="Print Letter",
|
||||
compute='_compute_channel_defaults',
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
do_join_invoices = fields.Boolean(
|
||||
string="Attach Invoices",
|
||||
compute='_compute_channel_defaults',
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
|
||||
# ---- Informational ----
|
||||
overdue_amount = fields.Monetary(
|
||||
string="Overdue Amount",
|
||||
related='followup_line_id.overdue_amount',
|
||||
readonly=True,
|
||||
currency_field='currency_id',
|
||||
)
|
||||
overdue_count = fields.Integer(
|
||||
string="Overdue Invoices",
|
||||
related='followup_line_id.overdue_count',
|
||||
readonly=True,
|
||||
)
|
||||
currency_id = fields.Many2one(
|
||||
comodel_name='res.currency',
|
||||
related='followup_line_id.currency_id',
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
# --------------------------------------------------
|
||||
# Default Values
|
||||
# --------------------------------------------------
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
"""Populate the wizard from the active follow-up line."""
|
||||
defaults = super().default_get(fields_list)
|
||||
active_id = self.env.context.get('active_id')
|
||||
if active_id and self.env.context.get('active_model') == 'fusion.followup.line':
|
||||
defaults['followup_line_id'] = active_id
|
||||
return defaults
|
||||
|
||||
# --------------------------------------------------
|
||||
# Computed Fields
|
||||
# --------------------------------------------------
|
||||
|
||||
@api.depends('followup_level_id', 'partner_id')
|
||||
def _compute_email_preview(self):
|
||||
"""Build a preview of the email subject and body.
|
||||
|
||||
Uses the level's email template if set, otherwise falls back to
|
||||
the level description or a sensible default.
|
||||
"""
|
||||
for wizard in self:
|
||||
level = wizard.followup_level_id
|
||||
partner = wizard.partner_id
|
||||
company = wizard.followup_line_id.company_id or self.env.company
|
||||
|
||||
if level and level.email_template_id:
|
||||
template = level.email_template_id
|
||||
# Render the template for the partner
|
||||
rendered = template._render_field(
|
||||
'body_html', [partner.id],
|
||||
engine='inline_template',
|
||||
compute_lang=True,
|
||||
)
|
||||
wizard.email_body = rendered.get(partner.id, '')
|
||||
rendered_subject = template._render_field(
|
||||
'subject', [partner.id],
|
||||
engine='inline_template',
|
||||
compute_lang=True,
|
||||
)
|
||||
wizard.email_subject = rendered_subject.get(partner.id, '')
|
||||
else:
|
||||
wizard.email_subject = _(
|
||||
"%(company)s - Payment Reminder",
|
||||
company=company.name,
|
||||
)
|
||||
if level and level.description:
|
||||
wizard.email_body = level.description
|
||||
else:
|
||||
wizard.email_body = _(
|
||||
"<p>Dear %(partner)s,</p>"
|
||||
"<p>This is a reminder that your account has an outstanding "
|
||||
"balance. Please arrange payment at your earliest convenience.</p>"
|
||||
"<p>Best regards,<br/>%(company)s</p>",
|
||||
partner=partner.name or _('Customer'),
|
||||
company=company.name,
|
||||
)
|
||||
|
||||
@api.depends('followup_level_id')
|
||||
def _compute_channel_defaults(self):
|
||||
"""Pre-fill channel toggles from the follow-up level configuration."""
|
||||
for wizard in self:
|
||||
level = wizard.followup_level_id
|
||||
if level:
|
||||
wizard.do_send_email = level.send_email
|
||||
wizard.do_send_sms = level.send_sms
|
||||
wizard.do_print_letter = level.send_letter
|
||||
wizard.do_join_invoices = level.join_invoices
|
||||
else:
|
||||
wizard.do_send_email = True
|
||||
wizard.do_send_sms = False
|
||||
wizard.do_print_letter = False
|
||||
wizard.do_join_invoices = False
|
||||
|
||||
# --------------------------------------------------
|
||||
# Actions
|
||||
# --------------------------------------------------
|
||||
|
||||
def action_send_followup(self):
|
||||
"""Send the follow-up using the wizard-configured channels and content.
|
||||
|
||||
Sends the (possibly edited) email, optionally triggers SMS,
|
||||
then advances the partner to the next follow-up level.
|
||||
|
||||
:returns: ``True`` to close the wizard.
|
||||
:raises UserError: If no follow-up line is linked.
|
||||
"""
|
||||
self.ensure_one()
|
||||
line = self.followup_line_id
|
||||
if not line:
|
||||
raise UserError(_("No follow-up record is linked to this wizard."))
|
||||
|
||||
partner = line.partner_id
|
||||
|
||||
# ---- Email ----
|
||||
if self.do_send_email:
|
||||
attachment_ids = []
|
||||
if self.do_join_invoices:
|
||||
attachment_ids = line._get_invoice_attachments(partner)
|
||||
|
||||
mail_values = {
|
||||
'subject': self.email_subject,
|
||||
'body_html': self.email_body,
|
||||
'email_from': (
|
||||
line.company_id.email
|
||||
or self.env.user.email_formatted
|
||||
),
|
||||
'email_to': partner.email,
|
||||
'author_id': self.env.user.partner_id.id,
|
||||
'res_id': partner.id,
|
||||
'model': 'res.partner',
|
||||
'attachment_ids': [(6, 0, attachment_ids)],
|
||||
}
|
||||
mail = self.env['mail.mail'].sudo().create(mail_values)
|
||||
mail.send()
|
||||
|
||||
# ---- SMS ----
|
||||
if self.do_send_sms and line.followup_level_id.sms_template_id:
|
||||
try:
|
||||
line.followup_level_id.sms_template_id._send_sms(partner.id)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ---- Advance Level ----
|
||||
level = line.followup_level_id
|
||||
if level:
|
||||
next_level = level._get_next_level()
|
||||
line.write({
|
||||
'date': fields.Date.context_today(self),
|
||||
'followup_level_id': next_level.id if next_level else level.id,
|
||||
})
|
||||
else:
|
||||
line.write({'date': fields.Date.context_today(self)})
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def action_preview_email(self):
|
||||
"""Recompute the email preview after manual edits to the level.
|
||||
|
||||
:returns: Action to reload the wizard form.
|
||||
"""
|
||||
self.ensure_one()
|
||||
self._compute_email_preview()
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': self._name,
|
||||
'res_id': self.id,
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
}
|
||||
Reference in New Issue
Block a user