changes
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
{
|
||||
'name': 'Fusion Plating — Reports',
|
||||
'version': '19.0.11.15.0',
|
||||
'version': '19.0.11.24.0',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'PDF reports for Fusion Plating: quote, SO, WO, packing, BoL, CoC, invoice, receipt, quality + compliance.',
|
||||
'depends': [
|
||||
|
||||
@@ -38,8 +38,18 @@
|
||||
<t t-set="signer_name" t-value="(signer_user and signer_user.name) or ''"/>
|
||||
|
||||
<style>
|
||||
/* padding-top history: original 50mm wasted too much
|
||||
page-1 space; dropped to 5mm caused the title to
|
||||
overlap the ENTECH header (the rendered header is
|
||||
taller than paperformat margin_top reserves). 20mm
|
||||
is the middle ground — title sits cleanly below the
|
||||
header, still saves ~30mm vs the original 50mm so the
|
||||
signature block fits on page 1. If the header logo /
|
||||
address changes height, bump this in step with
|
||||
paperformat.margin_top. See CLAUDE.md "wkhtmltopdf
|
||||
header overlap". */
|
||||
.fp-coc { font-family: Arial, sans-serif; font-size: 9pt; color: #000;
|
||||
padding-top: 50mm; }
|
||||
padding-top: 20mm; }
|
||||
.fp-coc h1 { text-align: center; font-size: 20pt; 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; margin-bottom: 6px; }
|
||||
@@ -72,6 +82,36 @@
|
||||
.fp-coc .small-label { font-size: 7.5pt; opacity: 0.7; }
|
||||
.fp-coc .brand-note { font-size: 7.5pt; color: #888; text-align: center;
|
||||
margin-top: 10px; font-style: italic; }
|
||||
/* Thickness block — single outer border, internal-only
|
||||
cell dividers so the title / metadata / image+readings
|
||||
look like one connected section. No nested .bordered
|
||||
class on inner tables; each cell explicitly draws the
|
||||
internal divider it needs. */
|
||||
.fp-coc .fp-thickness-block { border: 1px solid #000; margin-top: 14px; }
|
||||
.fp-coc .fp-thickness-block table { width: 100%; border-collapse: collapse;
|
||||
margin: 0; }
|
||||
.fp-coc .fp-thickness-block td,
|
||||
.fp-coc .fp-thickness-block th { padding: 5px 8px; vertical-align: top;
|
||||
font-size: 8.5pt; }
|
||||
.fp-coc .fp-thickness-block .ftk-title {
|
||||
background-color: #ededed; text-align: center; font-weight: bold;
|
||||
font-size: 11pt; padding: 6px; border-bottom: 1px solid #000; }
|
||||
.fp-coc .fp-thickness-block .ftk-label { background-color: #f7f7f7;
|
||||
font-weight: bold; }
|
||||
.fp-coc .fp-thickness-block .ftk-row-divider { border-bottom: 1px solid #000; }
|
||||
.fp-coc .fp-thickness-block .ftk-cell-divider { border-right: 1px solid #000; }
|
||||
.fp-coc .fp-thickness-block .ftk-img-cell {
|
||||
text-align: center; vertical-align: middle; padding: 6px;
|
||||
border-right: 1px solid #000; }
|
||||
.fp-coc .fp-thickness-block .ftk-img-cell img { max-width: 100%; max-height: 10cm; }
|
||||
.fp-coc .fp-thickness-block .ftk-readings-cell { padding: 0; vertical-align: top; }
|
||||
.fp-coc .fp-thickness-block .ftk-readings th {
|
||||
background-color: #ededed; text-align: center; font-weight: bold;
|
||||
border-bottom: 1px solid #000; }
|
||||
.fp-coc .fp-thickness-block .ftk-readings td { text-align: center; }
|
||||
.fp-coc .fp-thickness-block .ftk-readings .ftk-stat-mean {
|
||||
background-color: #ededed; font-weight: bold; }
|
||||
.fp-coc .fp-thickness-block .ftk-readings .ftk-stat { background-color: #f7f7f7; }
|
||||
</style>
|
||||
|
||||
<div class="fp-coc">
|
||||
@@ -193,12 +233,13 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Quantities / line item table -->
|
||||
<div class="text-end small-label" style="margin-top: 8px;">
|
||||
<strong t-if="not is_fr">Quantities</strong>
|
||||
<strong t-if="is_fr">Quantités</strong>
|
||||
</div>
|
||||
<table class="bordered">
|
||||
<!-- Line-item table — the column headers already speak
|
||||
for themselves (Shipped / NC Qty / etc.), so the
|
||||
hovering "Quantities" caption above was just visual
|
||||
noise. Removed 2026-05-21. Header row + body row
|
||||
stay together (page-break-inside on tr per CLAUDE.md). -->
|
||||
<table class="bordered" style="margin-top: 8px;
|
||||
page-break-inside: avoid;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20%;">
|
||||
@@ -244,9 +285,225 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Signature + certification statement -->
|
||||
<!-- Thickness readings (Fischerscope XRF) — full report
|
||||
block mirroring the original XDAL 600 export so the
|
||||
customer/auditor sees the same context the gauge
|
||||
produced: equipment, operator, calibration, product,
|
||||
application, measuring time, all readings, plus
|
||||
derived stats (mean, std dev, CoV, range, n). When
|
||||
the source upload was an RTF/.docx, this replaces
|
||||
the page-2 PDF merge. -->
|
||||
<t t-if="doc.thickness_reading_ids">
|
||||
<t t-set="readings" t-value="doc.thickness_reading_ids.sorted('reading_number')"/>
|
||||
<t t-set="calib" t-value="(doc.x_fc_thickness_calibration if 'x_fc_thickness_calibration' in doc._fields else '') or (readings and readings[0].calibration_std_ref or '')"/>
|
||||
<t t-set="n" t-value="len(readings)"/>
|
||||
<t t-set="nip_vals" t-value="[r.nip_mils for r in readings if r.nip_mils]"/>
|
||||
<t t-set="ni_vals" t-value="[r.ni_percent for r in readings if r.ni_percent]"/>
|
||||
<t t-set="p_vals" t-value="[r.p_percent for r in readings if r.p_percent]"/>
|
||||
<!-- Stats computed in the template so the wizard
|
||||
parser doesn't have to handle two number formats
|
||||
(XDAL exports `0.5857` and `92.727` etc; we
|
||||
recompute from the source readings to guarantee
|
||||
the printed report agrees with the source data). -->
|
||||
<t t-set="nip_mean" t-value="(sum(nip_vals) / len(nip_vals)) if nip_vals else 0"/>
|
||||
<t t-set="ni_mean" t-value="(sum(ni_vals) / len(ni_vals)) if ni_vals else 0"/>
|
||||
<t t-set="p_mean" t-value="(sum(p_vals) / len(p_vals)) if p_vals else 0"/>
|
||||
<t t-set="nip_std" t-value="((sum((v - nip_mean) ** 2 for v in nip_vals) / (len(nip_vals) - 1)) ** 0.5) if len(nip_vals) > 1 else 0"/>
|
||||
<t t-set="ni_std" t-value="((sum((v - ni_mean) ** 2 for v in ni_vals) / (len(ni_vals) - 1)) ** 0.5) if len(ni_vals) > 1 else 0"/>
|
||||
<t t-set="p_std" t-value="((sum((v - p_mean) ** 2 for v in p_vals) / (len(p_vals) - 1)) ** 0.5) if len(p_vals) > 1 else 0"/>
|
||||
<t t-set="nip_cov" t-value="(nip_std / nip_mean * 100) if nip_mean else 0"/>
|
||||
<t t-set="ni_cov" t-value="(ni_std / ni_mean * 100) if ni_mean else 0"/>
|
||||
<t t-set="p_cov" t-value="(p_std / p_mean * 100) if p_mean else 0"/>
|
||||
<t t-set="nip_range" t-value="(max(nip_vals) - min(nip_vals)) if nip_vals else 0"/>
|
||||
<t t-set="ni_range" t-value="(max(ni_vals) - min(ni_vals)) if ni_vals else 0"/>
|
||||
<t t-set="p_range" t-value="(max(p_vals) - min(p_vals)) if p_vals else 0"/>
|
||||
|
||||
<!-- Whole block stays together when it fits; wraps
|
||||
to a fresh page if it doesn't. Prevents the
|
||||
wkhtmltopdf company header from overlapping the
|
||||
readings table mid-row on page 2. -->
|
||||
<div class="fp-thickness-block">
|
||||
|
||||
<!-- Section header — full-width bar, drawn by the
|
||||
div's bottom-border, no internal table needed. -->
|
||||
<div class="ftk-title">
|
||||
<t t-if="not is_fr">Fischerscope XRF Thickness Report</t>
|
||||
<t t-if="is_fr">Rapport d'épaisseur Fischerscope XRF</t>
|
||||
</div>
|
||||
|
||||
<!-- Equipment metadata — 4-column key/value grid.
|
||||
Per-cell border-right + per-row border-bottom
|
||||
draw the internal grid; the outer perimeter
|
||||
comes from .fp-thickness-block's border. Last
|
||||
row + last column omit their dividers so we
|
||||
don't double up against the parent border. -->
|
||||
<table>
|
||||
<tr class="ftk-row-divider">
|
||||
<td class="ftk-label ftk-cell-divider" style="width: 18%;">
|
||||
<t t-if="not is_fr">Equipment</t>
|
||||
<t t-if="is_fr">Équipement</t>
|
||||
</td>
|
||||
<td class="ftk-cell-divider" style="width: 32%;">
|
||||
<t t-esc="doc.x_fc_thickness_equipment or '—'"/>
|
||||
</td>
|
||||
<td class="ftk-label ftk-cell-divider" style="width: 18%;">
|
||||
<t t-if="not is_fr">Calibration Std.</t>
|
||||
<t t-if="is_fr">Étalon</t>
|
||||
</td>
|
||||
<td style="width: 32%;"><t t-esc="calib or '—'"/></td>
|
||||
</tr>
|
||||
<tr class="ftk-row-divider">
|
||||
<td class="ftk-label ftk-cell-divider">
|
||||
<t t-if="not is_fr">Product</t>
|
||||
<t t-if="is_fr">Produit</t>
|
||||
</td>
|
||||
<td class="ftk-cell-divider"><t t-esc="doc.x_fc_thickness_product or '—'"/></td>
|
||||
<td class="ftk-label ftk-cell-divider">
|
||||
<t t-if="not is_fr">Operator</t>
|
||||
<t t-if="is_fr">Opérateur</t>
|
||||
</td>
|
||||
<td><t t-esc="doc.x_fc_thickness_operator or '—'"/></td>
|
||||
</tr>
|
||||
<tr class="ftk-row-divider">
|
||||
<td class="ftk-label ftk-cell-divider">
|
||||
<t t-if="not is_fr">Application</t>
|
||||
<t t-if="is_fr">Application</t>
|
||||
</td>
|
||||
<td class="ftk-cell-divider"><t t-esc="doc.x_fc_thickness_application or '—'"/></td>
|
||||
<td class="ftk-label ftk-cell-divider">
|
||||
<t t-if="not is_fr">Measured</t>
|
||||
<t t-if="is_fr">Mesuré le</t>
|
||||
</td>
|
||||
<td>
|
||||
<t t-if="doc.x_fc_thickness_datetime"
|
||||
t-esc="doc.x_fc_thickness_datetime.strftime('%Y-%m-%d %H:%M')"/>
|
||||
<t t-if="not doc.x_fc_thickness_datetime">—</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="ftk-row-divider">
|
||||
<td class="ftk-label ftk-cell-divider">
|
||||
<t t-if="not is_fr">Directory</t>
|
||||
<t t-if="is_fr">Répertoire</t>
|
||||
</td>
|
||||
<td class="ftk-cell-divider"><t t-esc="doc.x_fc_thickness_directory or '—'"/></td>
|
||||
<td class="ftk-label ftk-cell-divider">
|
||||
<t t-if="not is_fr">Measuring Time</t>
|
||||
<t t-if="is_fr">Durée de mesure</t>
|
||||
</td>
|
||||
<td>
|
||||
<t t-if="doc.x_fc_thickness_measuring_time_sec"
|
||||
t-esc="'%d sec' % doc.x_fc_thickness_measuring_time_sec"/>
|
||||
<t t-if="not doc.x_fc_thickness_measuring_time_sec">—</t>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- Image (left) + readings (right). The image
|
||||
cell's border-right is the only divider; the
|
||||
readings inner table is borderless on its
|
||||
perimeter (the parent cell's edges + the
|
||||
block's outer border do all the bounding).
|
||||
Inner-cell dividers are drawn per th/td. -->
|
||||
<table>
|
||||
<tr>
|
||||
<td t-if="doc.x_fc_thickness_image_id"
|
||||
class="ftk-img-cell" style="width: 45%;">
|
||||
<img t-att-src="'/web/image/%s' % doc.x_fc_thickness_image_id.id"/>
|
||||
</td>
|
||||
<td class="ftk-readings-cell"
|
||||
t-att-style="'width: 55%;' if doc.x_fc_thickness_image_id else 'width: 100%;'">
|
||||
<table class="ftk-readings">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="ftk-cell-divider" style="width: 28%;">#</th>
|
||||
<th class="ftk-cell-divider">NiP (mils)</th>
|
||||
<th class="ftk-cell-divider">Ni %</th>
|
||||
<th>P %</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr t-foreach="readings" t-as="r"
|
||||
class="ftk-row-divider"
|
||||
style="page-break-inside: avoid;">
|
||||
<td class="ftk-cell-divider"><t t-esc="r.reading_number or r_index + 1"/></td>
|
||||
<td class="ftk-cell-divider"><t t-esc="'%.4f' % (r.nip_mils or 0)"/></td>
|
||||
<td class="ftk-cell-divider"><t t-esc="'%.3f' % (r.ni_percent or 0)"/></td>
|
||||
<td><t t-esc="'%.3f' % (r.p_percent or 0)"/></td>
|
||||
</tr>
|
||||
<!-- Stats: Mean / Std Dev / CoV / Range / N -->
|
||||
<tr t-if="nip_vals"
|
||||
class="ftk-stat-mean ftk-row-divider"
|
||||
style="page-break-inside: avoid;">
|
||||
<td class="ftk-cell-divider">
|
||||
<t t-if="not is_fr">Mean</t>
|
||||
<t t-if="is_fr">Moyenne</t>
|
||||
</td>
|
||||
<td class="ftk-cell-divider"><t t-esc="'%.4f' % nip_mean"/></td>
|
||||
<td class="ftk-cell-divider"><t t-esc="'%.3f' % ni_mean"/></td>
|
||||
<td><t t-esc="'%.3f' % p_mean"/></td>
|
||||
</tr>
|
||||
<tr t-if="nip_vals and n > 1"
|
||||
class="ftk-stat ftk-row-divider"
|
||||
style="page-break-inside: avoid;">
|
||||
<td class="ftk-cell-divider">
|
||||
<t t-if="not is_fr">Std Dev</t>
|
||||
<t t-if="is_fr">Écart-type</t>
|
||||
</td>
|
||||
<td class="ftk-cell-divider"><t t-esc="'%.4f' % nip_std"/></td>
|
||||
<td class="ftk-cell-divider"><t t-esc="'%.3f' % ni_std"/></td>
|
||||
<td><t t-esc="'%.3f' % p_std"/></td>
|
||||
</tr>
|
||||
<tr t-if="nip_vals and n > 1"
|
||||
class="ftk-stat ftk-row-divider"
|
||||
style="page-break-inside: avoid;">
|
||||
<td class="ftk-cell-divider">CoV (%)</td>
|
||||
<td class="ftk-cell-divider"><t t-esc="'%.2f' % nip_cov"/></td>
|
||||
<td class="ftk-cell-divider"><t t-esc="'%.2f' % ni_cov"/></td>
|
||||
<td><t t-esc="'%.2f' % p_cov"/></td>
|
||||
</tr>
|
||||
<tr t-if="nip_vals and n > 1"
|
||||
class="ftk-stat ftk-row-divider"
|
||||
style="page-break-inside: avoid;">
|
||||
<td class="ftk-cell-divider">
|
||||
<t t-if="not is_fr">Range</t>
|
||||
<t t-if="is_fr">Étendue</t>
|
||||
</td>
|
||||
<td class="ftk-cell-divider"><t t-esc="'%.4f' % nip_range"/></td>
|
||||
<td class="ftk-cell-divider"><t t-esc="'%.3f' % ni_range"/></td>
|
||||
<td><t t-esc="'%.3f' % p_range"/></td>
|
||||
</tr>
|
||||
<tr t-if="nip_vals" class="ftk-stat"
|
||||
style="page-break-inside: avoid;">
|
||||
<td class="ftk-cell-divider">N</td>
|
||||
<td class="ftk-cell-divider"><t t-esc="n"/></td>
|
||||
<td class="ftk-cell-divider"><t t-esc="n"/></td>
|
||||
<td><t t-esc="n"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- Source-file footnote — italic + opacity:0.7
|
||||
(from .small-label) renders jagged/washed-out
|
||||
on entech wkhtmltopdf. Solid #555 grey at
|
||||
normal weight prints cleanly. -->
|
||||
<div t-if="doc.x_fc_thickness_source_filename"
|
||||
style="margin-top: 4px; font-size: 8pt; color: #555;">
|
||||
<strong t-if="not is_fr">Source file:</strong>
|
||||
<strong t-if="is_fr">Fichier source :</strong>
|
||||
<t t-esc="' ' + (doc.x_fc_thickness_source_filename or '')"/>
|
||||
<t t-if="doc.x_fc_local_thickness_evidence_id"> (attached to cert as evidence)</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Signature + certification statement — never split
|
||||
across pages (page-break-inside on the row works on
|
||||
entech wkhtmltopdf; see CLAUDE.md). -->
|
||||
<table style="margin-top: 18px;">
|
||||
<tr>
|
||||
<tr style="page-break-inside: avoid;">
|
||||
<td style="width: 50%; vertical-align: top;">
|
||||
<div>
|
||||
<strong t-if="not is_fr">Certified By:</strong>
|
||||
|
||||
Reference in New Issue
Block a user