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:
gsinghpal
2026-04-09 07:34:17 -04:00
parent 8b2cbd9085
commit 0fe8a71c05
17 changed files with 1390 additions and 11 deletions

View File

@@ -330,6 +330,77 @@
</div>
</div>
<!-- ============================================================= -->
<!-- MOD BLANK FORMS + HANDOFF FOLLOW-UP (2026-04 update) -->
<!-- ============================================================= -->
<h2>March of Dimes — Blank Forms &amp; Handoff Follow-Up</h2>
<p class="text-muted">
Upload the latest revision of the MOD-issued blank forms here.
They are auto-attached to outgoing emails so every case uses the
current version. Re-upload whenever March of Dimes publishes a
new revision.
</p>
<div class="row mt-4 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_right_pane">
<span class="o_form_label">MOD Application Form (blank)</span>
<div class="text-muted">
Attached to the handoff email when client or authorizer
is submitting the application themselves.
</div>
<div class="mt-2">
<field name="fc_mod_application_form"
filename="fc_mod_application_form_filename"
widget="binary"/>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_right_pane">
<span class="o_form_label">Verification of Disability Form (blank)</span>
<div class="text-muted">
Attached to the VOD request email sent to the authorizer
when our office is handling the MOD submission internally.
</div>
<div class="mt-2">
<field name="fc_mod_vod_form"
filename="fc_mod_vod_form_filename"
widget="binary"/>
</div>
</div>
</div>
</div>
<div class="row mt-4 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_right_pane">
<span class="o_form_label">Handoff Follow-up Assignee</span>
<div class="text-muted">
Who gets the follow-up activity when a client or authorizer
is handling the MOD submission themselves. "Office contact"
routes all follow-ups to a single designated person. "Sales
rep" assigns to the rep on each order.
</div>
<div class="mt-2">
<field name="fc_mod_followup_assignee_mode" widget="radio"/>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_right_pane">
<span class="o_form_label">Office Follow-up Contact</span>
<div class="text-muted">
The office user who receives MOD handoff follow-up activities
when assignee mode is set to Office Contact.
</div>
<div class="mt-2">
<field name="fc_mod_followup_office_contact_id"
invisible="fc_mod_followup_assignee_mode != 'office_contact'"
options="{'no_create': True}"/>
</div>
</div>
</div>
</div>
<!-- ============================================================= -->
<!-- DATA MIGRATION -->
<!-- ============================================================= -->

View File

