feat(sticker): per-box render loop + Notes override hook

Inner sticker template gains two parameters that outer templates
pre-set:

  _qty_total — total qty for the line/job. Inner wraps the body
    in t-foreach="range(int(_qty_total or 1))" so a qty=5 line
    produces 5 consecutive single-box stickers. Qty row in the
    body switches from "5" to "1 / 5", "2 / 5", ... "5 / 5".
    When _qty_total is missing/0/1, the Qty row keeps showing
    the plain integer (regression-free).

  _notes_content — Notes column source. Existing inner code
    hard-read _line.name; new code accepts an outer override
    and falls back to _line.name. External outers don't set it
    (unchanged behaviour); the new Internal outers (Task 4+5)
    pre-set it to x_fc_internal_description.

Defaults template initialises both new vars to False so the
inner's "outer-supplied OR fallback" pattern doesn't NameError
when called from existing outers that haven't been updated yet.

Verified regression-free: fp.job 2635 (qty=1) renders identically
to its pre-Task baseline — Qty row shows plain "1", Notes from
line.name as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-13 08:00:22 -04:00
parent e4681a58c6
commit 0a32ed2da7
2 changed files with 21 additions and 6 deletions

View File

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

View File

@@ -80,10 +80,12 @@
rendering. ASCII-only printable for any QR-label printer. -->
<t t-set="_thickness_dn" t-value="_line and 'x_fc_thickness_id' in _line._fields and _line.x_fc_thickness_id and _line.x_fc_thickness_id.display_name"/>
<t t-set="_thickness" t-value="(_thickness_dn and _thickness_dn.replace(u'', '-').replace(u'—', '-')) or '-'"/>
<!-- Notes content = customer-facing description. Per Sub 2 decision
Q6: SO line `name` is the customer-facing description (Odoo
standard). Falls back to product name when the line is bare. -->
<t t-set="_notes_content" t-value="(_line and _line.name)
<!-- Notes content — outer can pre-set this (e.g. the Internal
variant passes line.x_fc_internal_description). Otherwise
falls back to line.name (customer-facing description per
Sub 2 Q6), then to part.name. -->
<t t-set="_notes_content" t-value="_notes_content
or (_line and _line.name)
or (_part and _part.name)
or '-'"/>
<!-- Inline the QR as base64 data URI so wkhtmltopdf doesn't need
@@ -240,6 +242,11 @@
}
</style>
<!-- Per-box loop: renders one sticker page per physical box in
the line/job qty. When _qty_total is missing/0/1, falls
back to a single render (no "X / N" indicator). -->
<t t-foreach="range(int(_qty_total or 1))" t-as="_box_idx0">
<t t-set="_box_idx" t-value="_box_idx0 + 1"/>
<div class="fp-sticker">
<!-- 3-cell header: Logo | WO# | QR -->
<div class="fp-sticker-head-wrap">
@@ -346,7 +353,12 @@
<td class="fp-sticker-label">Qty:</td>
<td class="fp-sticker-value">
<span class="fp-sticker-strong">
<span t-esc="int(_qty) if _qty == int(_qty) else _qty"/>
<t t-if="_qty_total and int(_qty_total) &gt; 1">
<span t-esc="_box_idx"/> / <span t-esc="int(_qty_total)"/>
</t>
<t t-else="">
<span t-esc="int(_qty) if _qty == int(_qty) else _qty"/>
</t>
</span>
</td>
</tr>
@@ -360,6 +372,7 @@
</div>
</div>
</div>
</t>
</template>
<!-- =====================================================
@@ -381,6 +394,8 @@
<t t-set="_mo_ref" t-value="False"/>
<t t-set="_internal_note" t-value="False"/>
<t t-set="_scan_path" t-value="False"/>
<t t-set="_notes_content" t-value="False"/>
<t t-set="_qty_total" t-value="False"/>
</template>
<!-- ========== Outer template — mrp.workorder entry ========== -->