feat: add boxing module API — GET /box/info and POST /box

- Add box schemas (BoxInfoResponse, BoxSaveRequest, BoxSaveResponse)
- Add box service with ERP view query and save logic (supports many2one append)
- Add box router with GET /box/info and POST /box endpoints
- Register exception handlers for InvalidZongpaiError, ZongpaiNotFoundError, DuplicateBoxItemError
- Update RequestValidationError handler to cover INVALID_BOX_NO and INVALID_QUANTITY
- Add 7 integration tests for box API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-05-11 18:04:13 +08:00
parent 6e0e9d9584
commit c370ca36bc
6 changed files with 847 additions and 1 deletions

78
tests/test_box_api.py Normal file
View File

@@ -0,0 +1,78 @@
from fastapi.testclient import TestClient
# --- GET /box/info 测试 ---
def test_box_info_success(client: TestClient):
"""查询真实存在的总排号 → 200"""
resp = client.get(
"/CargoTrace/box/info", params={"zongpai_no": "26BW0011"}
)
assert resp.status_code == 200
data = resp.json()
assert data["zongpai_no"] == "26BW0011"
assert data["paichan_no"] == "W00009"
assert data["quantity"] == 80
assert "existing_boxes" in data
assert "max_box_no" in data
assert data["suggested_box_no"] == data["max_box_no"] + 1
def test_box_info_invalid_zongpai(client: TestClient):
"""无效总排号格式 → 400"""
resp = client.get(
"/CargoTrace/box/info", params={"zongpai_no": "INVALID"}
)
assert resp.status_code == 400
assert resp.json()["error_code"] == "INVALID_ZONGPAI"
def test_box_info_not_found(client: TestClient):
"""格式合法但 ERP 中不存在 → 404"""
resp = client.get(
"/CargoTrace/box/info", params={"zongpai_no": "26B99999"}
)
assert resp.status_code == 404
assert resp.json()["error_code"] == "ZONGPAI_NOT_FOUND"
# --- POST /box 测试 ---
def test_box_save_invalid_zongpai(client: TestClient):
"""无效总排号 → 400"""
resp = client.post(
"/CargoTrace/box",
json={"zongpai_no": "INVALID", "box_no": 1, "quantity": 10},
)
assert resp.status_code == 400
assert resp.json()["error_code"] == "INVALID_ZONGPAI"
def test_box_save_invalid_box_no(client: TestClient):
"""箱号 <= 0 → 400"""
resp = client.post(
"/CargoTrace/box",
json={"zongpai_no": "26BW0011", "box_no": 0, "quantity": 10},
)
assert resp.status_code == 400
def test_box_save_invalid_quantity(client: TestClient):
"""数量 <= 0 → 400"""
resp = client.post(
"/CargoTrace/box",
json={"zongpai_no": "26BW0011", "box_no": 1, "quantity": 0},
)
assert resp.status_code == 400
def test_box_save_zongpai_not_found(client: TestClient):
"""ERP 中不存在的总排号 → 404"""
resp = client.post(
"/CargoTrace/box",
json={"zongpai_no": "26B99999", "box_no": 1, "quantity": 10},
)
assert resp.status_code == 404
assert resp.json()["error_code"] == "ZONGPAI_NOT_FOUND"