feat(fusion_portal): funding-source selector on accessibility forms (#3)

* feat(fusion_portal): funding-source selector on accessibility forms

Reps can now mark an accessibility assessment's funding source on the web form
(Private / March of Dimes / ODSP / WSIB / Hardship / Insurance / Other) so the
generated draft sale order routes to the correct funding pipeline instead of
always defaulting to private pay. Adds Hardship to the x_fc_funding_source
selection + sale_type_map; the new form <select> is auto-serialised by the
existing FormData submit, and accessibility_assessment_save now maps
funding_source -> x_fc_funding_source. The model + SO routing were already in
place (2026-04 audit fix) — this closes the form + controller gap.

Plan: docs/superpowers/plans/2026-06-02-accessibility-funding-selector.md
Spec: docs/superpowers/specs/2026-06-02-assessment-visit-funding-design.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(fusion_portal): validate funding_source in accessibility save (parity with booking)

Coerce an unexpected/tampered funding_source to direct_private instead of passing
it raw into create() (which would raise on the Selection field). Mirrors the
/book-assessment controller; the whitelist is derived from the model selection so
it auto-covers hardship and any future values.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-06-02 01:44:19 -04:00
committed by GitHub
parent b616375679
commit 4f48bab6e9
4 changed files with 69 additions and 1 deletions

View File

@@ -2493,7 +2493,14 @@ class AuthorizerPortal(CustomerPortal):
assessment_type = post.get('assessment_type')
if not assessment_type:
return {'success': False, 'error': 'Assessment type is required'}
# Funding source drives the downstream sale-order workflow; coerce
# anything unexpected to private pay (mirrors /book-assessment).
_funding_keys = dict(Assessment._fields['x_fc_funding_source'].selection)
funding_source = post.get('funding_source') or 'direct_private'
if funding_source not in _funding_keys:
funding_source = 'direct_private'
# Build assessment values
vals = {
'assessment_type': assessment_type,
@@ -2507,6 +2514,7 @@ class AuthorizerPortal(CustomerPortal):
'client_address_postal': post.get('client_address_postal', '').strip(),
'client_phone': post.get('client_phone', '').strip(),
'client_email': post.get('client_email', '').strip(),
'x_fc_funding_source': funding_source,
'notes': post.get('notes', '').strip(),
}