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:
@@ -190,6 +190,22 @@ class FusionAssessmentVisit(models.Model):
|
||||
)
|
||||
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):
|
||||
"""Group the visit's accessibility assessments by funding workflow and
|
||||
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():
|
||||
self._create_grouped_sale_order(partner, sale_type, group)
|
||||
|
||||
# ADP equipment assessments: complete individually (one SO each) until
|
||||
# Phase 2 multi-device lets several share one ADP order.
|
||||
# ADP equipment assessments: one ADP order per funding type, with the
|
||||
# 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:
|
||||
if assessment.sale_order_id:
|
||||
continue
|
||||
so = assessment.action_complete()
|
||||
if so:
|
||||
so.visit_id = self.id
|
||||
adp_by_type.setdefault(self._assessment_sale_type(assessment), []).append(assessment)
|
||||
labels = dict(self.env['fusion.assessment']._fields['equipment_type'].selection)
|
||||
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})
|
||||
return self._action_view_sale_orders()
|
||||
|
||||
Reference in New Issue
Block a user