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:
@@ -0,0 +1,18 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
"""Box scan endpoint. The per-box QR on the External Job Sticker encodes
|
||||
``/fp/box/<id>``; scanning it (logged-in operator on the tablet) lands on
|
||||
the box's backend form where they can advance its status."""
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class FpBoxScan(http.Controller):
|
||||
|
||||
@http.route(['/fp/box/<int:box_id>'], type='http', auth='user', website=False)
|
||||
def fp_box_scan(self, box_id, **kw):
|
||||
box = request.env['fp.box'].sudo().browse(box_id).exists()
|
||||
if not box:
|
||||
return request.not_found()
|
||||
# Land on the box form in the web client (operator advances status there).
|
||||
return request.redirect('/web#id=%s&model=fp.box&view_type=form' % box.id)
|
||||
Reference in New Issue
Block a user