chore(plating): de-dash shipped code + intake-neutral customer emails

Replace em-dashes and en-dashes with hyphens across 789 shipped source
files (py/xml/js/scss) so the delivered module reads as human-written;
em-dashes had become a recognizable AI-generated tell. Internal .md dev
notes are excluded. The WO-sticker mojibake strippers keep their dash
search targets (now written — / –). No logic changes: comments
and display strings only; validated with py_compile + lxml parse.

Rewrite the 7 customer notification emails to be intake-neutral
(ship-in / drop-off / pickup) and repair-aware, and fix the Shipped
email documents line (packing slip vs bill of lading; certificate only
when issued). Subjects use a hyphen separator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-06-05 00:16:19 -04:00
parent c9eb61ee0c
commit 8c76a16366
789 changed files with 4692 additions and 4692 deletions

View File

@@ -16,7 +16,7 @@
<t t-foreach="rows" t-as="row">
<t t-call="web.external_layout">
<div class="page">
<h2>Job Margin <span t-esc="row['job'].name"/></h2>
<h2>Job Margin - <span t-esc="row['job'].name"/></h2>
<table class="table table-sm" style="margin-top: 1em; max-width: 600px;">
<tr><th>Customer</th><td><span t-esc="row['job'].partner_id.name"/></td></tr>
<tr><th>Recipe</th><td><span t-esc="row['job'].recipe_id.name or '-'"/></td></tr>

View File

@@ -4,10 +4,10 @@
License OPL-1 (Odoo Proprietary License v1.0)
Redesigned job stickers (thermal label, 6x4 in / 152x102 mm):
* Internal Job Sticker Layout A (stacked, full-width notes),
* Internal Job Sticker - Layout A (stacked, full-width notes),
ONE label per job. Shop copy: x_fc_internal_description notes,
job QR (/fp/job/<id>).
* External Job Sticker Layout B (left rail + tall notes),
* External Job Sticker - Layout B (left rail + tall notes),
ONE label per fp.box. Customer copy: factory logo, BOX n/N,
per-box QR (/fp/box/<id>), customer-facing description notes.
@@ -100,7 +100,7 @@
<!-- QR quiet-zone crop: the barcode bakes a ~12% white border
around the pattern. Render the image oversized in an
overflow:hidden wrapper, offset so the wrapper clips ~10% off
each edge (under the quiet zone, so no modules are lost) the
each edge (under the quiet zone, so no modules are lost) - the
black pattern then fills the box. White label cell around the
wrapper still provides the scan margin. CLAUDE.md rule 14. -->
.qfwrap-qr { display: inline-block; position: relative; overflow: hidden; width: 31mm; height: 31mm; vertical-align: middle; }
@@ -110,7 +110,7 @@
.qffull { line-height: 32mm; }
.qfwrap-full { display: inline-block; position: relative; overflow: hidden; width: 31mm; height: 31mm; vertical-align: middle; }
.qfwrap-full img { position: absolute; width: 38.75mm; height: 38.75mm; top: -3.875mm; left: -3.875mm; }
/* Internal (Layout A) header QR same ~10% quiet-zone crop. Trimmed
/* Internal (Layout A) header QR - same ~10% quiet-zone crop. Trimmed
30mm -> 27mm so the QR-driven black band is shorter and the freed
height flows to the NOTES block below. Still well above scan size. */
.qfwrap-int { display: inline-block; position: relative; overflow: hidden; width: 27mm; height: 27mm; vertical-align: middle; }
@@ -124,7 +124,7 @@
</style>
</template>
<!-- ===================== External body Layout B ===================== -->
<!-- ===================== External body - Layout B ===================== -->
<template id="fp_job_external_body">
<div class="label-page"><div class="label">
<div class="rail">
@@ -173,7 +173,7 @@
</tr></table></div>
</div>
<div class="main">
<!-- Plating thickness the team's most-watched spec. Relocated
<!-- Plating thickness - the team's most-watched spec. Relocated
out of the cramped rail to a prominent full-width banner at
the top of the main panel. -->
<t t-if="d['has_thk']">

View File