@@ -193,12 +193,57 @@
<!-- Exception buttons -->
<button name="action_mod_on_hold" type="object"
string="Hold" class="btn-warning" icon="fa-pause"
invisible="not x_fc_is_mod_sale or x_fc_mod_status not in ('contract_received', 'in_production', 'project_complete')"/>
invisible="not x_fc_is_mod_sale or x_fc_mod_status in ('on_hold', 'case_closed', 'cancelled', False)"/>
<button name="action_mod_resume" type="object"
string="Resume" class="btn-success" icon="fa-play"
invisible="not x_fc_is_mod_sale or x_fc_mod_status != 'on_hold'"/>
<!-- ======================================================= -->
<!-- MOD 2026-04 UPDATE — new submission-path + recovery btns -->
<!-- ======================================================= -->
<!-- Set MOD Submission Path (internal / client / authorizer) -->
<button name="action_mod_set_submission_path" type="object"
string="Set Submission Path" class="btn-info" icon="fa-sitemap"
invisible="not x_fc_is_mod_sale or x_fc_mod_status not in ('assessment_completed', 'processing_drawings', 'quote_submitted')"
help="Choose who is submitting the MOD application (our office, the client, or the authorizer)"/>
<!-- Request VOD from Authorizer (manual re-send) -->
<button name="action_mod_request_vod" type="object"
string="Request VOD from Authorizer" class="btn-warning" icon="fa-envelope"
invisible="not x_fc_is_mod_sale or x_fc_mod_submitted_by != 'internal' or x_fc_mod_vod_letter"
help="Email the authorizer the blank Verification of Disability form to complete. Fires automatically once on first setting submitted_by=internal, this button is for manual re-sends."/>
<!-- Handoff to Client/Authorizer (paths B/C) -->
<button name="action_mod_handoff_to_client" type="object"
string="Handoff Package" class="btn-primary" icon="fa-share"
invisible="not x_fc_is_mod_sale or x_fc_mod_submitted_by not in ('client', 'authorizer') or x_fc_mod_status not in ('processing_drawings', 'quote_submitted')"
confirm="This will email the full MOD application package to the client or authorizer and move the case to Handoff state. Continue?"
help="Email proposal + drawing + blank MOD application form to whoever is submitting, and move the case to handoff_to_client"/>
<!-- Confirm Submission (for handoff_to_client state) -->
<button name="action_mod_confirmed_submission" type="object"
string="Confirm Submission" class="btn-success" icon="fa-check-circle"
invisible="not x_fc_is_mod_sale or x_fc_mod_status != 'handoff_to_client'"
help="Client or authorizer confirmed they submitted the application to MOD. Record the date and advance to Awaiting Funding."/>
<!-- Recovery buttons for funding_denied -->
<button name="action_mod_resubmit_from_denied" type="object"
string="Resubmit" class="btn-primary" icon="fa-undo"
invisible="not x_fc_is_mod_sale or x_fc_mod_status != 'funding_denied'"
help="Revise and resubmit the case to March of Dimes after a denial"/>
<button name="action_mod_cancel_from_denied" type="object"
string="Cancel Case" class="btn-danger" icon="fa-times"
invisible="not x_fc_is_mod_sale or x_fc_mod_status != 'funding_denied'"
confirm="Cancel this denied MOD case? This action can be reversed with Reopen."/>
<button name="action_mod_reopen_cancelled" type="object"
string="Reopen" class="btn-info" icon="fa-refresh"
invisible="not x_fc_is_mod_sale or x_fc_mod_status != 'cancelled'"
confirm="Reopen this cancelled MOD case? Status will reset to Need to Schedule."/>
</xpath>
<!-- ============================================= -->
@@ -234,6 +279,59 @@
Upload Completion Photos and Proof of Delivery to submit to the case worker.
</div>
<!-- ===== 2026-04 MOD Update: Submission Path + Application Package ===== -->
<separator string="MOD Submission Path"/>
<div class="alert alert-secondary" role="alert"
invisible="x_fc_mod_submitted_by">
<i class="fa fa-question-circle"/> <strong>Who is submitting this application?</strong>
Click <strong>Set Submission Path</strong> in the status bar above to choose:
internal (we submit), client, or authorizer.
</div>
<group col="4">
<field name="x_fc_mod_submitted_by" readonly="1"/>
<field name="x_fc_mod_handoff_date" readonly="1"
invisible="x_fc_mod_submitted_by == 'internal'"/>
<field name="x_fc_mod_application_submitted_date" readonly="1"/>
<field name="x_fc_mod_vod_requested_date" readonly="1"
invisible="x_fc_mod_submitted_by != 'internal'"/>
<field name="x_fc_mod_accessibility_specialist_id"
options="{'no_create': True}"/>
</group>
<separator string="MOD Application Package (when WE submit on client's behalf)"
invisible="x_fc_mod_submitted_by != 'internal'"/>
<group col="2" invisible="x_fc_mod_submitted_by != 'internal'">
<field name="x_fc_mod_vod_letter"
filename="x_fc_mod_vod_letter_filename"
widget="binary"/>
<field name="x_fc_mod_application_form_doc"
filename="x_fc_mod_application_form_doc_filename"
widget="binary"/>
<field name="x_fc_mod_notice_of_assessment"
filename="x_fc_mod_notice_of_assessment_filename"
widget="binary"/>
<field name="x_fc_mod_property_tax"
filename="x_fc_mod_property_tax_filename"
widget="binary"/>
</group>
<separator string="Proposal Document"/>
<group col="2">
<field name="x_fc_mod_proposal_doc"
filename="x_fc_mod_proposal_doc_filename"
widget="binary"/>
</group>
<separator string="Funding Denial Details" invisible="x_fc_mod_status != 'funding_denied'"/>
<group invisible="x_fc_mod_status != 'funding_denied'">
<field name="x_fc_mod_funding_denial_reason" readonly="1" nolabel="1"/>
</group>
<separator string="Hold History" invisible="not x_fc_mod_previous_status_before_hold"/>
<group invisible="not x_fc_mod_previous_status_before_hold">
<field name="x_fc_mod_previous_status_before_hold" readonly="1"/>
</group>
<!-- ===== Row 1: Assessment Documents ===== -->
<div class="row">
<!-- Column 1: Assessment and Design -->