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
|
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()
|
||||||
|
|||||||
Reference in New Issue
Block a user