diff --git a/fusion_plating/fusion_plating/models/fp_rack.py b/fusion_plating/fusion_plating/models/fp_rack.py index 58402ec9..57831149 100644 --- a/fusion_plating/fusion_plating/models/fp_rack.py +++ b/fusion_plating/fusion_plating/models/fp_rack.py @@ -115,3 +115,67 @@ class FpRack(models.Model): """Add `delta` to the rack's MTO count. Called by the WO finish hook.""" for rec in self: rec.mto_count = (rec.mto_count or 0.0) + delta + + # ===== Sub 12b — racking lifecycle (orthogonal to wear-tracking state) = + racking_state = fields.Selection( + [ + ('empty', 'Empty'), + ('loading', 'Loading'), + ('loaded', 'Loaded'), + ('in_use', 'In Use'), + ('awaiting_unrack', 'Awaiting Unrack'), + ('out_of_service', 'Out of Service'), + ], + string='Racking State', default='empty', tracking=True, + help='Operational state in the rack→step→tank flow. Distinct ' + 'from the wear-tracking `state` (active/needs_strip/...).', + ) + tag_ids = fields.Many2many( + 'fp.rack.tag', + 'fp_rack_tag_rel', 'rack_id', 'tag_id', + string='Tags', + ) + capacity_count = fields.Integer( + string='Capacity (parts) — soft warn', + help='Soft warning threshold — runtime informs operator when ' + 'rack is loaded beyond this. Not enforced. Distinct from ' + '`capacity` field (planning capacity).', + ) + + current_job_step_id = fields.Many2one( + 'fp.job.step', string='Current Step', + compute='_compute_current_use', store=True, + ) + current_tank_id = fields.Many2one( + 'fusion.plating.tank', string='Current Tank', + compute='_compute_current_use', store=True, + ) + current_part_count = fields.Integer( + string='Parts on Rack', + compute='_compute_current_use', store=True, + ) + + @api.depends('racking_state') + def _compute_current_use(self): + # Walks the most recent fp.job.step.move row per rack to derive + # current step + tank + part count. For racks not currently in + # use, all values are blank. + Move = self.env['fp.job.step.move'] + for rack in self: + if rack.racking_state in ('empty', 'out_of_service'): + rack.current_job_step_id = False + rack.current_tank_id = False + rack.current_part_count = 0 + continue + recent = Move.search( + [('rack_id', '=', rack.id)], + order='move_datetime desc', + limit=1, + ) + rack.current_job_step_id = recent.to_step_id if recent else False + # current_tank_id pulls from the destination step's tank if set + rack.current_tank_id = ( + recent.to_tank_id or + (recent.to_step_id.tank_id if recent and recent.to_step_id else False) + ) if recent else False + rack.current_part_count = recent.qty_moved if recent else 0 diff --git a/fusion_plating/fusion_plating/views/fp_rack_views.xml b/fusion_plating/fusion_plating/views/fp_rack_views.xml index 12be9775..29d3d3c1 100644 --- a/fusion_plating/fusion_plating/views/fp_rack_views.xml +++ b/fusion_plating/fusion_plating/views/fp_rack_views.xml @@ -68,6 +68,20 @@ + + + + + + + + + + + +