feat(fusion_plating_jobs): de-rack/bake area_kind name override + rack-load Phase 1
- _compute_area_kind: name-based override so de-rack/de-mask steps land in the De-Racking column and bake/oven steps in Baking, regardless of a mis-tagged recipe kind (fixed WO cards scattering into the wrong shop-floor columns). - fp.rack.load jobs extension: racking-step resolution by area_kind (not the corrupt kind), equal-split/override ops, fp.job qty_racked/unracked rollups, and independent rack movement (per-line moves) + de-racking unrack. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -128,34 +128,83 @@ class FpJobStep(models.Model):
|
||||
@api.depends(
|
||||
'work_centre_id.area_kind',
|
||||
'recipe_node_id.kind_id.area_kind',
|
||||
'name',
|
||||
)
|
||||
def _compute_area_kind(self):
|
||||
"""Resolve the plant-view column this step belongs in.
|
||||
|
||||
Priority chain:
|
||||
1. work_centre.area_kind (explicit operator setup wins)
|
||||
2. recipe_node.kind_id.area_kind (kind taxonomy authoritative)
|
||||
3. catch-all 'plating' (data integrity issue if we land here)
|
||||
1. name-based override for unambiguous de-rack / de-mask steps
|
||||
(2026-06-03): their recipe kind AND/OR work-centre is
|
||||
frequently wrong (tagged 'racking'/'mask', a shared station,
|
||||
or left blank), which scattered de-racking cards across the
|
||||
Racking / Masking / Plating columns. The operator-facing step
|
||||
NAME is unambiguous for these, so it wins OUTRIGHT — even over
|
||||
an explicit work-centre. Bake/oven steps that merely mention
|
||||
"de-rack" in their name are excluded so they stay in Baking.
|
||||
2. work_centre.area_kind (explicit operator setup)
|
||||
3. recipe_node.kind_id.area_kind (kind taxonomy authoritative)
|
||||
4. catch-all 'plating' (data integrity issue if we land here)
|
||||
|
||||
The legacy _STEP_KIND_TO_AREA dict was removed — fp.step.kind
|
||||
now self-declares its area_kind, so the kind taxonomy IS the
|
||||
source of truth. See spec
|
||||
The kind taxonomy remains the source of truth for every area
|
||||
EXCEPT de-rack/de-mask (step 1). See spec
|
||||
2026-05-24-shopfloor-live-step-fix-design.md Change 6.
|
||||
"""
|
||||
for step in self:
|
||||
# 1. Explicit work_centre wins
|
||||
# 1. Name override (de-rack/de-mask -> De-Racking, bake/oven ->
|
||||
# Baking) — unambiguous; the authored kind / work-centre is
|
||||
# frequently wrong/blank for these. See _fp_area_from_step_name.
|
||||
name_area = self._fp_area_from_step_name(step.name)
|
||||
if name_area:
|
||||
step.area_kind = name_area
|
||||
continue
|
||||
# 2. Explicit work_centre setup
|
||||
if step.work_centre_id and step.work_centre_id.area_kind:
|
||||
step.area_kind = step.work_centre_id.area_kind
|
||||
continue
|
||||
# 2. Kind taxonomy
|
||||
# 3. Kind taxonomy
|
||||
node = step.recipe_node_id
|
||||
if node and node.kind_id and node.kind_id.area_kind:
|
||||
step.area_kind = node.kind_id.area_kind
|
||||
continue
|
||||
# 3. Catch-all — only reached for orphaned steps (no
|
||||
# 4. Catch-all — only reached for orphaned steps (no
|
||||
# work_centre AND no recipe_node).
|
||||
step.area_kind = 'plating'
|
||||
|
||||
@staticmethod
|
||||
def _fp_area_from_step_name(name):
|
||||
"""Unambiguous step-name -> area_kind override (area or None).
|
||||
|
||||
The recipe kind is frequently wrong/blank for these step types, so
|
||||
the operator-facing NAME is the more reliable signal and wins over
|
||||
kind/work-centre in _compute_area_kind:
|
||||
|
||||
- bake / oven -> 'baking' (checked FIRST so "Oven bake (Post
|
||||
de-rack)" counts as a bake, not a de-rack). Excludes
|
||||
inspection-of-bake names ("post-bake inspection/QC/test") and
|
||||
part-number / generic references ("General Processing -
|
||||
BAKE-K464034") so only real bake operations move.
|
||||
- de-rack / de-mask -> 'de_racking'.
|
||||
|
||||
Everything else returns None so the normal work-centre / kind /
|
||||
fallback chain applies.
|
||||
"""
|
||||
x = (name or '').strip().lower()
|
||||
if not x:
|
||||
return None
|
||||
# bake / oven first — a "post de-rack" oven bake IS a bake
|
||||
if 'oven' in x or 'bake' in x:
|
||||
if any(w in x for w in (
|
||||
'processing', 'inspect', 'check', 'qc',
|
||||
'test', 'verif', 'review')):
|
||||
return None
|
||||
return 'baking'
|
||||
# de-rack / de-mask
|
||||
flat = x.replace('-', '').replace('_', '').replace(' ', '')
|
||||
if 'derack' in flat or 'demask' in flat:
|
||||
return 'de_racking'
|
||||
return None
|
||||
|
||||
last_activity_at = fields.Datetime(
|
||||
string='Last Activity',
|
||||
index=True,
|
||||
|
||||
Reference in New Issue
Block a user