feat(fusion_plating): box-level tracking (fp.box) + thermal job-sticker redesign
Box registry: new fp.box model (fusion_plating_receiving), one record per received box, auto-created when a receiving is marked Counted (idempotent _fp_sync_boxes — grows/shrinks with box_count_in, never touches an advanced box). Status received -> racked -> in_process -> packed -> shipped, per-box scannable QR (/fp/box/<id> controller). Backfill migration for receivings counted before tracking shipped. Boxes list/kanban/form + receiving smart button. Job stickers redesigned (thermal label, 6x4 in / 152x102mm, mm layout @ paperformat dpi=96 so mm maps 1:1 in wkhtmltopdf — see rule 14): - Internal Job Sticker = Layout A, ONE per job (shop notes from x_fc_internal_description, job QR). - External Job Sticker = Layout B, ONE per fp.box (BOX n/N, per-box QR, factory company logo, customer-facing notes). Dynamic MASK badge (x_fc_masking_enabled) + BAKE block (x_fc_bake_instructions), length-tiered notes font. Display logic in fp.job._fp_sticker_data(). Also retains the SO/WO box-sticker MemoryError fix in report_fp_wo_sticker.xml (per-box loop sourced from fp.receiving.box_count_in + 100-label safety cap). Verified live on entech: 111 boxes backfilled (31 receivings), External renders one page per box, Internal one per job, scan endpoint 303->login. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -274,7 +274,14 @@
|
||||
<!-- 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">
|
||||
<!-- Hard safety cap (defense in depth): never render more than 100
|
||||
label pages in one pass, regardless of what _qty_total resolves
|
||||
to. A sticker is a per-box identification label; rendering
|
||||
thousands (each with an inlined logo + QR data-URI) OOMs the
|
||||
worker. WO-30072 (qty 2000 parts) crashed the PDF engine here. -->
|
||||
<t t-set="_label_count_raw" t-value="int(_qty_total or 1)"/>
|
||||
<t t-set="_label_count" t-value="100 if _label_count_raw > 100 else (1 if _label_count_raw < 1 else _label_count_raw)"/>
|
||||
<t t-foreach="range(_label_count)" t-as="_box_idx0">
|
||||
<t t-set="_box_idx" t-value="_box_idx0 + 1"/>
|
||||
<div class="fp-sticker">
|
||||
<!-- 3-cell header: Logo | WO# | QR -->
|
||||
@@ -517,7 +524,13 @@
|
||||
<t t-set="_spec" t-value="line.x_fc_customer_spec_id"/>
|
||||
<t t-set="_due" t-value="line.x_fc_part_deadline or so.commitment_date or False"/>
|
||||
<t t-set="_qty" t-value="line.product_uom_qty"/>
|
||||
<t t-set="_qty_total" t-value="line.product_uom_qty"/>
|
||||
<!-- One label per physical BOX (box_count_in on the
|
||||
SO's receiving), NOT per part. Was
|
||||
line.product_uom_qty, which rendered one label per
|
||||
part and OOM'd on large qty (WO-30072 = 2000).
|
||||
Falls back to 1 when no box count is recorded. -->
|
||||
<t t-set="_box_count" t-value="int(sum(so.env['fp.receiving'].sudo().search([('sale_order_id', '=', so.id)]).mapped('box_count_in')) or 0) if 'fp.receiving' in so.env else 0"/>
|
||||
<t t-set="_qty_total" t-value="_box_count if _box_count > 0 else 1"/>
|
||||
<t t-set="_partner_name" t-value="so.partner_id.name"/>
|
||||
<t t-set="_mo_ref" t-value="''"/>
|
||||
<t t-call="fusion_plating_reports.report_fp_wo_sticker_inner"/>
|
||||
@@ -572,7 +585,13 @@
|
||||
<t t-set="_spec" t-value="line.x_fc_customer_spec_id"/>
|
||||
<t t-set="_due" t-value="line.x_fc_part_deadline or so.commitment_date or False"/>
|
||||
<t t-set="_qty" t-value="line.product_uom_qty"/>
|
||||
<t t-set="_qty_total" t-value="line.product_uom_qty"/>
|
||||
<!-- One label per physical BOX (box_count_in on the
|
||||
SO's receiving), NOT per part. Was
|
||||
line.product_uom_qty, which rendered one label per
|
||||
part and OOM'd on large qty (WO-30072 = 2000).
|
||||
Falls back to 1 when no box count is recorded. -->
|
||||
<t t-set="_box_count" t-value="int(sum(so.env['fp.receiving'].sudo().search([('sale_order_id', '=', so.id)]).mapped('box_count_in')) or 0) if 'fp.receiving' in so.env else 0"/>
|
||||
<t t-set="_qty_total" t-value="_box_count if _box_count > 0 else 1"/>
|
||||
<t t-set="_partner_name" t-value="so.partner_id.name"/>
|
||||
<t t-set="_mo_ref" t-value="''"/>
|
||||
<!-- Internal override: read x_fc_internal_description -->
|
||||
|
||||
Reference in New Issue
Block a user