feat: support editable boxing assignments
This commit is contained in:
@@ -4,7 +4,7 @@ from sqlalchemy import bindparam, text
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.finished_goods import FinishedGoodsBox, FinishedGoodsBoxItem
|
||||
from app.schemas.box import BoxSaveRequest
|
||||
from app.schemas.box import BoxSaveRequest, BoxUpdateRequest
|
||||
|
||||
ZONGPAI_PATTERN = re.compile(r"^(\d{2}(B|C|T)\d+|\d{2}(BW|CW)\d{4})$")
|
||||
|
||||
@@ -30,6 +30,14 @@ class DuplicateZongpaiBindError(Exception):
|
||||
self.zongpai_no = zongpai_no
|
||||
|
||||
|
||||
class BoxItemNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidBoxItemError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def query_erp_info(db: Session, zongpai_no: str) -> dict:
|
||||
"""从 ERP 视图查询总排号对应的排产号、工令号和数量。"""
|
||||
sql = text(_erp_info_sql(db))
|
||||
@@ -115,13 +123,22 @@ def get_box_info(db: Session, zongpai_no: str) -> dict:
|
||||
work_order_map = query_erp_work_order_map(db, item_zongpai_nos)
|
||||
|
||||
existing_boxes = []
|
||||
current_zongpai_boxes = []
|
||||
max_box_no = 0
|
||||
for box in boxes:
|
||||
items = box_items[box.id]
|
||||
for item in items:
|
||||
if item.zongpai_no == zongpai_no:
|
||||
current_zongpai_boxes.append({
|
||||
"box_item_id": item.id,
|
||||
"box_no": box.box_no,
|
||||
"quantity": int(item.quantity or 0),
|
||||
})
|
||||
existing_boxes.append({
|
||||
"box_no": box.box_no,
|
||||
"items": [
|
||||
{
|
||||
"box_item_id": item.id,
|
||||
"zongpai_no": item.zongpai_no,
|
||||
"work_order_no": work_order_map.get(item.zongpai_no),
|
||||
"quantity": int(item.quantity or 0),
|
||||
@@ -137,6 +154,7 @@ def get_box_info(db: Session, zongpai_no: str) -> dict:
|
||||
"paichan_no": paichan_no,
|
||||
"work_order_no": erp["work_order_no"],
|
||||
"quantity": quantity,
|
||||
"current_zongpai_boxes": current_zongpai_boxes,
|
||||
"existing_boxes": existing_boxes,
|
||||
"max_box_no": max_box_no,
|
||||
"suggested_box_no": max_box_no + 1,
|
||||
@@ -171,6 +189,8 @@ def save_box_record(db: Session, req: BoxSaveRequest) -> dict:
|
||||
)
|
||||
|
||||
if box:
|
||||
if req.box_mode in ("one-to-one", "one-to-many"):
|
||||
raise DuplicateBoxItemError(paichan_no, req.box_no)
|
||||
existing_item = (
|
||||
db.query(FinishedGoodsBoxItem)
|
||||
.filter(
|
||||
@@ -199,9 +219,109 @@ def save_box_record(db: Session, req: BoxSaveRequest) -> dict:
|
||||
db.refresh(item)
|
||||
|
||||
return {
|
||||
"box_item_id": item.id,
|
||||
"paichan_no": paichan_no,
|
||||
"box_no": req.box_no,
|
||||
"zongpai_no": req.zongpai_no,
|
||||
"quantity": req.quantity,
|
||||
"created_at": item.created_at.isoformat(),
|
||||
}
|
||||
|
||||
|
||||
def update_box_item(db: Session, box_item_id: int, req: BoxUpdateRequest) -> dict:
|
||||
"""更新一码多箱已分配明细的箱号和数量。"""
|
||||
item = (
|
||||
db.query(FinishedGoodsBoxItem)
|
||||
.filter(FinishedGoodsBoxItem.id == box_item_id)
|
||||
.first()
|
||||
)
|
||||
if item is None:
|
||||
raise BoxItemNotFoundError()
|
||||
|
||||
current_box = (
|
||||
db.query(FinishedGoodsBox)
|
||||
.filter(FinishedGoodsBox.id == item.box_id)
|
||||
.first()
|
||||
)
|
||||
if current_box is None:
|
||||
raise InvalidBoxItemError()
|
||||
|
||||
paichan_no = current_box.paichan_no
|
||||
target_box = (
|
||||
db.query(FinishedGoodsBox)
|
||||
.filter(
|
||||
FinishedGoodsBox.paichan_no == paichan_no,
|
||||
FinishedGoodsBox.box_no == req.box_no,
|
||||
)
|
||||
.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:
|
||||
target_box = FinishedGoodsBox(paichan_no=paichan_no, box_no=req.box_no)
|
||||
db.add(target_box)
|
||||
db.flush()
|
||||
|
||||
old_box_id = item.box_id
|
||||
item.box_id = target_box.id
|
||||
item.quantity = req.quantity
|
||||
|
||||
if old_box_id != target_box.id:
|
||||
old_box_has_items = (
|
||||
db.query(FinishedGoodsBoxItem.id)
|
||||
.filter(
|
||||
FinishedGoodsBoxItem.box_id == old_box_id,
|
||||
FinishedGoodsBoxItem.id != item.id,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if old_box_has_items is None:
|
||||
old_box = (
|
||||
db.query(FinishedGoodsBox)
|
||||
.filter(FinishedGoodsBox.id == old_box_id)
|
||||
.first()
|
||||
)
|
||||
if old_box is not None:
|
||||
db.delete(old_box)
|
||||
|
||||
db.commit()
|
||||
db.refresh(item)
|
||||
|
||||
return {
|
||||
"box_item_id": item.id,
|
||||
"paichan_no": paichan_no,
|
||||
"box_no": req.box_no,
|
||||
"zongpai_no": item.zongpai_no,
|
||||
"quantity": int(item.quantity or 0),
|
||||
"updated_at": item.created_at.isoformat(),
|
||||
}
|
||||
|
||||
|
||||
def delete_box_item(db: Session, box_item_id: int) -> dict:
|
||||
"""删除误录的装箱明细;若箱号下无其他明细,同步删除空箱号。"""
|
||||
item = (
|
||||
db.query(FinishedGoodsBoxItem)
|
||||
.filter(FinishedGoodsBoxItem.id == box_item_id)
|
||||
.first()
|
||||
)
|
||||
if item is None:
|
||||
raise BoxItemNotFoundError()
|
||||
|
||||
box_id = item.box_id
|
||||
db.delete(item)
|
||||
db.flush()
|
||||
|
||||
remaining = (
|
||||
db.query(FinishedGoodsBoxItem.id)
|
||||
.filter(FinishedGoodsBoxItem.box_id == box_id)
|
||||
.first()
|
||||
)
|
||||
if remaining is None:
|
||||
box = db.query(FinishedGoodsBox).filter(FinishedGoodsBox.id == box_id).first()
|
||||
if box is not None:
|
||||
db.delete(box)
|
||||
|
||||
db.commit()
|
||||
return {"box_item_id": box_item_id, "deleted": True}
|
||||
|
||||
Reference in New Issue
Block a user