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
This commit is contained in:
@@ -61,6 +61,18 @@ class StatusChangeReasonWizard(models.TransientModel):
|
||||
help='Select the reason ADP denied the funding',
|
||||
)
|
||||
|
||||
# ==========================================================================
|
||||
# WITHDRAWAL INTENT (for 'withdrawn' status)
|
||||
# ==========================================================================
|
||||
withdrawal_intent = fields.Selection(
|
||||
selection=[
|
||||
('cancel', 'Cancel Application'),
|
||||
('resubmit', 'Withdraw for Correction & Resubmission'),
|
||||
],
|
||||
string='What would you like to do after withdrawal?',
|
||||
default='resubmit',
|
||||
)
|
||||
|
||||
reason = fields.Text(
|
||||
string='Reason / Additional Details',
|
||||
help='Please provide additional details for this status change.',
|
||||
@@ -181,8 +193,10 @@ class StatusChangeReasonWizard(models.TransientModel):
|
||||
}
|
||||
header_color, bg_color, border_color = status_colors.get(new_status, ('#17a2b8', '#f0f9ff', '#bee5eb'))
|
||||
|
||||
# For on_hold, also store the previous status and hold date
|
||||
# Build initial update vals
|
||||
update_vals = {'x_fc_adp_application_status': new_status}
|
||||
if new_status == 'withdrawn':
|
||||
update_vals['x_fc_previous_status_before_withdrawal'] = self.previous_status
|
||||
|
||||
# =================================================================
|
||||
# REJECTED: ADP rejected submission (within 24 hours)
|
||||
@@ -261,7 +275,7 @@ class StatusChangeReasonWizard(models.TransientModel):
|
||||
# Don't post message here - _send_on_hold_email() will post the message
|
||||
message_body = None
|
||||
elif new_status == 'withdrawn':
|
||||
# Don't post message here - _send_withdrawal_email() will post the message
|
||||
# Handled entirely below based on withdrawal_intent
|
||||
message_body = None
|
||||
elif new_status == 'cancelled':
|
||||
# Cancelled has its own detailed message posted later
|
||||
@@ -302,10 +316,129 @@ class StatusChangeReasonWizard(models.TransientModel):
|
||||
order._send_correction_needed_email(reason=reason)
|
||||
|
||||
# =================================================================
|
||||
# WITHDRAWN: Send email notification to all parties
|
||||
# WITHDRAWN: Branch based on withdrawal intent
|
||||
# =================================================================
|
||||
if new_status == 'withdrawn':
|
||||
order._send_withdrawal_email(reason=reason)
|
||||
intent = self.withdrawal_intent
|
||||
|
||||
if intent == 'cancel':
|
||||
# ---------------------------------------------------------
|
||||
# WITHDRAW & CANCEL: Cancel invoices + SO
|
||||
# ---------------------------------------------------------
|
||||
cancelled_invoices = []
|
||||
cancelled_so = False
|
||||
|
||||
# Cancel related invoices first
|
||||
invoices = order.invoice_ids.filtered(lambda inv: inv.state != 'cancel')
|
||||
for invoice in invoices:
|
||||
try:
|
||||
inv_msg = Markup(f'''
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h5 class="alert-heading"><i class="fa fa-ban"></i> Invoice Cancelled (Withdrawal)</h5>
|
||||
<ul>
|
||||
<li><strong>Related Order:</strong> {order.name}</li>
|
||||
<li><strong>Cancelled By:</strong> {user_name}</li>
|
||||
<li><strong>Date:</strong> {change_date}</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<p class="mb-0"><strong>Reason:</strong> {reason}</p>
|
||||
</div>
|
||||
''')
|
||||
invoice.message_post(
|
||||
body=inv_msg,
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
if invoice.state == 'posted':
|
||||
invoice.button_draft()
|
||||
invoice.button_cancel()
|
||||
cancelled_invoices.append(invoice.name)
|
||||
except Exception as e:
|
||||
warn_msg = Markup(f'''
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<p class="mb-0"><i class="fa fa-exclamation-triangle"></i> <strong>Warning:</strong> Could not cancel invoice {invoice.name}</p>
|
||||
<p class="mb-0 small">{str(e)}</p>
|
||||
</div>
|
||||
''')
|
||||
order.message_post(
|
||||
body=warn_msg,
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
|
||||
# Cancel the sale order itself
|
||||
if order.state not in ('cancel', 'done'):
|
||||
try:
|
||||
order._action_cancel()
|
||||
cancelled_so = True
|
||||
except Exception as e:
|
||||
warn_msg = Markup(f'''
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<p class="mb-0"><i class="fa fa-exclamation-triangle"></i> <strong>Warning:</strong> Could not cancel sale order</p>
|
||||
<p class="mb-0 small">{str(e)}</p>
|
||||
</div>
|
||||
''')
|
||||
order.message_post(
|
||||
body=warn_msg,
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
|
||||
# Build cancellation summary
|
||||
invoice_list_html = ''
|
||||
if cancelled_invoices:
|
||||
invoice_items = ''.join([f'<li>{inv}</li>' for inv in cancelled_invoices])
|
||||
invoice_list_html = f'<li><strong>Invoices Cancelled:</strong><ul>{invoice_items}</ul></li>'
|
||||
|
||||
so_status = 'Cancelled' if cancelled_so else 'Not applicable'
|
||||
summary_msg = Markup(f'''
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h5 class="alert-heading"><i class="fa fa-ban"></i> Application Withdrawn & Cancelled</h5>
|
||||
<ul>
|
||||
<li><strong>Withdrawn By:</strong> {user_name}</li>
|
||||
<li><strong>Date:</strong> {change_date}</li>
|
||||
<li><strong>Sale Order:</strong> {so_status}</li>
|
||||
{invoice_list_html}
|
||||
</ul>
|
||||
<hr>
|
||||
<p class="mb-0"><strong>Reason:</strong> {reason}</p>
|
||||
</div>
|
||||
''')
|
||||
order.message_post(
|
||||
body=summary_msg,
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
order._send_withdrawal_email(reason=reason, intent='cancel')
|
||||
|
||||
else:
|
||||
# ---------------------------------------------------------
|
||||
# WITHDRAW & RESUBMIT: Return to ready_submission
|
||||
# ---------------------------------------------------------
|
||||
order.with_context(skip_status_validation=True).write({
|
||||
'x_fc_adp_application_status': 'ready_submission',
|
||||
'x_fc_previous_status_before_withdrawal': self.previous_status,
|
||||
})
|
||||
|
||||
resubmit_msg = Markup(f'''
|
||||
<div class="alert alert-info" role="alert">
|
||||
<h5 class="alert-heading"><i class="fa fa-undo"></i> Application Withdrawn for Correction</h5>
|
||||
<ul>
|
||||
<li><strong>Withdrawn By:</strong> {user_name}</li>
|
||||
<li><strong>Date:</strong> {change_date}</li>
|
||||
<li><strong>Status Returned To:</strong> Ready for Submission</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<p class="mb-0"><strong>Reason:</strong> {reason}</p>
|
||||
<p class="mb-0 mt-2"><i class="fa fa-info-circle"></i> Make corrections and click <strong>Submit Application</strong> to resubmit.</p>
|
||||
</div>
|
||||
''')
|
||||
order.message_post(
|
||||
body=resubmit_msg,
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
order._send_withdrawal_email(reason=reason, intent='resubmit')
|
||||
|
||||
# =================================================================
|
||||
# ON HOLD: Send email notification to all parties
|
||||
|
||||
Reference in New Issue
Block a user