feat: complete production workflow migration

This commit is contained in:
2026-08-06 14:29:57 +08:00
parent 7f215e79c4
commit 8df5266abb
448 changed files with 56937 additions and 14619 deletions
+49 -15
View File
@@ -21,7 +21,7 @@ def _read(relative: str) -> str:
def _load_shop_paths(monkeypatch: pytest.MonkeyPatch, data_root: Path):
monkeypatch.setenv("GYXX_DATA_ROOT", str(data_root))
path = MODULES_ROOT / "shop_intelligence" / "runtime" / "paths.py"
path = MODULES_ROOT / "shop_intelligence" / "paths.py"
name = "_gyxx_test_shop_routing_paths"
spec = importlib.util.spec_from_file_location(name, path)
assert spec and spec.loader
@@ -56,10 +56,10 @@ def test_shop_output_resolver_confines_collectors_to_raw_root(
def test_shop_debug_and_cli_outputs_use_canonical_roots() -> None:
jd_shop = _read(
"src/gyxx_flow/modules/shop_intelligence/runtime/collectors/jd_data_collector.py"
"src/gyxx_flow/modules/shop_intelligence/collectors/jd_data_collector.py"
)
jd_peer = _read(
"src/gyxx_flow/modules/shop_intelligence/runtime/collectors/"
"src/gyxx_flow/modules/shop_intelligence/collectors/"
"jd_peer_store_data_collector.py"
)
@@ -71,28 +71,28 @@ def test_shop_debug_and_cli_outputs_use_canonical_roots() -> None:
def test_supply_python_outputs_use_state_raw_tmp_and_export_layers() -> None:
feishu = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/feishu_sheets.py"
"src/gyxx_flow/modules/supply_chain/orchestrator/feishu_sheets.py"
)
workflow = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/mcp_workflow.py"
"src/gyxx_flow/modules/supply_chain/orchestrator/mcp_workflow.py"
)
monitor = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/monitor.py"
"src/gyxx_flow/modules/supply_chain/orchestrator/monitor.py"
)
replenishment = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/scripts/"
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/"
"ProductReplenishment.py"
)
confirmation = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/scripts/"
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/"
"PurchaseConfirmation.py"
)
batch = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/scripts/"
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/"
"batch_process.py"
)
bitable = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/scripts/"
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/"
"insert_replenishment_bitable.py"
)
@@ -115,7 +115,7 @@ def test_supply_python_outputs_use_state_raw_tmp_and_export_layers() -> None:
def test_supply_raw_outputs_are_run_scoped_and_never_cleaned_in_place() -> None:
workflow = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/mcp_workflow.py"
"src/gyxx_flow/modules/supply_chain/orchestrator/mcp_workflow.py"
)
for script in (
"collect_confirmation.ps1",
@@ -123,7 +123,7 @@ def test_supply_raw_outputs_are_run_scoped_and_never_cleaned_in_place() -> None:
"collect_replenishment.ps1",
):
source = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/scripts/" + script
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/" + script
)
assert '"run_id=$workflowId"' in source
assert (
@@ -155,11 +155,11 @@ def test_supply_raw_outputs_are_run_scoped_and_never_cleaned_in_place() -> None:
def test_purchase_order_trigger_uses_state_task_and_never_cleans_raw_or_source() -> None:
trigger = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/scripts/"
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/"
"trigger_purchase_order_update.py"
)
collector = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/scripts/"
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/"
"collect_purchase_order_update.ps1"
)
@@ -179,7 +179,7 @@ def test_purchase_order_trigger_uses_state_task_and_never_cleans_raw_or_source()
)
def test_supply_powershell_prefers_injected_module_roots(script: str) -> None:
source = _read(
"src/gyxx_flow/modules/supply_chain/runtime/orchestrator/scripts/" + script
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/" + script
)
for variable in (
@@ -238,3 +238,37 @@ def test_native_adapter_injects_supply_module_roots(tmp_path: Path) -> None:
assert command.env["GYXX_SUPPLY_WORK_ROOT"] == str(
(module_root / "tmp" / "supply_chain").resolve()
)
def test_replenishment_producer_hands_off_current_xlsx_before_archiving() -> None:
producer = _read(
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/"
"ProductReplenishment.py"
)
consumer = _read(
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/batch_process.py"
)
assert "filepath = os.path.join(work_dir, filename)" in producer
assert "archive_path = os.path.join(export_dir, filename)" in producer
assert "shutil.copy2(filepath, archive_path)" in producer
assert "DATA_DIR = WORK_ROOT" in consumer
assert 'DATA_DIR.glob("补货建议_*.xlsx")' in consumer
def test_discontinued_sku_fallback_uses_portable_state_reference() -> None:
paths = _read("src/gyxx_flow/modules/supply_chain/paths.py")
producer = _read(
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/"
"ProductReplenishment.py"
)
consumer = _read(
"src/gyxx_flow/modules/supply_chain/orchestrator/scripts/batch_process.py"
)
assert 'REFERENCE_ROOT = STATE_ROOT / "reference"' in paths
assert 'else REFERENCE_ROOT / "停产产品.xlsx"' in paths
assert "GYXX_SUPPLY_DISCONTINUED_SKUS_FILE" in paths
assert "file_path = str(DISCONTINUED_PRODUCTS_FILE)" in producer
assert "file_path = DISCONTINUED_PRODUCTS_FILE" in consumer
assert "Downloads" not in paths