Files
Odoo-Modules/fusion_claims/wizard/application_received_wizard.py
Nexa Admin 431052920e feat: separate fusion field service and LTC into standalone modules, update core modules
- 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
2026-03-11 16:19:52 +00:00

179 lines
7.1 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 ApplicationReceivedWizard(models.TransientModel):
"""Wizard to upload ADP application documents when application is received."""
_name = 'fusion_claims.application.received.wizard'
_description = 'Application Received Wizard'
sale_order_id = fields.Many2one(
'sale.order',
string='Sale Order',
required=True,
readonly=True,
)
# Document uploads
original_application = fields.Binary(
string='Original ADP Application',
required=True,
help='Upload the original ADP application PDF received from the client',
)
original_application_filename = fields.Char(
string='Application Filename',
)
signed_pages_11_12 = fields.Binary(
string='Signed Pages 11 & 12',
help='Upload the signed pages 11 and 12 from the application. '
'Not required if a remote signing request has been sent.',
)
signed_pages_filename = fields.Char(
string='Pages Filename',
)
has_pending_page11_request = fields.Boolean(
compute='_compute_has_pending_page11_request',
)
has_signed_page11 = fields.Boolean(
compute='_compute_has_pending_page11_request',
)
notes = fields.Text(
string='Notes',
help='Any notes about the received application',
)
@api.depends('sale_order_id')
def _compute_has_pending_page11_request(self):
for wiz in self:
order = wiz.sale_order_id
if order:
requests = order.page11_sign_request_ids
wiz.has_pending_page11_request = bool(
requests.filtered(lambda r: r.state in ('draft', 'sent'))
)
wiz.has_signed_page11 = bool(
order.x_fc_signed_pages_11_12
or requests.filtered(lambda r: r.state == 'signed')
)
else:
wiz.has_pending_page11_request = False
wiz.has_signed_page11 = False
@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_original_application:
res['original_application'] = order.x_fc_original_application
res['original_application_filename'] = order.x_fc_original_application_filename
if order.x_fc_signed_pages_11_12:
res['signed_pages_11_12'] = order.x_fc_signed_pages_11_12
res['signed_pages_filename'] = order.x_fc_signed_pages_filename
return res
@api.constrains('original_application_filename')
def _check_application_file_type(self):
for wizard in self:
if wizard.original_application_filename:
if not wizard.original_application_filename.lower().endswith('.pdf'):
raise UserError(
"Original Application must be a PDF file.\n"
f"Uploaded file: '{wizard.original_application_filename}'"
)
@api.constrains('signed_pages_filename')
def _check_pages_file_type(self):
for wizard in self:
if wizard.signed_pages_filename:
if not wizard.signed_pages_filename.lower().endswith('.pdf'):
raise UserError(
"Signed Pages 11 & 12 must be a PDF file.\n"
f"Uploaded file: '{wizard.signed_pages_filename}'"
)
def action_confirm(self):
"""Save documents and mark application as received."""
self.ensure_one()
order = self.sale_order_id
if order.x_fc_adp_application_status not in ('assessment_completed', 'waiting_for_application'):
raise UserError("Can only receive application from 'Waiting for Application' status.")
if not self.original_application:
raise UserError("Please upload the Original ADP Application.")
page11_covered = bool(
self.signed_pages_11_12
or order.x_fc_signed_pages_11_12
or order.page11_sign_request_ids.filtered(
lambda r: r.state in ('sent', 'signed')
)
)
if not page11_covered:
raise UserError(
"Signed Pages 11 & 12 are required.\n\n"
"You can either upload the file here, or use the "
"'Request Page 11 Signature' button on the sale order "
"to send it for remote signing before confirming."
)
vals = {
'x_fc_adp_application_status': 'application_received',
'x_fc_original_application': self.original_application,
'x_fc_original_application_filename': self.original_application_filename,
}
if self.signed_pages_11_12:
vals['x_fc_signed_pages_11_12'] = self.signed_pages_11_12
vals['x_fc_signed_pages_filename'] = self.signed_pages_filename
order.with_context(skip_status_validation=True).write(vals)
# Post to chatter
from datetime import date
notes_html = f'<p style="margin: 4px 0 0 0;"><strong>Notes:</strong> {self.notes}</p>' if self.notes else ''
order.message_post(
body=Markup(
'<div style="background: #e8f4fd; border-left: 4px solid #17a2b8; padding: 12px; margin: 8px 0; border-radius: 4px;">'
'<h4 style="color: #17a2b8; margin: 0 0 8px 0;"><i class="fa fa-file-text-o"/> Application Received</h4>'
f'<p style="margin: 0;"><strong>Date:</strong> {date.today().strftime("%B %d, %Y")}</p>'
'<p style="margin: 8px 0 4px 0;"><strong>Documents Uploaded:</strong></p>'
'<ul style="margin: 0; padding-left: 20px;">'
f'<li><i class="fa fa-check text-success"/> Original ADP Application: {self.original_application_filename}</li>'
f'<li><i class="fa fa-check text-success"/> Signed Pages 11 & 12: {self.signed_pages_filename}</li>'
'</ul>'
f'{notes_html}'
'</div>'
),
message_type='notification',
subtype_xmlid='mail.mt_note',
)
return {'type': 'ir.actions.act_window_close'}
def action_request_page11_signature(self):
"""Open the Page 11 remote signing wizard from within the Application Received wizard."""
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': 'Request Page 11 Signature',
'res_model': 'fusion_claims.send.page11.wizard',
'view_mode': 'form',
'target': 'new',
'context': {'default_sale_order_id': self.sale_order_id.id},
}