feat(fusion_plating): Express masking reference images → mask step + workstation viewer

Order-entry shortcut: when masking is toggled ON for an Express order line,
an amber "MASK" button appears to attach reference image(s)/PDF(s). The files
ride the existing _fp_apply_express_overrides_to_job path onto the job's
masking step, so the operator sees exactly what to mask — no recipe edit or
custom prompt needed.

- configurator: masking_attachment_ids on the wizard line + SO line;
  action_upload_masking_ref; override branch writes refs onto mask steps;
  amber multi-file MASK button (express_action_btns) shown when masking is on.
- jobs: x_fc_masking_attachment_ids on fp.job.step (per-step) + computed
  rollup on fp.job; office "Masking Refs" form page (readonly preview).
- shopfloor: workspace step payload carries masking_refs (sudo'd attachment
  read, rule 13m); operator sees thumbnail/PDF tiles on the mask step that
  open in Odoo's full-screen FileViewer (zoom + swipe).

Verified end-to-end on entech: SO-line refs land on the mask step + job
rollup (WO-30091); payload mask_refs shape correct (is_image, /web/image).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-06-03 15:12:18 -04:00
parent b52b8758a1
commit 235c8fba39
16 changed files with 331 additions and 2 deletions

View File

@@ -573,6 +573,14 @@ class FpDirectOrderLine(models.Model):
help='Free-text bake instructions. Empty = bake steps are opted out. '
'Non-empty = bake step instructions on the operator tablet.',
)
masking_attachment_ids = fields.Many2many(
'ir.attachment',
'fp_direct_order_line_masking_att_rel', 'line_id', 'attachment_id',
string='Masking Reference(s)',
help='Image(s)/PDF(s) of what to mask. Carried to the SO line and '
'shown to the operator on the job\'s masking step. Only relevant '
'when Masking is enabled.',
)
# ---- Computes ----
@api.depends('quantity', 'unit_price')
@@ -766,6 +774,29 @@ class FpDirectOrderLine(models.Model):
'target': 'new',
}
def action_upload_masking_ref(self):
"""Attach a masking reference (image/PDF) to this line.
Called by the Express 'MASK REF' button — once per file (multi-select
loops in JS), via context keys fp_masking_file + fp_masking_filename.
Stored on the line's masking_attachment_ids; carried to the SO line
and the job's masking step at order confirm.
"""
self.ensure_one()
from odoo.exceptions import UserError
file_data = self.env.context.get('fp_masking_file')
filename = self.env.context.get('fp_masking_filename', 'masking-ref')
if not file_data:
raise UserError(_('No file data received.'))
att = self.env['ir.attachment'].sudo().create({
'name': filename,
'datas': file_data,
'res_model': 'fp.direct.order.line',
'res_id': self.id,
})
self.write({'masking_attachment_ids': [(4, att.id)]})
return True
def action_upload_drawing(self):
"""Attach a file (via context) to the line's part as a drawing.

View File

@@ -956,6 +956,7 @@ class FpDirectOrderWizard(models.Model):
'x_fc_customer_line_ref': line.customer_line_ref or False,
'x_fc_masking_enabled': line.masking_enabled,
'x_fc_bake_instructions': line.bake_instructions or False,
'x_fc_masking_attachment_ids': [(6, 0, line.masking_attachment_ids.ids)],
# Sub 9 — explicit tax override from the wizard line.
# When blank, Odoo will compute taxes from the product
# defaults at SO-line save time (the standard behaviour).