feat(box): simplify boxing mode API
This commit is contained in:
@@ -37,7 +37,7 @@ def create_box(req: BoxSaveRequest, db: Session = Depends(get_db)):
|
|||||||
|
|
||||||
@router.patch("/box/{box_item_id}", response_model=BoxUpdateResponse)
|
@router.patch("/box/{box_item_id}", response_model=BoxUpdateResponse)
|
||||||
def update_box(box_item_id: int, req: BoxUpdateRequest, db: Session = Depends(get_db)):
|
def update_box(box_item_id: int, req: BoxUpdateRequest, db: Session = Depends(get_db)):
|
||||||
"""更新一码多箱已分配装箱明细。"""
|
"""更新已分配装箱明细。"""
|
||||||
return update_box_item(db, box_item_id, req)
|
return update_box_item(db, box_item_id, req)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
27
app/main.py
27
app/main.py
@@ -22,8 +22,8 @@ from app.services.location_service import AlreadyOffShelfError, DuplicateLocatio
|
|||||||
from app.services.box_service import (
|
from app.services.box_service import (
|
||||||
BoxItemNotFoundError,
|
BoxItemNotFoundError,
|
||||||
DuplicateBoxItemError,
|
DuplicateBoxItemError,
|
||||||
DuplicateZongpaiBindError,
|
|
||||||
InvalidBoxItemError,
|
InvalidBoxItemError,
|
||||||
|
InvalidQuantityError,
|
||||||
InvalidZongpaiError,
|
InvalidZongpaiError,
|
||||||
ZongpaiNotFoundError,
|
ZongpaiNotFoundError,
|
||||||
)
|
)
|
||||||
@@ -126,20 +126,6 @@ async def duplicate_box_handler(request: Request, exc: DuplicateBoxItemError):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.exception_handler(DuplicateZongpaiBindError)
|
|
||||||
async def duplicate_zongpai_bind_handler(request: Request, exc: DuplicateZongpaiBindError):
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=409,
|
|
||||||
content={
|
|
||||||
"error_code": "DUPLICATE_ZONGPAI_BIND",
|
|
||||||
"message": f"总排号 {exc.zongpai_no} 已绑定箱号 {exc.box_no},请勿重复装箱",
|
|
||||||
"paichan_no": exc.paichan_no,
|
|
||||||
"box_no": exc.box_no,
|
|
||||||
"zongpai_no": exc.zongpai_no,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.exception_handler(BoxItemNotFoundError)
|
@app.exception_handler(BoxItemNotFoundError)
|
||||||
async def box_item_not_found_handler(request: Request, exc: BoxItemNotFoundError):
|
async def box_item_not_found_handler(request: Request, exc: BoxItemNotFoundError):
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
@@ -151,6 +137,17 @@ async def box_item_not_found_handler(request: Request, exc: BoxItemNotFoundError
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.exception_handler(InvalidQuantityError)
|
||||||
|
async def invalid_quantity_handler(request: Request, exc: InvalidQuantityError):
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=400,
|
||||||
|
content={
|
||||||
|
"error_code": "INVALID_QUANTITY",
|
||||||
|
"message": "装箱数量超出可装数量上限",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.exception_handler(InvalidBoxItemError)
|
@app.exception_handler(InvalidBoxItemError)
|
||||||
async def invalid_box_item_handler(request: Request, exc: InvalidBoxItemError):
|
async def invalid_box_item_handler(request: Request, exc: InvalidBoxItemError):
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ class BoxSaveRequest(BaseModel):
|
|||||||
zongpai_no: str
|
zongpai_no: str
|
||||||
box_no: int
|
box_no: int
|
||||||
quantity: int
|
quantity: int
|
||||||
box_mode: str | None = None # one-to-one | one-to-many | many-to-one
|
|
||||||
|
|
||||||
@field_validator("zongpai_no")
|
@field_validator("zongpai_no")
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -83,7 +82,6 @@ class BoxUpdateRequest(BaseModel):
|
|||||||
"""PATCH /box/{box_item_id} 请求"""
|
"""PATCH /box/{box_item_id} 请求"""
|
||||||
box_no: int
|
box_no: int
|
||||||
quantity: int
|
quantity: int
|
||||||
box_mode: str = "one-to-many"
|
|
||||||
|
|
||||||
@field_validator("box_no")
|
@field_validator("box_no")
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -23,13 +23,6 @@ class DuplicateBoxItemError(Exception):
|
|||||||
self.box_no = box_no
|
self.box_no = box_no
|
||||||
|
|
||||||
|
|
||||||
class DuplicateZongpaiBindError(Exception):
|
|
||||||
def __init__(self, paichan_no: str, box_no: int, zongpai_no: str):
|
|
||||||
self.paichan_no = paichan_no
|
|
||||||
self.box_no = box_no
|
|
||||||
self.zongpai_no = zongpai_no
|
|
||||||
|
|
||||||
|
|
||||||
class BoxItemNotFoundError(Exception):
|
class BoxItemNotFoundError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -38,6 +31,10 @@ class InvalidBoxItemError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidQuantityError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def query_erp_info(db: Session, zongpai_no: str) -> dict:
|
def query_erp_info(db: Session, zongpai_no: str) -> dict:
|
||||||
"""从 ERP 视图查询总排号对应的排产号、工令号和数量。"""
|
"""从 ERP 视图查询总排号对应的排产号、工令号和数量。"""
|
||||||
sql = text(_erp_info_sql(db))
|
sql = text(_erp_info_sql(db))
|
||||||
@@ -172,24 +169,48 @@ def get_box_info(db: Session, zongpai_no: str) -> dict:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _packed_quantity_for_zongpai(
|
||||||
|
db: Session,
|
||||||
|
paichan_no: str,
|
||||||
|
zongpai_no: str,
|
||||||
|
exclude_box_item_id: int | None = None,
|
||||||
|
) -> int:
|
||||||
|
query = (
|
||||||
|
db.query(FinishedGoodsBoxItem)
|
||||||
|
.join(FinishedGoodsBox, FinishedGoodsBoxItem.box_id == FinishedGoodsBox.id)
|
||||||
|
.filter(
|
||||||
|
FinishedGoodsBox.paichan_no == paichan_no,
|
||||||
|
FinishedGoodsBoxItem.zongpai_no == zongpai_no,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if exclude_box_item_id is not None:
|
||||||
|
query = query.filter(FinishedGoodsBoxItem.id != exclude_box_item_id)
|
||||||
|
return sum(int(item.quantity or 0) for item in query.all())
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_quantity_within_erp_total(
|
||||||
|
db: Session,
|
||||||
|
paichan_no: str,
|
||||||
|
zongpai_no: str,
|
||||||
|
erp_quantity: int,
|
||||||
|
submitted_quantity: int,
|
||||||
|
exclude_box_item_id: int | None = None,
|
||||||
|
) -> None:
|
||||||
|
packed_quantity = _packed_quantity_for_zongpai(
|
||||||
|
db,
|
||||||
|
paichan_no,
|
||||||
|
zongpai_no,
|
||||||
|
exclude_box_item_id=exclude_box_item_id,
|
||||||
|
)
|
||||||
|
if packed_quantity + submitted_quantity > erp_quantity:
|
||||||
|
raise InvalidQuantityError()
|
||||||
|
|
||||||
|
|
||||||
def save_box_record(db: Session, req: BoxSaveRequest) -> dict:
|
def save_box_record(db: Session, req: BoxSaveRequest) -> dict:
|
||||||
"""保存装箱记录。箱已存在时仅追加明细(多码一箱场景)。"""
|
"""保存装箱记录。同箱可凑箱,但同箱同总排不可重复。"""
|
||||||
erp = query_erp_info(db, req.zongpai_no)
|
erp = query_erp_info(db, req.zongpai_no)
|
||||||
paichan_no = erp["paichan_no"]
|
paichan_no = erp["paichan_no"]
|
||||||
|
|
||||||
if req.box_mode == "one-to-one":
|
|
||||||
existing_box_no = (
|
|
||||||
db.query(FinishedGoodsBox.box_no)
|
|
||||||
.join(FinishedGoodsBoxItem, FinishedGoodsBox.id == FinishedGoodsBoxItem.box_id)
|
|
||||||
.filter(
|
|
||||||
FinishedGoodsBox.paichan_no == paichan_no,
|
|
||||||
FinishedGoodsBoxItem.zongpai_no == req.zongpai_no,
|
|
||||||
)
|
|
||||||
.scalar()
|
|
||||||
)
|
|
||||||
if existing_box_no is not None:
|
|
||||||
raise DuplicateZongpaiBindError(paichan_no, existing_box_no, req.zongpai_no)
|
|
||||||
|
|
||||||
box = (
|
box = (
|
||||||
db.query(FinishedGoodsBox)
|
db.query(FinishedGoodsBox)
|
||||||
.filter(
|
.filter(
|
||||||
@@ -200,8 +221,6 @@ def save_box_record(db: Session, req: BoxSaveRequest) -> dict:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if box:
|
if box:
|
||||||
if req.box_mode in ("one-to-one", "one-to-many"):
|
|
||||||
raise DuplicateBoxItemError(paichan_no, req.box_no)
|
|
||||||
existing_item = (
|
existing_item = (
|
||||||
db.query(FinishedGoodsBoxItem)
|
db.query(FinishedGoodsBoxItem)
|
||||||
.filter(
|
.filter(
|
||||||
@@ -212,7 +231,16 @@ def save_box_record(db: Session, req: BoxSaveRequest) -> dict:
|
|||||||
)
|
)
|
||||||
if existing_item:
|
if existing_item:
|
||||||
raise DuplicateBoxItemError(paichan_no, req.box_no)
|
raise DuplicateBoxItemError(paichan_no, req.box_no)
|
||||||
else:
|
|
||||||
|
_ensure_quantity_within_erp_total(
|
||||||
|
db,
|
||||||
|
paichan_no,
|
||||||
|
req.zongpai_no,
|
||||||
|
erp["quantity"],
|
||||||
|
req.quantity,
|
||||||
|
)
|
||||||
|
|
||||||
|
if box is None:
|
||||||
box = FinishedGoodsBox(
|
box = FinishedGoodsBox(
|
||||||
paichan_no=paichan_no,
|
paichan_no=paichan_no,
|
||||||
box_no=req.box_no,
|
box_no=req.box_no,
|
||||||
@@ -240,7 +268,7 @@ def save_box_record(db: Session, req: BoxSaveRequest) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
def update_box_item(db: Session, box_item_id: int, req: BoxUpdateRequest) -> dict:
|
def update_box_item(db: Session, box_item_id: int, req: BoxUpdateRequest) -> dict:
|
||||||
"""更新一码多箱已分配明细的箱号和数量。"""
|
"""更新已分配明细的箱号和数量。"""
|
||||||
item = (
|
item = (
|
||||||
db.query(FinishedGoodsBoxItem)
|
db.query(FinishedGoodsBoxItem)
|
||||||
.filter(FinishedGoodsBoxItem.id == box_item_id)
|
.filter(FinishedGoodsBoxItem.id == box_item_id)
|
||||||
@@ -267,13 +295,32 @@ def update_box_item(db: Session, box_item_id: int, req: BoxUpdateRequest) -> dic
|
|||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
|
|
||||||
if target_box is not None and target_box.id != current_box.id:
|
|
||||||
raise DuplicateBoxItemError(paichan_no, req.box_no)
|
|
||||||
|
|
||||||
if target_box is None:
|
if target_box is None:
|
||||||
target_box = FinishedGoodsBox(paichan_no=paichan_no, box_no=req.box_no)
|
target_box = FinishedGoodsBox(paichan_no=paichan_no, box_no=req.box_no)
|
||||||
db.add(target_box)
|
db.add(target_box)
|
||||||
db.flush()
|
db.flush()
|
||||||
|
else:
|
||||||
|
duplicate_item = (
|
||||||
|
db.query(FinishedGoodsBoxItem)
|
||||||
|
.filter(
|
||||||
|
FinishedGoodsBoxItem.box_id == target_box.id,
|
||||||
|
FinishedGoodsBoxItem.zongpai_no == item.zongpai_no,
|
||||||
|
FinishedGoodsBoxItem.id != item.id,
|
||||||
|
)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
if duplicate_item is not None:
|
||||||
|
raise DuplicateBoxItemError(paichan_no, req.box_no)
|
||||||
|
|
||||||
|
erp = query_erp_info(db, item.zongpai_no)
|
||||||
|
_ensure_quantity_within_erp_total(
|
||||||
|
db,
|
||||||
|
paichan_no,
|
||||||
|
item.zongpai_no,
|
||||||
|
erp["quantity"],
|
||||||
|
req.quantity,
|
||||||
|
exclude_box_item_id=box_item_id,
|
||||||
|
)
|
||||||
|
|
||||||
old_box_id = item.box_id
|
old_box_id = item.box_id
|
||||||
item.box_id = target_box.id
|
item.box_id = target_box.id
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ def test_box_save_zongpai_not_found(client: TestClient):
|
|||||||
assert resp.json()["error_code"] == "ZONGPAI_NOT_FOUND"
|
assert resp.json()["error_code"] == "ZONGPAI_NOT_FOUND"
|
||||||
|
|
||||||
|
|
||||||
def test_box_save_many_to_one_appends_different_zongpais(client: TestClient):
|
def test_box_save_multi_code_appends_different_zongpais(client: TestClient):
|
||||||
"""多码一箱:同一排产号同一箱号可追加不同总排号。"""
|
"""多码凑箱:同一排产号同一箱号可追加不同总排号。"""
|
||||||
box_no = 901
|
box_no = 901
|
||||||
first = client.post(
|
first = client.post(
|
||||||
"/CargoTrace/box",
|
"/CargoTrace/box",
|
||||||
@@ -93,7 +93,6 @@ def test_box_save_many_to_one_appends_different_zongpais(client: TestClient):
|
|||||||
"zongpai_no": "26BW0011",
|
"zongpai_no": "26BW0011",
|
||||||
"box_no": box_no,
|
"box_no": box_no,
|
||||||
"quantity": 10,
|
"quantity": 10,
|
||||||
"box_mode": "many-to-one",
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert first.status_code == 200
|
assert first.status_code == 200
|
||||||
@@ -105,7 +104,6 @@ def test_box_save_many_to_one_appends_different_zongpais(client: TestClient):
|
|||||||
"zongpai_no": "26BW0012",
|
"zongpai_no": "26BW0012",
|
||||||
"box_no": box_no,
|
"box_no": box_no,
|
||||||
"quantity": 8,
|
"quantity": 8,
|
||||||
"box_mode": "many-to-one",
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert second.status_code == 200
|
assert second.status_code == 200
|
||||||
@@ -126,8 +124,8 @@ def test_box_save_many_to_one_appends_different_zongpais(client: TestClient):
|
|||||||
assert isinstance(item["total_quantity"], int)
|
assert isinstance(item["total_quantity"], int)
|
||||||
|
|
||||||
|
|
||||||
def test_box_save_many_to_one_duplicate_same_zongpai(client: TestClient):
|
def test_box_save_multi_code_duplicate_same_zongpai(client: TestClient):
|
||||||
"""多码一箱:同箱同总排重复录入返回 DUPLICATE_BOX_NO。"""
|
"""多码凑箱:同箱同总排重复录入返回 DUPLICATE_BOX_NO。"""
|
||||||
box_no = 902
|
box_no = 902
|
||||||
first = client.post(
|
first = client.post(
|
||||||
"/CargoTrace/box",
|
"/CargoTrace/box",
|
||||||
@@ -135,7 +133,6 @@ def test_box_save_many_to_one_duplicate_same_zongpai(client: TestClient):
|
|||||||
"zongpai_no": "26BW0011",
|
"zongpai_no": "26BW0011",
|
||||||
"box_no": box_no,
|
"box_no": box_no,
|
||||||
"quantity": 10,
|
"quantity": 10,
|
||||||
"box_mode": "many-to-one",
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert first.status_code == 200
|
assert first.status_code == 200
|
||||||
@@ -146,13 +143,52 @@ def test_box_save_many_to_one_duplicate_same_zongpai(client: TestClient):
|
|||||||
"zongpai_no": "26BW0011",
|
"zongpai_no": "26BW0011",
|
||||||
"box_no": box_no,
|
"box_no": box_no,
|
||||||
"quantity": 5,
|
"quantity": 5,
|
||||||
"box_mode": "many-to-one",
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert duplicate.status_code == 409
|
assert duplicate.status_code == 409
|
||||||
assert duplicate.json()["error_code"] == "DUPLICATE_BOX_NO"
|
assert duplicate.json()["error_code"] == "DUPLICATE_BOX_NO"
|
||||||
|
|
||||||
|
|
||||||
|
def test_box_save_split_same_zongpai_up_to_total_quantity(client: TestClient):
|
||||||
|
"""单码装箱:同一总排号可分箱提交,累计等于 ERP 数量时成功。"""
|
||||||
|
first = client.post(
|
||||||
|
"/CargoTrace/box",
|
||||||
|
json={"zongpai_no": "26BW0011", "box_no": 905, "quantity": 30},
|
||||||
|
)
|
||||||
|
assert first.status_code == 200
|
||||||
|
|
||||||
|
second = client.post(
|
||||||
|
"/CargoTrace/box",
|
||||||
|
json={"zongpai_no": "26BW0011", "box_no": 906, "quantity": 50},
|
||||||
|
)
|
||||||
|
assert second.status_code == 200
|
||||||
|
|
||||||
|
info = client.get("/CargoTrace/box/info", params={"zongpai_no": "26BW0011"})
|
||||||
|
assert info.status_code == 200
|
||||||
|
current_boxes = [
|
||||||
|
item
|
||||||
|
for item in info.json()["current_zongpai_boxes"]
|
||||||
|
if item["box_no"] in (905, 906)
|
||||||
|
]
|
||||||
|
assert sum(item["quantity"] for item in current_boxes) == 80
|
||||||
|
|
||||||
|
|
||||||
|
def test_box_save_rejects_quantity_over_remaining(client: TestClient):
|
||||||
|
"""保存后累计数量超过 ERP 总数量时返回 INVALID_QUANTITY。"""
|
||||||
|
created = client.post(
|
||||||
|
"/CargoTrace/box",
|
||||||
|
json={"zongpai_no": "26BW0011", "box_no": 907, "quantity": 70},
|
||||||
|
)
|
||||||
|
assert created.status_code == 200
|
||||||
|
|
||||||
|
over = client.post(
|
||||||
|
"/CargoTrace/box",
|
||||||
|
json={"zongpai_no": "26BW0011", "box_no": 908, "quantity": 11},
|
||||||
|
)
|
||||||
|
assert over.status_code == 400
|
||||||
|
assert over.json()["error_code"] == "INVALID_QUANTITY"
|
||||||
|
|
||||||
|
|
||||||
def test_box_update_same_box_no_does_not_conflict(client: TestClient):
|
def test_box_update_same_box_no_does_not_conflict(client: TestClient):
|
||||||
"""PATCH 原箱号未变时,应排除当前 box_item_id,避免误判重复。"""
|
"""PATCH 原箱号未变时,应排除当前 box_item_id,避免误判重复。"""
|
||||||
box_no = 903
|
box_no = 903
|
||||||
@@ -162,7 +198,6 @@ def test_box_update_same_box_no_does_not_conflict(client: TestClient):
|
|||||||
"zongpai_no": "26BW0011",
|
"zongpai_no": "26BW0011",
|
||||||
"box_no": box_no,
|
"box_no": box_no,
|
||||||
"quantity": 10,
|
"quantity": 10,
|
||||||
"box_mode": "one-to-many",
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert created.status_code == 200
|
assert created.status_code == 200
|
||||||
@@ -170,12 +205,35 @@ def test_box_update_same_box_no_does_not_conflict(client: TestClient):
|
|||||||
|
|
||||||
updated = client.patch(
|
updated = client.patch(
|
||||||
f"/CargoTrace/box/{box_item_id}",
|
f"/CargoTrace/box/{box_item_id}",
|
||||||
json={"box_no": box_no, "quantity": 7, "box_mode": "one-to-many"},
|
json={"box_no": box_no, "quantity": 7},
|
||||||
)
|
)
|
||||||
assert updated.status_code == 200
|
assert updated.status_code == 200
|
||||||
assert updated.json()["quantity"] == 7
|
assert updated.json()["quantity"] == 7
|
||||||
|
|
||||||
|
|
||||||
|
def test_box_update_rejects_quantity_over_remaining(client: TestClient):
|
||||||
|
"""PATCH 调整数量导致累计超过 ERP 总数量时返回 INVALID_QUANTITY。"""
|
||||||
|
first = client.post(
|
||||||
|
"/CargoTrace/box",
|
||||||
|
json={"zongpai_no": "26BW0011", "box_no": 909, "quantity": 70},
|
||||||
|
)
|
||||||
|
assert first.status_code == 200
|
||||||
|
|
||||||
|
second = client.post(
|
||||||
|
"/CargoTrace/box",
|
||||||
|
json={"zongpai_no": "26BW0011", "box_no": 910, "quantity": 5},
|
||||||
|
)
|
||||||
|
assert second.status_code == 200
|
||||||
|
box_item_id = second.json()["box_item_id"]
|
||||||
|
|
||||||
|
over = client.patch(
|
||||||
|
f"/CargoTrace/box/{box_item_id}",
|
||||||
|
json={"box_no": 910, "quantity": 11},
|
||||||
|
)
|
||||||
|
assert over.status_code == 400
|
||||||
|
assert over.json()["error_code"] == "INVALID_QUANTITY"
|
||||||
|
|
||||||
|
|
||||||
def test_box_delete_removes_empty_box(client: TestClient):
|
def test_box_delete_removes_empty_box(client: TestClient):
|
||||||
"""DELETE 删除最后一条明细后,同步清理空箱号。"""
|
"""DELETE 删除最后一条明细后,同步清理空箱号。"""
|
||||||
box_no = 904
|
box_no = 904
|
||||||
@@ -185,7 +243,6 @@ def test_box_delete_removes_empty_box(client: TestClient):
|
|||||||
"zongpai_no": "26BW0011",
|
"zongpai_no": "26BW0011",
|
||||||
"box_no": box_no,
|
"box_no": box_no,
|
||||||
"quantity": 10,
|
"quantity": 10,
|
||||||
"box_mode": "many-to-one",
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert created.status_code == 200
|
assert created.status_code == 200
|
||||||
@@ -201,7 +258,6 @@ def test_box_delete_removes_empty_box(client: TestClient):
|
|||||||
"zongpai_no": "26BW0012",
|
"zongpai_no": "26BW0012",
|
||||||
"box_no": box_no,
|
"box_no": box_no,
|
||||||
"quantity": 8,
|
"quantity": 8,
|
||||||
"box_mode": "one-to-many",
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert recreated.status_code == 200
|
assert recreated.status_code == 200
|
||||||
|
|||||||
Reference in New Issue
Block a user