- fusion_claims: separated field service logic, updated controllers/views - fusion_tasks: updated task views and map integration - fusion_authorizer_portal: added page 11 signing, schedule booking, migrations - fusion_shipping: new standalone shipping module (Canada Post, FedEx, DHL, Purolator) - fusion_ltc_management: new standalone LTC management module
244 lines
9.4 KiB
Python
244 lines
9.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2024-2025 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
|
|
from odoo import models, fields, api, _
|
|
from odoo.exceptions import UserError
|
|
from markupsafe import Markup
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class AssessmentCompletedWizard(models.TransientModel):
|
|
_name = 'fusion_claims.assessment.completed.wizard'
|
|
_description = 'Assessment Completed Wizard'
|
|
|
|
sale_order_id = fields.Many2one(
|
|
'sale.order',
|
|
string='Sale Order',
|
|
required=True,
|
|
readonly=True,
|
|
)
|
|
|
|
is_override = fields.Boolean(
|
|
string='Scheduling Override',
|
|
compute='_compute_is_override',
|
|
store=False,
|
|
)
|
|
|
|
assessment_start_date = fields.Date(
|
|
string='Assessment Start Date',
|
|
required=True,
|
|
help='Date the assessment was conducted',
|
|
)
|
|
|
|
completion_date = fields.Date(
|
|
string='Assessment Completion Date',
|
|
required=True,
|
|
default=fields.Date.context_today,
|
|
)
|
|
|
|
notes = fields.Text(
|
|
string='Notes',
|
|
help='Notes from the assessment',
|
|
)
|
|
|
|
override_reason = fields.Text(
|
|
string='Override Reason',
|
|
help='Mandatory when skipping the scheduling step. Explain why the assessment was completed without scheduling through the system.',
|
|
)
|
|
|
|
notify_authorizer = fields.Boolean(
|
|
string='Notify Authorizer',
|
|
default=True,
|
|
help='Send email to the authorizer about assessment completion',
|
|
)
|
|
|
|
@api.depends('sale_order_id')
|
|
def _compute_is_override(self):
|
|
for rec in self:
|
|
rec.is_override = (
|
|
rec.sale_order_id
|
|
and rec.sale_order_id.x_fc_adp_application_status == 'quotation'
|
|
)
|
|
|
|
@api.model
|
|
def default_get(self, fields_list):
|
|
res = super().default_get(fields_list)
|
|
active_id = self._context.get('active_id')
|
|
if active_id:
|
|
order = self.env['sale.order'].browse(active_id)
|
|
res['sale_order_id'] = order.id
|
|
if order.x_fc_assessment_start_date:
|
|
res['assessment_start_date'] = order.x_fc_assessment_start_date
|
|
else:
|
|
res['assessment_start_date'] = fields.Date.context_today(self)
|
|
return res
|
|
|
|
def action_complete(self):
|
|
"""Mark assessment as completed."""
|
|
self.ensure_one()
|
|
|
|
order = self.sale_order_id
|
|
current_status = order.x_fc_adp_application_status
|
|
is_override = current_status == 'quotation'
|
|
|
|
if current_status not in ('quotation', 'assessment_scheduled'):
|
|
raise UserError(
|
|
_("Can only complete assessment from 'Quotation' or 'Assessment Scheduled' status.")
|
|
)
|
|
|
|
if is_override and not (self.override_reason or '').strip():
|
|
raise UserError(
|
|
_("Override Reason is mandatory when skipping the assessment scheduling step. "
|
|
"Please explain why this assessment was completed without being scheduled through the system.")
|
|
)
|
|
|
|
if self.completion_date < self.assessment_start_date:
|
|
raise UserError(
|
|
_("Completion date (%s) cannot be before assessment start date (%s).")
|
|
% (self.completion_date, self.assessment_start_date)
|
|
)
|
|
|
|
write_vals = {
|
|
'x_fc_adp_application_status': 'assessment_completed',
|
|
'x_fc_assessment_end_date': self.completion_date,
|
|
}
|
|
if is_override or not order.x_fc_assessment_start_date:
|
|
write_vals['x_fc_assessment_start_date'] = self.assessment_start_date
|
|
|
|
order.with_context(skip_status_validation=True).write(write_vals)
|
|
|
|
if is_override:
|
|
override_html = Markup(
|
|
'<div style="background:#fff3cd;border-left:4px solid #ffc107;padding:12px;margin:8px 0;border-radius:4px;">'
|
|
'<h4 style="color:#856404;margin:0 0 8px 0;">'
|
|
'<i class="fa fa-exclamation-triangle"/> Assessment Scheduling Override</h4>'
|
|
'<p style="margin:0;"><strong>Override by:</strong> %s</p>'
|
|
'<p style="margin:4px 0 0 0;"><strong>Reason:</strong> %s</p>'
|
|
'<p style="margin:4px 0 0 0;"><strong>Assessment Date:</strong> %s to %s</p>'
|
|
'%s'
|
|
'</div>'
|
|
) % (
|
|
self.env.user.name,
|
|
self.override_reason.strip(),
|
|
self.assessment_start_date.strftime("%B %d, %Y"),
|
|
self.completion_date.strftime("%B %d, %Y"),
|
|
Markup('<p style="margin:4px 0 0 0;"><strong>Notes:</strong> %s</p>') % self.notes if self.notes else Markup(''),
|
|
)
|
|
order.message_post(
|
|
body=override_html,
|
|
message_type='notification',
|
|
subtype_xmlid='mail.mt_note',
|
|
)
|
|
else:
|
|
notes_html = (
|
|
Markup('<p style="margin:4px 0 0 0;"><strong>Notes:</strong> %s</p>') % self.notes
|
|
) if self.notes else Markup('')
|
|
|
|
order.message_post(
|
|
body=Markup(
|
|
'<div style="background:#d4edda;border-left:4px solid #28a745;padding:12px;margin:8px 0;border-radius:4px;">'
|
|
'<h4 style="color:#28a745;margin:0 0 8px 0;">'
|
|
'<i class="fa fa-check-square-o"/> Assessment Completed</h4>'
|
|
'<p style="margin:0;"><strong>Completion Date:</strong> %s</p>'
|
|
'%s'
|
|
'</div>'
|
|
) % (self.completion_date.strftime("%B %d, %Y"), notes_html),
|
|
message_type='notification',
|
|
subtype_xmlid='mail.mt_note',
|
|
)
|
|
|
|
if self.notify_authorizer:
|
|
self._send_backend_completion_email(order, is_override)
|
|
|
|
return {'type': 'ir.actions.act_window_close'}
|
|
|
|
def _send_backend_completion_email(self, order, is_override):
|
|
"""Send assessment completion email when done from backend."""
|
|
self.ensure_one()
|
|
|
|
if not order._email_is_enabled():
|
|
return
|
|
|
|
authorizer = order.x_fc_authorizer_id
|
|
if not authorizer or not authorizer.email:
|
|
_logger.info("No authorizer email for %s, skipping notification", order.name)
|
|
return
|
|
|
|
to_email = authorizer.email
|
|
cc_emails = []
|
|
if order.user_id and order.user_id.email:
|
|
cc_emails.append(order.user_id.email)
|
|
company = self.env.company
|
|
office_partners = company.sudo().x_fc_office_notification_ids
|
|
cc_emails.extend([p.email for p in office_partners if p.email])
|
|
|
|
client_name = order.partner_id.name or 'Client'
|
|
override_note = ''
|
|
if is_override:
|
|
override_note = (
|
|
'<div style="background:#fff3cd;border-left:3px solid #ffc107;padding:8px 12px;'
|
|
'margin:12px 0;border-radius:4px;">'
|
|
'<strong>Note:</strong> This assessment was completed without being scheduled '
|
|
'through the system. '
|
|
f'<strong>Reason:</strong> {self.override_reason.strip()}'
|
|
'</div>'
|
|
)
|
|
|
|
sections = [
|
|
('Assessment Details', [
|
|
('Client', client_name),
|
|
('Case', order.name),
|
|
('Assessment Date', f"{self.assessment_start_date.strftime('%B %d, %Y')} to {self.completion_date.strftime('%B %d, %Y')}"),
|
|
('Completed by', self.env.user.name),
|
|
]),
|
|
]
|
|
if self.notes:
|
|
sections.append(('Notes', [('', self.notes)]))
|
|
|
|
summary = (
|
|
f'The assessment for <strong>{client_name}</strong> ({order.name}) '
|
|
f'has been completed on {self.completion_date.strftime("%B %d, %Y")}.'
|
|
)
|
|
if is_override:
|
|
summary += f' {override_note}'
|
|
|
|
email_body = order._email_build(
|
|
title='Assessment Completed',
|
|
summary=summary,
|
|
email_type='success',
|
|
sections=sections,
|
|
note='<strong>Next step:</strong> Please submit the ADP application '
|
|
'(including pages 11-12 signed by the client) so we can proceed.',
|
|
button_url=f'{order.get_base_url()}/web#id={order.id}&model=sale.order&view_type=form',
|
|
button_text='View Case',
|
|
sender_name=order.user_id.name if order.user_id else 'The Team',
|
|
)
|
|
|
|
try:
|
|
self.env['mail.mail'].sudo().create({
|
|
'subject': f'Assessment Completed - {client_name} - {order.name}',
|
|
'body_html': email_body,
|
|
'email_to': to_email,
|
|
'email_cc': ', '.join(cc_emails) if cc_emails else False,
|
|
'model': 'sale.order',
|
|
'res_id': order.id,
|
|
'auto_delete': True,
|
|
}).send()
|
|
|
|
order.message_post(
|
|
body=Markup(
|
|
'<div class="alert alert-info" role="alert">'
|
|
'<strong>Assessment Completed email sent</strong>'
|
|
'<ul class="mb-0 mt-1"><li>To: %s</li>'
|
|
'<li>CC: %s</li></ul></div>'
|
|
) % (to_email, ', '.join(cc_emails) or 'None'),
|
|
message_type='notification',
|
|
subtype_xmlid='mail.mt_note',
|
|
)
|
|
_logger.info("Sent backend assessment completed email for %s", order.name)
|
|
except Exception as e:
|
|
_logger.error("Failed to send assessment completed email for %s: %s", order.name, e)
|