feat(server): add POST /attachment/box with real-evidence flip + cap

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-08-12 14:12:42 +08:00
parent 76d2095117
commit 0ef4f0e990
4 changed files with 300 additions and 1 deletions

View File

@@ -0,0 +1,151 @@
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from app.models.attachment import AttachmentCategory
def _seed(db: Session) -> list[int]:
cats = [
AttachmentCategory(name="TEST_CERT", sort_order=1, is_active=True),
AttachmentCategory(name="TEST_EXTRA", sort_order=2, is_active=True),
]
for c in cats:
db.add(c)
db.commit()
for c in cats:
db.refresh(c)
return [c.id for c in cats]
def test_attachment_box_basic_and_flip(client: TestClient, db: Session):
"""扫附件码即到货:未判定 → 自动 hasitem 不存在则按 ERP 数量建。"""
cert_id, _ = _seed(db)
resp = client.post(
"/CargoTrace/attachment/box",
json={
"zongpai_no": "26BW0011",
"category_id": cert_id,
"box_no": 931,
"quantity": 30,
},
)
assert resp.status_code == 200
body = resp.json()
assert body["paichan_no"] == "W00009"
assert body["box_no"] == 931
assert body["quantity"] == 30
status = client.get(
"/CargoTrace/attachment/status", params={"zongpai_no": "26BW0011"}
).json()
assert status["determination"] == "has"
item = status["items"][0]
assert item["expected_qty"] == 80 # ERP 数量兜底
assert item["boxed_qty"] == 30
def test_attachment_box_rejects_over_expected(client: TestClient, db: Session):
cert_id, _ = _seed(db)
client.put(
"/CargoTrace/attachment/config",
json={
"zongpai_no": "26BW0011",
"determination": "has",
"items": [{"category_id": cert_id, "expected_qty": 80}],
},
)
first = client.post(
"/CargoTrace/attachment/box",
json={
"zongpai_no": "26BW0011",
"category_id": cert_id,
"box_no": 932,
"quantity": 70,
},
)
assert first.status_code == 200
over = client.post(
"/CargoTrace/attachment/box",
json={
"zongpai_no": "26BW0011",
"category_id": cert_id,
"box_no": 933,
"quantity": 11,
},
)
assert over.status_code == 400
assert over.json()["error_code"] == "INVALID_QUANTITY"
def test_attachment_box_duplicate_in_same_box(client: TestClient, db: Session):
cert_id, _ = _seed(db)
client.post(
"/CargoTrace/attachment/box",
json={
"zongpai_no": "26BW0011",
"category_id": cert_id,
"box_no": 934,
"quantity": 10,
},
)
dup = client.post(
"/CargoTrace/attachment/box",
json={
"zongpai_no": "26BW0011",
"category_id": cert_id,
"box_no": 934,
"quantity": 5,
},
)
assert dup.status_code == 409
assert dup.json()["error_code"] == "DUPLICATE_BOX_NO"
def test_attachment_box_mixed_with_product(client: TestClient, db: Session):
"""附件与产品同箱:先装产品,再装附件,同 box_no。"""
cert_id, _ = _seed(db)
client.post(
"/CargoTrace/box",
json={"zongpai_no": "26BW0011", "box_no": 935, "quantity": 10},
)
resp = client.post(
"/CargoTrace/attachment/box",
json={
"zongpai_no": "26BW0011",
"category_id": cert_id,
"box_no": 935,
"quantity": 5,
},
)
assert resp.status_code == 200
info = client.get(
"/CargoTrace/box/info", params={"zongpai_no": "26BW0011"}
).json()
box = next(b for b in info["existing_boxes"] if b["box_no"] == 935)
kinds = {i["kind"] for i in box["items"]}
assert kinds == {"product", "attachment"}
def test_attachment_box_completion(client: TestClient, db: Session):
cert_id, _ = _seed(db)
client.put(
"/CargoTrace/attachment/config",
json={
"zongpai_no": "26BW0011",
"determination": "has",
"items": [{"category_id": cert_id, "expected_qty": 80}],
},
)
client.post(
"/CargoTrace/attachment/box",
json={
"zongpai_no": "26BW0011",
"category_id": cert_id,
"box_no": 936,
"quantity": 80,
},
)
status = client.get(
"/CargoTrace/attachment/status", params={"zongpai_no": "26BW0011"}
).json()
assert status["all_complete"] is True