diff --git a/fusion_plating/fusion_plating/__manifest__.py b/fusion_plating/fusion_plating/__manifest__.py index b5c25e37..15002879 100644 --- a/fusion_plating/fusion_plating/__manifest__.py +++ b/fusion_plating/fusion_plating/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Plating', - 'version': '19.0.8.5.0', + 'version': '19.0.8.5.1', 'category': 'Manufacturing/Plating', 'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.', 'description': """ diff --git a/fusion_plating/fusion_plating/models/fp_job_step.py b/fusion_plating/fusion_plating/models/fp_job_step.py index 01f09211..dd7fbc34 100644 --- a/fusion_plating/fusion_plating/models/fp_job_step.py +++ b/fusion_plating/fusion_plating/models/fp_job_step.py @@ -158,31 +158,31 @@ class FpJobStep(models.Model): # ------------------------------------------------------------------ # Implemented: button_start (ready/paused → in_progress), # button_finish (in_progress → done). - # Stubs (raise NotImplementedError for Task 1.6): + # Stubs (raise NotImplementedError; wiring deferred): # button_pause (in_progress → paused) # button_resume (covered by button_start when state='paused') # button_skip (pending/ready → skipped) # button_cancel (any non-done → cancelled) - # Predecessor-driven transition pending → ready will land in - # Task 1.6 along with first-step / dependency wiring. + # Predecessor-driven transition pending → ready will be wired + # alongside first-step / dependency logic in a future task. # ------------------------------------------------------------------ def button_pause(self): raise NotImplementedError(_( - "button_pause lands in Task 1.6 (operator pause / break / " + "button_pause is not yet implemented (operator pause / break / " "end-of-shift). Use button_finish to complete a step or set " "state directly via privileged code." )) def button_skip(self): raise NotImplementedError(_( - "button_skip lands in Task 1.6 (skip an opt-in step that " + "button_skip is not yet implemented (skip an opt-in step that " "wasn't activated for this job)." )) def button_cancel(self): raise NotImplementedError(_( - "button_cancel lands in Task 1.6 (cancelling a single step; " + "button_cancel is not yet implemented (cancelling a single step; " "cancelling the whole job runs through fp.job.action_cancel)." )) diff --git a/fusion_plating/fusion_plating/tests/test_fp_job_step_state_machine.py b/fusion_plating/fusion_plating/tests/test_fp_job_step_state_machine.py index 3169641c..abea0953 100644 --- a/fusion_plating/fusion_plating/tests/test_fp_job_step_state_machine.py +++ b/fusion_plating/fusion_plating/tests/test_fp_job_step_state_machine.py @@ -103,3 +103,20 @@ class TestFpJobStepStateMachine(TransactionCase): step.duration_actual = 30.0 # Recompute happens on read after a write to a depends field self.assertEqual(step.cost_total, 30.0) + + def test_cost_total_recomputes_when_rate_changes(self): + # Insurance test: verify @api.depends('cost_per_hour') triggers + # through the related-from-work_centre chain. If a future Odoo + # upgrade breaks related-depends, this test catches it. + wc = self.env['fp.work.centre'].create({ + 'name': 'WC4', 'code': 'WC4', 'kind': 'wet_line', + 'cost_per_hour': 60.0, + }) + step = self._make_step(work_centre_id=wc.id) + step.duration_actual = 30.0 + self.assertEqual(step.cost_total, 30.0) + # Change the rate; cost_total should recompute. + wc.cost_per_hour = 120.0 + # Force recompute via invalidate (Odoo recomputes on next read). + step.invalidate_recordset(['cost_total']) + self.assertEqual(step.cost_total, 60.0)