feat(jobs): button_start auto-routes contract_review steps to QA-005
User feedback on WH/JOB/00341 (S00279 retest): clicking Start on
the Contract Review step changed state to in_progress but didn't
take them to QA-005. They had to then click Finish & Next twice
to land on the form — confusing flow.
Better UX: when an operator clicks Start on a step where
recipe_node.default_kind='contract_review', the step starts AND
the QA-005 form opens immediately. Operator signs/dismisses,
navigates back, hits Finish & Next once → step finishes + advances.
Implementation:
fp.job.step.button_start, after super() returns and the
receiving check runs, calls _fp_contract_review_redirect()
(existing helper). If it returns an action, return that
instead of the parent's result. Single-record only — bulk
button_start (job-level start-all) shouldn't navigate.
Helper logic unchanged — same gate matrix:
* recipe_node.default_kind == 'contract_review'
* job has part_catalog_id
* review state NOT in (complete, dismissed)
When review is already complete, the gate clears: button_start
returns the normal True so the operator can advance the step
without bouncing through QA-005 again.
Tests:
test_button_start_routes_cr_step_to_qa005 — start opens QA-005
test_button_start_does_not_route_when_review_complete — start
does NOT redirect once review is signed off
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
{
|
{
|
||||||
'name': 'Fusion Plating — Native Jobs',
|
'name': 'Fusion Plating — Native Jobs',
|
||||||
'version': '19.0.8.17.0',
|
'version': '19.0.8.17.1',
|
||||||
'category': 'Manufacturing/Plating',
|
'category': 'Manufacturing/Plating',
|
||||||
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
||||||
'author': 'Nexa Systems Inc.',
|
'author': 'Nexa Systems Inc.',
|
||||||
|
|||||||
@@ -148,6 +148,20 @@ class FpJobStep(models.Model):
|
|||||||
'so': so.name or '',
|
'so': so.name or '',
|
||||||
'status': recv or 'unknown',
|
'status': recv or 'unknown',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Sub 12e v4 — when an operator starts a contract_review step,
|
||||||
|
# immediately route to the QA-005 form. The step stays
|
||||||
|
# in_progress in the background; the operator signs (or
|
||||||
|
# dismisses) the review on QA-005, navigates back to the job,
|
||||||
|
# then clicks Finish & Next to advance. This removes the
|
||||||
|
# earlier "click Start, then click Finish & Next, then maybe
|
||||||
|
# click Finish & Next again" friction.
|
||||||
|
# Single-record only — multi-record button_start (e.g. job
|
||||||
|
# bulk-start) shouldn't navigate.
|
||||||
|
if len(self) == 1:
|
||||||
|
cr_action = self._fp_contract_review_redirect()
|
||||||
|
if cr_action:
|
||||||
|
return cr_action
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def button_pause(self):
|
def button_pause(self):
|
||||||
|
|||||||
@@ -827,6 +827,47 @@ class TestContractReviewStepRouting(TransactionCase):
|
|||||||
% action,
|
% action,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_button_start_routes_cr_step_to_qa005(self):
|
||||||
|
"""Sub 12e v4 UX — clicking Start on a contract_review step
|
||||||
|
should set state=in_progress AND immediately return the QA-005
|
||||||
|
action so the operator lands on the form without needing to
|
||||||
|
click Finish & Next."""
|
||||||
|
# Use the setUp's CR step but reset state to 'ready' so we
|
||||||
|
# can call button_start. Skip the predecessor gate since
|
||||||
|
# there are no other steps in this minimal test job.
|
||||||
|
self.step.state = 'ready'
|
||||||
|
action = self.step.with_context(
|
||||||
|
fp_skip_predecessor_check=True,
|
||||||
|
).button_start()
|
||||||
|
# State must transition
|
||||||
|
self.assertEqual(self.step.state, 'in_progress')
|
||||||
|
# And the action returned must be the QA-005 form
|
||||||
|
self.assertTrue(
|
||||||
|
self._is_contract_review_action(action),
|
||||||
|
'button_start on a contract_review step must return the '
|
||||||
|
'QA-005 action, got: %r' % action,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_button_start_does_not_route_when_review_complete(self):
|
||||||
|
"""If the QA-005 review is already complete, button_start
|
||||||
|
on the CR step should NOT redirect — operator just starts
|
||||||
|
the step normally and clicks Finish & Next when ready."""
|
||||||
|
review = self.env['fp.contract.review'].create({
|
||||||
|
'part_id': self.part.id,
|
||||||
|
'state': 'complete',
|
||||||
|
})
|
||||||
|
self.part.x_fc_contract_review_id = review.id
|
||||||
|
self.step.state = 'ready'
|
||||||
|
action = self.step.with_context(
|
||||||
|
fp_skip_predecessor_check=True,
|
||||||
|
).button_start()
|
||||||
|
self.assertEqual(self.step.state, 'in_progress')
|
||||||
|
self.assertFalse(
|
||||||
|
self._is_contract_review_action(action),
|
||||||
|
'When review is complete, button_start must NOT redirect '
|
||||||
|
'(the gate is closed). Got: %r' % action,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestSequentialEnforcement(TransactionCase):
|
class TestSequentialEnforcement(TransactionCase):
|
||||||
"""Sub 13 — recipe-level + per-step sequential enforcement.
|
"""Sub 13 — recipe-level + per-step sequential enforcement.
|
||||||
|
|||||||
Reference in New Issue
Block a user