feat(plating): Sub 8 — split receiving vs inspection + box parity
fp.receiving simplifies to box-count-only (new primary state machine: draft → counted → staged → closed). Legacy inspecting/accepted/discrepancy/resolved states stay in the Selection so existing records load without error but are surfaced behind a manager-only toggle. New box_count_in field + banner that tells the receiver "count boxes only — parts are inspected by the racking crew." New fp.racking.inspection + fp.racking.inspection.line models — one record per MO, auto-created by mrp.production.create() with one line per contributing SO line (qty_expected seeded, qty_found + condition filled in by the racking crew when they open the boxes). State: draft → inspecting → done | discrepancy_flagged (flagged when any line has a non-ok condition or qty variance). Reopen restricted to Plating Manager. WO soft gate: first plating WO button_start raises a UserError when the MO's racking inspection is still Draft or Inspecting. Plating Manager bypasses; later WOs are not gated. fp.delivery gains x_fc_box_count_out. action_mark_delivered calls _fp_check_box_parity which posts a non-blocking chatter warning when boxes out ≠ boxes in (resolved via job_ref → MO.origin → SO → receiving). Warning only — never blocks shipping. Menu entry: Plating → Operations → Racking Inspection. Module version bumps: fusion_plating_receiving → 19.0.3.0.0 fusion_plating_logistics → 19.0.3.0.0 fusion_plating_bridge_mrp → 19.0.12.0.0 (+depends receiving) Smoke on entech: 12/12 assertions pass (one gate test skipped — MO had no WOs to test) including box-count state machine, inspection auto-create, lifecycle, discrepancy flag, and box-parity chatter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
{
|
||||
'name': 'Fusion Plating — Logistics',
|
||||
'version': '19.0.2.0.0',
|
||||
'version': '19.0.3.0.0',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': (
|
||||
'Pickup & delivery for plating shops: vehicle master, driver '
|
||||
|
||||
@@ -74,6 +74,17 @@ class FpDelivery(models.Model):
|
||||
x_fc_revision_snapshot = fields.Char(
|
||||
string='Revision (snapshot)',
|
||||
)
|
||||
|
||||
# ---- Sub 8 — box parity ------------------------------------------------
|
||||
# Shipping crew packs returns into the SAME boxes the parts arrived in
|
||||
# (client requirement). Receiving captures box_count_in; we capture
|
||||
# box_count_out here. action_mark_delivered posts a non-blocking
|
||||
# chatter warning if they don't match.
|
||||
x_fc_box_count_out = fields.Integer(
|
||||
string='Boxes Out',
|
||||
help='Number of boxes the shipping crew packed for return. '
|
||||
'Should match the box count captured at receiving.',
|
||||
)
|
||||
scheduled_date = fields.Datetime(
|
||||
string='Scheduled Date',
|
||||
tracking=True,
|
||||
@@ -226,6 +237,48 @@ class FpDelivery(models.Model):
|
||||
or 'Driver'),
|
||||
to_party=rec.partner_id.display_name,
|
||||
)
|
||||
# Sub 8 — box-parity warning. Non-blocking; just posts to
|
||||
# chatter so the shipping supervisor sees it on the record.
|
||||
rec._fp_check_box_parity()
|
||||
|
||||
def _fp_check_box_parity(self):
|
||||
"""Compare this delivery's boxes-out count to the boxes-in count
|
||||
captured at receiving. Post a chatter warning if they differ.
|
||||
|
||||
Never blocks — shipping has already happened by the time this
|
||||
fires. The warning is for audit + shipping-supervisor review.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if not self.x_fc_box_count_out:
|
||||
return
|
||||
Receiving = self.env.get('fp.receiving')
|
||||
if Receiving is None:
|
||||
return
|
||||
# Resolve SO via job_ref → MO.origin → SO.name
|
||||
so_name = False
|
||||
if self.job_ref:
|
||||
mo = self.env['mrp.production'].search(
|
||||
[('name', '=', self.job_ref)], limit=1,
|
||||
)
|
||||
if mo and mo.origin:
|
||||
so_name = mo.origin
|
||||
if not so_name:
|
||||
return
|
||||
so = self.env['sale.order'].search(
|
||||
[('name', '=', so_name)], limit=1,
|
||||
)
|
||||
if not so:
|
||||
return
|
||||
recv = Receiving.search(
|
||||
[('sale_order_id', '=', so.id)], limit=1,
|
||||
)
|
||||
if not recv or not recv.box_count_in:
|
||||
return
|
||||
if recv.box_count_in != self.x_fc_box_count_out:
|
||||
self.message_post(body=_(
|
||||
'Box parity check: shipped %(out)d box(es), received '
|
||||
'%(in)d. Verify consolidation was intended.'
|
||||
) % {'out': self.x_fc_box_count_out, 'in': recv.box_count_in})
|
||||
|
||||
def action_mark_refused(self):
|
||||
self.write({'state': 'refused'})
|
||||
|
||||
Reference in New Issue
Block a user