"""Custom profiles and configuration drift must use the actual confirmation API.""" from __future__ import annotations from fastapi.testclient import TestClient from tests.auth_provider import install_test_auth from tests.golden.test_ruiyang_intake_workflow import _chat, _confirm from tests.golden.test_workbook_profiles import _alternative, _config, _write from tests.pi_primary_adapter import install_fake_pi_tool_adapter from tests.workbook_acceptance import load_expectations, source_for_test def _client(monkeypatch): monkeypatch.setenv("APS_SEED_DEMO", "0") install_test_auth(monkeypatch, "configured-intake-test") install_fake_pi_tool_adapter(monkeypatch) from server.gateway.app import create_app return TestClient(create_app()) def _upload(client, raw): assert client.post("/api/auth/login", json={"username": "planner", "password": "test"}).status_code == 200 project = client.post("/api/projects", json={"name": "另一个工厂"}).json() pid, sid = project["project"]["id"], project["session"]["id"] result = client.post(f"/api/projects/{pid}/files/upload", files=[("files", ("different-name.xlsx", raw))]) assert result.status_code == 200, result.text return pid, sid def test_alternative_profile_uses_same_upload_adoption_and_review_flow(tmp_path, monkeypatch): expected = load_expectations() raw, config, changed_codes = _alternative(source_for_test().read_bytes(), _config()) directory = tmp_path / "profiles" _write(directory, config) monkeypatch.setenv("APS_WORKBOOK_PROFILE_DIR", str(directory)) with _client(monkeypatch) as client: pid, sid = _upload(client, raw) blocks, text = _chat(client, pid, sid, "分析一下数据文件") assert len(blocks) == 2, text review = blocks[0]["props"] assert review["profile"] == config["id"] assert review["summary"] == expected["reviewCounts"] assert client.get("/api/master").json()["materials"] == [] applied = _confirm(client, sid, blocks[1]) assert applied["refresh"] is True and "资料已采用" in applied["message"], applied assert len(client.get("/api/master").json()["materials"]) == expected["entityCounts"]["materials"] formal = client.get("/api/flex/world").json()["orders"] assert {row["orderNo"] for row in formal} == {changed_codes[code] for code in expected["formalOrderNos"]} again, text = _chat(client, pid, sid, "分析一下数据文件") assert not any(block["type"] == "confirm-card" for block in again), text result, text = _chat(client, pid, sid, "根据这些数据排产") plan = next(block for block in result if block["type"] == "flex-schedule") assert plan["props"]["trialOnly"] is True assert plan["props"]["stats"]["orderCount"] == expected["entityCounts"]["orders"] def test_changed_mapping_is_a_readable_rejection_not_an_http_error(tmp_path, monkeypatch): config = _config() directory = tmp_path / "profiles" _write(directory, config) monkeypatch.setenv("APS_WORKBOOK_PROFILE_DIR", str(directory)) with _client(monkeypatch) as client: pid, sid = _upload(client, source_for_test().read_bytes()) blocks, _ = _chat(client, pid, sid, "分析一下数据文件") card = next(block for block in blocks if block["type"] == "confirm-card") config["planning"]["timeZone"] = "Europe/Berlin" _write(directory, config) response = _confirm(client, sid, card) assert response["refresh"] is False assert response["errorCode"] == "INTAKE_REVIEW_REQUIRED" assert "重新检查" in response["message"] assert client.get("/api/master").json()["materials"] == []