- Internal Job Sticker is no longer a separate Layout A: it's now a COPY of the External sticker (Layout B, one per box, logo + WO + BOX + QR + rail fields + prominent PLATING THICKNESS banner) but feeds the INTERNAL description and labels its notes "INTERNAL NOTES" so the shop copy can't be confused with the customer copy. The old Layout-A body template is deleted. - Removed the Internal sticker from the fp.job Print menu (binding_model_id -> False); it now prints from the Receiving screen instead. - Added "External Sticker" + "Internal Sticker" print buttons to the fp.receiving form header (shown once a WO exists). Each renders one label per tracked box for the receiving's work order (passes a single WO so the SO-scoped box loop doesn't reprint each label per job). Verified on entech (WO-30094 / RCV-30096): internal renders Layout B with the internal description + INTERNAL NOTES; external unchanged; both receiving buttons return the right report actions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
100 lines
3.8 KiB
Python
100 lines
3.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
#
|
|
# Adds the Work Order smart button + header action to fp.receiving so
|
|
# the receiving form mirrors the SO's WO entry point. Button appears
|
|
# once the receiving is closed and stays until every linked fp.job
|
|
# reaches state='done'.
|
|
|
|
from odoo import _, fields, models
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class FpReceiving(models.Model):
|
|
_inherit = 'fp.receiving'
|
|
|
|
x_fc_fp_job_count = fields.Integer(
|
|
string='Work Orders',
|
|
compute='_compute_fp_job_count',
|
|
)
|
|
x_fc_show_work_order_btn = fields.Boolean(
|
|
string='Show Work Order Button',
|
|
compute='_compute_show_work_order_btn',
|
|
help='True once this receiving is closed and at least one linked '
|
|
'work order is still open (state != done). Hidden again '
|
|
'when every job is done.',
|
|
)
|
|
|
|
def _compute_fp_job_count(self):
|
|
Job = self.env['fp.job'].sudo()
|
|
for rec in self:
|
|
if rec.sale_order_id:
|
|
rec.x_fc_fp_job_count = Job.search_count(
|
|
[('sale_order_id', '=', rec.sale_order_id.id)]
|
|
)
|
|
else:
|
|
rec.x_fc_fp_job_count = 0
|
|
|
|
def _compute_show_work_order_btn(self):
|
|
Job = self.env['fp.job'].sudo()
|
|
for rec in self:
|
|
if rec.state != 'closed' or not rec.sale_order_id:
|
|
rec.x_fc_show_work_order_btn = False
|
|
continue
|
|
jobs = Job.search([('sale_order_id', '=', rec.sale_order_id.id)])
|
|
rec.x_fc_show_work_order_btn = bool(jobs) and any(
|
|
j.state != 'done' for j in jobs
|
|
)
|
|
|
|
def action_view_fp_jobs(self):
|
|
"""Open the work order(s) linked to this receiving's sale order."""
|
|
self.ensure_one()
|
|
if not self.sale_order_id:
|
|
return False
|
|
jobs = self.env['fp.job'].search([
|
|
('sale_order_id', '=', self.sale_order_id.id),
|
|
])
|
|
action = {
|
|
'type': 'ir.actions.act_window',
|
|
'name': _('Work Orders'),
|
|
'res_model': 'fp.job',
|
|
'view_mode': 'list,form',
|
|
'domain': [('sale_order_id', '=', self.sale_order_id.id)],
|
|
'context': {'default_sale_order_id': self.sale_order_id.id},
|
|
}
|
|
if len(jobs) == 1:
|
|
action.update({'view_mode': 'form', 'res_id': jobs.id})
|
|
return action
|
|
|
|
# ---- Sticker printing from the Receiving screen (2026-06-04) ----------
|
|
# Both stickers loop the SO's boxes (one label per box). Pass a SINGLE
|
|
# work order: the box loop is sale-order-scoped, so feeding every job
|
|
# would reprint each box label once per job. One job → exactly one label
|
|
# per box. Falls back to a single 1/1 label when no boxes exist yet.
|
|
def _fp_sticker_jobs(self):
|
|
self.ensure_one()
|
|
if not self.sale_order_id:
|
|
return self.env['fp.job']
|
|
return self.env['fp.job'].sudo().search(
|
|
[('sale_order_id', '=', self.sale_order_id.id)], order='id', limit=1)
|
|
|
|
def _fp_print_sticker(self, xmlid):
|
|
self.ensure_one()
|
|
jobs = self._fp_sticker_jobs()
|
|
if not jobs:
|
|
raise UserError(_(
|
|
'No work order exists for this receiving yet — create the '
|
|
'Work Order before printing stickers.'))
|
|
return self.env.ref(xmlid).report_action(jobs)
|
|
|
|
def action_print_external_sticker(self):
|
|
"""Customer (external) box sticker(s) for this receiving's WO."""
|
|
return self._fp_print_sticker(
|
|
'fusion_plating_jobs.action_report_fp_job_sticker')
|
|
|
|
def action_print_internal_sticker(self):
|
|
"""Shop (internal) box sticker(s) — same layout, internal notes."""
|
|
return self._fp_print_sticker(
|
|
'fusion_plating_jobs.action_report_fp_job_sticker_internal')
|