feat(server): add PUT /attachment/config with removal guard
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -84,3 +84,113 @@ def test_status_reflects_config_and_boxed(client: TestClient, db: Session):
|
||||
assert item["expected_qty"] == 80
|
||||
assert item["boxed_qty"] == 30
|
||||
assert item["complete"] is False
|
||||
|
||||
|
||||
def test_config_sets_none(client: TestClient):
|
||||
resp = client.put(
|
||||
"/CargoTrace/attachment/config",
|
||||
json={"zongpai_no": "26BW0011", "determination": "none", "items": []},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["determination"] == "none"
|
||||
assert resp.json()["items"] == []
|
||||
|
||||
|
||||
def test_config_creates_and_updates_items(client: TestClient, db: Session):
|
||||
cert_id, extra_id, _ = _seed_categories(db)
|
||||
client.put(
|
||||
"/CargoTrace/attachment/config",
|
||||
json={
|
||||
"zongpai_no": "26BW0011",
|
||||
"determination": "has",
|
||||
"items": [
|
||||
{"category_id": cert_id, "expected_qty": 80},
|
||||
{"category_id": extra_id, "expected_qty": 5},
|
||||
],
|
||||
},
|
||||
)
|
||||
# Update: change extra expected, drop nothing
|
||||
resp = client.put(
|
||||
"/CargoTrace/attachment/config",
|
||||
json={
|
||||
"zongpai_no": "26BW0011",
|
||||
"determination": "has",
|
||||
"items": [
|
||||
{"category_id": cert_id, "expected_qty": 80},
|
||||
{"category_id": extra_id, "expected_qty": 8},
|
||||
],
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
extra = next(i for i in resp.json()["items"] if i["category_id"] == extra_id)
|
||||
assert extra["expected_qty"] == 8
|
||||
|
||||
|
||||
def test_config_rejects_removing_type_with_boxes(client: TestClient, db: Session):
|
||||
cert_id, _, _ = _seed_categories(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": 922,
|
||||
"quantity": 10,
|
||||
},
|
||||
)
|
||||
# Try to drop the type that now has boxes
|
||||
resp = client.put(
|
||||
"/CargoTrace/attachment/config",
|
||||
json={
|
||||
"zongpai_no": "26BW0011",
|
||||
"determination": "has",
|
||||
"items": [],
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 409
|
||||
assert resp.json()["error_code"] == "CATEGORY_HAS_BOXES"
|
||||
|
||||
|
||||
def test_config_allows_removing_type_with_zero_boxes(client: TestClient, db: Session):
|
||||
cert_id, extra_id, _ = _seed_categories(db)
|
||||
client.put(
|
||||
"/CargoTrace/attachment/config",
|
||||
json={
|
||||
"zongpai_no": "26BW0011",
|
||||
"determination": "has",
|
||||
"items": [
|
||||
{"category_id": cert_id, "expected_qty": 80},
|
||||
{"category_id": extra_id, "expected_qty": 5},
|
||||
],
|
||||
},
|
||||
)
|
||||
resp = client.put(
|
||||
"/CargoTrace/attachment/config",
|
||||
json={
|
||||
"zongpai_no": "26BW0011",
|
||||
"determination": "has",
|
||||
"items": [{"category_id": cert_id, "expected_qty": 80}],
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert {i["category_id"] for i in resp.json()["items"]} == {cert_id}
|
||||
|
||||
|
||||
def test_config_rejects_unknown_category(client: TestClient):
|
||||
resp = client.put(
|
||||
"/CargoTrace/attachment/config",
|
||||
json={
|
||||
"zongpai_no": "26BW0011",
|
||||
"determination": "has",
|
||||
"items": [{"category_id": 9999999, "expected_qty": 1}],
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 404
|
||||
assert resp.json()["error_code"] == "CATEGORY_NOT_FOUND"
|
||||
|
||||
Reference in New Issue
Block a user