From 5d9c78f8cece18739e9e2d6cf4791dd4c4302d28 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Wed, 22 Apr 2026 21:50:18 -0400 Subject: [PATCH] =?UTF-8?q?feat(plating):=20Sub=204=20=E2=80=94=20Check=20?= =?UTF-8?q?All=20/=20Clear=20All=20buttons=20+=20fix=20QA-005=20PDF=20logo?= =?UTF-8?q?=20render?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New bulk-toggle actions on fp.contract.review flip all 10 checklist items in Section 2.0 (and all 11 in Section 3.0) in one click. Rendered as "Check All" / "Clear All" buttons above each checklist. User can still tick boxes individually. Buttons hide once the section is signed (locked). - Fix QA-005 PDF: replaced `to_text(...)` (not in QWeb context) with `image_data_uri(...)` for the company logo embed. PDF now renders with the full colour ENTECH logo (render size 103 KB). - Smoke test extended: 5 new assertions covering bulk-toggle on/off and locked-section guard. 17/17 pass on entech. fusion_plating_quality → 19.0.2.1.0 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../tests/2026-04-22-sub4-smoke.py | 39 +++++++++++++ .../fusion_plating_quality/__manifest__.py | 2 +- .../models/fp_contract_review.py | 56 +++++++++++++++++++ .../reports/fp_contract_review_template.xml | 2 +- .../views/fp_contract_review_views.xml | 30 ++++++++++ 5 files changed, 127 insertions(+), 2 deletions(-) diff --git a/fusion_plating/docs/superpowers/tests/2026-04-22-sub4-smoke.py b/fusion_plating/docs/superpowers/tests/2026-04-22-sub4-smoke.py index 9c0d0933..f10be09f 100644 --- a/fusion_plating/docs/superpowers/tests/2026-04-22-sub4-smoke.py +++ b/fusion_plating/docs/superpowers/tests/2026-04-22-sub4-smoke.py @@ -135,6 +135,45 @@ if demo_user: else: print('[SKIP] No demo user for non-roster check') +# ---- Bulk-toggle (Check All / Clear All) buttons ---------------------- +part4 = Part.create({ + 'partner_id': cust.id, + 'part_number': 'SUB4-SMOKE-004', + 'revision': 'A', +}) +part4.action_start_contract_review() +part4.invalidate_recordset() +rev4 = part4.x_fc_contract_review_id + +rev4.action_check_all_section_20() +for f in rev4._SECTION_20_CHECKLIST: + assert rev4[f] is True, f'{f} should be True after Check All' +print('[OK] Section 2.0 Check All ticks all 10 boxes') + +rev4.action_clear_all_section_20() +for f in rev4._SECTION_20_CHECKLIST: + assert rev4[f] is False, f'{f} should be False after Clear All' +print('[OK] Section 2.0 Clear All clears all 10 boxes') + +rev4.action_check_all_section_30() +for f in rev4._SECTION_30_CHECKLIST: + assert rev4[f] is True, f'{f} should be True after Check All' +print('[OK] Section 3.0 Check All ticks all 11 boxes') + +rev4.action_clear_all_section_30() +for f in rev4._SECTION_30_CHECKLIST: + assert rev4[f] is False, f'{f} should be False after Clear All' +print('[OK] Section 3.0 Clear All clears all 11 boxes') + +# Lock section 2.0, bulk toggle should refuse +rev4.with_user(admin).action_sign_section_20() +try: + rev4.action_check_all_section_20() + assert False, 'bulk toggle should fail on locked section' +except Exception as e: + assert 'locked' in str(e).lower() or 'signed' in str(e).lower() + print('[OK] Bulk toggle blocked on locked section') + # ---- QWeb render ------------------------------------------------------- report = env.ref('fusion_plating_quality.action_report_contract_review') pdf_bytes, mime = report._render_qweb_pdf('fusion_plating_quality.report_contract_review_qa005', [review.id]) diff --git a/fusion_plating/fusion_plating_quality/__manifest__.py b/fusion_plating/fusion_plating_quality/__manifest__.py index 9bb854ed..42d1484b 100644 --- a/fusion_plating/fusion_plating_quality/__manifest__.py +++ b/fusion_plating/fusion_plating_quality/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Plating — Quality (QMS)', - 'version': '19.0.2.0.0', + 'version': '19.0.2.1.0', 'category': 'Manufacturing/Plating', 'summary': 'Native QMS for plating shops: NCR, CAPA, calibration, AVL, FAIR, ' 'internal audits, customer specs, document control. CE + EE compatible.', diff --git a/fusion_plating/fusion_plating_quality/models/fp_contract_review.py b/fusion_plating/fusion_plating_quality/models/fp_contract_review.py index 83a86ffe..541427d2 100644 --- a/fusion_plating/fusion_plating_quality/models/fp_contract_review.py +++ b/fusion_plating/fusion_plating_quality/models/fp_contract_review.py @@ -258,6 +258,62 @@ class FpContractReview(models.Model): ) % self.env.user.name) return True + # Checklist fields per section, for the "Check All" / "Clear All" + # bulk-toggle buttons. Only the checklist boxes are flipped — + # outcome fields (Accepted, Evaluate Risk, Risk Level / Matrix, + # Mitigation Plan Required) remain under the user's explicit + # decision so they don't get accidentally ticked. + _SECTION_20_CHECKLIST = ( + 's20_acceptable_lead_time', + 's20_capacity_to_process', + 's20_skills_to_process', + 's20_fixtures_required', + 's20_prime_approvals', + 's20_pricing', + 's20_approved_technique', + 's20_drawings_available', + 's20_process_type_class_grade', + 's20_pre_post_processing_steps', + ) + _SECTION_30_CHECKLIST = ( + 's30_source_control_docs', + 's30_quality_clauses_supplied', + 's30_quality_clauses_attainable', + 's30_critical_tolerance', + 's30_measuring_tooling', + 's30_quality_tests_verified', + 's30_specification_revisions', + 's30_certifications_requirements', + 's30_psd_rfd_reviewed', + 's30_specification_deviations', + 's30_design_authority', + ) + + def _bulk_toggle_checklist(self, fields_tuple, value, locked_field): + self.ensure_one() + if self[locked_field]: + raise UserError(_( + 'Section is already signed — checklist is locked.' + )) + self.write({f: value for f in fields_tuple}) + return True + + def action_check_all_section_20(self): + return self._bulk_toggle_checklist( + self._SECTION_20_CHECKLIST, True, 's20_locked') + + def action_clear_all_section_20(self): + return self._bulk_toggle_checklist( + self._SECTION_20_CHECKLIST, False, 's20_locked') + + def action_check_all_section_30(self): + return self._bulk_toggle_checklist( + self._SECTION_30_CHECKLIST, True, 's30_locked') + + def action_clear_all_section_30(self): + return self._bulk_toggle_checklist( + self._SECTION_30_CHECKLIST, False, 's30_locked') + def action_reopen(self): """Clear all sign-off data and revert to draft. Manager only.""" self.ensure_one() diff --git a/fusion_plating/fusion_plating_quality/reports/fp_contract_review_template.xml b/fusion_plating/fusion_plating_quality/reports/fp_contract_review_template.xml index af3e906c..37b8bcd1 100644 --- a/fusion_plating/fusion_plating_quality/reports/fp_contract_review_template.xml +++ b/fusion_plating/fusion_plating_quality/reports/fp_contract_review_template.xml @@ -46,7 +46,7 @@
diff --git a/fusion_plating/fusion_plating_quality/views/fp_contract_review_views.xml b/fusion_plating/fusion_plating_quality/views/fp_contract_review_views.xml index f418823a..670a3634 100644 --- a/fusion_plating/fusion_plating_quality/views/fp_contract_review_views.xml +++ b/fusion_plating/fusion_plating_quality/views/fp_contract_review_views.xml @@ -69,6 +69,21 @@ +
+
@@ -101,6 +116,21 @@ +
+