feat(certificates): orphan-cert attachment gate + render early-return

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) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-27 02:04:10 -04:00
parent fb6cccc8b1
commit b7211468b2

View File

@@ -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 = (