feat(fusion_portal): Phase 2b - ADP multi-device grouping + combination guard

The visit groups its ADP assessments by funding type onto ONE ADP order (first
device creates the SO via the existing express completion; the rest attach),
enforcing the combination rule: at most one seated-mobility device (manual WC /
power WC / scooter) + optionally one walker, no duplicates. Also fixes a Phase 1b
bug - it called action_complete() (needs signatures, returns an action dict) for
ADP; now uses action_complete_express() which returns the SO.

Untested locally (Enterprise dep) - clone verification pending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-06-02 02:31:38 -04:00
parent e0ddd9ef40
commit 89467432a7

View File

@@ -190,6 +190,22 @@ class FusionAssessmentVisit(models.Model):
) )
return sale_order return sale_order
def _validate_adp_combination(self, adp_assessments):
"""Enforce ADP device-combination rules: at most one seated-mobility
device (manual wheelchair / power wheelchair / scooter), optionally one
walker/rollator, no duplicates."""
seated_types = {'wheelchair', 'powerchair', 'scooter'}
seated = [a for a in adp_assessments if a.equipment_type in seated_types]
walkers = [a for a in adp_assessments if a.equipment_type == 'rollator']
labels = dict(self.env['fusion.assessment']._fields['equipment_type'].selection)
if len(seated) > 1:
raise UserError(_(
'An ADP order can include only one seated-mobility device '
'(manual wheelchair, power wheelchair, or scooter). This visit has: %s.'
) % ', '.join(labels.get(a.equipment_type, a.equipment_type) for a in seated))
if len(walkers) > 1:
raise UserError(_('An ADP order can include only one walker / rollator.'))
def action_complete_visit(self): def action_complete_visit(self):
"""Group the visit's accessibility assessments by funding workflow and """Group the visit's accessibility assessments by funding workflow and
create one draft SO per workflow. ADP equipment assessments keep their create one draft SO per workflow. ADP equipment assessments keep their
@@ -215,14 +231,39 @@ class FusionAssessmentVisit(models.Model):
for sale_type, group in by_sale_type.items(): for sale_type, group in by_sale_type.items():
self._create_grouped_sale_order(partner, sale_type, group) self._create_grouped_sale_order(partner, sale_type, group)
# ADP equipment assessments: complete individually (one SO each) until # ADP equipment assessments: one ADP order per funding type, with the
# Phase 2 multi-device lets several share one ADP order. # device-combination guard, reusing the existing (prod-tested) express
# completion. The first device creates the SO; the rest attach to it.
adp_by_type = {}
for assessment in self.adp_assessment_ids: for assessment in self.adp_assessment_ids:
if assessment.sale_order_id: if assessment.sale_order_id:
continue continue
so = assessment.action_complete() adp_by_type.setdefault(self._assessment_sale_type(assessment), []).append(assessment)
if so: labels = dict(self.env['fusion.assessment']._fields['equipment_type'].selection)
so.visit_id = self.id for sale_type, group in adp_by_type.items():
self._validate_adp_combination(group)
# Make sure each device carries the visit's client + OT so the
# existing completion logic has what it needs.
for assessment in group:
vals = {}
if not assessment.client_name:
vals['client_name'] = self.client_name or partner.name
if not assessment.authorizer_id and self.authorizer_id:
vals['authorizer_id'] = self.authorizer_id.id
if not assessment.partner_id:
vals['partner_id'] = partner.id
if vals:
assessment.write(vals)
primary = group[0]
sale_order = primary.action_complete_express()
sale_order.write({'visit_id': self.id, 'x_fc_sale_type': sale_type})
for extra in group[1:]:
extra.write({'state': 'completed', 'sale_order_id': sale_order.id})
sale_order.message_post(
body=Markup('<p><strong>Additional ADP device on this order:</strong> %s</p>')
% labels.get(extra.equipment_type, extra.equipment_type or 'device'),
subtype_xmlid='mail.mt_note',
)
self.write({'state': 'done', 'partner_id': partner.id}) self.write({'state': 'done', 'partner_id': partner.id})
return self._action_view_sale_orders() return self._action_view_sale_orders()