Files
Odoo-Modules/fusion_plating/fusion_plating_jobs/tests/test_blocker_compute.py
gsinghpal 8c76a16366 chore(plating): de-dash shipped code + intake-neutral customer emails
Replace em-dashes and en-dashes with hyphens across 789 shipped source
files (py/xml/js/scss) so the delivered module reads as human-written;
em-dashes had become a recognizable AI-generated tell. Internal .md dev
notes are excluded. The WO-sticker mojibake strippers keep their dash
search targets (now written — / –). No logic changes: comments
and display strings only; validated with py_compile + lxml parse.

Rewrite the 7 customer notification emails to be intake-neutral
(ship-in / drop-off / pickup) and repair-aware, and fix the Shipped
email documents line (packing slip vs bill of lading; certificate only
when issued). Subjects use a hyphen separator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 00:16:19 -04:00

71 lines
2.9 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc. - License OPL-1
from odoo.tests.common import TransactionCase, tagged
@tagged('-at_install', 'post_install', 'fp_jobs')
class TestBlockerCompute(TransactionCase):
"""fp.job.step.blocker_kind / blocker_reason / blocker_jump_target_*
- Gate visualizer source of truth for the OWL GateViz component.
"""
def setUp(self):
super().setUp()
self.partner = self.env['res.partner'].create({'name': 'Test Cust'})
self.product = self.env['product.product'].create({'name': 'Test Prod'})
self.job = self.env['fp.job'].create({
'name': 'WH/JOB/T1',
'partner_id': self.partner.id,
'product_id': self.product.id,
'qty': 1,
})
def _make_step(self, name, sequence, state='ready'):
return self.env['fp.job.step'].create({
'job_id': self.job.id,
'name': name,
'sequence': sequence,
'state': state,
})
def test_terminal_step_has_no_blocker(self):
step = self._make_step('Done step', 10, state='done')
self.assertEqual(step.blocker_kind, 'none')
self.assertEqual(step.blocker_reason, '')
def test_in_progress_step_has_no_blocker(self):
step = self._make_step('Running step', 10, state='in_progress')
self.assertEqual(step.blocker_kind, 'none')
def test_solo_ready_step_not_blocked(self):
step = self._make_step('Solo', 10, state='ready')
# No predecessor → blocker_kind = 'none'
self.assertEqual(step.blocker_kind, 'none')
self.assertEqual(step.blocker_reason, '')
def test_predecessor_open_blocks(self):
s1 = self._make_step('Earlier', 10, state='in_progress')
s2 = self._make_step('Later', 20, state='ready')
# If recipe enforces sequential OR step requires predecessor,
# blocker_kind should be 'predecessor'. Default depends on job
# config; if neither flag triggers we'd see 'none' instead.
s2.invalidate_recordset([
'blocker_kind', 'blocker_reason',
'blocker_jump_target_model', 'blocker_jump_target_id',
])
if s2._fp_should_block_predecessors():
self.assertEqual(s2.blocker_kind, 'predecessor')
self.assertIn(s1.name, s2.blocker_reason or '')
self.assertEqual(s2.blocker_jump_target_model, 'fp.job.step')
self.assertEqual(s2.blocker_jump_target_id, s1.id)
else:
self.assertEqual(s2.blocker_kind, 'none')
def test_explicit_requires_predecessor_blocks(self):
s1 = self._make_step('Earlier', 10, state='ready')
s2 = self._make_step('Later', 20, state='ready')
s2.requires_predecessor_done = True
s2.invalidate_recordset(['blocker_kind', 'blocker_reason'])
self.assertEqual(s2.blocker_kind, 'predecessor')
self.assertEqual(s2.blocker_jump_target_id, s1.id)