@@ -4,18 +4,18 @@
License OPL-1 (Odoo Proprietary License v1.0)
Part of the Fusion Plating product family.
Sub 12c v2 paper-style A4 landscape job traveller.
Sub 12c v2 - paper-style A4 landscape job traveller.
Mirrors the Amphenol Canada paper sheets (Steelhead screens 16-18):
barcode + WO header, item-info block, recipe sub-process header, then
the routing table with target ranges + actuals + sign-off cells per
step. Operators print one of these per job, pencil in actuals; the
tablet captures the same data digitally printed traveller is the
tablet captures the same data digitally - printed traveller is the
redundant audit copy.
-->
<odoo>
<record id="paperformat_fp_traveller_landscape" model="report.paperformat">
<field name="name">FP Traveller A4 landscape narrow margins</field>
<field name="name">FP Traveller - A4 landscape narrow margins</field>
<field name="format">A4</field>
<field name="orientation">Landscape</field>
<!-- margin_top + header_spacing both reserve room above the body
@@ -84,28 +84,28 @@
</td>
<td style="width: 18%;">
<strong>Date In:</strong>
<span t-esc="job.create_date and job.create_date.strftime('%d-%m-%Y') or ''"/><br/>
<span t-esc="job.create_date and job.create_date.strftime('%d-%m-%Y') or '-'"/><br/>
<strong>Due Date:</strong>
<span t-esc="job.date_deadline and job.date_deadline.strftime('%d-%m-%Y') or ''"/><br/>
<span t-esc="job.date_deadline and job.date_deadline.strftime('%d-%m-%Y') or '-'"/><br/>
<strong>Type:</strong>
<span t-esc="(job.recipe_id and job.recipe_id.name) or ''"/>
<span t-esc="(job.recipe_id and job.recipe_id.name) or '-'"/>
</td>
<td style="width: 18%;">
<strong>Order #:</strong>
<span t-esc="(job.sale_order_id and job.sale_order_id.name) or ''"/><br/>
<span t-esc="(job.sale_order_id and job.sale_order_id.name) or '-'"/><br/>
<strong>P.O. #:</strong>
<span t-esc="(job.sale_order_id and job.sale_order_id.client_order_ref) or ''"/><br/>
<span t-esc="(job.sale_order_id and job.sale_order_id.client_order_ref) or '-'"/><br/>
<strong>WO Generated By:</strong>
<span t-esc="(job.create_uid and job.create_uid.name) or ''"/>
<span t-esc="(job.create_uid and job.create_uid.name) or '-'"/>
</td>
<td style="width: 28%; vertical-align: top;">
<strong t-esc="(job.partner_id and job.partner_id.name) or ''"/><br/>
<strong t-esc="(job.partner_id and job.partner_id.name) or '-'"/><br/>
<span t-esc="(job.partner_id and job.partner_id.street) or ''"/><br/>
<span t-esc="(job.partner_id and job.partner_id.city) or ''"/>,
<span t-esc="(job.partner_id and job.partner_id.state_id and job.partner_id.state_id.code) or ''"/>
<span t-esc="(job.partner_id and job.partner_id.zip) or ''"/><br/>
<strong>Tel:</strong>
<span t-esc="(job.partner_id and job.partner_id.phone) or ''"/>
<span t-esc="(job.partner_id and job.partner_id.phone) or '-'"/>
</td>
</tr>
</table>
@@ -125,31 +125,31 @@
<td>
<strong>Part #:</strong>
<t t-if="'part_catalog_id' in job._fields and job.part_catalog_id">
<span t-esc="job.part_catalog_id.part_number or ''"/>
<span t-esc="job.part_catalog_id.part_number or '-'"/>
</t>
<t t-else=""></t><br/>
<t t-else="">-</t><br/>
<strong>Rev:</strong>
<t t-if="'part_catalog_id' in job._fields and job.part_catalog_id and 'revision' in job.part_catalog_id._fields">
<span t-esc="job.part_catalog_id.revision or ''"/>
<span t-esc="job.part_catalog_id.revision or '-'"/>
</t>
<t t-else=""></t><br/>
<t t-else="">-</t><br/>
<strong>Mat:</strong>
<t t-if="'part_catalog_id' in job._fields and job.part_catalog_id and 'base_material' in job.part_catalog_id._fields">
<span t-esc="job.part_catalog_id.base_material or ''"/>
<span t-esc="job.part_catalog_id.base_material or '-'"/>
</t>
<t t-else=""></t><br/>
<t t-else="">-</t><br/>
<strong>Catg:</strong>
<span t-esc="(job.recipe_id and job.recipe_id.name) or ''"/><br/>
<span t-esc="(job.recipe_id and job.recipe_id.name) or '-'"/><br/>
<strong>S/N:</strong>
<t t-if="'serial_number' in job._fields"><span t-esc="job.serial_number or ''"/></t>
</td>
<td>
<strong>
<t t-if="'part_catalog_id' in job._fields and job.part_catalog_id">
<span t-esc="job.part_catalog_id.name or job.product_id.name or ''"/>
<span t-esc="job.part_catalog_id.name or job.product_id.name or '-'"/>
</t>
<t t-else="">
<span t-esc="(job.product_id and job.product_id.name) or ''"/>
<span t-esc="(job.product_id and job.product_id.name) or '-'"/>
</t>
</strong>
<div style="font-size: 7.5pt; margin-top: 2px;">
@@ -166,19 +166,19 @@
<t t-if="'qty_visual_inspection_rejects' in job._fields">
<span t-esc="job.qty_visual_inspection_rejects or 0"/>
</t>
<t t-else=""></t>
<t t-else="">-</t>
</td>
<td class="text-center">
<t t-if="'qty_rework' in job._fields">
<span t-esc="job.qty_rework or 0"/>
</t>
<t t-else=""></t>
<t t-else="">-</t>
</td>
<td style="font-size: 7pt; white-space: pre-wrap;">
<t t-if="'special_requirements' in job._fields">
<span t-esc="job.special_requirements or ''"/>
<span t-esc="job.special_requirements or '-'"/>
</t>
<t t-else=""></t>
<t t-else="">-</t>
</td>
<td class="fp-trav-stamp"/>
</tr>
@@ -192,12 +192,12 @@
<th style="width: 50%;">Spec / Info</th>
</tr>
<tr>
<td><span t-esc="(job.recipe_id and job.recipe_id.name) or ''"/></td>
<td><span t-esc="(job.recipe_id and job.recipe_id.name) or '-'"/></td>
<td>
<t t-if="job.recipe_id and job.recipe_id.process_type_id">
<span t-esc="job.recipe_id.process_type_id.name"/>
</t>
<t t-else=""></t>
<t t-else="">-</t>
</td>
<td>
<t t-if="'customer_spec_id' in job._fields and job.customer_spec_id">
@@ -208,12 +208,12 @@
</table>
<!-- ===== ROUTING TABLE =====
Continues on subsequent pages paperformat handles
Continues on subsequent pages - paperformat handles
page break automatically. Footer (Ship Order To +
Additional Notes) closes the document. -->
<!-- inline routing follows; footer appears below -->
<!-- (placed after the routing table see end-of-template) -->
<!-- (placed after the routing table - see end-of-template) -->
<!-- ===== ROUTING TABLE ===== -->
<table class="bordered" style="margin-top: 4px;">
@@ -238,7 +238,7 @@
<tr>
<td class="text-center"><span t-esc="step_index + 1"/></td>
<td class="text-center">
<span t-esc="(step.tank_id and step.tank_id.code) or ''"/>
<span t-esc="(step.tank_id and step.tank_id.code) or '-'"/>
</td>
<td>
<strong t-esc="step.name"/>
@@ -261,7 +261,7 @@
<t t-if="rn and 'time_unit' in rn._fields and rn.time_unit">
<span t-esc="rn.time_unit"/>
</t>
<t t-else=""></t>
<t t-else="">-</t>
</td>
<td class="text-center fp-trav-target">
<t t-if="rn and 'material_callout' in rn._fields and rn.material_callout">
@@ -298,7 +298,7 @@
</tbody>
</table>
<!-- ===== FOOTER SHIP ORDER + NOTES ===== -->
<!-- ===== FOOTER - SHIP ORDER + NOTES ===== -->
<table class="bordered" style="margin-top: 6px;">
<tr>
<th style="width: 30%;">Ship Order To</th>
@@ -306,7 +306,7 @@
</tr>
<tr>
<td style="vertical-align: top;">
<strong t-esc="(job.partner_id and job.partner_id.name) or ''"/><br/>
<strong t-esc="(job.partner_id and job.partner_id.name) or '-'"/><br/>
<span t-esc="(job.partner_id and job.partner_id.street) or ''"/><br/>
<span t-if="job.partner_id and job.partner_id.street2"
t-esc="job.partner_id.street2"/>

