fix(plating): compact CoC first column + 3-line part data

- Column titles now render inline "English / French" on one line (was
  stacked), cutting header height. First column drops "Line Item": it is
  now Part Number / No. de pièce, Description / Description, Serial Number /
  Numéro de série with a tight line-height.
- First-column DATA shows three lines — part number, part name, serial
  number — via new fp.certificate._fp_resolve_part_identity() (part name
  from the job's part catalog, serials from the matching SO line; blanks
  fall back to "-"). Bump certificates 19.0.9.2.0, reports 19.0.11.31.0.

Deployed + verified on entech (CoC-30059: ('9876699373',
'VALVE BODY - COMPLETE - ASSY', ''), 243KB render).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-28 22:28:04 -04:00
parent ec78fc148d
commit 6a5364e053
4 changed files with 63 additions and 26 deletions

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Certificates',
'version': '19.0.9.1.0',
'version': '19.0.9.2.0',
'category': 'Manufacturing/Plating',
'summary': 'Certificate registry for CoC, thickness reports, and quality documents.',
'description': """

View File

@@ -777,6 +777,49 @@ class FpCertificate(models.Model):
desc = line.name
return (desc or '').strip()
def _fp_resolve_part_identity(self):
"""Return (part_number, part_name, serials) for the CoC line-item
cell's three lines (client request 2026-05-28).
- part_number: the cert's own field, falling back to the job's
part_catalog part_number.
- part_name: the job's part_catalog.name.
- serials: the matching SO line's x_fc_serial_ids names,
comma-joined.
All cross-module access is guarded so the method stays safe even
if the jobs / configurator layers aren't installed (returns ''
for the unresolved pieces).
"""
self.ensure_one()
job = self.x_fc_job_id if 'x_fc_job_id' in self._fields else False
part = (job.part_catalog_id
if job and 'part_catalog_id' in job._fields else False)
part_number = (
self.part_number
or (part.part_number
if part and 'part_number' in part._fields else '')
or ''
)
part_name = (part.name if part and 'name' in part._fields else '') or ''
serials = ''
so = self.sale_order_id or (
job.sale_order_id
if job and 'sale_order_id' in job._fields else False
)
if so:
lines = so.order_line.filtered(lambda l: not l.display_type)
line = self.env['sale.order.line']
if part and lines and 'x_fc_part_catalog_id' in lines._fields:
line = lines.filtered(
lambda l: l.x_fc_part_catalog_id == part
)[:1]
if not line:
line = lines[:1]
if line and 'x_fc_serial_ids' in line._fields and line.x_fc_serial_ids:
serials = ', '.join(line.x_fc_serial_ids.mapped('name'))
return (part_number, part_name, serials)
def _fp_render_and_attach_pdf(self):
"""Render the CoC PDF via the bound report action, OPTIONALLY
merge the Fischerscope thickness report PDF (uploaded by the

View File

@@ -3,7 +3,7 @@
# License OPL-1 (Odoo Proprietary License v1.0)
{
'name': 'Fusion Plating — Reports',
'version': '19.0.11.30.0',
'version': '19.0.11.31.0',
'category': 'Manufacturing/Plating',
'summary': 'PDF reports for Fusion Plating: quote, SO, WO, packing, BoL, CoC, invoice, receipt, quality + compliance.',
'depends': [

View File

@@ -239,16 +239,13 @@
<thead>
<tr>
<th style="width: 33%;">
<span class="fp-bl-en-stk">Date of Certification</span>
<span class="fp-bl-fr-stk">Date du certificat</span>
<span class="fp-bl-en">Date of Certification</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Date du certificat</span>
</th>
<th style="width: 34%;">
<span class="fp-bl-en-stk">Generated By</span>
<span class="fp-bl-fr-stk">Créé par</span>
<span class="fp-bl-en">Generated By</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Créé par</span>
</th>
<th style="width: 33%;">
<span class="fp-bl-en-stk">Work Order #</span>
<span class="fp-bl-fr-stk">Bon de travail</span>
<span class="fp-bl-en">Work Order #</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Bon de travail</span>
</th>
</tr>
</thead>
@@ -276,39 +273,36 @@
page-break-inside: avoid;">
<thead>
<tr>
<th style="width: 20%;">
<span class="fp-bl-en-stk">Part Number / Line Item</span>
<span class="fp-bl-fr-stk">No. de pièce / Ligne</span>
<span class="fp-bl-en-stk" style="margin-top: 4px;">Description</span>
<span class="fp-bl-fr-stk">Description</span>
<span class="fp-bl-en-stk" style="margin-top: 4px;">Serial Number</span>
<span class="fp-bl-fr-stk">Numéro de série</span>
<th style="width: 20%; line-height: 1.25;">
<div><span class="fp-bl-en">Part Number</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">No. de pièce</span></div>
<div><span class="fp-bl-en">Description</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Description</span></div>
<div><span class="fp-bl-en">Serial Number</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Numéro de série</span></div>
</th>
<th style="width: 32%;">
<span class="fp-bl-en-stk">Process</span>
<span class="fp-bl-fr-stk">Procédé</span>
<span class="fp-bl-en">Process</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Procédé</span>
</th>
<th style="width: 16%;">
<span class="fp-bl-en-stk">Customer PO</span>
<span class="fp-bl-fr-stk">Bon de commande</span>
<span class="fp-bl-en">Customer PO</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Bon de commande</span>
</th>
<th style="width: 10%;">
<span class="fp-bl-en-stk">Shipped</span>
<span class="fp-bl-fr-stk">Expédié</span>
<span class="fp-bl-en">Shipped</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Expédié</span>
</th>
<th style="width: 10%;">
<span class="fp-bl-en-stk">NC Qty</span>
<span class="fp-bl-fr-stk">Qté NC</span>
<span class="fp-bl-en">NC Qty</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Qté NC</span>
</th>
<th style="width: 12%;">
<span class="fp-bl-en-stk">Customer Job No.</span>
<span class="fp-bl-fr-stk">Bon de travail client</span>
<span class="fp-bl-en">Customer Job No.</span><span class="fp-bl-sep">/</span><span class="fp-bl-fr">Bon de travail client</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-center"><t t-esc="doc.part_number or '-'"/></td>
<td class="text-center" style="line-height: 1.3;">
<t t-set="pid" t-value="doc._fp_resolve_part_identity()"/>
<div><t t-esc="pid[0] or '-'"/></div>
<div><t t-esc="pid[1] or '-'"/></div>
<div><t t-esc="pid[2] or '-'"/></div>
</td>
<td>
<!-- Customer-facing description is the cert's
spec / certificate info (client request