"""Canonical work-center action precedence and reconstructed review state. The operator must see one first safe action across the work center and the opportunity board. This module intentionally contains no database access so it can be reused by UI/view-model code and tested in isolation. """ from __future__ import annotations from datetime import datetime, timezone from typing import Any, Mapping ASSOCIATION_ACTION_CODES = { "ASSOCIATE_OPPORTUNITY", "REVIEW_ASSOCIATION", "LINK_DOCUMENT", } RECONSTRUCTED_SENSITIVE_ACTIONS = { "SEND_PROFORMA", "SEND_INVOICE", "CONFIRM_PAYMENT", "CONFIRM_PAYMENT_AND_PREPARE_SHIPMENT", "PREPARE_ORDER", "VALIDATE_PHYSICAL_ORDER", "CREATE_SHIPMENT", "SHIP_ORDER", } RECONSTRUCTED_RECORD_MODES = { "reconstructed_invoice_review", "historical_reconstructed", "legacy_review", } ACTION_ALIASES = {"SHIP_ORDER": "CREATE_SHIPMENT"} def _s(value: Any) -> str: return str(value or "").strip() def _lower(value: Any) -> str: return _s(value).casefold() def _upper(value: Any) -> str: return _s(value).upper() def _as_mapping(value: Any) -> Mapping[str, Any]: return value if isinstance(value, Mapping) else {} def _truthy(value: Any) -> bool: if value is True: return True return _lower(value) in {"1", "true", "yes", "sim", "required", "validated", "waived"} def _explicit_false(value: Any) -> bool: if value is False: return True return _lower(value) in {"0", "false", "no", "não", "nao", "cleared", "validated", "waived"} def canonical_action_code(value: Any) -> str: code = _upper(value) return ACTION_ALIASES.get(code, code) def is_reconstructed_record(metadata: Any) -> bool: data = _as_mapping(metadata) return _lower(data.get("clientflow_record_mode")) in RECONSTRUCTED_RECORD_MODES def reconstructed_review_status(metadata: Any) -> str: """Return required/validated/waived/legacy_unset/not_applicable. v132 persists ``reconstructed_review_status``. Legacy keys are still read so upgrades do not re-open a review that was already completed. """ data = _as_mapping(metadata) nested = _as_mapping(data.get("reconstructed_review")) direct = _lower(nested.get("status") or data.get("reconstructed_review_status")) if direct in {"required", "validated", "waived"}: return direct validated_keys = ( "reconstructed_process_validated", "historical_evidence_validated", "reconstructed_review_validated", ) if any(_truthy(data.get(key)) for key in validated_keys): return "validated" required_keys = ( "historical_evidence_review_required", "reconstructed_process_review_required", "reconstructed_review_required", ) if any(_truthy(data.get(key)) for key in required_keys): return "required" # Some older repair scripts cleared the boolean instead of writing a # validated marker. Only interpret that as validated for a known legacy # reconstructed record. if is_reconstructed_record(data) and any( key in data and _explicit_false(data.get(key)) for key in required_keys ): return "validated" return "legacy_unset" if is_reconstructed_record(data) else "not_applicable" def reconstructed_review_required(metadata: Any) -> bool: return reconstructed_review_status(metadata) == "required" def reconstructed_review_cleared(metadata: Any) -> bool: return reconstructed_review_status(metadata) in {"validated", "waived"} def association_review_required(*, action_code: Any = "", linking_status: Any = "") -> bool: code = canonical_action_code(action_code) linking = _lower(linking_status) return code in ASSOCIATION_ACTION_CODES or linking in { "ambiguous", "review_required", "required", "conflict", } def effective_action_code( action_code: Any, *, metadata: Any = None, linking_status: Any = "", ) -> str: """Return the first explicitly supported operator action. Titles and free text are deliberately ignored. A blocker must be persisted as an action/linking status or reconstructed review state. """ code = canonical_action_code(action_code) if association_review_required(action_code=code, linking_status=linking_status): return "ASSOCIATE_OPPORTUNITY" if reconstructed_review_required(metadata) and code in { canonical_action_code(item) for item in RECONSTRUCTED_SENSITIVE_ACTIONS }: return "REVIEW_RECONSTRUCTED_PROCESS" return code def reconstructed_review_metadata_patch( status: str, *, actor: str, reason: str = "", blocked_action_code: str = "", ) -> dict[str, Any]: normalized = _lower(status) if normalized not in {"required", "validated", "waived"}: raise ValueError(f"Unsupported reconstructed review status: {status}") now = datetime.now(timezone.utc).isoformat() nested: dict[str, Any] = { "status": normalized, "updated_at": now, "updated_by": actor, } if reason: nested["reason"] = reason if blocked_action_code: nested["blocked_action_code"] = canonical_action_code(blocked_action_code) if normalized == "required": nested["required_at"] = now elif normalized == "validated": nested["validated_at"] = now nested["validated_by"] = actor else: nested["waived_at"] = now nested["waived_by"] = actor patch: dict[str, Any] = { "reconstructed_review_status": normalized, "reconstructed_review": nested, "reconstructed_review_required": normalized == "required", "reconstructed_review_validated": normalized == "validated", } return patch