View File

@@ -4,7 +4,7 @@
License OPL-1 (Odoo Proprietary License v1.0)
Part of the Fusion Plating product family.
Steelhead-style "Work Order Detail" PDF the post-job audit cert
Steelhead-style "Work Order Detail" PDF - the post-job audit cert
that walks fp.job.step.move records chronologically, lists captured
inputs per step, and ends with a Certified By + Cert Statement
page. Bound to fp.job directly (not fp.certificate) so a manager
@@ -18,7 +18,7 @@
<odoo>
<record id="paperformat_fp_wo_detail" model="report.paperformat">
<field name="name">FP Work Order Detail A4 portrait</field>
<field name="name">FP Work Order Detail - A4 portrait</field>
<field name="format">A4</field>
<field name="orientation">Portrait</field>
<!-- margin_top + header_spacing both reserve room above the body
@@ -56,11 +56,11 @@
<!-- All datetimes in Postgres are naive UTC. QWeb's
eval scope exposes neither pytz nor format_datetime,
so timestamp formatting happens via job.fp_format_local()
on the record itself record methods are always
on the record itself - record methods are always
available in templates. The helper resolves user.tz
→ company.x_fc_default_tz → UTC. -->
<!-- First SO line linked to this job source of truth
<!-- First SO line linked to this job - source of truth
for the customer-facing description, serial(s),
and part metadata. -->
<t t-set="primary_line" t-value="job.sale_order_line_ids[:1]"/>
@@ -88,7 +88,7 @@
or (job.name or '').split('/')[-1]
)"/>
<!-- Photo evidence collect every captured-input value
<!-- Photo evidence - collect every captured-input value
that has an attachment, in step / time order. We
number them globally (Photo 1..N) and use those
numbers both in the per-step measurement tables
@@ -128,7 +128,7 @@
.fp-wo-detail .fp-spec { font-size: 10pt; font-weight: bold; margin: 10px 0 6px 0; }
.fp-wo-detail .fp-step-block { page-break-inside: avoid; margin-bottom: 14px; }
.fp-wo-detail .fp-prepared { margin-bottom: 14px; }
/* Photo gallery bordered tile per attachment.
/* Photo gallery - bordered tile per attachment.
flex-wrap so wkhtmltopdf lays out two per row
on A4 portrait; page-break-inside on the tile
keeps captions glued to their image. */
@@ -166,7 +166,7 @@
white-space: nowrap;
}
/* Inline signature image inside the step
measurement Value cell rendered when a
measurement Value cell - rendered when a
`signature` prompt has a recorder with a
Plating Signature on file. Sized to fit the
table row without blowing it up. */
@@ -178,11 +178,11 @@
<h1>Work Order Detail</h1>
<!-- ===== HEADER Prepared For + summary table ===== -->
<!-- ===== HEADER - Prepared For + summary table ===== -->
<div class="fp-prepared">
<strong>Prepared For:</strong>
<span style="font-size: 11pt;"
t-esc="(job.partner_id and job.partner_id.name) or ''"/>
t-esc="(job.partner_id and job.partner_id.name) or '-'"/>
</div>
<table class="bordered">
@@ -198,14 +198,14 @@
<tr>
<td>
<t t-if="'part_catalog_id' in job._fields and job.part_catalog_id">
<span t-esc="job.part_catalog_id.part_number or ''"/>
<span t-esc="job.part_catalog_id.part_number or '-'"/>
<t t-if="'revision' in job.part_catalog_id._fields and job.part_catalog_id.revision">
<br/>
<span style="font-size: 7.5pt;">Rev <span t-esc="job.part_catalog_id.revision"/></span>
</t>
</t>
<t t-else="">
<span t-esc="(job.product_id and job.product_id.default_code) or ''"/>
<span t-esc="(job.product_id and job.product_id.default_code) or '-'"/>
</t>
</td>
<td style="vertical-align: top;">
@@ -221,7 +221,7 @@
pre-line preserves the operator's
intentional \n\n paragraph
breaks but nothing else. -->
<div style="white-space: pre-line;"><t t-if="customer_desc"><span t-esc="customer_desc.strip()"/></t><t t-elif="'part_catalog_id' in job._fields and job.part_catalog_id"><span t-esc="job.part_catalog_id.name or job.product_id.name or ''"/></t><t t-else=""><span t-esc="(job.product_id and job.product_id.name) or ''"/></t></div>
<div style="white-space: pre-line;"><t t-if="customer_desc"><span t-esc="customer_desc.strip()"/></t><t t-elif="'part_catalog_id' in job._fields and job.part_catalog_id"><span t-esc="job.part_catalog_id.name or job.product_id.name or '-'"/></t><t t-else=""><span t-esc="(job.product_id and job.product_id.name) or '-'"/></t></div>
</td>
<td class="text-center">
<span t-esc="job.qty"/>
@@ -230,10 +230,10 @@
<span t-esc="short_wo"/>
</td>
<td>
<span t-esc="po_number or ''"/>
<span t-esc="po_number or '-'"/>
</td>
<td>
<span t-esc="serial_names or ''"/>
<span t-esc="serial_names or '-'"/>
</td>
<td>
<t t-set="_hdr_dt"
@@ -283,20 +283,20 @@
<span style="font-weight: bold; color: #2e2e2e;">QA-005 Approved</span>
</t>
<t t-else="">
<span style="color: #aa0000;">Pending <span t-esc="dict(review._fields['state'].selection).get(review.state, review.state)"/></span>
<span style="color: #aa0000;">Pending - <span t-esc="dict(review._fields['state'].selection).get(review.state, review.state)"/></span>
</t>
</td>
<td>
<span t-esc="(_signer and _signer.name) or ''"/>
<span t-esc="(_signer and _signer.name) or '-'"/>
</td>
<td>
<span style="font-weight: bold;" t-esc="_initials or ''"/>
<span style="font-weight: bold;" t-esc="_initials or '-'"/>
</td>
<td>
<t t-if="_signed_dt">
<span t-esc="job.fp_format_local(_signed_dt, '%Y-%m-%d')"/>
</t>
<t t-else=""></t>
<t t-else="">-</t>
</td>
</tr>
</table>
@@ -304,7 +304,7 @@
<div class="fp-spec">Specification(s):
<span style="font-weight: normal;"
t-esc="(job.recipe_id and job.recipe_id.name) or ''"/>
t-esc="(job.recipe_id and job.recipe_id.name) or '-'"/>
</div>
<hr class="heavy"/>
@@ -313,7 +313,7 @@
<t t-foreach="all_steps" t-as="step">
<!-- Aggregate captured input values from any
move that touches this step (incoming or
outgoing the Record Inputs wizard
outgoing - the Record Inputs wizard
creates a self-loop move with from=to=step). -->
<t t-set="step_moves"
t-value="job.move_ids.filtered(
@@ -335,12 +335,12 @@
<div class="fp-step-block">
<h3>
<span t-esc="step.name or ''"/>
<span t-esc="step.name or '-'"/>
<t t-if="step.tank_id and step.tank_id.code">
(<span t-esc="step.tank_id.code"/>)
</t>
<t t-if="step.state == 'skipped'">
<span style="font-size: 9pt; color: #888; font-weight: normal;"> SKIPPED</span>
<span style="font-size: 9pt; color: #888; font-weight: normal;">- SKIPPED</span>
</t>
</h3>
<div class="fp-meta">
@@ -357,14 +357,14 @@
<t t-if="display_user or display_dt">
<br/>
<strong>Moved By:</strong>
<span t-esc="display_user or ''"/>
<span t-esc="display_user or '-'"/>
<span> </span>
<strong>Time:</strong>
<span t-esc="job.fp_format_local(display_dt, '%b %d, %Y %I:%M:%S %p') or ''"/>
<span t-esc="job.fp_format_local(display_dt, '%b %d, %Y %I:%M:%S %p') or '-'"/>
</t>
</div>
<!-- Captured inputs table only rendered
<!-- Captured inputs table - only rendered
when this step has at least one
value recorded across all its moves. -->
<t t-if="step_values">
@@ -463,7 +463,7 @@
<t t-if="not all_steps">
<p style="color: #888; font-style: italic;">
No steps on this job yet operators progress the
No steps on this job yet - operators progress the
job via Start / Finish &amp; Next on the form, or
via the tablet.
</p>
@@ -507,7 +507,7 @@
t-att-alt="att.name"/>
</div>
<div class="fp-photo-title">
Photo #<span t-esc="pidx"/> <span t-esc="ptitle"/>
Photo #<span t-esc="pidx"/> - <span t-esc="ptitle"/>
</div>
<div class="fp-photo-desc">
<t t-if="pstep">
@@ -515,7 +515,7 @@
</t>
<t t-if="puser or pdt">
<strong>Captured by:</strong>
<span t-esc="puser or ''"/>
<span t-esc="puser or '-'"/>
<t t-if="pdt">
on <span t-esc="job.fp_format_local(pdt, '%b %d, %Y %I:%M %p')"/>
</t>
@@ -548,7 +548,7 @@
Signature (`x_fc_signature_image`) from
Preferences → My Profile.
Resolution priority added 2026-05-17 per
ops request was auto-defaulting to the
ops request - was auto-defaulting to the
current user (whoever the job manager
happened to be) which signed every cert as
the wrong person. -->