diff --git a/inventory-backend/app/services/inbound/inbound_summary_service.py b/inventory-backend/app/services/inbound/inbound_summary_service.py index 68981df..ea8b340 100644 --- a/inventory-backend/app/services/inbound/inbound_summary_service.py +++ b/inventory-backend/app/services/inbound/inbound_summary_service.py @@ -1,4 +1,5 @@ -from sqlalchemy import select, literal, union_all, desc, asc, func, or_, cast, String, Numeric, Date # .material -> .base refactor checked +from sqlalchemy import select, literal, union_all, desc, asc, func, or_, cast, String, Numeric, \ + Date # .material -> .base refactor checked from app.extensions import db from app.models.inbound.buy import StockBuy from app.models.inbound.semi import StockSemi @@ -21,6 +22,8 @@ class InboundSummaryService: try: # ========================================================= # 1. 构建三个子查询 (Subqueries) + # 使用 getattr 动态安全地获取 batch_number 和 serial_number(或 sn) + # 避免因不同表结构缺失字段导致报错 # ========================================================= # --- A. 采购件 (StockBuy) --- @@ -34,7 +37,9 @@ class InboundSummaryService: cast(StockBuy.supplier_name, String).label('source_info'), StockBuy.status.label('orig_status'), - cast(StockBuy.batch_number, String).label('batch_number'), + cast(getattr(StockBuy, 'batch_number', literal('')), String).label('batch_number'), + cast(getattr(StockBuy, 'serial_number', getattr(StockBuy, 'sn', literal(''))), String).label( + 'serial_number'), cast(literal('buy'), String).label('source_type') ) @@ -49,7 +54,9 @@ class InboundSummaryService: cast(StockSemi.production_manager, String).label('source_info'), StockSemi.status.label('orig_status'), - cast(StockSemi.batch_number, String).label('batch_number'), + cast(getattr(StockSemi, 'batch_number', literal('')), String).label('batch_number'), + cast(getattr(StockSemi, 'serial_number', getattr(StockSemi, 'sn', literal(''))), String).label( + 'serial_number'), cast(literal('semi'), String).label('source_type') ) @@ -64,7 +71,9 @@ class InboundSummaryService: cast(StockProduct.production_manager, String).label('source_info'), StockProduct.status.label('orig_status'), - cast(StockProduct.serial_number, String).label('batch_number'), + cast(getattr(StockProduct, 'batch_number', literal('')), String).label('batch_number'), + cast(getattr(StockProduct, 'serial_number', getattr(StockProduct, 'sn', literal(''))), String).label( + 'serial_number'), cast(literal('product'), String).label('source_type') ) @@ -95,6 +104,7 @@ class InboundSummaryService: cte.c.sku.ilike(f'%{keyword}%'), cte.c.source_info.ilike(f'%{keyword}%'), cte.c.batch_number.ilike(f'%{keyword}%'), + cte.c.serial_number.ilike(f'%{keyword}%'), # 加入对序列号的搜索支持 MaterialBase.name.ilike(f'%{keyword}%'), MaterialBase.spec_model.ilike(f'%{keyword}%') ) @@ -159,6 +169,14 @@ class InboundSummaryService: elif current_qty < in_qty: final_status = "部分出库" + # 处理 批次 / 序列号 展示逻辑 + b_num = row.batch_number or "" + s_num = row.serial_number or "" + if b_num and s_num and b_num != s_num: + display_batch_sn = f"{b_num} / {s_num}" + else: + display_batch_sn = b_num or s_num + items.append({ 'id': row.id, 'sku': row.sku or "", @@ -174,7 +192,7 @@ class InboundSummaryService: 'status': final_status, 'source_type': row.source_type, 'type_label': type_map.get(row.source_type, "未知类型"), - 'batch_number': row.batch_number or "" + 'batch_number': display_batch_sn # 输出统一的批次与序列号组合字符串给前端 }) return { @@ -187,4 +205,4 @@ class InboundSummaryService: except Exception as e: print("【InboundSummaryService Error】:", str(e)) traceback.print_exc() - raise e + raise e \ No newline at end of file