feat(server): add PATCH/DELETE /attachment/box mirroring product box ops

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-08-12 14:15:51 +08:00
parent 0ef4f0e990
commit 4d55420958
4 changed files with 235 additions and 0 deletions

View File

@@ -371,3 +371,119 @@ def save_attachment_box(db: Session, req) -> dict:
"quantity": req.quantity,
"created_at": record.created_at.isoformat(),
}
def update_attachment_box(db: Session, item_id: int, req) -> dict:
record = (
db.query(FinishedGoodsBoxAttachmentItem)
.filter(FinishedGoodsBoxAttachmentItem.id == item_id)
.first()
)
if record is None:
raise AttachmentItemNotFoundError()
current_box = (
db.query(FinishedGoodsBox)
.filter(FinishedGoodsBox.id == record.box_id)
.first()
)
if current_box is None:
raise AttachmentItemNotFoundError()
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 None:
target_box = FinishedGoodsBox(paichan_no=paichan_no, box_no=req.box_no)
db.add(target_box)
db.flush()
else:
dup = (
db.query(FinishedGoodsBoxAttachmentItem)
.filter(
FinishedGoodsBoxAttachmentItem.box_id == target_box.id,
FinishedGoodsBoxAttachmentItem.zongpai_no == record.zongpai_no,
FinishedGoodsBoxAttachmentItem.category_id == record.category_id,
FinishedGoodsBoxAttachmentItem.id != record.id,
)
.first()
)
if dup is not None:
raise DuplicateAttachmentBoxItemError(paichan_no, req.box_no)
item = (
db.query(FinishedGoodsAttachmentItem)
.filter(
FinishedGoodsAttachmentItem.zongpai_no == record.zongpai_no,
FinishedGoodsAttachmentItem.category_id == record.category_id,
)
.first()
)
expected_qty = item.expected_qty if item is not None else 0
already_boxed = _boxed_for_category(
db, record.zongpai_no, record.category_id, exclude_item_id=record.id
)
if already_boxed + req.quantity > expected_qty:
raise InvalidQuantityError()
old_box_id = record.box_id
record.box_id = target_box.id
record.quantity = req.quantity
if old_box_id != target_box.id:
_cleanup_empty_box(db, old_box_id, exclude_item_id=record.id)
db.commit()
db.refresh(record)
return {
"box_item_id": record.id,
"paichan_no": paichan_no,
"box_no": req.box_no,
"zongpai_no": record.zongpai_no,
"category_id": record.category_id,
"quantity": int(record.quantity or 0),
"updated_at": record.created_at.isoformat(),
}
def delete_attachment_box(db: Session, item_id: int) -> dict:
record = (
db.query(FinishedGoodsBoxAttachmentItem)
.filter(FinishedGoodsBoxAttachmentItem.id == item_id)
.first()
)
if record is None:
raise AttachmentItemNotFoundError()
box_id = record.box_id
db.delete(record)
db.flush()
_cleanup_empty_box(db, box_id)
db.commit()
return {"box_item_id": item_id, "deleted": True}
def _cleanup_empty_box(db: Session, box_id: int, exclude_item_id: int | None = None) -> None:
"""If a box has no product items and no attachment items, delete it."""
from app.models.finished_goods import FinishedGoodsBoxItem
product_q = db.query(FinishedGoodsBoxItem.id).filter(
FinishedGoodsBoxItem.box_id == box_id
)
if product_q.first() is not None:
return
att_q = db.query(FinishedGoodsBoxAttachmentItem.id).filter(
FinishedGoodsBoxAttachmentItem.box_id == box_id
)
if exclude_item_id is not None:
att_q = att_q.filter(FinishedGoodsBoxAttachmentItem.id != exclude_item_id)
if att_q.first() is not None:
return
box = db.query(FinishedGoodsBox).filter(FinishedGoodsBox.id == box_id).first()
if box is not None:
db.delete(box)