diff --git a/fusion_portal/__manifest__.py b/fusion_portal/__manifest__.py index 7e7ae2f4..d87fcb75 100644 --- a/fusion_portal/__manifest__.py +++ b/fusion_portal/__manifest__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- { 'name': 'Fusion Authorizer & Sales Portal', - 'version': '19.0.2.9.0', + 'version': '19.0.2.10.0', 'category': 'Sales/Portal', 'summary': 'Portal for Authorizers (OTs) and Sales Reps with Assessment Forms', 'description': """ diff --git a/fusion_portal/controllers/portal_assessment.py b/fusion_portal/controllers/portal_assessment.py index 7a69d431..47e018b4 100644 --- a/fusion_portal/controllers/portal_assessment.py +++ b/fusion_portal/controllers/portal_assessment.py @@ -458,6 +458,7 @@ class AssessmentPortal(CustomerPortal): 'current_page': 1, 'total_pages': 2, 'assessment': None, + 'visit_id': kw.get('visit_id', ''), 'google_maps_api_key': google_maps_api_key, } @@ -516,6 +517,7 @@ class AssessmentPortal(CustomerPortal): 'partner': partner, 'user': user, 'assessment': assessment, + 'visit_id': kw.get('visit_id') or (assessment.visit_id.id if assessment.visit_id else ''), 'authorizers': authorizers, 'authorizers_json': authorizers_json, 'clients': clients, @@ -630,6 +632,30 @@ class AssessmentPortal(CustomerPortal): except Exception as e: _logger.error(f"Error saving Page 11 signature: {e}") + # ===== Visit-linked: defer SO creation to visit completion ===== + # Started from a visit workspace: do NOT complete into a standalone + # sale order. Leave it as a draft linked to the visit so + # visit.action_complete_visit() groups the visit's ADP devices + # (combination-checked) into ONE ADP order. The Page 11 signature is + # already saved above; pre-generate its PDF so it is ready. + if assessment.visit_id and action == 'submit': + if assessment.signature_page_11 and assessment.consent_declaration_accepted: + try: + pdf_bytes = assessment.generate_template_pdf('Page 11') + if pdf_bytes: + import base64 as b64 + assessment.write({ + 'signed_page_11_pdf': b64.b64encode(pdf_bytes), + 'signed_page_11_pdf_filename': f'ADP_Page11_{assessment.reference}.pdf', + }) + except Exception as pdf_e: + _logger.warning(f"Visit-linked Page 11 PDF generation failed (non-blocking): {pdf_e}") + _logger.info( + f"Express assessment {assessment.reference} saved to visit " + f"{assessment.visit_id.name} (completion deferred to visit)" + ) + return request.redirect(f'/my/visit/{assessment.visit_id.id}') + # Handle navigation if action == 'submit': # If already completed, we just saved consent/signature above -- redirect with success @@ -803,6 +829,13 @@ class AssessmentPortal(CustomerPortal): def _build_express_assessment_vals(self, kw): """Build values dict from express form POST data""" vals = {} + + # Visit linkage (assessment started from a visit workspace) + if kw.get('visit_id'): + try: + vals['visit_id'] = int(kw.get('visit_id')) + except (ValueError, TypeError): + pass # Equipment type if kw.get('equipment_type'): diff --git a/fusion_portal/models/assessment.py b/fusion_portal/models/assessment.py index de288bee..8a171269 100644 --- a/fusion_portal/models/assessment.py +++ b/fusion_portal/models/assessment.py @@ -1486,20 +1486,18 @@ class FusionAssessment(models.Model): }) def _send_completion_notifications(self): - """Send email notifications when assessment is completed""" + """Notify the CLIENT that the assessment is complete. + + The authorizer, sales rep and office are already emailed (with the full + assessment report) by ``_send_assessment_completed_email`` inside + ``_create_draft_sale_order``. This method used to ALSO send the + authorizer a second, template-only email — that duplicate is removed; + here we only notify the client. + """ self.ensure_one() - - # Send to authorizer - if self.authorizer_id and self.authorizer_id.email: - try: - template = self.env.ref('fusion_portal.mail_template_assessment_complete_authorizer', raise_if_not_found=False) - if template: - template.send_mail(self.id, force_send=True) - _logger.info(f"Sent assessment completion email to authorizer {self.authorizer_id.email}") - except Exception as e: - _logger.error(f"Failed to send authorizer notification: {e}") - - # Send to client + + # Send to client (authorizer/rep/office already emailed by + # _send_assessment_completed_email in _create_draft_sale_order) if self.client_email: try: template = self.env.ref('fusion_portal.mail_template_assessment_complete_client', raise_if_not_found=False) diff --git a/fusion_portal/models/visit.py b/fusion_portal/models/visit.py index 010b78ee..f2b2b69e 100644 --- a/fusion_portal/models/visit.py +++ b/fusion_portal/models/visit.py @@ -184,6 +184,16 @@ class FusionAssessmentVisit(models.Model): subtype_xmlid='mail.mt_note', ) assessment.write({'state': 'completed'}) + # One completion notification per SO (not per assessment) — mirrors the + # standalone accessibility completion's office email. + if accessibility_assessments: + try: + accessibility_assessments[0]._send_completion_email(sale_order) + except Exception as e: + _logger.warning( + "Visit %s: completion email failed for %s: %s", + self.name, sale_order.name, e, + ) _logger.info( "Visit %s created %s sale order %s grouping %d accessibility assessment(s)", self.name, sale_type, sale_order.name, len(accessibility_assessments), @@ -206,6 +216,15 @@ class FusionAssessmentVisit(models.Model): if len(walkers) > 1: raise UserError(_('An ADP order can include only one walker / rollator.')) + def _assessment_sale_type(self, adp_assessment): + """Funding workflow key for an ADP equipment assessment, mirroring + fusion.assessment._create_draft_sale_order: ADP+ODSP when the client + type is an ODSP stream, plain ADP otherwise. ADP devices that share a + key are grouped onto one sale order.""" + if adp_assessment.client_type in ('ods', 'acs', 'owp'): + return 'adp_odsp' + return 'adp' + 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 diff --git a/fusion_portal/views/portal_assessment_express.xml b/fusion_portal/views/portal_assessment_express.xml index b265e5be..c7d43f35 100644 --- a/fusion_portal/views/portal_assessment_express.xml +++ b/fusion_portal/views/portal_assessment_express.xml @@ -85,7 +85,19 @@ - + + + +
+ +
+ Part of an assessment visit. + Completing this device returns you to the visit — it is grouped with the + visit's other ADP devices into a single sale order when you complete the visit. +
+
+
@@ -1246,9 +1258,10 @@
- + Cancel
diff --git a/fusion_portal/views/portal_templates.xml b/fusion_portal/views/portal_templates.xml index f6b9e544..7d92664f 100644 --- a/fusion_portal/views/portal_templates.xml +++ b/fusion_portal/views/portal_templates.xml @@ -50,6 +50,25 @@