feat(jobs): Phase 2 — card_state + mini_timeline + precedence helpers

PV-Phase2 of the plant-view redesign.

Implements the 13-state classifier on fp.job:
  - card_state Char field, stored + indexed for fast filtering
  - _compute_card_state with explicit precedence dispatch matching
    spec §6.2 / §9.3 exactly (no_parts → on_hold → awaiting_signoff
    → awaiting_qc → bake_due → predecessor_locked → idle_warning →
    done → contract_review → running/_mine → ready/_mine)

Six precedence helpers, each isolated for testability:
  _fp_inbound_not_received, _fp_has_open_hold, _fp_has_pending_qc,
  _fp_bake_window_due_soon, _fp_is_mine + _fp_has_unfinished_predecessors
  on fp.job.step.

mini_timeline_json compute: 9-element array (one per column) with
state in {done, current, upcoming} and an optional 'variant' on the
current marker keyed to card_state for renderer color mapping.

Verified live:
  - 14 jobs in contract_review (no active step yet)
  - 8 in no_parts (confirmed + draft fp.receiving)
  - 1 running (WO-30051 with Pre-Measurements at Plating column)
  - mini_timeline JSON renders the full 9-area structure with the
    plating slot marked current+variant=running.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-23 20:48:14 -04:00
parent 63d692b322
commit 7c2ae84e32
2 changed files with 228 additions and 0 deletions

View File

@@ -109,6 +109,16 @@ class FpJobStep(models.Model):
# Free-flow recipe — only the legacy per-step flag still gates.
return bool(self.requires_predecessor_done)
def _fp_has_unfinished_predecessors(self):
"""True when an earlier-sequence step on the same job is not yet
in a terminal state. Composes with _fp_should_block_predecessors
to drive the plant-view predecessor_locked card state."""
self.ensure_one()
return bool(self.job_id.step_ids.filtered(
lambda s: s.sequence < self.sequence
and s.state not in ('done', 'skipped', 'cancelled')
))
can_start = fields.Boolean(
string='Can Start',
compute='_compute_can_start',