from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def test_ship_order_is_normalized_to_create_shipment(): text = (ROOT / "app" / "opportunity_action_task_materializer.py").read_text(encoding="utf-8") assert 'ACTION_ALIASES = {"SHIP_ORDER": "CREATE_SHIPMENT"}' in text assert 'MATERIALIZED_ACTIONS.add("CREATE_SHIPMENT")' in text assert '"CREATE_SHIPMENT": "logistica"' in text catalog = (ROOT / "app" / "action_catalog.py").read_text(encoding="utf-8") assert '"CREATE_SHIPMENT": {' in catalog assert '"route": "logistica"' in catalog def test_odoo_sync_skips_unique_existing_operation_link(): text = (ROOT / "app" / "external_reconciliation_sync.py").read_text(encoding="utf-8") assert "def _existing_odoo_sale_links" in text assert "def _resolve_existing_odoo_reconciliation_item" in text assert "if len(existing_links) == 1" in text assert '"already_linked": already_linked' in text def test_reconciliation_apply_preserves_advanced_stage(): text = (ROOT / "app" / "reconciliation_service.py").read_text(encoding="utf-8") assert "current_rank >= suggested_rank" in text assert '"stage_regression_prevented"' in text assert "_materialize_current_opportunity_action(opportunity_id, actor=actor)" in text def test_cleanup_script_is_dry_run_by_default(): text = (ROOT / "scripts" / "apply_reconciliation_coherence_fixes.py").read_text(encoding="utf-8") assert 'parser.add_argument("--apply", action="store_true"' in text assert "Dry-run only" in text assert "preserve_opportunity_stage" in text assert "review_amount" not in text def test_operator_ui_reports_existing_links_and_action_map_supports_shipping(): page = (ROOT / "app" / "admin_ui" / "pages" / "reconciliation.py").read_text(encoding="utf-8") tasks = (ROOT / "app" / "task_service.py").read_text(encoding="utf-8") assert 'candidatos obsoletos resolvidos' in page assert '"CREATE_SHIPMENT": ("logistica", "Enviar encomenda")' in tasks