fusion_claims: MOD workflow rework — two-assessment split, 3 submission paths, recovery actions (v19.0.8.0.3)
Reworks the March of Dimes workflow to match reality: the OT does their own disability assessment and provides the VOD letter; our accessibility specialist then visits to produce the proposal/drawings/quote; and the application can be submitted by us (internal), the client, or the authorizer themselves. The old workflow flattened all this into one assessment state with a dead-end funding_denied and no document tracking. Data model (13 new sale.order fields): - 5 new document binaries + filenames: VOD letter, Application Form (filled), Notice of Assessment, Property Tax, Proposal Document - x_fc_mod_submitted_by Selection (internal/client/authorizer) - x_fc_mod_handoff_date, x_fc_mod_vod_requested_date - x_fc_mod_accessibility_specialist_id (m2o res.partner — internal or external) - x_fc_mod_previous_status_before_hold (for proper resume) - x_fc_mod_funding_denial_reason (captured via wizard) Settings (4 res.company fields + res_config_settings mirrors): - x_fc_mod_application_form (blank) + filename - x_fc_mod_vod_form (blank) + filename - x_fc_mod_followup_assignee_mode (office_contact / sales_rep) - x_fc_mod_followup_office_contact_id res.partner: added 'accessibility_specialist' to x_fc_contact_type. State machine: - New state handoff_to_client between quote_submitted and awaiting_funding, used for paths B/C (client or authorizer submits themselves) - Fixed action_mod_on_hold to save x_fc_mod_previous_status_before_hold - Fixed action_mod_resume to restore previous status (was hardcoded to in_production, losing context for cases held earlier) 4 new wizards: - mod_submission_path_wizard — chooses submitted_by, auto-fires VOD request email on first switch to 'internal' - mod_funding_denied_wizard — captures denial category + reason - mod_resubmit_wizard — revises + resubmits denied cases (with optional doc clearing) - mod_submission_confirmed_wizard — records client/authorizer confirmed submission, advances to awaiting_funding 8 new action methods: - action_mod_set_submission_path, action_mod_request_vod, action_mod_handoff_to_client (validates docs, fires handoff email), action_mod_confirmed_submission, action_mod_resubmit_from_denied, action_mod_cancel_from_denied, action_mod_reopen_cancelled - action_mod_funding_denied now opens the denial wizard 3 new email methods + 2 existing fixes: - _send_mod_vod_request_email — auto-attaches blank VOD form from company settings, sent to authorizer when we are handling submission - _send_mod_handoff_email — two templates (client vs authorizer), attaches proposal + drawing + blank MOD Application Form - _mod_company_attachment helper for building attachments from company Binary - Fixed _send_mod_assessment_completed_email to include authorizer - Fixed _send_mod_pod_submitted_email to include client New cron: - _cron_mod_handoff_followup (daily 09:00) — creates mail.activity for office to confirm MOD submission. Assignee via company setting (office contact or sales rep). Uses existing rolling-window cap (2/month per order). Views: - sale_order form: new status-bar buttons (set path, request VOD, handoff, confirm, resubmit, cancel, reopen), new document section in MOD Documents tab with submission-path tracking, denial details, hold history - res_config_settings: new MOD blank forms upload + assignee config Deployed to odoo-westin (westin-v19) and odoo-mobility (mobility). Pre-deploy FK cleanup from earlier session means mobility updated cleanly without workaround. HTTP 200 on both, cron verified active, all new fields present.
This commit is contained in:
@@ -23,6 +23,10 @@ from . import send_to_mod_wizard
|
||||
from . import mod_awaiting_funding_wizard
|
||||
from . import mod_funding_approved_wizard
|
||||
from . import mod_pca_received_wizard
|
||||
from . import mod_submission_path_wizard
|
||||
from . import mod_funding_denied_wizard
|
||||
from . import mod_resubmit_wizard
|
||||
from . import mod_submission_confirmed_wizard
|
||||
from . import odsp_sa_mobility_wizard
|
||||
from . import odsp_discretionary_wizard
|
||||
from . import odsp_pre_approved_wizard
|
||||
|
||||
84
fusion_claims/wizard/mod_funding_denied_wizard.py
Normal file
84
fusion_claims/wizard/mod_funding_denied_wizard.py
Normal file
@@ -0,0 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2024-2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
"""
|
||||
MOD Funding Denied Wizard — captures the denial reason and sets the order
|
||||
status. Previously action_mod_funding_denied was a bare write with no reason
|
||||
capture; this wizard replaces that flow.
|
||||
"""
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from markupsafe import Markup
|
||||
|
||||
|
||||
class ModFundingDeniedWizard(models.TransientModel):
|
||||
_name = 'fusion_claims.mod.funding.denied.wizard'
|
||||
_description = 'MOD - Funding Denied Reason Capture'
|
||||
|
||||
sale_order_id = fields.Many2one('sale.order', required=True, readonly=True)
|
||||
denial_date = fields.Date(
|
||||
string='Denial Date',
|
||||
required=True,
|
||||
default=fields.Date.context_today,
|
||||
)
|
||||
denial_reason_category = fields.Selection(
|
||||
selection=[
|
||||
('income_too_high', 'Client income exceeds MOD threshold'),
|
||||
('residency', 'Residency requirement not met'),
|
||||
('project_scope', 'Project scope not eligible'),
|
||||
('missing_docs', 'Missing documentation'),
|
||||
('funding_depleted', 'MOD funding depleted for this period'),
|
||||
('other', 'Other'),
|
||||
],
|
||||
string='Denial Category',
|
||||
required=True,
|
||||
)
|
||||
denial_reason = fields.Text(
|
||||
string='Denial Details',
|
||||
required=True,
|
||||
help='MOD\'s stated reason for denying funding. Captured for the '
|
||||
'audit trail and used when generating the client denial email.',
|
||||
)
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
if self.env.context.get('active_id'):
|
||||
order = self.env['sale.order'].browse(self.env.context['active_id'])
|
||||
res['sale_order_id'] = order.id
|
||||
return res
|
||||
|
||||
def action_confirm(self):
|
||||
self.ensure_one()
|
||||
order = self.sale_order_id
|
||||
if order.x_fc_mod_status not in ('awaiting_funding', 'quote_submitted', 'handoff_to_client'):
|
||||
raise UserError(
|
||||
_("Funding can only be denied from awaiting_funding, "
|
||||
"quote_submitted or handoff_to_client. Current: %s") % order.x_fc_mod_status
|
||||
)
|
||||
|
||||
labels = dict(self._fields['denial_reason_category'].selection)
|
||||
category_label = labels.get(self.denial_reason_category, self.denial_reason_category)
|
||||
full_reason = f'[{category_label}] {self.denial_reason}'
|
||||
|
||||
order.write({
|
||||
'x_fc_mod_status': 'funding_denied',
|
||||
'x_fc_mod_funding_denial_reason': full_reason,
|
||||
})
|
||||
|
||||
body = (
|
||||
f'<div class="alert alert-danger" role="alert">'
|
||||
f'<strong><i class="fa fa-ban"></i> Funding Denied by March of Dimes</strong>'
|
||||
f'<ul>'
|
||||
f'<li><strong>Date:</strong> {self.denial_date.strftime("%B %d, %Y")}</li>'
|
||||
f'<li><strong>Category:</strong> {category_label}</li>'
|
||||
f'<li><strong>Details:</strong> {self.denial_reason}</li>'
|
||||
f'</ul>'
|
||||
f'</div>'
|
||||
)
|
||||
order.message_post(
|
||||
body=Markup(body),
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
40
fusion_claims/wizard/mod_funding_denied_wizard_views.xml
Normal file
40
fusion_claims/wizard/mod_funding_denied_wizard_views.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_mod_funding_denied_wizard_form" model="ir.ui.view">
|
||||
<field name="name">fusion_claims.mod.funding.denied.wizard.form</field>
|
||||
<field name="model">fusion_claims.mod.funding.denied.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="MOD Funding Denied">
|
||||
<sheet>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<strong><i class="fa fa-ban"/> Record MOD Funding Denial</strong>
|
||||
<p class="mb-0 mt-2">
|
||||
Capture the denial reason from March of Dimes. This will be logged
|
||||
to the case history and included in the notification sent to the
|
||||
client and authorizer.
|
||||
</p>
|
||||
</div>
|
||||
<field name="sale_order_id" invisible="1"/>
|
||||
<group>
|
||||
<field name="denial_date"/>
|
||||
<field name="denial_reason_category" required="1"/>
|
||||
<field name="denial_reason" required="1"
|
||||
placeholder="Paste or summarise MOD's stated reason..."/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="action_confirm" type="object"
|
||||
string="Record Denial" class="btn-danger"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_mod_funding_denied_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Funding Denied by MOD</field>
|
||||
<field name="res_model">fusion_claims.mod.funding.denied.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
87
fusion_claims/wizard/mod_resubmit_wizard.py
Normal file
87
fusion_claims/wizard/mod_resubmit_wizard.py
Normal file
@@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2024-2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
"""
|
||||
MOD Resubmit Wizard — lets the office revise an order that MOD has denied,
|
||||
and kick it back into the workflow at `processing_drawings` so the specialist
|
||||
can update drawings/proposal/quotation before it is re-submitted to MOD.
|
||||
"""
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from markupsafe import Markup
|
||||
|
||||
|
||||
class ModResubmitWizard(models.TransientModel):
|
||||
_name = 'fusion_claims.mod.resubmit.wizard'
|
||||
_description = 'MOD - Resubmit After Denial'
|
||||
|
||||
sale_order_id = fields.Many2one('sale.order', required=True, readonly=True)
|
||||
revision_notes = fields.Text(
|
||||
string='Revision Notes',
|
||||
required=True,
|
||||
help='Describe what is being revised for the resubmission '
|
||||
'(scope changes, updated pricing, additional documentation, etc).',
|
||||
)
|
||||
clear_old_documents = fields.Boolean(
|
||||
string='Clear old drawings / proposal / quotation',
|
||||
default=False,
|
||||
help='Tick this if the new submission needs entirely new drawings and '
|
||||
'proposal. The previous documents are preserved in chatter before '
|
||||
'being cleared.',
|
||||
)
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
if self.env.context.get('active_id'):
|
||||
order = self.env['sale.order'].browse(self.env.context['active_id'])
|
||||
res['sale_order_id'] = order.id
|
||||
return res
|
||||
|
||||
def action_confirm(self):
|
||||
self.ensure_one()
|
||||
order = self.sale_order_id
|
||||
if order.x_fc_mod_status != 'funding_denied':
|
||||
raise UserError(_("Only denied orders can be resubmitted via this wizard."))
|
||||
|
||||
if self.clear_old_documents:
|
||||
# Preserve the old docs in chatter before clearing them.
|
||||
preserved = []
|
||||
if order.x_fc_mod_drawing:
|
||||
preserved.append('Drawing')
|
||||
if order.x_fc_mod_proposal_doc:
|
||||
preserved.append('Proposal')
|
||||
if preserved:
|
||||
order.message_post(
|
||||
body=Markup(
|
||||
f'<div class="alert alert-warning" role="alert">'
|
||||
f'<strong>Previous documents cleared for resubmission:</strong> '
|
||||
f'{", ".join(preserved)}<br/>'
|
||||
f'See prior chatter for the originals.'
|
||||
f'</div>'
|
||||
),
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
order.with_context(skip_status_emails=True).write({
|
||||
'x_fc_mod_drawing': False,
|
||||
'x_fc_mod_drawing_filename': False,
|
||||
'x_fc_mod_proposal_doc': False,
|
||||
'x_fc_mod_proposal_doc_filename': False,
|
||||
})
|
||||
|
||||
order.with_context(skip_status_emails=True).write({
|
||||
'x_fc_mod_status': 'processing_drawings',
|
||||
})
|
||||
body = (
|
||||
f'<div class="alert alert-info" role="alert">'
|
||||
f'<strong><i class="fa fa-undo"></i> Resubmitting to March of Dimes after denial</strong>'
|
||||
f'<p class="mb-0 mt-2"><strong>Revision notes:</strong> {self.revision_notes}</p>'
|
||||
f'</div>'
|
||||
)
|
||||
order.message_post(
|
||||
body=Markup(body),
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
39
fusion_claims/wizard/mod_resubmit_wizard_views.xml
Normal file
39
fusion_claims/wizard/mod_resubmit_wizard_views.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_mod_resubmit_wizard_form" model="ir.ui.view">
|
||||
<field name="name">fusion_claims.mod.resubmit.wizard.form</field>
|
||||
<field name="model">fusion_claims.mod.resubmit.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Resubmit to MOD">
|
||||
<sheet>
|
||||
<div class="alert alert-info" role="alert">
|
||||
<strong><i class="fa fa-undo"/> Resubmit Denied Application</strong>
|
||||
<p class="mb-0 mt-2">
|
||||
Return this denied case to <strong>Processing Drawings</strong> so the
|
||||
accessibility specialist can update the proposal, drawings, or quote
|
||||
before resubmitting to March of Dimes.
|
||||
</p>
|
||||
</div>
|
||||
<field name="sale_order_id" invisible="1"/>
|
||||
<group>
|
||||
<field name="revision_notes" required="1"
|
||||
placeholder="What is being revised? Scope change, updated pricing, new docs..."/>
|
||||
<field name="clear_old_documents"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="action_confirm" type="object"
|
||||
string="Resubmit" class="btn-primary"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_mod_resubmit_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Resubmit to MOD</field>
|
||||
<field name="res_model">fusion_claims.mod.resubmit.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
92
fusion_claims/wizard/mod_submission_confirmed_wizard.py
Normal file
92
fusion_claims/wizard/mod_submission_confirmed_wizard.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2024-2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
"""
|
||||
MOD Submission Confirmed Wizard — office confirms that a client or authorizer
|
||||
has submitted the application to MOD, captures the actual submission date,
|
||||
and advances the order from handoff_to_client to awaiting_funding.
|
||||
"""
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from markupsafe import Markup
|
||||
|
||||
|
||||
class ModSubmissionConfirmedWizard(models.TransientModel):
|
||||
_name = 'fusion_claims.mod.submission.confirmed.wizard'
|
||||
_description = 'MOD - Confirm Application Submitted'
|
||||
|
||||
sale_order_id = fields.Many2one('sale.order', required=True, readonly=True)
|
||||
submitted_by_label = fields.Char(string='Submitted By', readonly=True)
|
||||
application_submitted_date = fields.Date(
|
||||
string='Actual Submission Date',
|
||||
required=True,
|
||||
default=fields.Date.context_today,
|
||||
help='Date the client or authorizer told us they actually submitted '
|
||||
'the application to March of Dimes.',
|
||||
)
|
||||
confirmation_source = fields.Selection(
|
||||
selection=[
|
||||
('phone_call', 'Phone call with client'),
|
||||
('email', 'Email from client'),
|
||||
('client_portal', 'Client used our portal'),
|
||||
('authorizer', 'Confirmed by authorizer (OT)'),
|
||||
('other', 'Other'),
|
||||
],
|
||||
string='How was this confirmed?',
|
||||
required=True,
|
||||
default='phone_call',
|
||||
)
|
||||
confirmation_notes = fields.Text(
|
||||
string='Notes from confirmation',
|
||||
help='What did the client say? Confirmation number from MOD if given?',
|
||||
)
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
if self.env.context.get('active_id'):
|
||||
order = self.env['sale.order'].browse(self.env.context['active_id'])
|
||||
res['sale_order_id'] = order.id
|
||||
path_labels = {
|
||||
'internal': 'We (internal)',
|
||||
'client': 'Client',
|
||||
'authorizer': 'Authorizer (OT)',
|
||||
}
|
||||
res['submitted_by_label'] = path_labels.get(
|
||||
order.x_fc_mod_submitted_by, 'Unknown')
|
||||
return res
|
||||
|
||||
def action_confirm(self):
|
||||
self.ensure_one()
|
||||
order = self.sale_order_id
|
||||
if order.x_fc_mod_status != 'handoff_to_client':
|
||||
raise UserError(
|
||||
_("This wizard is only for orders that have been handed off "
|
||||
"to the client or authorizer for submission. Current status: %s")
|
||||
% order.x_fc_mod_status
|
||||
)
|
||||
|
||||
order.write({
|
||||
'x_fc_mod_status': 'awaiting_funding',
|
||||
'x_fc_mod_application_submitted_date': self.application_submitted_date,
|
||||
})
|
||||
|
||||
source_labels = dict(self._fields['confirmation_source'].selection)
|
||||
body = (
|
||||
f'<div class="alert alert-success" role="alert">'
|
||||
f'<strong><i class="fa fa-check-circle"></i> Application Submission Confirmed</strong>'
|
||||
f'<ul>'
|
||||
f'<li><strong>Submitted By:</strong> {self.submitted_by_label}</li>'
|
||||
f'<li><strong>Submission Date:</strong> {self.application_submitted_date.strftime("%B %d, %Y")}</li>'
|
||||
f'<li><strong>Confirmed Via:</strong> {source_labels[self.confirmation_source]}</li>'
|
||||
f'</ul>'
|
||||
)
|
||||
if self.confirmation_notes:
|
||||
body += f'<p class="mb-0"><strong>Notes:</strong> {self.confirmation_notes}</p>'
|
||||
body += '</div>'
|
||||
order.message_post(
|
||||
body=Markup(body),
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_mod_submission_confirmed_wizard_form" model="ir.ui.view">
|
||||
<field name="name">fusion_claims.mod.submission.confirmed.wizard.form</field>
|
||||
<field name="model">fusion_claims.mod.submission.confirmed.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Confirm MOD Submission">
|
||||
<sheet>
|
||||
<div class="alert alert-success" role="alert">
|
||||
<strong><i class="fa fa-check-circle"/> Confirm Application Submission</strong>
|
||||
<p class="mb-0 mt-2">
|
||||
Record that the <strong>client</strong> or <strong>authorizer</strong>
|
||||
has actually submitted the application to March of Dimes. The order
|
||||
will advance to <strong>Awaiting Funding</strong>.
|
||||
</p>
|
||||
</div>
|
||||
<field name="sale_order_id" invisible="1"/>
|
||||
<group>
|
||||
<field name="submitted_by_label" readonly="1"/>
|
||||
<field name="application_submitted_date" required="1"/>
|
||||
<field name="confirmation_source" required="1"/>
|
||||
<field name="confirmation_notes"
|
||||
placeholder="What did the client say? Any reference number from MOD?"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="action_confirm" type="object"
|
||||
string="Confirm Submission" class="btn-primary"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_mod_submission_confirmed_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Confirm MOD Submission</field>
|
||||
<field name="res_model">fusion_claims.mod.submission.confirmed.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
76
fusion_claims/wizard/mod_submission_path_wizard.py
Normal file
76
fusion_claims/wizard/mod_submission_path_wizard.py
Normal file
@@ -0,0 +1,76 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2024-2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
"""
|
||||
MOD Submission Path Wizard — asks the office which party is submitting the
|
||||
March of Dimes application. Sets x_fc_mod_submitted_by on the order and,
|
||||
when the path is 'internal', auto-triggers the VOD request email to the
|
||||
authorizer the first time it is selected.
|
||||
"""
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from markupsafe import Markup
|
||||
|
||||
|
||||
class ModSubmissionPathWizard(models.TransientModel):
|
||||
_name = 'fusion_claims.mod.submission.path.wizard'
|
||||
_description = 'MOD - Set Submission Path'
|
||||
|
||||
sale_order_id = fields.Many2one('sale.order', required=True, readonly=True)
|
||||
submitted_by = fields.Selection(
|
||||
selection=[
|
||||
('internal', 'We submit on client\'s behalf'),
|
||||
('client', 'Client submits themselves'),
|
||||
('authorizer', 'Authorizer (OT) submits'),
|
||||
],
|
||||
string='Who is submitting to March of Dimes?',
|
||||
required=True,
|
||||
)
|
||||
notes = fields.Text(string='Notes')
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
if self.env.context.get('active_id'):
|
||||
order = self.env['sale.order'].browse(self.env.context['active_id'])
|
||||
res['sale_order_id'] = order.id
|
||||
if order.x_fc_mod_submitted_by:
|
||||
res['submitted_by'] = order.x_fc_mod_submitted_by
|
||||
return res
|
||||
|
||||
def action_confirm(self):
|
||||
self.ensure_one()
|
||||
order = self.sale_order_id
|
||||
previous = order.x_fc_mod_submitted_by
|
||||
vals = {'x_fc_mod_submitted_by': self.submitted_by}
|
||||
order.with_context(skip_status_emails=True).write(vals)
|
||||
|
||||
labels = dict(self._fields['submitted_by'].selection)
|
||||
body = (
|
||||
f'<div class="alert alert-info" role="alert">'
|
||||
f'<strong>MOD submission path set:</strong> {labels[self.submitted_by]}'
|
||||
)
|
||||
if self.notes:
|
||||
body += f'<br/>{self.notes}'
|
||||
body += '</div>'
|
||||
order.message_post(
|
||||
body=Markup(body),
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
|
||||
# First-time internal path → auto-trigger the VOD request email so
|
||||
# the authorizer knows to fill and send the VOD form back.
|
||||
if (
|
||||
self.submitted_by == 'internal'
|
||||
and previous != 'internal'
|
||||
and not order.x_fc_mod_vod_requested_date
|
||||
):
|
||||
try:
|
||||
order._send_mod_vod_request_email()
|
||||
except Exception:
|
||||
# Don't block the wizard if the email fails — office can
|
||||
# retry via the manual "Request VOD" button.
|
||||
pass
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
39
fusion_claims/wizard/mod_submission_path_wizard_views.xml
Normal file
39
fusion_claims/wizard/mod_submission_path_wizard_views.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_mod_submission_path_wizard_form" model="ir.ui.view">
|
||||
<field name="name">fusion_claims.mod.submission.path.wizard.form</field>
|
||||
<field name="model">fusion_claims.mod.submission.path.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Set MOD Submission Path">
|
||||
<sheet>
|
||||
<div class="alert alert-info" role="alert">
|
||||
<strong><i class="fa fa-info-circle"/> Who is submitting this application to March of Dimes?</strong>
|
||||
<p class="mb-0 mt-2">
|
||||
This determines which document gates apply and whether we hand off materials
|
||||
to the client or authorizer for them to submit. Selecting
|
||||
<strong>"We submit on client's behalf"</strong> will automatically email the
|
||||
authorizer the blank Verification of Disability form to complete.
|
||||
</p>
|
||||
</div>
|
||||
<field name="sale_order_id" invisible="1"/>
|
||||
<group>
|
||||
<field name="submitted_by" widget="radio" required="1"/>
|
||||
<field name="notes" placeholder="Optional notes..."/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="action_confirm" type="object"
|
||||
string="Confirm" class="btn-primary"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_mod_submission_path_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Set MOD Submission Path</field>
|
||||
<field name="res_model">fusion_claims.mod.submission.path.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user