Files
Odoo-Modules/fusion_claims/wizard/ready_for_submission_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

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'}