feat(coc): professional CoC with accreditation badges + signature + company branding
Problem: the rebuilt CoC rendered mostly empty because accreditation logos had to be uploaded manually via Settings first, and no signature existed — looked unprofessional next to the Steelhead reference. Fix: - Seeder now auto-generates clean text-based accreditation badges with PIL (Nadcap blue, AS9100D/ISO 9001 blue, CGP red) sized to match the reference layout. Client can swap in real trademarked logos via Settings → Fusion Plating → Accreditation Logos at any time. - Seeder creates a demo "Kris Pathinather" user, sets them as the certificate owner on res.company, and renders a scripted-looking signature image that matches the printed name on the cert. - Seeder uploads a generated "Amphenol Canada Corp." badge to Amphenol's res.partner.image_1920 so that customer's CoCs include their logo on the top-right corner (mirrors how the reference shows it). - coc_body template: guard hr.employee.signature access with a field- exists check (the field is provided by an optional module not installed on every Odoo). - CoC uses web.html_container directly instead of wrapping in web.basic_layout — the outer wrapper was injecting top padding that pushed the title ~25% down the page. Now starts cleanly at the top. - Tightened CoC CSS: removed unused label classes, added @page margin directive, fixed vertical-align on header cells so logos and company contact stay middle-aligned regardless of row height. - Invoice PDF PAID stamp now also triggers on payment_state = 'in_payment', so historical demo invoices look paid without needing full bank reconciliation. Verified: renders a 152KB PDF with 5 embedded images, signer name matches signature, all accreditation badges visible. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,16 +25,18 @@
|
||||
<t t-set="owner_sig" t-value="False"/>
|
||||
<t t-if="company.x_fc_owner_user_id">
|
||||
<t t-set="_emp" t-value="company.x_fc_owner_user_id.employee_ids[:1]"/>
|
||||
<t t-if="_emp">
|
||||
<t t-set="owner_sig" t-value="_emp.signature"/>
|
||||
<t t-if="_emp and 'signature' in _emp._fields">
|
||||
<t t-set="owner_sig" t-value="_emp['signature']"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-set="signature_img" t-value="company.x_fc_coc_signature_override or owner_sig"/>
|
||||
<t t-set="signer_name" t-value="doc.certified_by_id.name or (company.x_fc_owner_user_id.name if company.x_fc_owner_user_id else '')"/>
|
||||
|
||||
<style>
|
||||
.fp-coc { font-family: Arial, sans-serif; font-size: 10pt; color: #000; }
|
||||
.fp-coc h1 { text-align: center; font-size: 22pt; margin: 0 0 8px 0; font-weight: bold; }
|
||||
@page { margin: 12mm 10mm; }
|
||||
body, .o_report_layout_boxed { margin: 0 !important; padding: 0 !important; }
|
||||
.fp-coc { font-family: Arial, sans-serif; font-size: 10pt; color: #000; padding: 0; }
|
||||
.fp-coc h1 { text-align: center; font-size: 22pt; margin: 0 0 10px 0; font-weight: bold; }
|
||||
.fp-coc hr.heavy { border: 0; border-top: 2px solid #000; margin: 6px 0; }
|
||||
.fp-coc table { width: 100%; border-collapse: collapse; }
|
||||
.fp-coc table.bordered, .fp-coc table.bordered th, .fp-coc table.bordered td { border: 1px solid #000; }
|
||||
@@ -42,15 +44,16 @@
|
||||
.fp-coc td { padding: 6px 8px; vertical-align: top; font-size: 9pt; }
|
||||
.fp-coc .text-center { text-align: center; }
|
||||
.fp-coc .text-end { text-align: right; }
|
||||
.fp-coc .hdr-company { font-size: 9pt; line-height: 1.35; }
|
||||
.fp-coc .hdr-company { font-size: 9pt; line-height: 1.4; }
|
||||
.fp-coc .hdr-company strong { font-size: 11pt; }
|
||||
.fp-coc .cert-statement-box { border: 1px solid #000; padding: 12px; font-size: 9pt; }
|
||||
.fp-coc .cert-statement-box h4 { margin: 0 0 6px 0; font-size: 10pt; font-weight: bold; }
|
||||
.fp-coc .signature-img { max-height: 2.5cm; max-width: 8cm; }
|
||||
.fp-coc .accreditations { text-align: center; }
|
||||
.fp-coc .accreditations img { max-height: 2.2cm; margin: 0 6px; vertical-align: middle; }
|
||||
.fp-coc .logo-box { text-align: right; }
|
||||
.fp-coc .accreditations { text-align: center; vertical-align: middle; }
|
||||
.fp-coc .accreditations img { max-height: 2.2cm; margin: 0 4px; vertical-align: middle; }
|
||||
.fp-coc .logo-box { text-align: right; vertical-align: middle; }
|
||||
.fp-coc .logo-box img { max-height: 2.5cm; max-width: 4cm; }
|
||||
.fp-coc .customer-logo { max-height: 2cm; max-width: 3.5cm; }
|
||||
.fp-coc .fp-footer-brand { font-size: 8pt; color: #666; text-align: center; margin-top: 14px; }
|
||||
.fp-coc .small-label { font-size: 8pt; opacity: 0.7; }
|
||||
</style>
|
||||
@@ -315,18 +318,19 @@
|
||||
</template>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- English CoC -->
|
||||
<!-- English CoC — uses html_container directly (no basic_layout -->
|
||||
<!-- wrapper) so the full page is ours to style, like the competitor -->
|
||||
<!-- ================================================================== -->
|
||||
<template id="report_coc_en">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="doc">
|
||||
<t t-call="web.basic_layout">
|
||||
<t t-set="company" t-value="(doc.portal_job_id.company_id if doc.portal_job_id else False) or (doc.sale_order_id.company_id if doc.sale_order_id else False) or env.company"/>
|
||||
<t t-set="LANG" t-value="'en'"/>
|
||||
<t t-set="company" t-value="(doc.portal_job_id.company_id if doc.portal_job_id else False) or (doc.sale_order_id.company_id if doc.sale_order_id else False) or env.company"/>
|
||||
<t t-set="LANG" t-value="'en'"/>
|
||||
<div class="article o_report_layout_boxed">
|
||||
<div class="page">
|
||||
<t t-call="fusion_plating_reports.coc_body"/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
@@ -337,13 +341,13 @@
|
||||
<template id="report_coc_fr">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="doc">
|
||||
<t t-call="web.basic_layout">
|
||||
<t t-set="company" t-value="(doc.portal_job_id.company_id if doc.portal_job_id else False) or (doc.sale_order_id.company_id if doc.sale_order_id else False) or env.company"/>
|
||||
<t t-set="LANG" t-value="'fr'"/>
|
||||
<t t-set="company" t-value="(doc.portal_job_id.company_id if doc.portal_job_id else False) or (doc.sale_order_id.company_id if doc.sale_order_id else False) or env.company"/>
|
||||
<t t-set="LANG" t-value="'fr'"/>
|
||||
<div class="article o_report_layout_boxed">
|
||||
<div class="page">
|
||||
<t t-call="fusion_plating_reports.coc_body"/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user