feat(server): extend GET /box/info with mixed items and attachment summary
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,12 +6,15 @@ ZONGPAI_PATTERN = re.compile(r"^(\d{2}(B|C|T)\d+|\d{2}(BW|CW)\d{4})$")
|
||||
|
||||
|
||||
class BoxItemDetail(BaseModel):
|
||||
"""箱号下某个总排号的明细"""
|
||||
"""箱号下某个总排号的明细(产品或附件)"""
|
||||
box_item_id: int | None = None
|
||||
zongpai_no: str
|
||||
work_order_no: str | None = None
|
||||
quantity: int
|
||||
total_quantity: int | None = None
|
||||
kind: str = "product"
|
||||
category_id: int | None = None
|
||||
category_name: str | None = None
|
||||
|
||||
|
||||
class CurrentZongpaiBox(BaseModel):
|
||||
@@ -27,6 +30,12 @@ class BoxDetail(BaseModel):
|
||||
items: list[BoxItemDetail]
|
||||
|
||||
|
||||
class AttachmentSummary(BaseModel):
|
||||
determination: str
|
||||
all_complete: bool
|
||||
pending_count: int
|
||||
|
||||
|
||||
class BoxInfoResponse(BaseModel):
|
||||
"""GET /box/info 响应"""
|
||||
zongpai_no: str
|
||||
@@ -37,6 +46,7 @@ class BoxInfoResponse(BaseModel):
|
||||
existing_boxes: list[BoxDetail]
|
||||
max_box_no: int
|
||||
suggested_box_no: int
|
||||
attachment_summary: AttachmentSummary
|
||||
|
||||
|
||||
class BoxSaveRequest(BaseModel):
|
||||
|
||||
@@ -3,6 +3,12 @@ import re
|
||||
from sqlalchemy import bindparam, text
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.attachment import (
|
||||
AttachmentCategory,
|
||||
FinishedGoodsAttachment,
|
||||
FinishedGoodsAttachmentItem,
|
||||
FinishedGoodsBoxAttachmentItem,
|
||||
)
|
||||
from app.models.finished_goods import FinishedGoodsBox, FinishedGoodsBoxItem
|
||||
from app.schemas.box import BoxSaveRequest, BoxUpdateRequest
|
||||
|
||||
@@ -128,6 +134,41 @@ def get_box_info(db: Session, zongpai_no: str) -> dict:
|
||||
existing_boxes = []
|
||||
current_zongpai_boxes = []
|
||||
max_box_no = 0
|
||||
paichan_box_rows = (
|
||||
db.query(FinishedGoodsBox)
|
||||
.filter(FinishedGoodsBox.paichan_no == paichan_no)
|
||||
.all()
|
||||
)
|
||||
att_rows = (
|
||||
db.query(FinishedGoodsBoxAttachmentItem)
|
||||
.filter(
|
||||
FinishedGoodsBoxAttachmentItem.box_id.in_(
|
||||
[b.id for b in paichan_box_rows]
|
||||
)
|
||||
)
|
||||
.all()
|
||||
)
|
||||
att_category_ids = {r.category_id for r in att_rows}
|
||||
att_names = {
|
||||
c.id: c.name
|
||||
for c in db.query(AttachmentCategory)
|
||||
.filter(AttachmentCategory.id.in_(list(att_category_ids)))
|
||||
.all()
|
||||
} if att_category_ids else {}
|
||||
items_by_box: dict[int, list[dict]] = {}
|
||||
for r in att_rows:
|
||||
items_by_box.setdefault(r.box_id, []).append(
|
||||
{
|
||||
"box_item_id": r.id,
|
||||
"zongpai_no": r.zongpai_no,
|
||||
"work_order_no": None,
|
||||
"quantity": int(r.quantity or 0),
|
||||
"total_quantity": None,
|
||||
"kind": "attachment",
|
||||
"category_id": r.category_id,
|
||||
"category_name": att_names.get(r.category_id),
|
||||
}
|
||||
)
|
||||
for box in boxes:
|
||||
items = box_items[box.id]
|
||||
for item in items:
|
||||
@@ -150,13 +191,50 @@ def get_box_info(db: Session, zongpai_no: str) -> dict:
|
||||
"total_quantity": erp_item_info_map.get(
|
||||
item.zongpai_no, {}
|
||||
).get("total_quantity"),
|
||||
"kind": "product",
|
||||
}
|
||||
for item in items
|
||||
],
|
||||
] + items_by_box.get(box.id, []),
|
||||
})
|
||||
if box.box_no > max_box_no:
|
||||
max_box_no = box.box_no
|
||||
|
||||
# Attachment summary for the scanned总排号
|
||||
att_row = (
|
||||
db.query(FinishedGoodsAttachment)
|
||||
.filter(FinishedGoodsAttachment.zongpai_no == zongpai_no)
|
||||
.first()
|
||||
)
|
||||
determination = att_row.determination if att_row else "undetermined"
|
||||
plan_items = (
|
||||
db.query(FinishedGoodsAttachmentItem)
|
||||
.filter(FinishedGoodsAttachmentItem.zongpai_no == zongpai_no)
|
||||
.all()
|
||||
)
|
||||
pending_count = 0
|
||||
for it in plan_items:
|
||||
boxed = sum(
|
||||
int(r.quantity or 0)
|
||||
for r in db.query(FinishedGoodsBoxAttachmentItem)
|
||||
.filter(
|
||||
FinishedGoodsBoxAttachmentItem.zongpai_no == zongpai_no,
|
||||
FinishedGoodsBoxAttachmentItem.category_id == it.category_id,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
if boxed < it.expected_qty:
|
||||
pending_count += 1
|
||||
all_complete = (
|
||||
determination == "has"
|
||||
and len(plan_items) > 0
|
||||
and pending_count == 0
|
||||
)
|
||||
attachment_summary = {
|
||||
"determination": determination,
|
||||
"all_complete": all_complete,
|
||||
"pending_count": pending_count,
|
||||
}
|
||||
|
||||
return {
|
||||
"zongpai_no": zongpai_no,
|
||||
"paichan_no": paichan_no,
|
||||
@@ -166,6 +244,7 @@ def get_box_info(db: Session, zongpai_no: str) -> dict:
|
||||
"existing_boxes": existing_boxes,
|
||||
"max_box_no": max_box_no,
|
||||
"suggested_box_no": max_box_no + 1,
|
||||
"attachment_summary": attachment_summary,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user