From b7211468b23961d1c0eb9d1f6a50172e04193491 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Wed, 27 May 2026 02:04:10 -0400 Subject: [PATCH] feat(certificates): orphan-cert attachment gate + render early-return MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Block fp.certificate.action_issue on Nadcap / Mill Test / Customer- Specific certs when attachment_id is empty. These three cert types are manual-attach only — operator uploads the supplier doc / regulator-issued cert / filled customer template PDF before the cert can be issued. Prevents shipping the customer an empty PDF. _fp_render_and_attach_pdf gets an early-return guard so an orphan- type cert never tries to render a CoC QWeb template. Sub: docs/superpowers/specs/2026-05-27-recipe-cert-toggles-design.md Task: T5. Makes test_orphan_cert_issue_blocks_without_attachment pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../models/fp_certificate.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/fusion_plating/fusion_plating_certificates/models/fp_certificate.py b/fusion_plating/fusion_plating_certificates/models/fp_certificate.py index 65be18b3..359bb441 100644 --- a/fusion_plating/fusion_plating_certificates/models/fp_certificate.py +++ b/fusion_plating/fusion_plating_certificates/models/fp_certificate.py @@ -551,6 +551,27 @@ class FpCertificate(models.Model): 'name': rec.name or rec.display_name, 'c': rec.contact_partner_id.name, }) + # Orphan cert types (Nadcap / Mill Test / Customer-Specific) + # are manual-attach only — operator uploads supplier doc / + # regulator-issued cert / filled customer template. Block + # issuance until an attachment is present so the customer + # doesn't receive an empty PDF. See spec 2026-05-27. + ORPHAN_TYPES = ('nadcap_cert', 'mill_test', 'customer_specific') + if (rec.certificate_type in ORPHAN_TYPES + and not rec.attachment_id): + type_label = dict( + rec._fields['certificate_type'].selection + ).get(rec.certificate_type, rec.certificate_type) + raise UserError(_( + 'Cannot issue %(type)s "%(name)s" — no PDF attached.' + '\n\nThis certificate type expects a PDF you upload ' + 'from disk (supplier doc / regulator-issued cert / ' + 'filled customer template). Upload the PDF to the ' + 'Attachment field on this cert before clicking Issue.' + ) % { + 'type': type_label, + 'name': rec.name or rec.display_name, + }) # Thickness data requirement — unified gate covering both # cert types. A customer needs thickness data on the cert # when ANY of these is true: @@ -729,6 +750,13 @@ class FpCertificate(models.Model): import base64 import io self.ensure_one() + # Orphan cert types (Nadcap / Mill Test / Customer-Specific) are + # manual-attach only — never render a CoC QWeb template for them. + # action_issue's precondition gate already enforces the + # attachment requirement, so by the time we get here the operator + # has uploaded the right PDF. See spec 2026-05-27 §4. + if self.certificate_type != 'coc': + return self.attachment_id or False if self.attachment_id: return self.attachment_id report = (