- 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
197 lines
8.4 KiB
Python
197 lines
8.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
|
|
from datetime import date
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ReadyForSubmissionWizard(models.TransientModel):
|
|
"""Wizard to collect required fields before marking as Ready for Submission."""
|
|
_name = 'fusion_claims.ready.for.submission.wizard'
|
|
_description = 'Ready for Submission Wizard'
|
|
|
|
sale_order_id = fields.Many2one(
|
|
'sale.order',
|
|
string='Sale Order',
|
|
required=True,
|
|
readonly=True,
|
|
)
|
|
|
|
# Authorization Details
|
|
claim_authorization_date = fields.Date(
|
|
string='Claim Authorization Date',
|
|
required=True,
|
|
default=fields.Date.context_today,
|
|
help='Date when the claim was authorized by the OT/Authorizer',
|
|
)
|
|
|
|
# Client References (may already be filled)
|
|
client_ref_1 = fields.Char(
|
|
string='Client Reference 1',
|
|
help='First two letters of the client\'s first name and last two letters of their last name. Example: John Doe = JODO',
|
|
)
|
|
client_ref_2 = fields.Char(
|
|
string='Client Reference 2',
|
|
help='Last four digits of the client\'s health card number. Example: 1234',
|
|
)
|
|
|
|
# Reason for Application
|
|
reason_for_application = fields.Selection([
|
|
('first_access', 'First Time Access - NO previous ADP'),
|
|
('additions', 'Additions'),
|
|
('mod_non_adp', 'Modification/Upgrade - Original NOT through ADP'),
|
|
('mod_adp', 'Modification/Upgrade - Original through ADP'),
|
|
('replace_status', 'Replacement - Change in Status'),
|
|
('replace_size', 'Replacement - Change in Body Size'),
|
|
('replace_worn', 'Replacement - Worn out (past useful life)'),
|
|
('replace_lost', 'Replacement - Lost'),
|
|
('replace_stolen', 'Replacement - Stolen'),
|
|
('replace_damaged', 'Replacement - Damaged beyond repair'),
|
|
('replace_no_longer_meets', 'Replacement - No longer meets needs'),
|
|
('growth', 'Growth/Change in condition'),
|
|
], string='Reason for Application')
|
|
|
|
# Previous Funding (required for some reasons)
|
|
requires_previous_funding = fields.Boolean(
|
|
string='Requires Previous Funding Date',
|
|
compute='_compute_requires_previous_funding',
|
|
)
|
|
previous_funding_date = fields.Date(
|
|
string='Previous Funding Date',
|
|
help='Date of previous ADP funding (required for modifications/replacements)',
|
|
)
|
|
|
|
# Show which fields are already filled
|
|
has_authorization_date = fields.Boolean(compute='_compute_field_status')
|
|
has_client_refs = fields.Boolean(compute='_compute_field_status')
|
|
has_reason = fields.Boolean(compute='_compute_field_status')
|
|
has_documents = fields.Boolean(compute='_compute_field_status')
|
|
|
|
notes = fields.Text(
|
|
string='Notes',
|
|
help='Any notes about the submission preparation',
|
|
)
|
|
|
|
@api.depends('reason_for_application')
|
|
def _compute_requires_previous_funding(self):
|
|
no_prev_funding_reasons = ['first_access', 'mod_non_adp']
|
|
for wizard in self:
|
|
reason = wizard.reason_for_application
|
|
wizard.requires_previous_funding = bool(reason) and reason not in no_prev_funding_reasons
|
|
|
|
@api.depends('sale_order_id')
|
|
def _compute_field_status(self):
|
|
for wizard in self:
|
|
order = wizard.sale_order_id
|
|
wizard.has_authorization_date = bool(order.x_fc_claim_authorization_date)
|
|
wizard.has_client_refs = bool(order.x_fc_client_ref_1 and order.x_fc_client_ref_2)
|
|
wizard.has_reason = bool(order.x_fc_reason_for_application)
|
|
wizard.has_documents = bool(order.x_fc_original_application and order.x_fc_signed_pages_11_12)
|
|
|
|
@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
|
|
# Pre-fill from existing values
|
|
if order.x_fc_claim_authorization_date:
|
|
res['claim_authorization_date'] = order.x_fc_claim_authorization_date
|
|
if order.x_fc_client_ref_1:
|
|
res['client_ref_1'] = order.x_fc_client_ref_1
|
|
if order.x_fc_client_ref_2:
|
|
res['client_ref_2'] = order.x_fc_client_ref_2
|
|
if order.x_fc_reason_for_application:
|
|
res['reason_for_application'] = order.x_fc_reason_for_application
|
|
if order.x_fc_previous_funding_date:
|
|
res['previous_funding_date'] = order.x_fc_previous_funding_date
|
|
return res
|
|
|
|
def action_confirm(self):
|
|
"""Validate and mark as ready for submission."""
|
|
self.ensure_one()
|
|
|
|
order = self.sale_order_id
|
|
|
|
if order.x_fc_adp_application_status != 'application_received':
|
|
raise UserError("Can only mark ready for submission from 'Application Received' status.")
|
|
|
|
# Validate required fields
|
|
missing = []
|
|
|
|
if not self.claim_authorization_date:
|
|
missing.append('Claim Authorization Date')
|
|
if not self.client_ref_1 and not order.x_fc_client_ref_1:
|
|
missing.append('Client Reference 1')
|
|
if not self.client_ref_2 and not order.x_fc_client_ref_2:
|
|
missing.append('Client Reference 2')
|
|
if not self.reason_for_application and not order.x_fc_reason_for_application:
|
|
missing.append('Reason for Application')
|
|
|
|
# Check previous funding if required
|
|
reason = self.reason_for_application or order.x_fc_reason_for_application
|
|
no_prev_funding_reasons = ['first_access', 'mod_non_adp']
|
|
if reason and reason not in no_prev_funding_reasons:
|
|
if not self.previous_funding_date and not order.x_fc_previous_funding_date:
|
|
missing.append('Previous Funding Date')
|
|
|
|
# Check documents
|
|
if not order.x_fc_original_application:
|
|
missing.append('Original ADP Application (upload in Application Received step)')
|
|
if not order.x_fc_signed_pages_11_12:
|
|
missing.append('Page 11 & 12 Signed (upload in Application Received step)')
|
|
|
|
if missing:
|
|
raise UserError(
|
|
"Cannot mark as Ready for Submission.\n\n"
|
|
"Required fields/documents missing:\n• " + "\n• ".join(missing)
|
|
)
|
|
|
|
# Build update values
|
|
update_vals = {
|
|
'x_fc_adp_application_status': 'ready_submission',
|
|
'x_fc_claim_authorization_date': self.claim_authorization_date,
|
|
}
|
|
|
|
# Only update if new values provided
|
|
if self.client_ref_1:
|
|
update_vals['x_fc_client_ref_1'] = self.client_ref_1
|
|
if self.client_ref_2:
|
|
update_vals['x_fc_client_ref_2'] = self.client_ref_2
|
|
if self.reason_for_application:
|
|
update_vals['x_fc_reason_for_application'] = self.reason_for_application
|
|
if self.previous_funding_date:
|
|
update_vals['x_fc_previous_funding_date'] = self.previous_funding_date
|
|
|
|
# Update sale order
|
|
order.with_context(skip_status_validation=True).write(update_vals)
|
|
|
|
# Post to chatter
|
|
reason_label = ''
|
|
if self.reason_for_application:
|
|
reason_label = dict(self._fields['reason_for_application'].selection or []).get(
|
|
self.reason_for_application, ''
|
|
)
|
|
|
|
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"/> Ready for Submission</h4>'
|
|
f'<p style="margin: 0;"><strong>Authorization Date:</strong> {self.claim_authorization_date.strftime("%B %d, %Y")}</p>'
|
|
f'{f"<p style=\'margin: 4px 0 0 0;\'><strong>Reason:</strong> {reason_label}</p>" if reason_label else ""}'
|
|
'<p style="margin: 8px 0 0 0; color: #666;">Application is ready to be submitted to ADP. Use "Submit Application" to proceed.</p>'
|
|
'</div>'
|
|
),
|
|
message_type='notification',
|
|
subtype_xmlid='mail.mt_note',
|
|
)
|
|
|
|
return {'type': 'ir.actions.act_window_close'}
|