From 1ba0dbfde5634c8bf2ec20891d6b226b996f6b59 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 02 九月 2026 14:24:38 +0800
Subject: [PATCH] refactor(mes): 优化MES生产扫码入库功能支持多类型扫码
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java | 12
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityPageReqVO.java | 21
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/batch/MesTraceBatchController.java | 39
.playwright-mcp/page-2026-09-02T06-08-53-561Z.yml | 1
.playwright-mcp/page-2026-09-02T06-16-10-960Z.yml | 190 +++
.playwright-mcp/page-2026-09-02T06-11-00-277Z.yml | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicRespVO.java | 38
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstockbag/MesWmMaterialStockBagMapper.java | 82 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmWarehouseTypeEnum.java | 20
sql/mysql/mes_qc_seed_quality_record_menu.sql | 14
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java | 4
.playwright-mcp/page-2026-09-02T06-14-34-873Z.yml | 190 +++
yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/returnobj/AfterSaleReturnServiceImpl.java | 2
sql/mysql/mes_wm_qualified_warehouse.sql | 85 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/MesWmSalesNoticeController.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeDO.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java | 93 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseRespVO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/batch/MesProBatchMapper.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagRespVO.java | 29
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java | 5
.playwright-mcp/page-2026-09-02T06-07-41-739Z.yml | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineRespVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java | 22
.playwright-mcp/page-2026-09-02T06-16-32-193Z.yml | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java | 61
docs/sales_notice_to_product_sales.md | 14
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java | 25
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProBagCodeQcStatusEnum.java | 40
docs/scan_in_multi_type_inbound.md | 80 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeSaveReqVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesSaveReqVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesRespVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventCreateReqVO.java | 12
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehousePageReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagServiceImpl.java | 165 ++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/home/MesBagCodeHomeStatisticsMapper.java | 17
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/warehouse/MesWmWarehouseMapper.java | 7
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/salesnotice/MesWmSalesNoticeMapper.java | 16
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/warehouse/MesWmWarehouseDO.java | 7
docs/batch_trace_refactor_integration.md | 102 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeService.java | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java | 24
.playwright-mcp/page-2026-09-02T06-03-42-523Z.yml | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionPageReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java | 101 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java | 7
sql/mysql/mes_wm_product_sales_add_columns.sql | 12
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java | 6
docs/sql/trace_platform_01_schema.sql | 79 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java | 22
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java | 59
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java | 84 +
.playwright-mcp/page-2026-09-02T06-14-13-812Z.yml | 1
sql/mysql/mes_pro_scan_event_scan_type.sql | 14
docs/mes_wm_material_stock_bag_api.md | 69 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java | 3
.playwright-mcp/page-2026-09-02T05-27-28-818Z.yml | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventRespVO.java | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMaterialStockBagStatusEnum.java | 15
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java | 45
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java | 20
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagPageReqVO.java | 18
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeServiceImpl.java | 65 -
.playwright-mcp/page-2026-09-02T05-56-04-640Z.yml | 1
yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/returnsales/dto/MesWmReturnSalesCreateReqDTO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java | 37
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstockbag/MesWmMaterialStockBagDO.java | 44
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java | 4
.playwright-mcp/page-2026-09-02T06-08-22-302Z.yml | 196 +++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeRespVO.java | 7
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagService.java | 59
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java | 239 +++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java | 13
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java | 21
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java | 15
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java | 22
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java | 52
yudao-module-mes/src/main/resources/mapper/home/MesBagCodeHomeStatisticsMapper.xml | 39
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java | 11
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeLineDO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticePageReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/scan/MesProScanEventDO.java | 7
.playwright-mcp/page-2026-09-02T06-08-26-480Z.yml | 1
.playwright-mcp/page-2026-09-02T06-08-42-531Z.yml | 196 +++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/home/MesBagCodeHomeStatisticsServiceImpl.java | 11
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnsales/MesWmReturnSalesMapper.java | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseService.java | 22
docs/seed_quality_bag_granularity.md | 88 +
sql/mysql/mes_wm_material_stock_bag.sql | 31
sql/mysql/wls_sales_outbound_menu_extract.sql | 25
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesDO.java | 8
.playwright-mcp/page-2026-09-02T05-57-05-545Z.yml | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/home/vo/MesBagCodeHomeSummaryRespVO.java | 19
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesPageReqVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedQualityMapper.java | 11
docs/bagcode_home_dashboard_integration.md | 83 +
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java | 12
.playwright-mcp/page-2026-09-02T05-54-09-946Z.yml | 1
sql/mysql/mes_wm_transaction_bag_code.sql | 17
/dev/null | 41
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseSaveReqVO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/MesProScanEventController.java | 2
docs/wm_transaction_query.md | 50
sql/mysql/mes_pro_bag_code_qc_status.sql | 13
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java | 3
118 files changed, 3,128 insertions(+), 447 deletions(-)
diff --git a/.playwright-mcp/page-2026-09-02T05-27-28-818Z.yml b/.playwright-mcp/page-2026-09-02T05-27-28-818Z.yml
new file mode 100644
index 0000000..cd16c02
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T05-27-28-818Z.yml
@@ -0,0 +1 @@
+- generic [active] [ref=e1]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T05-54-09-946Z.yml b/.playwright-mcp/page-2026-09-02T05-54-09-946Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T05-54-09-946Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T05-56-04-640Z.yml b/.playwright-mcp/page-2026-09-02T05-56-04-640Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T05-56-04-640Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T05-57-05-545Z.yml b/.playwright-mcp/page-2026-09-02T05-57-05-545Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T05-57-05-545Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-03-42-523Z.yml b/.playwright-mcp/page-2026-09-02T06-03-42-523Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-03-42-523Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-07-41-739Z.yml b/.playwright-mcp/page-2026-09-02T06-07-41-739Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-07-41-739Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-08-22-302Z.yml b/.playwright-mcp/page-2026-09-02T06-08-22-302Z.yml
new file mode 100644
index 0000000..6b5b078
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-08-22-302Z.yml
@@ -0,0 +1,196 @@
+- generic [ref=f10e7]:
+ - complementary [ref=f10e9]:
+ - generic [ref=f10e10]:
+ - link [ref=f10e13] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f10e16]
+ - menu [ref=f10e19]:
+ - menuitem [ref=f10e20] [cursor=pointer]
+ - listitem [ref=f10e24]:
+ - generic [ref=f10e25] [cursor=pointer]
+ - listitem [ref=f10e31]:
+ - generic [ref=f10e32] [cursor=pointer]
+ - listitem [ref=f10e36]:
+ - generic [ref=f10e37] [cursor=pointer]
+ - listitem [ref=f10e43]:
+ - generic [ref=f10e44] [cursor=pointer]
+ - listitem [ref=f10e48]:
+ - generic [ref=f10e49] [cursor=pointer]
+ - listitem [ref=f10e53]:
+ - generic [ref=f10e54] [cursor=pointer]
+ - listitem [ref=f10e58]:
+ - generic [ref=f10e59] [cursor=pointer]
+ - listitem [ref=f10e63]:
+ - generic [ref=f10e64] [cursor=pointer]
+ - listitem [ref=f10e68]:
+ - generic [ref=f10e69] [cursor=pointer]
+ - generic [ref=f10e74] [cursor=pointer]
+ - generic [ref=f10e79]:
+ - generic [ref=f10e80]:
+ - banner [ref=f10e81]:
+ - button [ref=f10e82] [cursor=pointer]
+ - button [ref=f10e85] [cursor=pointer]
+ - navigation "breadcrumb" [ref=f10e90]:
+ - list [ref=f10e91]:
+ - listitem [ref=f10e625]:
+ - link "鍑哄簱娴侀�氱鐞�" [ref=f10e626] [cursor=pointer]:
+ - /url: javascript:void 0
+ - listitem [ref=f10e630]
+ - listitem [ref=f10e633]:
+ - link "閿�鍞嚭搴�" [disabled] [ref=f10e634]
+ - generic [ref=f10e98]:
+ - generic [ref=f10e100] [cursor=pointer]:
+ - generic [ref=f10e104]: 鎼滅储
+ - generic [ref=f10e105]: Ctrl K
+ - button [ref=f10e107] [cursor=pointer]
+ - button "dark" [ref=f10e112] [cursor=pointer]
+ - button [ref=f10e121] [cursor=pointer]
+ - button [ref=f10e127] [cursor=pointer]
+ - button [ref=f10e130] [cursor=pointer]
+ - button [ref=f10e136] [cursor=pointer]:
+ - button [ref=f10e138]
+ - button "宸ヤ綔鍙�" [ref=f10e142] [cursor=pointer]
+ - button "鐞嗗憳" [ref=f10e146] [cursor=pointer]
+ - generic [ref=f10e153]:
+ - generic [ref=f10e158]:
+ - generic [ref=f10e159] [cursor=pointer]: 棣栭〉
+ - generic [ref=f10e641] [cursor=pointer]: 閿�鍞嚭搴�
+ - generic [ref=f10e173]:
+ - button [ref=f10e174] [cursor=pointer]
+ - generic [ref=f10e181] [cursor=pointer]
+ - generic [ref=f10e185] [cursor=pointer]
+ - main [ref=f10e192]:
+ - generic [ref=f10e196]:
+ - generic [ref=f10e197]:
+ - generic [ref=f10e198]: 涓氬姟鍏ㄩ摼璺�
+ - generic [ref=f10e210]:
+ - generic [ref=f10e217] [cursor=pointer]:
+ - generic [ref=f10e218]: 鍝佺
+ - generic [ref=f10e219]: "1"
+ - generic [ref=f10e227] [cursor=pointer]:
+ - generic [ref=f10e228]: 浜х嚎
+ - generic [ref=f10e229]: "1"
+ - generic [ref=f10e240] [cursor=pointer]:
+ - generic [ref=f10e241]: 鐢熶骇鎵规
+ - generic [ref=f10e242]: "103"
+ - generic [ref=f10e250] [cursor=pointer]:
+ - generic [ref=f10e251]: 琚嬬爜
+ - generic [ref=f10e252]: 1,101
+ - generic [ref=f10e262] [cursor=pointer]:
+ - generic [ref=f10e263]: 鎵樼洏鐮�
+ - generic [ref=f10e264]: "11"
+ - generic [ref=f10e275] [cursor=pointer]:
+ - generic [ref=f10e276]: 閿�鍞嚭搴�
+ - generic [ref=f10e277]: "0"
+ - generic [ref=f10e285] [cursor=pointer]:
+ - generic [ref=f10e286]: 娴侀�氭壂鐮�
+ - generic [ref=f10e287]: "23"
+ - generic [ref=f10e295] [cursor=pointer]:
+ - generic [ref=f10e296]: 闃茬獪/婧簮
+ - generic [ref=f10e297]: "0"
+ - generic [ref=f10e298]:
+ - generic [ref=f10e308] [cursor=pointer]:
+ - generic [ref=f10e309]: 鍝佺鎬绘暟
+ - generic [ref=f10e310]: "1"
+ - generic [ref=f10e312]: 鍩虹鏁版嵁
+ - generic [ref=f10e323] [cursor=pointer]:
+ - generic [ref=f10e324]: 鐢熶骇鎵规
+ - generic [ref=f10e325]: "103"
+ - generic [ref=f10e327]: 涓�琚嬩竴鐮�
+ - generic [ref=f10e335] [cursor=pointer]:
+ - generic [ref=f10e336]: 琚嬬爜
+ - generic [ref=f10e337]: 1,101
+ - generic [ref=f10e339]: 璧嬬爜
+ - generic [ref=f10e349] [cursor=pointer]:
+ - generic [ref=f10e350]: 鎵樼洏鐮�
+ - generic [ref=f10e351]: "11"
+ - generic [ref=f10e353]: 鎵樼洏
+ - generic [ref=f10e364] [cursor=pointer]:
+ - generic [ref=f10e365]: 閿�鍞嚭搴撳崟
+ - generic [ref=f10e366]: "0"
+ - generic [ref=f10e368]: 鍑哄簱娴侀��
+ - generic [ref=f10e376] [cursor=pointer]:
+ - generic [ref=f10e377]: 绱鎵爜
+ - generic [ref=f10e378]: "23"
+ - generic [ref=f10e380]: 婧簮
+ - generic [ref=f10e387] [cursor=pointer]:
+ - generic [ref=f10e388]: 搴撳瓨棰勮
+ - generic [ref=f10e389]: "0"
+ - generic [ref=f10e391]: 浠撳偍
+ - generic [ref=f10e399] [cursor=pointer]:
+ - generic [ref=f10e400]: 寰呰瘎瀹′笉鍚堟牸
+ - generic [ref=f10e401]: "0"
+ - generic [ref=f10e403]: 璐ㄩ噺
+ - generic [ref=f10e404]:
+ - generic [ref=f10e408]:
+ - generic [ref=f10e409]: 琚嬬爜鐢熸垚瓒嬪娍
+ - generic [ref=f10e411]:
+ - generic [ref=f10e412] [cursor=pointer]:
+ - generic [ref=f10e413]:
+ - radio "杩� 7 澶�" [checked]
+ - generic [ref=f10e414]: 杩� 7 澶�
+ - generic [ref=f10e415] [cursor=pointer]:
+ - generic [ref=f10e416]:
+ - radio "杩� 30 澶�"
+ - generic [ref=f10e417]: 杩� 30 澶�
+ - generic [ref=f10e422]: 娑堣垂鑰呮壂鐮佸湴鍖哄垎甯�
+ - generic [ref=f10e431]:
+ - generic [ref=f10e432]: 鎵规鐘舵�佸垎甯�
+ - generic [ref=f10e441]: 琚嬬爜鐘舵�佸垎甯�
+ - generic [ref=f10e451]:
+ - generic [ref=f10e452]: 寰呭姙涓庨璀�
+ - generic [ref=f10e456]:
+ - generic [ref=f10e461] [cursor=pointer]:
+ - generic [ref=f10e462]: 绐滆揣棰勮
+ - generic [ref=f10e463]: 寰呭鐞嗙殑绐滆揣棰勮
+ - generic [ref=f10e467] [cursor=pointer]:
+ - generic [ref=f10e468]: 搴撳瓨棰勮
+ - generic [ref=f10e469]: 鏈鐞嗙殑搴撳瓨棰勮
+ - generic [ref=f10e474] [cursor=pointer]:
+ - generic [ref=f10e475]: 涓嶅悎鏍煎搧
+ - generic [ref=f10e476]: 寰呰瘎瀹$殑涓嶅悎鏍煎搧鍗�
+ - generic [ref=f10e477]:
+ - generic [ref=f10e478]: 蹇嵎鍏ュ彛
+ - generic [ref=f10e482]:
+ - generic [ref=f10e484]:
+ - generic [ref=f10e485]: 鍩虹鏁版嵁
+ - generic [ref=f10e486]:
+ - generic [ref=f10e487] [cursor=pointer]: 鍝佺绠$悊
+ - generic [ref=f10e493] [cursor=pointer]: 鍝佺鍒嗙被
+ - generic [ref=f10e499] [cursor=pointer]: 璁¢噺鍗曚綅
+ - generic [ref=f10e504]:
+ - generic [ref=f10e505]: 涓�琚嬩竴鐮佺敓浜�
+ - generic [ref=f10e506]:
+ - generic [ref=f10e507] [cursor=pointer]: 浜х嚎缁存姢
+ - generic [ref=f10e511] [cursor=pointer]: 鎵规鐢熶骇
+ - generic [ref=f10e518] [cursor=pointer]: 璧嬬爜绠$悊
+ - generic [ref=f10e522] [cursor=pointer]: 鎵樼洏鐮�
+ - generic [ref=f10e528] [cursor=pointer]: 鎵爜鍏ュ簱
+ - generic [ref=f10e533]:
+ - generic [ref=f10e534]: 鍑哄簱娴侀��
+ - generic [ref=f10e535]:
+ - generic [ref=f10e536] [cursor=pointer]: 鍙戣揣閫氱煡
+ - generic [ref=f10e540] [cursor=pointer]: 閿�鍞嚭搴�
+ - generic [ref=f10e547] [cursor=pointer]: 閿�鍞��璐�
+ - generic [ref=f10e554]:
+ - generic [ref=f10e555]: 闃蹭吉闃茬獪璐�
+ - generic [ref=f10e556]:
+ - generic [ref=f10e557] [cursor=pointer]: 绐滆揣棰勮
+ - generic [ref=f10e561] [cursor=pointer]: 鎵爜鍦扮悊鍒嗗竷
+ - generic [ref=f10e567] [cursor=pointer]: 瀹屾暣鎬ф牎楠�
+ - generic [ref=f10e575]:
+ - generic [ref=f10e576]: 婧簮鍒嗘瀽
+ - generic [ref=f10e577]: 娑堣垂鑰呮壂鐮佺粺璁�
+ - generic [ref=f10e583]:
+ - generic [ref=f10e584]: 浠撳偍鐗╂祦
+ - generic [ref=f10e585]:
+ - generic [ref=f10e586] [cursor=pointer]: 浠撳簱璁剧疆
+ - generic [ref=f10e592] [cursor=pointer]: 搴撳瓨鐜版湁閲�
+ - generic [ref=f10e598] [cursor=pointer]: 搴撳瓨棰勮
+ - generic [ref=f10e601] [cursor=pointer]: 杞Щ璋冩嫧
+ - generic [ref=f10e606]:
+ - generic [ref=f10e607]: 璐ㄩ噺绠$悊
+ - generic [ref=f10e608]:
+ - generic [ref=f10e609] [cursor=pointer]: 鎵规杩芥函
+ - generic [ref=f10e615] [cursor=pointer]: 涓嶅悎鏍煎搧
+ - generic [ref=f10e619] [cursor=pointer]: 绉嶅瓙璐ㄦ
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-08-26-480Z.yml b/.playwright-mcp/page-2026-09-02T06-08-26-480Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-08-26-480Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-08-42-531Z.yml b/.playwright-mcp/page-2026-09-02T06-08-42-531Z.yml
new file mode 100644
index 0000000..2559c12
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-08-42-531Z.yml
@@ -0,0 +1,196 @@
+- generic [ref=f11e7]:
+ - complementary [ref=f11e9]:
+ - generic [ref=f11e10]:
+ - link [ref=f11e13] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f11e16]
+ - menu [ref=f11e19]:
+ - menuitem [ref=f11e20] [cursor=pointer]
+ - listitem [ref=f11e24]:
+ - generic [ref=f11e25] [cursor=pointer]
+ - listitem [ref=f11e31]:
+ - generic [ref=f11e32] [cursor=pointer]
+ - listitem [ref=f11e36]:
+ - generic [ref=f11e37] [cursor=pointer]
+ - listitem [ref=f11e43]:
+ - generic [ref=f11e44] [cursor=pointer]
+ - listitem [ref=f11e48]:
+ - generic [ref=f11e49] [cursor=pointer]
+ - listitem [ref=f11e53]:
+ - generic [ref=f11e54] [cursor=pointer]
+ - listitem [ref=f11e58]:
+ - generic [ref=f11e59] [cursor=pointer]
+ - listitem [ref=f11e63]:
+ - generic [ref=f11e64] [cursor=pointer]
+ - listitem [ref=f11e68]:
+ - generic [ref=f11e69] [cursor=pointer]
+ - generic [ref=f11e74] [cursor=pointer]
+ - generic [ref=f11e79]:
+ - generic [ref=f11e80]:
+ - banner [ref=f11e81]:
+ - button [ref=f11e82] [cursor=pointer]
+ - button [ref=f11e85] [cursor=pointer]
+ - navigation "breadcrumb" [ref=f11e90]:
+ - list [ref=f11e91]:
+ - listitem [ref=f11e630]:
+ - link "闃蹭吉闃茬獪璐х鐞�" [ref=f11e631] [cursor=pointer]:
+ - /url: javascript:void 0
+ - listitem [ref=f11e635]
+ - listitem [ref=f11e638]:
+ - link "绐滆揣棰勮" [disabled] [ref=f11e639]
+ - generic [ref=f11e98]:
+ - generic [ref=f11e100] [cursor=pointer]:
+ - generic [ref=f11e104]: 鎼滅储
+ - generic [ref=f11e105]: Ctrl K
+ - button [ref=f11e107] [cursor=pointer]
+ - button "dark" [ref=f11e112] [cursor=pointer]
+ - button [ref=f11e121] [cursor=pointer]
+ - button [ref=f11e127] [cursor=pointer]
+ - button [ref=f11e130] [cursor=pointer]
+ - button [ref=f11e136] [cursor=pointer]:
+ - button [ref=f11e138]
+ - button "宸ヤ綔鍙�" [ref=f11e142] [cursor=pointer]
+ - button "鐞嗗憳" [ref=f11e146] [cursor=pointer]
+ - generic [ref=f11e153]:
+ - generic [ref=f11e158]:
+ - generic [ref=f11e159] [cursor=pointer]: 棣栭〉
+ - generic [ref=f11e645] [cursor=pointer]: 绐滆揣棰勮
+ - generic [ref=f11e173]:
+ - button [ref=f11e174] [cursor=pointer]
+ - generic [ref=f11e181] [cursor=pointer]
+ - generic [ref=f11e185] [cursor=pointer]
+ - main [ref=f11e192]:
+ - generic [ref=f11e196]:
+ - generic [ref=f11e197]:
+ - generic [ref=f11e198]: 涓氬姟鍏ㄩ摼璺�
+ - generic [ref=f11e210]:
+ - generic [ref=f11e217] [cursor=pointer]:
+ - generic [ref=f11e218]: 鍝佺
+ - generic [ref=f11e219]: "1"
+ - generic [ref=f11e227] [cursor=pointer]:
+ - generic [ref=f11e228]: 浜х嚎
+ - generic [ref=f11e229]: "1"
+ - generic [ref=f11e240] [cursor=pointer]:
+ - generic [ref=f11e241]: 鐢熶骇鎵规
+ - generic [ref=f11e242]: "103"
+ - generic [ref=f11e250] [cursor=pointer]:
+ - generic [ref=f11e251]: 琚嬬爜
+ - generic [ref=f11e252]: 1,101
+ - generic [ref=f11e262] [cursor=pointer]:
+ - generic [ref=f11e263]: 鎵樼洏鐮�
+ - generic [ref=f11e264]: "11"
+ - generic [ref=f11e275] [cursor=pointer]:
+ - generic [ref=f11e276]: 閿�鍞嚭搴�
+ - generic [ref=f11e277]: "0"
+ - generic [ref=f11e285] [cursor=pointer]:
+ - generic [ref=f11e286]: 娴侀�氭壂鐮�
+ - generic [ref=f11e287]: "23"
+ - generic [ref=f11e295] [cursor=pointer]:
+ - generic [ref=f11e296]: 闃茬獪/婧簮
+ - generic [ref=f11e297]: "0"
+ - generic [ref=f11e298]:
+ - generic [ref=f11e308] [cursor=pointer]:
+ - generic [ref=f11e309]: 鍝佺鎬绘暟
+ - generic [ref=f11e310]: "1"
+ - generic [ref=f11e312]: 鍩虹鏁版嵁
+ - generic [ref=f11e323] [cursor=pointer]:
+ - generic [ref=f11e324]: 鐢熶骇鎵规
+ - generic [ref=f11e325]: "103"
+ - generic [ref=f11e327]: 涓�琚嬩竴鐮�
+ - generic [ref=f11e335] [cursor=pointer]:
+ - generic [ref=f11e336]: 琚嬬爜
+ - generic [ref=f11e337]: 1,101
+ - generic [ref=f11e339]: 璧嬬爜
+ - generic [ref=f11e349] [cursor=pointer]:
+ - generic [ref=f11e350]: 鎵樼洏鐮�
+ - generic [ref=f11e351]: "11"
+ - generic [ref=f11e353]: 鎵樼洏
+ - generic [ref=f11e364] [cursor=pointer]:
+ - generic [ref=f11e365]: 閿�鍞嚭搴撳崟
+ - generic [ref=f11e366]: "0"
+ - generic [ref=f11e368]: 鍑哄簱娴侀��
+ - generic [ref=f11e376] [cursor=pointer]:
+ - generic [ref=f11e377]: 绱鎵爜
+ - generic [ref=f11e378]: "23"
+ - generic [ref=f11e380]: 婧簮
+ - generic [ref=f11e387] [cursor=pointer]:
+ - generic [ref=f11e388]: 搴撳瓨棰勮
+ - generic [ref=f11e389]: "0"
+ - generic [ref=f11e391]: 浠撳偍
+ - generic [ref=f11e399] [cursor=pointer]:
+ - generic [ref=f11e400]: 寰呰瘎瀹′笉鍚堟牸
+ - generic [ref=f11e401]: "0"
+ - generic [ref=f11e403]: 璐ㄩ噺
+ - generic [ref=f11e404]:
+ - generic [ref=f11e408]:
+ - generic [ref=f11e409]: 琚嬬爜鐢熸垚瓒嬪娍
+ - generic [ref=f11e411]:
+ - generic [ref=f11e412] [cursor=pointer]:
+ - generic [ref=f11e413]:
+ - radio "杩� 7 澶�" [checked]
+ - generic [ref=f11e414]: 杩� 7 澶�
+ - generic [ref=f11e415] [cursor=pointer]:
+ - generic [ref=f11e416]:
+ - radio "杩� 30 澶�"
+ - generic [ref=f11e417]: 杩� 30 澶�
+ - generic [ref=f11e422]: 娑堣垂鑰呮壂鐮佸湴鍖哄垎甯�
+ - generic [ref=f11e431]:
+ - generic [ref=f11e432]: 鎵规鐘舵�佸垎甯�
+ - generic [ref=f11e441]: 琚嬬爜鐘舵�佸垎甯�
+ - generic [ref=f11e451]:
+ - generic [ref=f11e452]: 寰呭姙涓庨璀�
+ - generic [ref=f11e456]:
+ - generic [ref=f11e461] [cursor=pointer]:
+ - generic [ref=f11e462]: 绐滆揣棰勮
+ - generic [ref=f11e463]: 寰呭鐞嗙殑绐滆揣棰勮
+ - generic [ref=f11e467] [cursor=pointer]:
+ - generic [ref=f11e468]: 搴撳瓨棰勮
+ - generic [ref=f11e469]: 鏈鐞嗙殑搴撳瓨棰勮
+ - generic [ref=f11e474] [cursor=pointer]:
+ - generic [ref=f11e475]: 涓嶅悎鏍煎搧
+ - generic [ref=f11e476]: 寰呰瘎瀹$殑涓嶅悎鏍煎搧鍗�
+ - generic [ref=f11e477]:
+ - generic [ref=f11e478]: 蹇嵎鍏ュ彛
+ - generic [ref=f11e482]:
+ - generic [ref=f11e484]:
+ - generic [ref=f11e485]: 鍩虹鏁版嵁
+ - generic [ref=f11e486]:
+ - generic [ref=f11e487] [cursor=pointer]: 鍝佺绠$悊
+ - generic [ref=f11e493] [cursor=pointer]: 鍝佺鍒嗙被
+ - generic [ref=f11e499] [cursor=pointer]: 璁¢噺鍗曚綅
+ - generic [ref=f11e504]:
+ - generic [ref=f11e505]: 涓�琚嬩竴鐮佺敓浜�
+ - generic [ref=f11e506]:
+ - generic [ref=f11e507] [cursor=pointer]: 浜х嚎缁存姢
+ - generic [ref=f11e511] [cursor=pointer]: 鎵规鐢熶骇
+ - generic [ref=f11e518] [cursor=pointer]: 璧嬬爜绠$悊
+ - generic [ref=f11e522] [cursor=pointer]: 鎵樼洏鐮�
+ - generic [ref=f11e528] [cursor=pointer]: 鎵爜鍏ュ簱
+ - generic [ref=f11e533]:
+ - generic [ref=f11e534]: 鍑哄簱娴侀��
+ - generic [ref=f11e535]:
+ - generic [ref=f11e536] [cursor=pointer]: 鍙戣揣閫氱煡
+ - generic [ref=f11e540] [cursor=pointer]: 閿�鍞嚭搴�
+ - generic [ref=f11e547] [cursor=pointer]: 閿�鍞��璐�
+ - generic [ref=f11e554]:
+ - generic [ref=f11e555]: 闃蹭吉闃茬獪璐�
+ - generic [ref=f11e556]:
+ - generic [ref=f11e557] [cursor=pointer]: 绐滆揣棰勮
+ - generic [ref=f11e561] [cursor=pointer]: 鎵爜鍦扮悊鍒嗗竷
+ - generic [ref=f11e567] [cursor=pointer]: 瀹屾暣鎬ф牎楠�
+ - generic [ref=f11e575]:
+ - generic [ref=f11e576]: 婧簮鍒嗘瀽
+ - generic [ref=f11e577]: 娑堣垂鑰呮壂鐮佺粺璁�
+ - generic [ref=f11e583]:
+ - generic [ref=f11e584]: 浠撳偍鐗╂祦
+ - generic [ref=f11e585]:
+ - generic [ref=f11e586] [cursor=pointer]: 浠撳簱璁剧疆
+ - generic [ref=f11e592] [cursor=pointer]: 搴撳瓨鐜版湁閲�
+ - generic [ref=f11e598] [cursor=pointer]: 搴撳瓨棰勮
+ - generic [ref=f11e601] [cursor=pointer]: 杞Щ璋冩嫧
+ - generic [ref=f11e606]:
+ - generic [ref=f11e607]: 璐ㄩ噺绠$悊
+ - generic [ref=f11e608]:
+ - generic [ref=f11e609] [cursor=pointer]: 鎵规杩芥函
+ - generic [ref=f11e615] [cursor=pointer]: 涓嶅悎鏍煎搧
+ - generic [ref=f11e619] [cursor=pointer]: 绉嶅瓙璐ㄦ
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-08-53-561Z.yml b/.playwright-mcp/page-2026-09-02T06-08-53-561Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-08-53-561Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-11-00-277Z.yml b/.playwright-mcp/page-2026-09-02T06-11-00-277Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-11-00-277Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-14-13-812Z.yml b/.playwright-mcp/page-2026-09-02T06-14-13-812Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-14-13-812Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-14-34-873Z.yml b/.playwright-mcp/page-2026-09-02T06-14-34-873Z.yml
new file mode 100644
index 0000000..63c6e2e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-14-34-873Z.yml
@@ -0,0 +1,190 @@
+- generic [ref=f15e7]:
+ - complementary [ref=f15e9]:
+ - generic [ref=f15e10]:
+ - link [ref=f15e13] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f15e16]
+ - menu [ref=f15e19]:
+ - menuitem [ref=f15e20] [cursor=pointer]
+ - listitem [ref=f15e24]:
+ - generic [ref=f15e25] [cursor=pointer]
+ - listitem [ref=f15e31]:
+ - generic [ref=f15e32] [cursor=pointer]
+ - listitem [ref=f15e36]:
+ - generic [ref=f15e37] [cursor=pointer]
+ - listitem [ref=f15e43]:
+ - generic [ref=f15e44] [cursor=pointer]
+ - listitem [ref=f15e48]:
+ - generic [ref=f15e49] [cursor=pointer]
+ - listitem [ref=f15e53]:
+ - generic [ref=f15e54] [cursor=pointer]
+ - listitem [ref=f15e58]:
+ - generic [ref=f15e59] [cursor=pointer]
+ - listitem [ref=f15e63]:
+ - generic [ref=f15e64] [cursor=pointer]
+ - listitem [ref=f15e68]:
+ - generic [ref=f15e69] [cursor=pointer]
+ - generic [ref=f15e74] [cursor=pointer]
+ - generic [ref=f15e79]:
+ - generic [ref=f15e80]:
+ - banner [ref=f15e81]:
+ - button [ref=f15e82] [cursor=pointer]
+ - button [ref=f15e85] [cursor=pointer]
+ - navigation "breadcrumb" [ref=f15e90]:
+ - list [ref=f15e91]:
+ - listitem [ref=f15e92]:
+ - link "棣栭〉" [disabled] [ref=f15e93]
+ - generic [ref=f15e98]:
+ - generic [ref=f15e100] [cursor=pointer]:
+ - generic [ref=f15e104]: 鎼滅储
+ - generic [ref=f15e105]: Ctrl K
+ - button [ref=f15e107] [cursor=pointer]
+ - button "dark" [ref=f15e112] [cursor=pointer]
+ - button [ref=f15e121] [cursor=pointer]
+ - button [ref=f15e127] [cursor=pointer]
+ - button [ref=f15e130] [cursor=pointer]
+ - button [ref=f15e136] [cursor=pointer]:
+ - button [ref=f15e138]
+ - button "宸ヤ綔鍙�" [ref=f15e142] [cursor=pointer]
+ - button "鐞嗗憳" [ref=f15e146] [cursor=pointer]
+ - generic [ref=f15e153]:
+ - generic [ref=f15e154]: 棣栭〉
+ - generic [ref=f15e173]:
+ - button [ref=f15e174] [cursor=pointer]
+ - generic [ref=f15e181] [cursor=pointer]
+ - generic [ref=f15e185] [cursor=pointer]
+ - main [ref=f15e192]:
+ - generic [ref=f15e196]:
+ - generic [ref=f15e197]:
+ - generic [ref=f15e198]: 涓氬姟鍏ㄩ摼璺�
+ - generic [ref=f15e210]:
+ - generic [ref=f15e217] [cursor=pointer]:
+ - generic [ref=f15e218]: 鍝佺
+ - generic [ref=f15e219]: "1"
+ - generic [ref=f15e227] [cursor=pointer]:
+ - generic [ref=f15e228]: 浜х嚎
+ - generic [ref=f15e229]: "1"
+ - generic [ref=f15e240] [cursor=pointer]:
+ - generic [ref=f15e241]: 鐢熶骇鎵规
+ - generic [ref=f15e242]: "103"
+ - generic [ref=f15e250] [cursor=pointer]:
+ - generic [ref=f15e251]: 琚嬬爜
+ - generic [ref=f15e252]: 1,101
+ - generic [ref=f15e262] [cursor=pointer]:
+ - generic [ref=f15e263]: 鎵樼洏鐮�
+ - generic [ref=f15e264]: "11"
+ - generic [ref=f15e275] [cursor=pointer]:
+ - generic [ref=f15e276]: 閿�鍞嚭搴�
+ - generic [ref=f15e277]: "0"
+ - generic [ref=f15e285] [cursor=pointer]:
+ - generic [ref=f15e286]: 娴侀�氭壂鐮�
+ - generic [ref=f15e287]: "23"
+ - generic [ref=f15e295] [cursor=pointer]:
+ - generic [ref=f15e296]: 闃茬獪/婧簮
+ - generic [ref=f15e297]: "0"
+ - generic [ref=f15e298]:
+ - generic [ref=f15e308] [cursor=pointer]:
+ - generic [ref=f15e309]: 鍝佺鎬绘暟
+ - generic [ref=f15e310]: "1"
+ - generic [ref=f15e311]: 鍩虹鏁版嵁
+ - generic [ref=f15e322] [cursor=pointer]:
+ - generic [ref=f15e323]: 鐢熶骇鎵规
+ - generic [ref=f15e324]: "92"
+ - generic [ref=f15e325]: 涓�琚嬩竴鐮�
+ - generic [ref=f15e333] [cursor=pointer]:
+ - generic [ref=f15e334]: 琚嬬爜
+ - generic [ref=f15e335]: "981"
+ - generic [ref=f15e336]: 璧嬬爜
+ - generic [ref=f15e346] [cursor=pointer]:
+ - generic [ref=f15e347]: 鎵樼洏鐮�
+ - generic [ref=f15e348]: "10"
+ - generic [ref=f15e349]: 鎵樼洏
+ - generic [ref=f15e360] [cursor=pointer]:
+ - generic [ref=f15e361]: 閿�鍞嚭搴撳崟
+ - generic [ref=f15e362]: "0"
+ - generic [ref=f15e363]: 鍑哄簱娴侀��
+ - generic [ref=f15e371] [cursor=pointer]:
+ - generic [ref=f15e372]: 绱鎵爜
+ - generic [ref=f15e373]: "20"
+ - generic [ref=f15e374]: 婧簮
+ - generic [ref=f15e381] [cursor=pointer]:
+ - generic [ref=f15e382]: 搴撳瓨棰勮
+ - generic [ref=f15e383]: "0"
+ - generic [ref=f15e384]: 浠撳偍
+ - generic [ref=f15e392] [cursor=pointer]:
+ - generic [ref=f15e393]: 寰呰瘎瀹′笉鍚堟牸
+ - generic [ref=f15e394]: "0"
+ - generic [ref=f15e395]: 璐ㄩ噺
+ - generic [ref=f15e396]:
+ - generic [ref=f15e400]:
+ - generic [ref=f15e401]: 琚嬬爜鐢熸垚瓒嬪娍
+ - generic [ref=f15e403]:
+ - generic [ref=f15e404] [cursor=pointer]:
+ - generic [ref=f15e405]:
+ - radio "杩� 7 澶�" [checked]
+ - generic [ref=f15e406]: 杩� 7 澶�
+ - generic [ref=f15e407] [cursor=pointer]:
+ - generic [ref=f15e408]:
+ - radio "杩� 30 澶�"
+ - generic [ref=f15e409]: 杩� 30 澶�
+ - generic [ref=f15e414]: 娑堣垂鑰呮壂鐮佸湴鍖哄垎甯�
+ - generic [ref=f15e423]:
+ - generic [ref=f15e424]: 鎵规鐘舵�佸垎甯�
+ - generic [ref=f15e433]: 琚嬬爜鐘舵�佸垎甯�
+ - generic [ref=f15e443]:
+ - generic [ref=f15e444]: 寰呭姙涓庨璀�
+ - generic [ref=f15e448]:
+ - generic [ref=f15e453] [cursor=pointer]:
+ - generic [ref=f15e454]: 绐滆揣棰勮
+ - generic [ref=f15e455]: 寰呭鐞嗙殑绐滆揣棰勮
+ - generic [ref=f15e459] [cursor=pointer]:
+ - generic [ref=f15e460]: 搴撳瓨棰勮
+ - generic [ref=f15e461]: 鏈鐞嗙殑搴撳瓨棰勮
+ - generic [ref=f15e466] [cursor=pointer]:
+ - generic [ref=f15e467]: 涓嶅悎鏍煎搧
+ - generic [ref=f15e468]: 寰呰瘎瀹$殑涓嶅悎鏍煎搧鍗�
+ - generic [ref=f15e469]:
+ - generic [ref=f15e470]: 蹇嵎鍏ュ彛
+ - generic [ref=f15e474]:
+ - generic [ref=f15e476]:
+ - generic [ref=f15e477]: 鍩虹鏁版嵁
+ - generic [ref=f15e478]:
+ - generic [ref=f15e479] [cursor=pointer]: 鍝佺绠$悊
+ - generic [ref=f15e485] [cursor=pointer]: 鍝佺鍒嗙被
+ - generic [ref=f15e491] [cursor=pointer]: 璁¢噺鍗曚綅
+ - generic [ref=f15e496]:
+ - generic [ref=f15e497]: 涓�琚嬩竴鐮佺敓浜�
+ - generic [ref=f15e498]:
+ - generic [ref=f15e499] [cursor=pointer]: 浜х嚎缁存姢
+ - generic [ref=f15e503] [cursor=pointer]: 鎵规鐢熶骇
+ - generic [ref=f15e510] [cursor=pointer]: 璧嬬爜绠$悊
+ - generic [ref=f15e514] [cursor=pointer]: 鎵樼洏鐮�
+ - generic [ref=f15e520] [cursor=pointer]: 鎵爜鍏ュ簱
+ - generic [ref=f15e525]:
+ - generic [ref=f15e526]: 鍑哄簱娴侀��
+ - generic [ref=f15e527]:
+ - generic [ref=f15e528] [cursor=pointer]: 鍙戣揣閫氱煡
+ - generic [ref=f15e532] [cursor=pointer]: 閿�鍞嚭搴�
+ - generic [ref=f15e539] [cursor=pointer]: 閿�鍞��璐�
+ - generic [ref=f15e546]:
+ - generic [ref=f15e547]: 闃蹭吉闃茬獪璐�
+ - generic [ref=f15e548]:
+ - generic [ref=f15e549] [cursor=pointer]: 绐滆揣棰勮
+ - generic [ref=f15e553] [cursor=pointer]: 鎵爜鍦扮悊鍒嗗竷
+ - generic [ref=f15e559] [cursor=pointer]: 瀹屾暣鎬ф牎楠�
+ - generic [ref=f15e567]:
+ - generic [ref=f15e568]: 婧簮鍒嗘瀽
+ - generic [ref=f15e569]: 娑堣垂鑰呮壂鐮佺粺璁�
+ - generic [ref=f15e575]:
+ - generic [ref=f15e576]: 浠撳偍鐗╂祦
+ - generic [ref=f15e577]:
+ - generic [ref=f15e578] [cursor=pointer]: 浠撳簱璁剧疆
+ - generic [ref=f15e584] [cursor=pointer]: 搴撳瓨鐜版湁閲�
+ - generic [ref=f15e590] [cursor=pointer]: 搴撳瓨棰勮
+ - generic [ref=f15e593] [cursor=pointer]: 杞Щ璋冩嫧
+ - generic [ref=f15e598]:
+ - generic [ref=f15e599]: 璐ㄩ噺绠$悊
+ - generic [ref=f15e600]:
+ - generic [ref=f15e601] [cursor=pointer]: 鎵规杩芥函
+ - generic [ref=f15e607] [cursor=pointer]: 涓嶅悎鏍煎搧
+ - generic [ref=f15e611] [cursor=pointer]: 绉嶅瓙璐ㄦ
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-16-10-960Z.yml b/.playwright-mcp/page-2026-09-02T06-16-10-960Z.yml
new file mode 100644
index 0000000..4c7a07d
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-16-10-960Z.yml
@@ -0,0 +1,190 @@
+- generic [ref=f15e7]:
+ - complementary [ref=f15e9]:
+ - generic [ref=f15e10]:
+ - link [ref=f15e13] [cursor=pointer]:
+ - /url: javascript:void 0
+ - img "宸ヤ笟AI鏅洪�犲钩鍙�" [ref=f15e16]
+ - menu [ref=f15e19]:
+ - menuitem [ref=f15e20] [cursor=pointer]
+ - listitem [ref=f15e24]:
+ - generic [ref=f15e25] [cursor=pointer]
+ - listitem [ref=f15e31]:
+ - generic [ref=f15e32] [cursor=pointer]
+ - listitem [ref=f15e36]:
+ - generic [ref=f15e37] [cursor=pointer]
+ - listitem [ref=f15e43]:
+ - generic [ref=f15e44] [cursor=pointer]
+ - listitem [ref=f15e48]:
+ - generic [ref=f15e49] [cursor=pointer]
+ - listitem [ref=f15e53]:
+ - generic [ref=f15e54] [cursor=pointer]
+ - listitem [ref=f15e58]:
+ - generic [ref=f15e59] [cursor=pointer]
+ - listitem [ref=f15e63]:
+ - generic [ref=f15e64] [cursor=pointer]
+ - listitem [ref=f15e68]:
+ - generic [ref=f15e69] [cursor=pointer]
+ - generic [ref=f15e74] [cursor=pointer]
+ - generic [ref=f15e79]:
+ - generic [ref=f15e80]:
+ - banner [ref=f15e81]:
+ - button [ref=f15e82] [cursor=pointer]
+ - button [ref=f15e85] [cursor=pointer]
+ - navigation "breadcrumb" [ref=f15e90]:
+ - list [ref=f15e91]:
+ - listitem [ref=f15e92]:
+ - link "棣栭〉" [disabled] [ref=f15e93]
+ - generic [ref=f15e98]:
+ - generic [ref=f15e100] [cursor=pointer]:
+ - generic [ref=f15e104]: 鎼滅储
+ - generic [ref=f15e105]: Ctrl K
+ - button [ref=f15e107] [cursor=pointer]
+ - button "dark" [ref=f15e112] [cursor=pointer]
+ - button [ref=f15e121] [cursor=pointer]
+ - button [ref=f15e127] [cursor=pointer]
+ - button [ref=f15e130] [cursor=pointer]
+ - button [ref=f15e136] [cursor=pointer]:
+ - button [ref=f15e138]
+ - button "宸ヤ綔鍙�" [ref=f15e142] [cursor=pointer]
+ - button "鐞嗗憳" [ref=f15e146] [cursor=pointer]
+ - generic [ref=f15e153]:
+ - generic [ref=f15e154]: 棣栭〉
+ - generic [ref=f15e173]:
+ - button [ref=f15e174] [cursor=pointer]
+ - generic [ref=f15e181] [cursor=pointer]
+ - generic [ref=f15e185] [cursor=pointer]
+ - main [ref=f15e192]:
+ - generic [ref=f15e196]:
+ - generic [ref=f15e197]:
+ - generic [ref=f15e198]: 涓氬姟鍏ㄩ摼璺�
+ - generic [ref=f15e210]:
+ - generic [ref=f15e217] [cursor=pointer]:
+ - generic [ref=f15e218]: 鍝佺
+ - generic [ref=f15e219]: "1"
+ - generic [ref=f15e227] [cursor=pointer]:
+ - generic [ref=f15e228]: 浜х嚎
+ - generic [ref=f15e229]: "1"
+ - generic [ref=f15e240] [cursor=pointer]:
+ - generic [ref=f15e241]: 鐢熶骇鎵规
+ - generic [ref=f15e242]: "103"
+ - generic [ref=f15e250] [cursor=pointer]:
+ - generic [ref=f15e251]: 琚嬬爜
+ - generic [ref=f15e252]: 1,101
+ - generic [ref=f15e262] [cursor=pointer]:
+ - generic [ref=f15e263]: 鎵樼洏鐮�
+ - generic [ref=f15e264]: "11"
+ - generic [ref=f15e275] [cursor=pointer]:
+ - generic [ref=f15e276]: 閿�鍞嚭搴�
+ - generic [ref=f15e277]: "0"
+ - generic [ref=f15e285] [cursor=pointer]:
+ - generic [ref=f15e286]: 娴侀�氭壂鐮�
+ - generic [ref=f15e287]: "23"
+ - generic [ref=f15e295] [cursor=pointer]:
+ - generic [ref=f15e296]: 闃茬獪/婧簮
+ - generic [ref=f15e297]: "0"
+ - generic [ref=f15e298]:
+ - generic [ref=f15e308] [cursor=pointer]:
+ - generic [ref=f15e309]: 鍝佺鎬绘暟
+ - generic [ref=f15e310]: "1"
+ - generic [ref=f15e311]: 鍩虹鏁版嵁
+ - generic [ref=f15e322] [cursor=pointer]:
+ - generic [ref=f15e323]: 鐢熶骇鎵规
+ - generic [ref=f15e324]: "103"
+ - generic [ref=f15e325]: 涓�琚嬩竴鐮�
+ - generic [ref=f15e333] [cursor=pointer]:
+ - generic [ref=f15e334]: 琚嬬爜
+ - generic [ref=f15e335]: 1,101
+ - generic [ref=f15e336]: 璧嬬爜
+ - generic [ref=f15e346] [cursor=pointer]:
+ - generic [ref=f15e347]: 鎵樼洏鐮�
+ - generic [ref=f15e348]: "11"
+ - generic [ref=f15e349]: 鎵樼洏
+ - generic [ref=f15e360] [cursor=pointer]:
+ - generic [ref=f15e361]: 閿�鍞嚭搴撳崟
+ - generic [ref=f15e362]: "0"
+ - generic [ref=f15e363]: 鍑哄簱娴侀��
+ - generic [ref=f15e371] [cursor=pointer]:
+ - generic [ref=f15e372]: 绱鎵爜
+ - generic [ref=f15e373]: "23"
+ - generic [ref=f15e374]: 婧簮
+ - generic [ref=f15e381] [cursor=pointer]:
+ - generic [ref=f15e382]: 搴撳瓨棰勮
+ - generic [ref=f15e383]: "0"
+ - generic [ref=f15e384]: 浠撳偍
+ - generic [ref=f15e392] [cursor=pointer]:
+ - generic [ref=f15e393]: 寰呰瘎瀹′笉鍚堟牸
+ - generic [ref=f15e394]: "0"
+ - generic [ref=f15e395]: 璐ㄩ噺
+ - generic [ref=f15e396]:
+ - generic [ref=f15e400]:
+ - generic [ref=f15e401]: 琚嬬爜鐢熸垚瓒嬪娍
+ - generic [ref=f15e403]:
+ - generic [ref=f15e404] [cursor=pointer]:
+ - generic [ref=f15e405]:
+ - radio "杩� 7 澶�" [checked]
+ - generic [ref=f15e406]: 杩� 7 澶�
+ - generic [ref=f15e407] [cursor=pointer]:
+ - generic [ref=f15e408]:
+ - radio "杩� 30 澶�"
+ - generic [ref=f15e409]: 杩� 30 澶�
+ - generic [ref=f15e414]: 娑堣垂鑰呮壂鐮佸湴鍖哄垎甯�
+ - generic [ref=f15e423]:
+ - generic [ref=f15e424]: 鎵规鐘舵�佸垎甯�
+ - generic [ref=f15e433]: 琚嬬爜鐘舵�佸垎甯�
+ - generic [ref=f15e443]:
+ - generic [ref=f15e444]: 寰呭姙涓庨璀�
+ - generic [ref=f15e448]:
+ - generic [ref=f15e453] [cursor=pointer]:
+ - generic [ref=f15e454]: 绐滆揣棰勮
+ - generic [ref=f15e455]: 寰呭鐞嗙殑绐滆揣棰勮
+ - generic [ref=f15e459] [cursor=pointer]:
+ - generic [ref=f15e460]: 搴撳瓨棰勮
+ - generic [ref=f15e461]: 鏈鐞嗙殑搴撳瓨棰勮
+ - generic [ref=f15e466] [cursor=pointer]:
+ - generic [ref=f15e467]: 涓嶅悎鏍煎搧
+ - generic [ref=f15e468]: 寰呰瘎瀹$殑涓嶅悎鏍煎搧鍗�
+ - generic [ref=f15e469]:
+ - generic [ref=f15e470]: 蹇嵎鍏ュ彛
+ - generic [ref=f15e474]:
+ - generic [ref=f15e476]:
+ - generic [ref=f15e477]: 鍩虹鏁版嵁
+ - generic [ref=f15e478]:
+ - generic [ref=f15e479] [cursor=pointer]: 鍝佺绠$悊
+ - generic [ref=f15e485] [cursor=pointer]: 鍝佺鍒嗙被
+ - generic [ref=f15e491] [cursor=pointer]: 璁¢噺鍗曚綅
+ - generic [ref=f15e496]:
+ - generic [ref=f15e497]: 涓�琚嬩竴鐮佺敓浜�
+ - generic [ref=f15e498]:
+ - generic [ref=f15e499] [cursor=pointer]: 浜х嚎缁存姢
+ - generic [ref=f15e503] [cursor=pointer]: 鎵规鐢熶骇
+ - generic [ref=f15e510] [cursor=pointer]: 璧嬬爜绠$悊
+ - generic [ref=f15e514] [cursor=pointer]: 鎵樼洏鐮�
+ - generic [ref=f15e520] [cursor=pointer]: 鎵爜鍏ュ簱
+ - generic [ref=f15e525]:
+ - generic [ref=f15e526]: 鍑哄簱娴侀��
+ - generic [ref=f15e527]:
+ - generic [ref=f15e528] [cursor=pointer]: 鍙戣揣閫氱煡
+ - generic [ref=f15e532] [cursor=pointer]: 閿�鍞嚭搴�
+ - generic [ref=f15e539] [cursor=pointer]: 閿�鍞��璐�
+ - generic [ref=f15e546]:
+ - generic [ref=f15e547]: 闃蹭吉闃茬獪璐�
+ - generic [ref=f15e548]:
+ - generic [ref=f15e549] [cursor=pointer]: 绐滆揣棰勮
+ - generic [ref=f15e553] [cursor=pointer]: 鎵爜鍦扮悊鍒嗗竷
+ - generic [ref=f15e559] [cursor=pointer]: 瀹屾暣鎬ф牎楠�
+ - generic [ref=f15e567]:
+ - generic [ref=f15e568]: 婧簮鍒嗘瀽
+ - generic [ref=f15e569]: 娑堣垂鑰呮壂鐮佺粺璁�
+ - generic [ref=f15e575]:
+ - generic [ref=f15e576]: 浠撳偍鐗╂祦
+ - generic [ref=f15e577]:
+ - generic [ref=f15e578] [cursor=pointer]: 浠撳簱璁剧疆
+ - generic [ref=f15e584] [cursor=pointer]: 搴撳瓨鐜版湁閲�
+ - generic [ref=f15e590] [cursor=pointer]: 搴撳瓨棰勮
+ - generic [ref=f15e593] [cursor=pointer]: 杞Щ璋冩嫧
+ - generic [ref=f15e598]:
+ - generic [ref=f15e599]: 璐ㄩ噺绠$悊
+ - generic [ref=f15e600]:
+ - generic [ref=f15e601] [cursor=pointer]: 鎵规杩芥函
+ - generic [ref=f15e607] [cursor=pointer]: 涓嶅悎鏍煎搧
+ - generic [ref=f15e611] [cursor=pointer]: 绉嶅瓙璐ㄦ
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-09-02T06-16-32-193Z.yml b/.playwright-mcp/page-2026-09-02T06-16-32-193Z.yml
new file mode 100644
index 0000000..6adf37e
--- /dev/null
+++ b/.playwright-mcp/page-2026-09-02T06-16-32-193Z.yml
@@ -0,0 +1 @@
+- generic [active]: 宸ヤ笟AI鏅洪�犲钩鍙�
\ No newline at end of file
diff --git a/docs/bagcode_home_dashboard_integration.md b/docs/bagcode_home_dashboard_integration.md
new file mode 100644
index 0000000..bb11421
--- /dev/null
+++ b/docs/bagcode_home_dashboard_integration.md
@@ -0,0 +1,83 @@
+# 涓�琚嬩竴鐮侀椤垫敼鐗�(鍏ㄩ摼璺┚椹惰埍) 鈥� 鍓嶇鑱旇皟鏂规
+
+## 鑳屾櫙
+
+灏� `/bagcode-home` 棣栭〉浠�"鍩虹鏁版嵁 + 涓�琚嬩竴鐮佺敓浜�"鐨勫眬閮ㄧ粺璁¢〉,閲嶆瀯涓鸿鐩�**瀹屾暣浠峰�奸摼**鐨勯┚椹惰埍:鍝佺 鈫� 浜х嚎/鎵规 鈫� 琚嬬爜/鎵樼洏 鈫� 閿�鍞嚭搴� 鈫� 娴侀�氭壂鐮� 鈫� 闃茬獪婧簮,骞朵覆鑱斾粨鍌ㄥ簱瀛樸�佽川閲忛璀︺�佸揩鎹峰叆鍙c�傛暣浣撹瑙夊榻愮櫥褰曢〉鐨�**鍐滀笟缈犵豢鐜荤拑**椋庢牸銆�
+
+## 娑夊強椤甸潰
+
+- 棣栭〉(椹鹃┒鑸�):`src/views/dashboard/bagCodeHome/index.vue` 鈥斺�� 鍏ㄩ摼璺噸鏋�
+- 鍏宠仈璺宠浆椤甸潰:鍩虹鏁版嵁銆佷竴琚嬩竴鐮佺敓浜с�佸嚭搴撴祦閫氥�侀槻浼槻绐滆揣銆佹函婧愬垎鏋愩�佷粨鍌ㄧ墿娴併�佽川閲忕鐞� 涓嬬殑鍚勪笟鍔¢〉
+
+## 鎺ュ彛鍙樻洿
+
+### 1. 鎵╁睍姹囨�绘帴鍙�(杩斿洖鏂板瀛楁)
+
+`GET /mes/bag-code-home-statistics/summary`
+
+鏂板鍝嶅簲瀛楁(鍧� `Long`,鏃犻粯璁ゅ�兼椂杩斿洖 0):
+
+| 瀛楁 | 璇存槑 | 鏁版嵁鏉ユ簮琛� |
+|------|------|-----------|
+| `salesNoticeCount` | 鍙戣揣閫氱煡鍗曟暟 | `mes_wm_sales_notice` |
+| `productSalesCount` | 閿�鍞嚭搴撳崟鏁� | `mes_wm_product_sales` |
+| `returnSalesCount` | 閿�鍞��璐у崟鏁� | `mes_wm_return_sales` |
+| `stockWarningPendingCount` | 鏈鐞嗗簱瀛橀璀︽暟(`status=10`) | `mes_wm_stock_warning` |
+| `ncrPendingCount` | 寰呰瘎瀹′笉鍚堟牸鍝佸崟鏁�(`status=0`) | `mes_qc_ncr` |
+
+鍘熸湁瀛楁(`mdmItemCount/mesItemCount/itemTypeCount/unitMeasureCount/lineCount/batchCount/bagCodeCount/palletCount/batchStatusList/bagCodeStatusList`)淇濇寔涓嶅彉銆�
+
+### 2. 澶嶇敤宸叉湁缁熻鎺ュ彛(鏃犻渶鏀瑰姩)
+
+| 鎺ュ彛 | 鐢ㄩ�� | 鍓嶇 API |
+|------|------|---------|
+| `GET /mes/trace-cross-region/summary` | 绐滆揣棰勮姹囨��(`total/pending/handled/falseAlarm/crossProvince/crossCity`) | `api/mes/trace-cross-region`(鏂板) |
+| `GET /mes/trace-consumer-scan/summary` | 绱鎵爜/鎴愬姛/澶辫触/娑夊強鎵规 | 宸叉湁 |
+| `GET /mes/trace-consumer-scan/distribution?groupBy=province` | 娑堣垂鑰呮壂鐮佸湴鍖哄垎甯� | 宸叉湁 |
+
+## 鍓嶇淇敼鐐�
+
+### 1. 棣栭〉缁撴瀯(index.vue)
+
+| 鍖哄潡 | 缁勪欢 | 鏁版嵁 |
+|------|------|------|
+| 涓氬姟鍏ㄩ摼璺� | `modules/business-flow.vue` | summary + 鎵爜鎬绘暟 + 绐滆揣鎬绘暟 |
+| 鍏ㄩ摼璺� KPI 鎬昏(8 鍗�) | `modules/kpi-cards.vue` | summary + 鎵爜鎬绘暟 |
+| 琚嬬爜鐢熸垚瓒嬪娍 | `modules/trend-chart.vue`(澶嶇敤) | `summary/trend` |
+| 娑堣垂鑰呮壂鐮佸湴鍖哄垎甯� | `modules/scan-region-chart.vue`(鏂板) | `distribution/groupBy=province` |
+| 鎵规鐘舵�佸垎甯� / 琚嬬爜鐘舵�佸垎甯� | `batch-status-chart.vue` / `bag-code-status-chart.vue`(澶嶇敤) | summary 鐘舵�佸垪琛� |
+| 寰呭姙涓庨璀� | `modules/alert-panel.vue`(鏂板) | summary + 绐滆揣姹囨�� |
+| 鍒嗙粍蹇嵎鍏ュ彛 | `modules/shortcuts.vue`(閲嶅啓涓哄垎缁�) | 闈欐�佽矾鐢遍厤缃� |
+
+### 2. 鏂板/鍒犻櫎鏂囦欢
+
+- 鏂板:`api/mes/trace-cross-region/index.ts`
+- 鏂板:棣栭〉 `modules/business-flow.vue`銆乣kpi-cards.vue`銆乣scan-region-chart.vue`銆乣alert-panel.vue`
+- 閲嶅啓:棣栭〉 `index.vue`銆乣modules/shortcuts.vue`
+- 鏇存柊:`api/mes/bag-code-home/index.ts`(Summary 鍔� 5 瀛楁)銆乣data.ts`銆乣chart-options.ts`
+- 鍒犻櫎:`modules/basic-cards.vue`銆乣modules/bag-code-cards.vue`(涓嶅啀浣跨敤)
+
+### 3. 鏍峰紡涓婚
+
+- 棣栭〉鍐呭鍖虹粺涓�"鍐滀笟缈犵豢鐜荤拑"涓婚:娴呰壊缈犵豢娓愬彉鑳屾櫙(鏃犺儗鏅浘)銆佺櫧鑹茬(鐮傜幓鐠冨崱鐗囥�佽杽鑽风櫧/澧ㄧ豢鏂囧瓧銆�
+- 鍥捐〃缁熶竴缈犵豢涓昏壊(`#10b981`)骞堕�傞厤娴呭簳鏂囧瓧鑹层��
+- 涓婚鏍峰紡闆嗕腑鍦� `index.vue` 鐨勯潪 scoped `<style>` 涓�(`.agri-dashboard` 瀹瑰櫒涓轰綔鐢ㄥ煙),鍚勫崱鐗囩粍浠朵娇鐢ㄥ搴旂幓鐠冪被銆�
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 鍝佺鎬绘暟 | KPI + 涓氬姟閾捐矾 | 鐐规寜璺宠浆 `MdmItem` |
+| 鐢熶骇鎵规 | KPI + 涓氬姟閾捐矾 | 璺宠浆 `MesProBatch` |
+| 琚嬬爜 / 鎵樼洏鐮� | KPI + 涓氬姟閾捐矾 | 璺宠浆 `MesProBagCode` / `MesProPallet` |
+| 閿�鍞嚭搴撳崟鏁� | KPI + 涓氬姟閾捐矾 | 璺宠浆 `MesWmProductSales` |
+| 绱鎵爜 | KPI + 涓氬姟閾捐矾 | 鏉ヨ嚜 `trace-consumer-scan/summary`,璺宠浆 `MesConsumerScanStatistics` |
+| 绐滆揣棰勮鎬绘暟 | 涓氬姟閾捐矾(闃茬獪/婧簮) | 鏉ヨ嚜 `trace-cross-region/summary`,璺宠浆 `MesTraceCrossRegion` |
+| 搴撳瓨棰勮(鏈鐞�) | KPI + 寰呭姙棰勮 | 璺宠浆 `MesWmStockWarning` |
+| 寰呰瘎瀹′笉鍚堟牸 | KPI + 寰呭姙棰勮 | 璺宠浆 `MesQcNcr` |
+
+## 娉ㄦ剰浜嬮」
+
+- 鏂板鐨� 5 涓眹鎬诲瓧娈甸渶瑕�**鍚庣閲嶆柊缂栬瘧骞堕噸鍚�**鍚庢墠浼氳繑鍥�;閲嶅惎鍓嶅墠绔凡鍋� `?? 0` 鍏滃簳,鐩稿叧鍗$墖/鑺傜偣鏄剧ず 0,涓嶅奖鍝嶅叾瀹冩暟鎹��
+- 璺敱璺宠浆浣跨敤**璺敱 name**(宸蹭笌鑿滃崟 `component_name` 瀵归綈),鏈姞杞界殑鑿滃崟娌跨敤 `message.warning('褰撳墠鑿滃崟灏氭湭鍔犺浇...')` 鍏滃簳銆�
+- 娑堣垂鑰呮壂鐮�/绐滆揣鏃犵粡绾害瀛楁,浠呮敮鎸佺渷/甯傛枃鏈垎甯冨浘,涓嶆敮鎸佸湴鍥惧潗鏍囥��
diff --git a/docs/batch_trace_refactor_integration.md b/docs/batch_trace_refactor_integration.md
new file mode 100644
index 0000000..85f11b5
--- /dev/null
+++ b/docs/batch_trace_refactor_integration.md
@@ -0,0 +1,102 @@
+# 鎵规杩芥函缁熶竴鑱氬悎鎺ュ彛 - 鍓嶇鑱旇皟鏂规
+
+## 娑夊強椤甸潰
+
+- MES 鈫� 璐ㄦ 鈫� 鎵规杩芥函锛坄/qc/batch-trace`锛�
+- 鎵规杩芥函璇︽儏
+- 鎵规鐮併�佹墭鐩樼爜銆佽鐮佹壂鐮佽拷婧叆鍙�
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+1. 鍦ㄦ壒娆¤拷婧垪琛ㄨ緭鍏ョ敓浜ф壒娆$爜銆佷复鏃舵壒娆$爜銆佽鐮佹垨鎵樼洏鐮併��
+2. 椤甸潰璋冪敤缁熶竴璇︽儏鎺ュ彛锛屽悗绔皢鍏ュ彛鐮佽В鏋愬埌鐢熶骇鎵规锛屽苟鑱氬悎鐢熶骇銆佽川妫�銆佷粨鍌ㄣ�侀攢鍞拰闃蹭吉淇℃伅銆�
+3. 璇︽儏椤典互鐢熶骇鎵规涓烘牴灞曠ず鍏ㄩ摼璺暟鎹紱琚嬬爜鍜屾墭鐩樹俊鎭潵鑷敓浜ц祴鐮佹暟鎹紝浠撳偍涓庨攢鍞俊鎭潵鑷粨鍌ㄤ笟鍔℃暟鎹��
+4. 鍓嶅悜杩芥函灞曠ず褰撳墠鎵规浜у嚭鐨勪笅娓告壒娆★紱鍚庡悜杩芥函灞曠ず褰撳墠鎵规娑堣�楃殑涓婃父鎵规銆�
+5. 鏃堕棿绾裤�侀樁娈佃鍥惧拰鍐崇瓥鎽樿鍧囦娇鐢ㄥ悓涓�娆¤仛鍚堝搷搴旓紝閬垮厤鎵撳紑璇︽儏鍚庨噸澶嶈姹傚涓棫鎺ュ彛銆�
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|---|---|---|
+| GET | `/mes/trace/batch/detail` | 鏌ヨ缁熶竴鎵规杩芥函璇︽儏 |
+
+### 璇锋眰鍙傛暟
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `code` | String | 鏄� | 鐢熶骇鎵规鐮併�佷复鏃舵壒娆$爜銆佽鐮佹垨鎵樼洏鐮� |
+
+绀轰緥锛歚code=BAG-202608280001`
+
+### 鍝嶅簲涓昏瀛楁
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `sourceType` | String | 鍏ュ彛绫诲瀷锛歚BAG`銆乣PALLET`銆乣BATCH` |
+| `requestCode` | String | 鍘熷杈撳叆鐮� |
+| `itemCode` / `itemName` | String | 鍝佺缂栫爜銆佸悕绉� |
+| `itemSpecification` | String | 鍝佺瑙勬牸 |
+| `batchCode` / `tempCode` | String | 姝e紡鎵规鍙枫�佷复鏃舵壒娆$爜 |
+| `batchStatusName` | String | 鎵规鐘舵�佸悕绉� |
+| `produceDate` | DateTime | 鐢熶骇鏃ユ湡 |
+| `lineCode` / `lineName` | String | 浜х嚎缂栫爜銆佸悕绉� |
+| `ownerUserName` | String | 鐢熶骇璐d换浜� |
+| `planQuantity` | Decimal | 璁″垝鏁伴噺 |
+| `bagQuantity` / `palletQuantity` | Integer | 琚嬬爜鏁伴噺銆佹墭鐩樻暟閲� |
+| `workers` | Array | 鐢熶骇浜哄憳 |
+| `pallets` | Array | 鎵樼洏鎽樿 |
+| `bagTotal` / `bags` | Long / Array | 琚嬬爜鎬绘暟鍙婃渶澶� 100 鏉℃槑缁� |
+| `inbound` | Object | 鏈�鏂板叆搴撲簨浠� |
+| `quality` | Object | 绉嶅瓙璐ㄩ噺妫�楠屼笌鎸囨爣 |
+| `antiFake` | Object | 褰撳墠杩芥函鐮佹壂鐮佹鏁般�侀娆″拰鏈�杩戞壂鐮佹椂闂� |
+| `purchaseSources` | Array | 閲囪喘鏉ユ簮銆佷緵搴斿晢鍜� IQC 淇℃伅 |
+| `salesTargets` | Array | 閿�鍞嚭搴撱�佸鎴峰拰 OQC 淇℃伅 |
+| `processTraces` | Array | 宸ュ簭鎶曞叆銆佷骇鍑烘祦杞俊鎭� |
+
+### 鍝嶅簲绀轰緥
+
+```json
+{
+ "code": 0,
+ "data": {
+ "sourceType": "BAG",
+ "requestCode": "BAG-202608280001",
+ "batchCode": "B20260828001",
+ "itemName": "绀轰緥鍝佺",
+ "batchStatusName": "宸插畬鎴�",
+ "workers": [],
+ "pallets": [],
+ "bags": [],
+ "purchaseSources": [],
+ "salesTargets": [],
+ "processTraces": []
+ }
+}
+```
+
+## 椤甸潰灞曠ず瑙勫垯
+
+| 瑙嗗浘 | 灞曠ず鍐呭 |
+|---|---|
+| 闃舵鎬昏 | 鏉ユ簮銆佺敓浜с�佽川妫�銆佽祴鐮併�佸叆搴撱�侀攢鍞�佹秷璐广�侀槻浼叓涓樁娈电殑鐘舵�佸拰鏁伴噺 |
+| 鍏ㄩ摼璺椂闂寸嚎 | 鎸夋椂闂村睍绀洪噰璐�佺敓浜с�佽川妫�銆佽祴鐮併�佸叆搴撱�佸嚭搴撳拰鎵爜浜嬩欢锛涘紓甯哥姸鎬佷紭鍏堥珮浜� |
+| 娴佸姩鍥捐氨 | 浠ユ壒娆°�佸伐搴忋�佷粨搴撱�佹墭鐩樸�佽鐮併�侀攢鍞崟鍜屽鎴蜂负鑺傜偣锛涢粯璁ゅ睍绀烘壒娆$骇鍏崇郴 |
+| 鍐崇瓥鍒嗘瀽 | 灞曠ず璐ㄩ噺缁撹銆佸簱瀛樻暟閲忋�侀攢鍞幓鍚戙�侀槻浼壂鐮佹鏁板拰绐滆揣椋庨櫓 |
+| 閲囪喘鏉ユ簮 | 灞曠ず閲囪喘鍏ュ簱銆佷緵搴斿晢銆侀噰璐鍗曘�両QC 鍗曞彿鍙婃楠岀粨璁� |
+| 閿�鍞幓鍚� | 灞曠ず閿�鍞嚭搴撱�佸鎴枫�侀攢鍞鍗曘�丱QC 鍗曞彿鍙婅川閲忕姸鎬� |
+| 宸ュ簭娴佽浆 | `IN` 鏄剧ず涓烘姇鍏ワ紝`OUT` 鏄剧ず涓轰骇鍑� |
+
+## 涓氬姟瑙勫垯
+
+- 杈撳叆琚嬬爜鎴栨墭鐩樼爜鏃讹紝璇︽儏浠嶄互鍏舵墍灞炵敓浜ф壒娆′负鏍硅繘琛岃仛鍚堛��
+- 褰撳墠鎺ュ彛杩斿洖鐨勮鐮佹槑缁嗘渶澶� 100 鏉★紝`bagTotal` 鐢ㄤ簬灞曠ず瀹屾暣鏁伴噺锛涘ぇ鎵规涓嶅緱鎸夋槑缁嗘暟閲忓垽鏂�婚噺銆�
+- 绌烘暟缁勮〃绀鸿涓氬姟闃舵鏆傛棤璁板綍锛沗quality`銆乣inbound`銆乣antiFake` 涓虹┖琛ㄧず鏆傛棤瀵瑰簲淇℃伅銆�
+- 闃蹭吉鎵爜缁熻浠呯敤浜庡睍绀猴紝涓嶈兘鏇夸唬璐ㄩ噺妫�楠岀粨璁烘垨鍑哄簱鐘舵�併��
+- 瀹㈡埛銆佷緵搴斿晢銆佹搷浣滀汉绛夊悕绉板簲浠ユ帴鍙h繑鍥炲�间负鍑嗭紝涓嶅湪鍓嶇閲嶅鏌ヨ鏃ф壒娆℃帴鍙c��
+
+## 娉ㄦ剰浜嬮」
+
+- 绠$悊绔帴鍙i渶瑕佹壒娆¤拷婧煡璇㈡潈闄愶細`mes:trace-batch:query`銆�
+- 鏃х殑 `/mes/wm/batch/*` 鎺ュ彛缁х画渚涗粨鍌ㄦ壒娆¢〉闈娇鐢紝鎵规杩芥函椤甸潰鍒囨崲鍚庝笉搴斿啀骞惰璇锋眰鏃х殑浜斾釜璇︽儏鎺ュ彛銆�
+- 鍚庣画鎵╁睍鏃堕棿绾垮拰鍥捐氨鏃讹紝寤鸿鍚庣澧炲姞鍒嗛〉涓庤妭鐐瑰眰绾у弬鏁帮紝閬垮厤涓�娆℃�у姞杞藉叏閮ㄨ鐮併��
+- 灞曠ず娑堣垂鑰呮壂鐮佷俊鎭椂涓嶅緱灞曠ず IP 鍦板潃鍜� User-Agent 鍘熸枃銆�
\ No newline at end of file
diff --git a/docs/mes_wm_material_stock_bag_api.md b/docs/mes_wm_material_stock_bag_api.md
new file mode 100644
index 0000000..bbda426
--- /dev/null
+++ b/docs/mes_wm_material_stock_bag_api.md
@@ -0,0 +1,69 @@
+# 搴撳瓨琚嬬爜鏄庣粏鑱旇皟鏂规
+
+## 涓氬姟娴佺▼
+
+绉嶅瓙璐ㄦ浠ヨ鐮佹彁浜ゃ�傝川妫�鍚堟牸鏃讹紝鏆傚瓨搴撳瓨姹囨�绘暟閲忓噺灏� 1锛屽悎鏍煎簱瀛樻眹鎬绘暟閲忓鍔� 1锛屽悓鏃惰琚嬬爜鏄庣粏杩佺Щ鍒板悎鏍间粨锛涜川妫�涓嶅悎鏍兼椂锛屾殏瀛樺簱瀛樻眹鎬绘暟閲忓噺灏� 1锛岃鐮佹槑缁嗘爣璁颁负鎶ュ簾銆傚叾浠栬鐮佷笉鍙楀奖鍝嶃��
+
+搴撳瓨鍙拌处缁х画鎸夌墿鏂欍�佹壒娆°�佷粨搴撱�佸簱鍖恒�佸簱浣嶅拰渚涘簲鍟嗘眹鎬伙紱琚嬬爜鏄庣粏鐢ㄤ簬璁板綍姣忎釜琚嬬爜鐨勫叿浣撶姸鎬佸拰浣嶇疆銆�
+
+## 琚嬬爜鏄庣粏鐢熷懡鍛ㄦ湡锛堢粺涓�鏈嶅姟鎵樼锛�
+
+鎵�鏈夊甫琚嬬爜鐨勫簱瀛樺彉鍔ㄧ粺涓�閫氳繃搴撳瓨浜嬪姟鏈嶅姟鍦ㄥ悓涓�浜嬪姟鍐呭悓姝ョ淮鎶� **姹囨�诲簱瀛� + 琚嬬爜鏄庣粏 + 搴撳瓨娴佹按** 涓夎�呬竴鑷达紝鍚勪笟鍔″叆鍙f棤闇�鍚勮嚜瀹炵幇琚嬬爜閫昏緫銆傜敓鍛藉懆鏈燂細
+
+| 闃舵 | 鍔ㄤ綔 | 琚嬬爜鏄庣粏鍙樺寲 |
+|------|------|--------------|
+| 鍗曡鎵爜鍏ュ簱 | 鐢熶骇鎵爜鍏ュ簱锛堟壂鐮佺被鍨� BAG锛� | 寤虹珛娲诲姩鏄庣粏锛堟殏瀛樺簱锛� |
+| 绉嶅瓙璐ㄦ鍚堟牸 | 鏆傚瓨鍑哄簱 + 鍚堟牸鍏ュ簱 | 鏄庣粏鐢辨殏瀛樺簱杩佺Щ鍒板悎鏍煎簱 |
+| 绉嶅瓙璐ㄦ涓嶅悎鏍� | 鏆傚瓨鍑哄簱 | 鏄庣粏鎶ュ簾 |
+| 閿�鍞嚭搴撳畬鎴� | 鍑哄簱鎵e噺 | 鏄庣粏缃负宸插嚭搴� |
+| 鏁翠綅绉诲簱 | 璋冩嫧绉诲嚭 + 绉诲叆 | 鏄庣粏浣嶇疆杩佺Щ鍒扮洰鏍囧簱浣� |
+
+璇存槑锛�
+- 鎵樼洏锛圥ALLET锛�/鎵规锛圔ATCH锛夋暣鎵瑰叆搴撱�侀噰璐�/鏉傞」/閫�璐х瓑鎸夎鎸夋暟閲忓叆搴撶殑鍑哄叆鍙o紝涓烘壒閲忔眹鎬伙紝涓嶉�愯寤虹珛鏄庣粏锛涜繖浜涜鐮佸湪棣栨绉嶅瓙璐ㄦ鏃堕�氳繃鎸夋壒娆″畾浣嶆殏瀛樺簱瀛樿ˉ寤烘槑缁嗐��
+- 浜嬪姟娴佹按 DTO 澧炲姞 `bagCodeId`/`bagCode` 瀛楁锛涘嚭搴�/绉诲叆鎸夎鐮佽嚜鍔ㄦ洿鏂拌鐮佹槑缁嗐��
+- 姣忕瑪甯﹁鐮佺殑鍏ュ簱銆佸嚭搴撱�佺Щ搴撱�佽川妫�閮戒細鐢熸垚瀵瑰簲鐨� `mes_wm_transaction` 娴佹按骞跺洖濉鐮侊紝渚夸簬鍦ㄥ簱瀛樻祦姘撮〉闈㈡寜琚嬬爜绛涢�夎拷婧��
+
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | `/mes/wm/material-stock/page` | 搴撳瓨姹囨�诲垎椤碉紝鍝嶅簲澧炲姞琚嬬爜缁熻瀛楁 |
+| GET | `/mes/wm/material-stock/bag-details` | 鏌ヨ鎸囧畾搴撳瓨姹囨�昏褰曚笅鐨勫湪搴撹鐮佹槑缁� |
+| GET | `/mes/wm/transaction/page` | 搴撳瓨浜嬪姟娴佹按锛屾敮鎸� `bagCode` 绛涢�夊苟杩斿洖琚嬬爜 |
+
+### 琚嬬爜鏄庣粏鏌ヨ
+
+璇锋眰鍙傛暟锛�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| materialStockId | Long | 鏄� | 搴撳瓨姹囨�昏褰� ID |
+| bagCode | String | 鍚� | 琚嬬爜妯$硦鏌ヨ |
+| pageNo | Integer | 鏄� | 椤电爜 |
+| pageSize | Integer | 鏄� | 姣忛〉鏉℃暟 |
+
+鍝嶅簲瀛楁鍖呮嫭 `bagCode`銆乣batchCode`銆乣stockState`銆乣status`銆乣quantity`銆乣warehouseId`銆乣locationId`銆乣areaId`銆乣inboundTime` 鍜� `outboundTime`銆�
+
+搴撳瓨姹囨�诲垎椤靛搷搴旀柊澧烇細
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| bagCount | Long | 褰撳墠鍦ㄥ簱琚嬬爜鏄庣粏鏁伴噺 |
+| bagDetailSupported | Boolean | 鏄惁瀛樺湪琚嬬爜鏄庣粏锛涘巻鍙叉棤娉曡繕鍘熻鐮佺殑搴撳瓨涓� false |
+
+## 鍓嶇璋冪敤鏃跺簭
+
+1. 璋冪敤搴撳瓨鍙拌处鍒嗛〉鎺ュ彛鑾峰彇姹囨�昏褰曘��
+2. 瀵� `bagDetailSupported=true` 鐨勮褰曟樉绀衡�滄煡鐪嬭鐮佲�濄��
+3. 鐐瑰嚮鍚庤皟鐢� `/mes/wm/material-stock/bag-details`锛屼紶鍏ュ綋鍓嶈 `id` 浣滀负 `materialStockId`銆�
+4. 琚嬬爜鏄庣粏涓殑 `bagCode` 鍙户缁皟鐢ㄦ壒娆�/琚嬬爜杩芥函鎺ュ彛鏌ョ湅璐ㄦ鍜岀敓浜т俊鎭��
+5. 搴撳瓨娴佹按椤甸潰浣跨敤 `bagCode` 绛涢�夋椂锛屽睍绀鸿川妫�杩佺Щ浜х敓鐨勮鐮佺骇娴佹按銆�
+
+## 涓氬姟瑙勫垯
+
+- 鍚屼竴琚嬬爜鍙兘瀛樺湪涓�鏉″簱瀛樿鐮佹槑缁嗐��
+- 璐ㄦ鎸夊疄闄呰鐮佸畾浣嶆殏瀛樺簱瀛橈紝涓嶆寜鎵规闅忔満鎵e噺銆�
+- 鎶ュ簾琚嬬爜涓嶈鍏ュ湪搴撴槑缁嗘煡璇紝浣嗕繚鐣欐槑缁嗚褰曠敤浜庤拷婧��
+- 鏃犳硶浠庡巻鍙叉眹鎬诲簱瀛樿繕鍘熻鐮佹椂锛屼笉浼�犺鐮佹槑缁嗐��
+- SQL 鑴氭湰涓嶅寘鍚� `tenant_id` 瀛楁銆�
diff --git a/docs/sales_notice_to_product_sales.md b/docs/sales_notice_to_product_sales.md
index ff668cf..1eca419 100644
--- a/docs/sales_notice_to_product_sales.md
+++ b/docs/sales_notice_to_product_sales.md
@@ -101,6 +101,20 @@
**娉ㄦ剰锛�** 鎷h揣鏄庣粏闇�瑕佹墜鍔ㄦ坊鍔�
+## 鍙戣揣閫氱煡琛岀墿鏂欐牎楠�
+
+鏂板鎴栦慨鏀瑰彂璐ч�氱煡琛屾椂锛岀墿鏂欏繀椤诲叧鑱旀壒娆★紝涓旇鐗╂枡鎵规蹇呴』瀛樺湪姝e紡搴撳簱瀛樸�傛寮忓簱鎸囧簱瀛樼姸鎬佷负鍚堟牸搴擄紙`stockState = 20`锛夌殑搴撳瓨璁板綍銆�
+
+| 鏍¢獙椤� | 瑙勫垯 |
+|--------|------|
+| 鐗╂枡 | 蹇呴』瀛樺湪涓斿惎鐢� |
+| 鎵规 | `batchId` 鎴� `batchCode` 蹇呴』鑳藉尮閰嶆湁鏁堟壒娆★紝涓旀壒娆″睘浜庢墍閫夌墿鏂� |
+| 姝e紡搴撳瓨 | 浠呯粺璁″悎鏍煎簱搴撳瓨锛屼笉缁熻鏆傚瓨搴撳簱瀛� |
+| 鏁伴噺 | 鍚屼竴鐗╂枡銆佹壒娆$殑鍚堟牸搴撳簱瀛樺悎璁″繀椤讳笉灏戜簬鍙戣揣鏁伴噺 |
+| 搴撳瓨鍙樻洿 | 淇濆瓨鍙戣揣閫氱煡琛屾椂涓嶆墸鍑忋�佷笉棰勫崰搴撳瓨锛屽疄闄呭嚭搴撴椂鍐嶆鏍¢獙 |
+
+搴撳瓨涓嶈冻鏃讹紝鍓嶇搴旂洿鎺ュ睍绀哄悗绔繑鍥炵殑鈥滃簱瀛樻暟閲忎笉瓒斥�濅笟鍔℃彁绀猴紝骞朵繚鐣欑敤鎴峰~鍐欑殑琛ㄥ崟鍐呭銆�
+
## 瀛楁鏄犲皠琛�
### 涓昏〃瀛楁鏄犲皠
diff --git a/docs/scan_in_multi_type_inbound.md b/docs/scan_in_multi_type_inbound.md
new file mode 100644
index 0000000..283635c
--- /dev/null
+++ b/docs/scan_in_multi_type_inbound.md
@@ -0,0 +1,80 @@
+# 鐢熶骇绾挎壂鐮佸叆搴擄細鏀寔琚嬬爜/鎵樼洏鐮�/鎵规鐮� + 鍘绘帀璁惧缂栫爜 - 鍓嶇鑱旇皟鏂规
+
+## 娑夊強椤甸潰
+
+- 鐢熶骇绾挎壂鐮佸叆搴擄紙`src/views/mes/pro/scan-in/index.vue`锛�
+
+## 涓氬姟鍙樻洿
+
+1. **鍘绘帀璁惧缂栫爜**锛氭壂鐮佸叆搴撲笉鍐嶅綍鍏�/灞曠ず璁惧缂栫爜锛屾帴鍙� `deviceCode` 鏀逛负闈炲繀濉紝鍓嶇涓嶅啀浼犮��
+2. **浜х嚎銆佸簱鍖恒�佸簱浣嶆敼涓轰笅鎷夐�夋嫨**锛氭暟鎹簮涓虹幇鏈夌簿绠�鍒楄〃鎺ュ彛锛屼笉鍐嶆墜濉紪鍙枫��
+3. **绛夊緟鎵爜鍖哄鍔�"鎵爜绫诲瀷"閫夋嫨**锛氳鐮� / 鎵樼洏鐮� / 鎵规鐮佷笁閫変竴锛屾壂鐮佹闅忕被鍨嬫彁浜ゅ搴旂爜鍊笺��
+
+## API
+
+### 涓绘帴鍙o細杩芥函鐮佹壂鐮佸叆搴�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | /mes/pro/scan-in/inbound | 杩芥函鐮佹壂鐮佸叆搴擄紙琚嬬爜/鎵樼洏鐮�/鎵规鐮侊級 |
+
+**璇锋眰鍙傛暟锛堟湰娆″彉鏇达級锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 鍙樻洿 | 璇存槑 |
+|------|------|------|------|------|
+| scanType | String | 鍚� | 鏂板 | 鎵爜绫诲瀷锛歚BAG` 琚嬬爜 / `PALLET` 鎵樼洏鐮� / `BATCH` 鎵规鐮侊紝涓嶄紶榛樿 `BAG` |
+| deviceCode | String | 鍚� | 鏀逛负闈炲繀濉� | 璁惧缂栫爜锛屽墠绔笉鍐嶄紶 |
+| bagCode | String | 鏄� | 璇箟鎵╁睍 | 鎵爜鍐呭锛氳鐮�/鎵樼洏鐮�/鎵规鐮佺殑鐮佸�硷紙鍚复鏃剁爜锛� |
+| eventId | String | 鏄� | - | 浜嬩欢鍙凤紙寤鸿鐢� `{scanType}-{鏃堕棿鎴硙` 淇濊瘉鍞竴锛� |
+| quantity | Number | 鏄� | - | 琚嬬爜鍦烘櫙浼� 1锛涙墭鐩�/鎵规鍦烘櫙鍚庣蹇界暐璇ュ�硷紝鎸夊凡瑁呰鏁�/鎵规琚嬫暟璁$畻 |
+| lineCode | String | 鍚� | - | 浜х嚎缂栫爜锛堝墠绔笅鎷夐�夋嫨锛� |
+| locationId | Long | 鏄� | - | WIP 鏆傚瓨搴撳尯缂栧彿锛堝墠绔笅鎷夐�夋嫨锛� |
+| areaId | Long | 鏄� | - | WIP 鏆傚瓨搴撲綅缂栧彿锛堝墠绔笅鎷夐�夋嫨锛� |
+
+**鍝嶅簲鏂板瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| scanType | String | 鏈鎵爜绫诲瀷锛圔AG/PALLET/BATCH锛� |
+
+**鍏ュ簱鏁伴噺鍙e緞锛�**
+
+| scanType | 鏁伴噺 | 璇存槑 |
+|----------|------|------|
+| BAG | 鍓嶇浼� 1 | 鍗曡鍏ュ簱 |
+| PALLET | 鎵樼洏宸茶琚嬫暟 `bag_count` | 鏁存墭涓�娆℃�у叆鏆傚瓨搴� |
+| BATCH | 鎵规琚嬫暟 `bag_quantity` | 鏁存壒涓�娆℃�у叆鏆傚瓨搴� |
+
+**鍏ュ簱鍘婚噸锛�** 琚嬬爜銆佹墭鐩樼爜銆佹壒娆$爜鍧囦互鍚勮嚜 `inbound_event_id` 鍒ゆ柇鏄惁宸插叆搴擄紝閲嶅鎵爜杩斿洖瀵瑰簲"宸插叆搴�"閿欒鐮侊紝涓嶄細閲嶅鍐欏叆搴撳瓨浜嬪姟銆�
+
+### 涓嬫媺鏁版嵁婧愶紙澶嶇敤鐜版湁鎺ュ彛锛屾棤鏂板锛�
+
+| 鐢ㄩ�� | 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|------|
+| 浜х嚎 | GET | /mes/pro/line/simple-list | 杩斿洖鍚敤浜х嚎 `{id, code, name}` |
+| 搴撳尯 | GET | /mes/wm/warehouse-location/simple-list | 杩斿洖搴撳尯 `{id, code, name}`锛涢�夊簱鍖哄悗鑱斿姩鍔犺浇鍏朵笅搴撲綅 |
+| 搴撲綅 | GET | /mes/wm/warehouse-area/simple-list?locationId= | 杩斿洖搴撲綅 `{id, code, name}` |
+
+## 鏁版嵁甯﹀叆璇存槑
+
+- 浜х嚎/搴撳尯/搴撲綅锛氫笅鎷夐�夋嫨锛岄〉闈� `onMounted` 涓�娆℃�у姞杞戒骇绾裤�佸簱鍖猴紱閫夋嫨搴撳尯鍚庢寜 `locationId` 鑱斿姩鍔犺浇搴撲綅銆�
+- 鎵爜鎻愪氦锛歚locationId`銆乣areaId`銆乣scanType`銆乣bagCode` 涓�骞跺甫鍏ュ叆搴撴帴鍙o紱浜х嚎 `lineCode` 鏈夊�兼墠浼犮��
+- 浜嬩欢鍒楄〃/鐪嬫澘锛氫互 `scanType` 鍖哄垎杩芥函鐮佺被鍨嬪睍绀猴紙鍘嗗彶鏃犵被鍨嬬殑鏁版嵁榛樿鏄剧ず"琚嬬爜"锛夈��
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 鎵爜绫诲瀷 | 绛夊緟鎵爜鍖轰笅鎷� | 涓夐�変竴锛氳鐮�/鎵樼洏鐮�/鎵规鐮� |
+| 鐢熶骇浜х嚎 | 鎵爜鍗¢厤缃尯 + 鐘舵�佸崱 | 涓嬫媺閫夋嫨锛屽彲娓呯┖ |
+| WIP 鏆傚瓨搴撳尯/搴撲綅 | 鎵爜鍗¢厤缃尯 + 鐘舵�佸崱 | 涓嬫媺閫夋嫨锛屽簱浣嶉殢搴撳尯鑱斿姩绂佺敤/鍚敤 |
+| 鏈�杩戝叆搴撹拷婧爜 | 缁熻鍗� | 灞曠ず鏈�鏂颁竴鏉℃壂鐮佸唴瀹� |
+| 杩芥函鐮�/绫诲瀷/浜х嚎 | 鏈�杩戞壂鐮佷簨浠惰〃 | 琛ㄦ牸鏂板"绫诲瀷"鍒楋紝鍘�"璁惧/浜х嚎"鍒楁敼涓�"浜х嚎" |
+| 鏈�杩戞壂鐮佺被鍨� | 鐘舵�佸崱 | 灞曠ず鏈�鏂颁簨浠舵壂鐮佺被鍨� |
+
+## 娉ㄦ剰浜嬮」
+
+1. 鍚庣闇�**鎵ц SQL 鑴氭湰** `sql/mysql/mes_pro_scan_event_scan_type.sql`锛坄mes_pro_scan_event` 澧炲姞 `scan_type` 鍒楋紝`mes_pro_pallet` 澧炲姞 `inbound_event_id`/`inbound_time` 鍒楋級锛屽啀**閲嶆柊缂栬瘧骞堕噸鍚�**銆�
+2. 閲嶅惎鍓嶆棫鎺ュ彛浼氬拷鐣� `scanType`锛堟寜琚嬬爜澶勭悊锛夛紝鎵樼洏/鎵规鐮佹壂鐮佷細杩斿洖"琚嬬爜涓嶅瓨鍦�"锛涘墠绔被鍨嬩笅鎷夌収甯稿彲閫夛紝鍔熻兘闄嶇骇涓轰粎琚嬬爜銆�
+3. 浜х嚎/搴撳尯/搴撲綅涓嬫媺鑻ユ帴鍙� 404锛堝悗绔湭閲嶅惎锛夛紝涓嬫媺涓虹┖锛岄渶鍏堜繚闅滃悗绔彲鐢ㄣ��
+4. 鎵樼洏銆佹壒娆℃暣鎵�/鏁存壒鍏ュ簱浼氬悓姝ユ妸鍏朵笅鏈叆搴撹鐮佹爣璁颁负宸插叆搴擄紝閬垮厤鍚庣画鍗曡鎵爜閲嶅鍏ュ簱銆�
diff --git a/docs/seed_quality_bag_granularity.md b/docs/seed_quality_bag_granularity.md
new file mode 100644
index 0000000..c6c0bc3
--- /dev/null
+++ b/docs/seed_quality_bag_granularity.md
@@ -0,0 +1,88 @@
+# 绉嶅瓙璐ㄦ鎸夎鐮佺矑搴︽祦杞簱瀛� - 鍓嶇鑱旇皟鏂规
+
+## 鑳屾櫙
+
+绉嶅瓙璐ㄦ鍘熼�昏緫锛氳川妫�鍚堟牸鍚�**鏁存壒**灏嗕粨搴撴壒娆″簱瀛樹粠鏆傚瓨搴�(10)杞负鍚堟牸搴�(20)锛屼竴琚嬪悎鏍煎嵆鏁存壒鏀捐锛岄绮掑害杩囩矖銆�
+
+鏈鏀归�犱负**鎸夎鐮佺矑搴�**锛氳川妫�鍙拡瀵硅鎵殑閭d竴琚嬶紝鍚堟牸浠呭皢璇ヨ瀵瑰簲搴撳瓨浠庢殏瀛樺簱杞叆鍚堟牸搴擄紝鍚屾壒娆″叾浠栬淇濇寔鏆傚瓨搴撳緟妫�锛涘悓鏃剁粰姣忚鎵撲笂璐ㄦ鏍囪锛坄qc_status`锛夛紝閿�鍞嚭搴撴壂琚嬬爜/鎵樼洏鏃舵牎楠屽凡璐ㄦ鍚堟牸鎵嶅厑璁稿嚭搴撱��
+
+## 娑夊強椤甸潰
+
+- 璐ㄩ噺绠$悊-绉嶅瓙璐ㄦ锛堟彁浜よ川妫�琛ㄥ崟锛�
+- 閿�鍞嚭搴�-鎵爜鎷h揣锛堟壂琚嬬爜/鎵樼洏锛�
+- 搴撳瓨鍙拌处锛坄mes_wm_material_stock` 鍒嗛〉锛氬悓鎵规鍙兘鍚屾椂鍑虹幇鏆傚瓨搴撲笌鍚堟牸搴撲袱鏉¤褰曪紝鐘舵�佸垪宸叉寜瀛楀吀灞曠ず鏂囧瓧锛�
+
+## API
+
+鏈**鏃犳柊澧�/淇敼鎺ュ彛**锛屽潎涓烘棦鏈夋帴鍙g殑鏍¢獙璇箟涓庢暟鎹祦杞彉鍖栥��
+
+### 1. 鎻愪氦绉嶅瓙璐ㄦ
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | `/mes/qc/seed-quality/submit` | 鎻愪氦绉嶅瓙璐ㄦ锛堟寜琚嬬爜锛� |
+
+**璇锋眰鍙傛暟锛堜笉鍙橈級锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| code | String | 鏄� | 琚嬬爜锛堟壂鐮佸唴瀹癸級锛�**蹇呴』涓烘湁鏁堣鐮�** |
+| batchCode | String | 鍚� | 鐢熶骇鎵规鍙凤紙鍏煎棰勭暀锛� |
+| indicators | Array | 鏄� | 鍥涢」鎸囨爣锛坧urity/cleanliness/germination_rate/moisture锛� |
+| reason | String | 鍚� | 澶囨敞 |
+
+**鍝嶅簲锛堜笉鍙橈級锛�** `{ "code": 0, "data": 璐ㄦ璁板綍ID }`
+
+### 2. 鎵爜鎷h揣
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | `/mes/wm/product-sales/scan` | 鎵爜鎷h揣锛堣鐮�/鎵樼洏锛� |
+
+**璇锋眰鍙傛暟锛堜笉鍙橈級锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| salesId | Long | 鏄� | 閿�鍞嚭搴撳崟ID |
+| scanContent | String | 鏄� | 琚嬬爜鎴栨墭鐩樼爜 |
+| quantity | BigDecimal | 鍚� | 鍑哄簱鏁伴噺锛堢己鐪佺敤琛屾暟閲忥級 |
+
+**鍝嶅簲锛堜笉鍙橈級锛�** 娌跨敤 `MesWmProductSalesScanRespVO`锛宍availableQuantity`/`outboundQuantity` 鍧囧熀浜�**鍚堟牸搴�**搴撳瓨璁$畻銆�
+
+## 涓氬姟瑙勫垯鍙樺寲
+
+| 鍦烘櫙 | 鍘熻涓� | 鏂拌涓� |
+|------|--------|--------|
+| 绉嶅瓙璐ㄦ鎻愪氦闈炶鐮� | 鍏煎鎵规鐮佹彁浜� | 鎶ラ敊銆屾湭瑙f瀽鍒版湁鏁堣鐮侊紝绉嶅瓙璐ㄦ蹇呴』浠ヨ鐮佹彁浜ゃ�� |
+| 璐ㄦ鍚堟牸 | 鏁存壒鏆傚瓨搴撯啋鍚堟牸搴� | 浠呰琚嬶細鏆傚瓨搴� -1銆佸悎鏍煎簱 +1锛堝悓鎵规鍏朵粬琚嬩粛涓烘殏瀛樺簱锛夛紱琚嬬爜 qc_status=20 |
+| 璐ㄦ涓嶅悎鏍� | 鏃犲簱瀛樺彉鍖� | 璇ヨ浠庢殏瀛樺簱瀛樻竻闄わ紙鎶ュ簾锛夛紱琚嬬爜 qc_status=30 |
+| 閿�鍞嚭搴撴壂琚嬬爜 | 涓嶆牎楠岃川妫� | qc_status 蹇呴』涓� 20锛屽惁鍒欐姤銆岃琚嬬爜鏈川妫�鍚堟牸锛岀姝㈠嚭搴撱�� |
+| 閿�鍞嚭搴撴壂鎵樼洏 | 涓嶆牎楠岃川妫� | 鎵樼洏涓嬫墍鏈夎鐮� qc_status 蹇呴』涓� 20锛屽惁鍒欐姤銆屾墭鐩樹笅瀛樺湪鏈川妫�琚嬬爜锛岀姝㈡暣鎵樺嚭搴撱�� |
+| 閿�鍞嚭搴撻�夊簱瀛� | 鍙兘閫変腑鏆傚瓨搴撹褰� | 浠呬粠鍚堟牸搴�(20)璁板綍涓�夋暟閲忚冻澶熺殑 |
+
+## 搴撳瓨璇箟璇存槑
+
+鍚屼竴娆★紙鍏ュ簱浠嶆寜鎵规鑱氬悎锛夎川妫�鍚堟牸鍚庯紝鍚屾壒娆� `mes_wm_material_stock` 浼氬悓鏃跺瓨鍦ㄤ袱鏉¤褰曪細
+
+| 璁板綍 | stock_state | 鍚箟 | 鏄惁鍙嚭搴� |
+|------|-------------|------|-----------|
+| 鏆傚瓨搴� | 10 | 璇ユ壒娆℃湭璐ㄦ鐨勫墿浣欒鏁� | 鍚� |
+| 鍚堟牸搴� | 20 | 宸茶川妫�鍚堟牸銆佸彲閿�鍞殑琚嬫暟 | 鏄� |
+
+绀轰緥锛氭壒娆″叆搴� 3 琚嬶紙quantity=3銆佹殏瀛樺簱锛夈�傝川妫�鍚堟牸 1 琚嬪悗 鈫� 鏆傚瓨搴� quantity=2 + 鍚堟牸搴� quantity=1銆�
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 璐ㄦ鐘舵�侊紙qc_status锛� | 绉嶅瓙璐ㄦ鎻愪氦缁撴灉鍙嶉 | 鍓嶇鏃犻渶灞曠ず锛屽悗绔湪绗簩娆℃彁浜ゅ悓涓�琚嬬爜鏃舵姤銆岃琚嬬爜宸茶川妫�锛岀姝㈤噸澶嶆彁浜ゃ�� |
+| 搴撳瓨鐘舵�� | 搴撳瓨鍙拌处鍒楄〃 | 鍚屼竴鐗╂枡/鎵规鍙兘鍑虹幇涓ゆ潯涓嶅悓鐘舵�佽褰曪紝鍧囦负姝e父鐜拌薄 |
+| 鍙嚭搴撴暟閲� | 鎵爜鎷h揣缁撴灉 | 浠� `availableQuantity` 涓哄噯锛屽彧鍙嶆槧鍚堟牸搴撳簱瀛� |
+
+## 娉ㄦ剰浜嬮」
+
+1. **绉嶅瓙璐ㄦ鎻愪氦蹇呴』浼犺鐮�**锛歚code` 瀛楁鐜板湪蹇呴』鏄郴缁熶腑瀛樺湪鐨勬湁鏁堣鐮侊紱浠呬紶鎵规鍙蜂笉鍐嶈鎺ュ彈銆�
+2. **璐ㄦ鎴愬姛鍚庡簱瀛樻�绘暟涓嶅彉**锛氭殏瀛樺簱 -1 涓庡悎鏍煎簱 +1 鍚屾鍙戠敓锛岀墿鏂欏湪搴撴�绘暟瀹堟亽锛屽彧鏄粠"寰呮"鍙樹负"鍙敭"銆�
+3. **鍚屾壒娆″弻鐘舵�佸苟瀛�**锛氭殏瀛樺簱涓庡悎鏍煎簱璁板綍鍚屾椂瀛樺湪鏄鏈熻涓猴紝鍓嶇鍦ㄥ簱瀛樺彴璐︺�佸嚭搴撻�夊簱瀛樻椂搴旇兘鎺ュ彈鍚屼竴鐗╂枡/鎵规鍑虹幇澶氳銆�
+4. **鍑哄簱鏁伴噺鎻愮ず**锛氳嫢鏌愭壒娆′粎閮ㄥ垎琚嬭川妫�鍚堟牸锛屾壂鐮佹嫞璐у彲鍑哄簱鏁伴噺鍙寘鍚悎鏍艰锛屽墠绔彁绀哄簲浠ユ帴鍙h繑鍥炵殑 `availableQuantity` 涓哄噯銆�
+5. **涓嶅悎鏍艰鎶ュ簾**锛氳川妫�涓嶅悎鏍肩殑琚嬩細浠庢殏瀛樺簱瀛樹腑鎵i櫎锛屼笖璇ヨ鐮� qc_status=30锛岀姝㈠嚭搴撱��
diff --git a/docs/sql/trace_platform_01_schema.sql b/docs/sql/trace_platform_01_schema.sql
new file mode 100644
index 0000000..b4bd50f
--- /dev/null
+++ b/docs/sql/trace_platform_01_schema.sql
@@ -0,0 +1,79 @@
+-- 鎵规杩芥函鏁版嵁妯″瀷琛ュ己
+-- 璇存槑锛氬瓧娈靛厛鍏佽涓虹┖锛屽巻鍙叉暟鎹洖濉畬鎴愬悗鍐嶈瘎浼版槸鍚︽敹绱х害鏉熴��
+-- 娉ㄦ剰锛氶」鐩笉浣跨敤 tenant_id锛涙墽琛屽墠璇风‘璁ゅ瓧娈靛拰绱㈠紩涓嶅瓨鍦ㄣ��
+
+ALTER TABLE mes_wm_batch
+ ADD COLUMN pro_batch_id BIGINT NULL COMMENT '瀵瑰簲鐢熶骇鎵规ID' AFTER id;
+ALTER TABLE mes_wm_batch
+ ADD INDEX idx_mes_wm_batch_pro_batch_id (pro_batch_id);
+
+ALTER TABLE mes_wm_sn
+ ADD COLUMN pro_batch_id BIGINT NULL COMMENT '鐢熶骇鎵规ID' AFTER id;
+ALTER TABLE mes_wm_sn
+ ADD COLUMN bag_code_id BIGINT NULL COMMENT '琚嬬爜ID' AFTER pro_batch_id;
+ALTER TABLE mes_wm_sn
+ ADD COLUMN pallet_id BIGINT NULL COMMENT '鎵樼洏ID' AFTER bag_code_id;
+ALTER TABLE mes_wm_sn
+ ADD COLUMN sales_id BIGINT NULL COMMENT '閿�鍞嚭搴撳崟ID' AFTER pallet_id;
+ALTER TABLE mes_wm_sn
+ ADD INDEX idx_mes_wm_sn_pro_batch_id (pro_batch_id);
+ALTER TABLE mes_wm_sn
+ ADD INDEX idx_mes_wm_sn_bag_code_id (bag_code_id);
+
+ALTER TABLE mes_qc_seed_quality
+ ADD COLUMN batch_id BIGINT NULL COMMENT '鐢熶骇鎵规ID' AFTER item_id;
+ALTER TABLE mes_qc_seed_quality
+ ADD INDEX idx_mes_qc_seed_quality_batch_id (batch_id);
+
+CREATE TABLE mes_trace_event (
+ id BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ event_no VARCHAR(64) NOT NULL COMMENT '浜嬩欢缂栧彿',
+ event_type VARCHAR(32) NOT NULL COMMENT '浜嬩欢绫诲瀷',
+ event_category VARCHAR(32) NULL COMMENT '浜嬩欢鍒嗙被',
+ event_time DATETIME NOT NULL COMMENT '浜嬩欢鏃堕棿',
+ pro_batch_id BIGINT NULL COMMENT '鐢熶骇鎵规ID',
+ wm_batch_id BIGINT NULL COMMENT '浠撳偍鎵规ID',
+ bag_code_id BIGINT NULL COMMENT '琚嬬爜ID',
+ pallet_id BIGINT NULL COMMENT '鎵樼洏ID',
+ sn_id BIGINT NULL COMMENT 'SN ID',
+ item_id BIGINT NULL COMMENT '鐗╂枡ID',
+ biz_type VARCHAR(32) NULL COMMENT '涓氬姟绫诲瀷',
+ biz_id BIGINT NULL COMMENT '涓氬姟ID',
+ biz_code VARCHAR(100) NULL COMMENT '涓氬姟缂栫爜',
+ biz_line_id BIGINT NULL COMMENT '涓氬姟鏄庣粏ID',
+ from_node_type VARCHAR(32) NULL COMMENT '鏉ユ簮鑺傜偣绫诲瀷',
+ from_node_id BIGINT NULL COMMENT '鏉ユ簮鑺傜偣ID',
+ from_node_code VARCHAR(100) NULL COMMENT '鏉ユ簮鑺傜偣缂栫爜',
+ to_node_type VARCHAR(32) NULL COMMENT '鐩爣鑺傜偣绫诲瀷',
+ to_node_id BIGINT NULL COMMENT '鐩爣鑺傜偣ID',
+ to_node_code VARCHAR(100) NULL COMMENT '鐩爣鑺傜偣缂栫爜',
+ quantity DECIMAL(18, 6) NULL COMMENT '鏁伴噺',
+ warehouse_id BIGINT NULL COMMENT '浠撳簱ID',
+ location_id BIGINT NULL COMMENT '搴撳尯ID',
+ area_id BIGINT NULL COMMENT '搴撲綅ID',
+ line_id BIGINT NULL COMMENT '浜х嚎ID',
+ work_order_id BIGINT NULL COMMENT '宸ュ崟ID',
+ process_id BIGINT NULL COMMENT '宸ュ簭ID',
+ sales_id BIGINT NULL COMMENT '閿�鍞嚭搴撳崟ID',
+ quality_id BIGINT NULL COMMENT '璐ㄦ璁板綍ID',
+ operator_id BIGINT NULL COMMENT '鎿嶄綔浜篒D',
+ payload_json JSON NULL COMMENT '浜嬩欢鎵╁睍鏁版嵁',
+ content_hash VARCHAR(64) NULL COMMENT '浜嬩欢鍐呭SHA-256鎽樿',
+ prev_hash VARCHAR(64) NULL COMMENT '鍓嶄竴浜嬩欢鎽樿',
+ creator VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ updater VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ deleted BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (id),
+ UNIQUE KEY uk_mes_trace_event_no (event_no),
+ KEY idx_mes_trace_event_batch_time (pro_batch_id, event_time),
+ KEY idx_mes_trace_event_biz (biz_type, biz_id, biz_line_id),
+ KEY idx_mes_trace_event_nodes (from_node_id, to_node_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES缁熶竴杩芥函浜嬩欢';
+
+-- 鍘嗗彶鏁版嵁鍥炲~绀轰緥锛岀‘璁ゆ暟鎹川閲忓悗鎵ц锛�
+-- UPDATE mes_wm_batch w JOIN mes_pro_batch p ON p.code = w.code AND p.deleted = b'0'
+-- SET w.pro_batch_id = p.id WHERE w.pro_batch_id IS NULL AND w.deleted = b'0';
+-- UPDATE mes_qc_seed_quality q JOIN mes_pro_batch p ON p.code = q.batch_code AND p.deleted = b'0'
+-- SET q.batch_id = p.id WHERE q.batch_id IS NULL AND q.deleted = b'0';
diff --git a/docs/wm_transaction_query.md b/docs/wm_transaction_query.md
index 33b616f..c48c2b9 100644
--- a/docs/wm_transaction_query.md
+++ b/docs/wm_transaction_query.md
@@ -9,6 +9,7 @@
| 鏂规硶 | 璺緞 | 璇存槑 |
|------|------|------|
| GET | /mes/wm/transaction/page | 鍒嗛〉鏌ヨ搴撳瓨浜嬪姟娴佹按 |
+| GET | /mes/pro/batch/get-by-code | 鐐瑰嚮鎵规鍙锋煡璇㈢敓浜ф壒娆°�佹墭鐩樺強琚嬬爜淇℃伅 |
### 璇锋眰鍙傛暟
@@ -23,10 +24,37 @@
| bizType | Integer | 鍚� | 涓氬姟绫诲瀷 |
| bizCode | String | 鍚� | 涓氬姟鍗曞彿锛屾ā绯婂尮閰� |
| materialStockId | Long | 鍚� | 搴撳瓨璁板綍ID |
+| bagCode | String | 鍚� | 琚嬬爜锛屾ā绯婂尮閰嶏紙璐ㄦ銆侀攢鍞嚭搴撶瓑琚嬬爜绾ф祦姘达級 |
| startTime | String | 鍚� | 寮�濮嬫椂闂达紙鏍煎紡锛歽yyy-MM-dd HH:mm:ss锛� |
| endTime | String | 鍚� | 缁撴潫鏃堕棿锛堟牸寮忥細yyyy-MM-dd HH:mm:ss锛� |
| pageNo | Integer | 鏄� | 椤电爜锛岄粯璁�1 |
| pageSize | Integer | 鏄� | 姣忛〉鏉℃暟锛岄粯璁�10 |
+
+### 鎵规杩芥函鏌ヨ
+
+鐐瑰嚮娴佹按鍒楄〃涓殑鎵规鍙锋椂锛屼娇鐢ㄥ綋鍓嶈鐨� `batchCode` 璋冪敤浠ヤ笅鎺ュ彛锛�
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| code | String | 鏄� | 鎵规鍙锋垨鎵规浜岀淮鐮佸唴瀹� |
+
+璇锋眰绀轰緥锛歚GET /mes/pro/batch/get-by-code?code={batchCode}`
+
+鎺ュ彛杩斿洖鐨勯噸鐐瑰瓧娈碉細
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| id | Long | 鐢熶骇鎵规ID |
+| code | String | 姝e紡鎵规鍙� |
+| tempCode | String | 涓存椂鎵规鐮� |
+| itemCode | String | 鐗╂枡缂栫爜 |
+| itemName | String | 鐗╂枡鍚嶇О |
+| workers | Array | 鎵规浜哄憳閰嶇疆 |
+| pallets | Array | 鎵规涓嬬殑鎵樼洏鍒楄〃 |
+| bagTotal | Integer | 琚嬬爜鎬绘暟 |
+| bags | Array | 鎵规涓嬬殑琚嬬爜鍒楄〃 |
+
+璇ユ帴鍙e悓鏃舵敮鎸佹寮忔壒娆″彿鍜屼复鏃舵壒娆$爜銆傝嫢鎵规鍙蜂负绌猴紝涓嶆樉绀虹偣鍑诲叆鍙o紱鑻ユ煡璇笉鍒扮敓浜ф壒娆★紝鎸夋帴鍙h繑鍥炵殑涓氬姟閿欒鎻愮ず鐢ㄦ埛銆�
### 鍝嶅簲瀛楁
@@ -44,6 +72,8 @@
| quantity | BigDecimal | 鍙樺姩鏁伴噺锛堟鏁�=鍏ュ簱锛岃礋鏁�=鍑哄簱锛� |
| batchId | Long | 鎵规ID |
| batchCode | String | 鎵规鍙� |
+| bagCodeId | Long | 琚嬬爜ID锛堣鐮佺骇娴佹按闈炵┖锛� |
+| bagCode | String | 琚嬬爜锛堣鐮佺骇娴佹按闈炵┖锛屽璐ㄦ銆侀攢鍞嚭搴撱�佺Щ搴擄級 |
| warehouseId | Long | 浠撳簱ID |
| warehouseName | String | 浠撳簱鍚嶇О |
| locationId | Long | 搴撳尯ID |
@@ -111,6 +141,24 @@
| 121 | 澶栧崗鍙戞枡 | 澶栧崗鍙戞枡 |
| 122 | 澶栧崗鍏ュ簱 | 澶栧崗鍏ュ簱 |
+## 璋冪敤鏃跺簭
+
+1. 杩涘叆搴撳瓨浜嬪姟娴佹按椤甸潰鏃讹紝璋冪敤 `/mes/wm/transaction/page` 鑾峰彇娴佹按鍒楄〃銆�
+2. 鍒楄〃涓睍绀� `batchCode`锛涙壒娆″彿闈炵┖鏃跺厑璁哥偣鍑汇��
+3. 鐐瑰嚮鎵规鍙峰悗锛屽皢褰撳墠琛岀殑 `batchCode` 浣滀负 `code` 璋冪敤 `/mes/pro/batch/get-by-code`銆�
+4. 鏍规嵁杩斿洖缁撴灉灞曠ず鐢熶骇鎵规淇℃伅銆佹墭鐩樺垪琛ㄥ拰琚嬬爜鍒楄〃锛沗bagTotal` 鐢ㄤ簬鏄剧ず琚嬬爜鎬绘暟锛宍bags` 鐢ㄤ簬灞曠ず琚嬬爜鏄庣粏銆�
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| batchCode | 搴撳瓨娴佹按鍒楄〃 | 鎵规鍙烽潪绌烘椂浣滀负鍙偣鍑诲叆鍙� |
+| code | 鎵规璇︽儏 | 姝e紡鎵规鍙� |
+| tempCode | 鎵规璇︽儏 | 涓存椂鎵规鐮侊紝鏈夊�兼椂灞曠ず |
+| bagTotal | 鎵规璇︽儏 | 灞曠ず璇ユ壒娆¤鐮佹�绘暟 |
+| bags[].code | 鎵规璇︽儏 | 灞曠ず琚嬬爜鏄庣粏 |
+| pallets | 鎵规璇︽儏 | 灞曠ず璇ユ壒娆″叧鑱旂殑鎵樼洏淇℃伅 |
+
## 鎼滅储鏉′欢
| 鏉′欢瀛楁 | 缁勪欢绫诲瀷 | 璇存槑 |
@@ -140,6 +188,7 @@
| 搴撳尯 | locationName | 100 | - |
| 搴撲綅 | areaName | 100 | - |
| 浜嬪姟鏃堕棿 | transactionTime | 160 | 鏍煎紡锛歽yyy-MM-dd HH:mm:ss |
+| 琚嬬爜 | bagCode | 150 | 琚嬬爜绾ф祦姘寸殑琚嬬爜锛涙壒娆�/琚嬬爜鍙户缁拷婧� |
## 涓氬姟瑙勫垯璇存槑
@@ -150,6 +199,7 @@
| 鏁伴噺鏄剧ず | quantity > 0 鏄剧ず缁胯壊锛宷uantity < 0 鏄剧ず绾㈣壊 |
| 绫诲瀷鏍囩 | 鍏ュ簱鏄剧ず缁胯壊 success 鏍囩锛屽嚭搴撴樉绀虹孩鑹� danger 鏍囩 |
| 涓氬姟鍗曞彿璺宠浆 | 鐐瑰嚮 bizCode 鍙烦杞埌瀵瑰簲涓氬姟鍗曟嵁璇︽儏椤� |
+| 琚嬬爜绛涢�� | 浼� bagCode 鍙煡鐪嬫寚瀹氳鐮佺殑瀹屾暣娴佽浆锛堣川妫�鏆傚瓨鍑哄簱/鍚堟牸鍏ュ簱/閿�鍞嚭搴撶瓑锛� |
## 鏉冮檺閰嶇疆
diff --git a/sql/mysql/mes_pro_bag_code_qc_status.sql b/sql/mysql/mes_pro_bag_code_qc_status.sql
new file mode 100644
index 0000000..54e3fe4
--- /dev/null
+++ b/sql/mysql/mes_pro_bag_code_qc_status.sql
@@ -0,0 +1,13 @@
+-- =========================================
+-- 琚嬬爜璐ㄦ鐘舵�侊細鏀寔绉嶅瓙璐ㄦ鎸夎鐮佺矑搴︽祦杞簱瀛�
+-- qc_status锛�10 鏈川妫� / 20 璐ㄦ鍚堟牸 / 30 璐ㄦ涓嶅悎鏍�
+-- 鏂板鍒楃敤浜庤褰曟瘡琚嬬殑璐ㄦ缁撴灉锛岄攢鍞嚭搴撴壂琚嬬爜鏃舵牎楠岃琚嬪凡璐ㄦ鍚堟牸銆�
+-- =========================================
+
+ALTER TABLE `mes_pro_bag_code`
+ ADD COLUMN `qc_status` TINYINT NOT NULL DEFAULT 10 COMMENT '璐ㄦ鐘舵�侊紙10鏈川妫� 20璐ㄦ鍚堟牸 30璐ㄦ涓嶅悎鏍硷級' AFTER `status`;
+
+-- 鍥炲~瀛橀噺鏁版嵁锛氭寜宸叉湁绉嶅瓙璐ㄦ璁板綍鍚屾琚嬬爜璐ㄦ鐘舵��
+UPDATE `mes_pro_bag_code` b
+ JOIN `mes_qc_seed_quality` q ON b.code = q.code AND b.deleted = 0
+SET b.qc_status = IF(q.result = 1, 20, 30), b.update_time = NOW();
diff --git a/sql/mysql/mes_pro_scan_event_scan_type.sql b/sql/mysql/mes_pro_scan_event_scan_type.sql
new file mode 100644
index 0000000..cf2b728
--- /dev/null
+++ b/sql/mysql/mes_pro_scan_event_scan_type.sql
@@ -0,0 +1,14 @@
+-- 鐢熶骇绾挎壂鐮佸叆搴擄細鏀寔琚嬬爜/鎵樼洏鐮�/鎵规鐮佷笁绉嶆壂鐮佺被鍨嬶紝骞跺幓鎺夎澶囩紪鐮佸繀濉�
+-- 璇存槑锛�
+-- 1. mes_pro_scan_event 澧炲姞 scan_type 鍒楋紝鏍囪鎵爜绫诲瀷锛圔AG 琚嬬爜 / PALLET 鎵樼洏鐮� / BATCH 鎵规鐮侊級锛屽巻鍙茶鐮佹暟鎹洖濉� BAG
+-- 2. mes_pro_pallet 澧炲姞鍏ュ簱鏍囪鍒楋紙鎵樼洏鍘熷厛鏃犲叆搴撴爣璁板瓧娈碉紝鏁存墭鍏ュ簱闇�鍘婚噸锛岄槻姝㈠悓涓�鎵樼洏閲嶅鎵爜鍏ュ簱锛�
+
+ALTER TABLE mes_pro_scan_event ADD COLUMN scan_type VARCHAR(16) NULL COMMENT '鎵爜绫诲瀷锛圔AG琚嬬爜/PALLET鎵樼洏鐮�/BATCH鎵规鐮侊級' AFTER bag_code;
+
+-- 璁惧缂栫爜涓嶅啀蹇呭~锛堝墠绔幓鎺夎澶囩紪鐮侊紝鍘嗗彶鍒椾繚鎸佸吋瀹癸級
+ALTER TABLE mes_pro_scan_event MODIFY COLUMN device_code VARCHAR(64) NULL DEFAULT NULL COMMENT '璁惧缂栫爜锛堜笉鍐嶅繀濉級';
+
+ALTER TABLE mes_pro_pallet ADD COLUMN inbound_event_id BIGINT NULL COMMENT '鏈�杩戝叆搴撴壂鐮佷簨浠剁紪鍙�' AFTER bag_count;
+ALTER TABLE mes_pro_pallet ADD COLUMN inbound_time DATETIME NULL COMMENT '鏈�杩戝叆搴撴椂闂�' AFTER inbound_event_id;
+
+UPDATE mes_pro_scan_event SET scan_type = 'BAG' WHERE scan_type IS NULL;
diff --git a/sql/mysql/mes_qc_seed_quality_record_menu.sql b/sql/mysql/mes_qc_seed_quality_record_menu.sql
new file mode 100644
index 0000000..11bd3f2
--- /dev/null
+++ b/sql/mysql/mes_qc_seed_quality_record_menu.sql
@@ -0,0 +1,14 @@
+-- =============================================
+-- 绉嶅瓙璐ㄦ璁板綍鐙珛鑿滃崟
+-- 灏嗚川妫�璁板綍浠庛�岀瀛愯川妫�銆嶉〉(鎻愪氦+璁板綍鍚堜竴)鎷嗗嚭锛岀嫭绔嬫垚鑿滃崟椤甸潰
+-- 璇存槑锛�
+-- 1. 绉嶅瓙璐ㄦ鎻愪氦椤碉細seed-quality -> mes/qc/seedQuality/index锛堜粎鎻愪氦锛�
+-- 2. 璐ㄦ璁板綍椤碉細seed-quality-record -> mes/qc/seedQuality/record锛堜粎璁板綍鏌ヨ锛�
+-- 鎸傚湪銆岃川閲忕鐞嗐��(5500) 鐩綍涓嬶紱骞傜瓑锛屽彲閲嶅鎵ц锛涙棤绉熸埛瀛楁銆�
+-- =============================================
+
+INSERT INTO system_menu
+(id, name, parent_id, type, sort, status, path, icon, component, component_name, permission, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted)
+SELECT 1065224, '璐ㄦ璁板綍', 5500, 2, 95, 0, 'seed-quality-record', 'ep:list', 'mes/qc/seedQuality/record', 'MesQcSeedQualityRecord', '', b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM system_menu WHERE id = 1065224 AND deleted = b'0');
diff --git a/sql/mysql/mes_wm_material_stock_bag.sql b/sql/mysql/mes_wm_material_stock_bag.sql
new file mode 100644
index 0000000..e659a95
--- /dev/null
+++ b/sql/mysql/mes_wm_material_stock_bag.sql
@@ -0,0 +1,31 @@
+CREATE TABLE mes_wm_material_stock_bag (
+ id BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ material_stock_id BIGINT NOT NULL COMMENT '搴撳瓨姹囨�昏褰旾D',
+ bag_code_id BIGINT NOT NULL COMMENT '鐢熶骇琚嬬爜ID',
+ bag_code VARCHAR(64) NOT NULL COMMENT '琚嬬爜',
+ item_id BIGINT NOT NULL COMMENT '鐗╂枡ID',
+ batch_id BIGINT NULL COMMENT '浠撳簱鎵规ID',
+ batch_code VARCHAR(64) NULL COMMENT '鎵规鍙�',
+ vendor_id BIGINT NULL COMMENT '渚涘簲鍟咺D',
+ warehouse_id BIGINT NOT NULL COMMENT '浠撳簱ID',
+ location_id BIGINT NULL COMMENT '搴撳尯ID',
+ area_id BIGINT NULL COMMENT '搴撲綅ID',
+ stock_state TINYINT NOT NULL COMMENT '搴撳瓨鐘舵�侊細10鏆傚瓨锛�20鍚堟牸锛�30宸插嚭搴擄紝40鎶ュ簾',
+ status TINYINT NOT NULL DEFAULT 1 COMMENT '鏄庣粏鐘舵�侊細1鍦ㄥ簱锛�2宸插嚭搴擄紝3宸叉姤搴�',
+ quantity DECIMAL(18, 6) NOT NULL DEFAULT 1 COMMENT '琚嬬爜搴撳瓨鏁伴噺',
+ frozen BIT NOT NULL DEFAULT 0 COMMENT '鏄惁鍐荤粨',
+ last_transaction_id BIGINT NULL COMMENT '鏈�杩戝簱瀛樹簨鍔D',
+ inbound_time DATETIME NULL COMMENT '鍏ュ簱鏃堕棿',
+ outbound_time DATETIME NULL COMMENT '鍑哄簱鏃堕棿',
+ creator VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ updater VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ deleted BIT NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (id),
+ UNIQUE KEY uk_bag_code (bag_code),
+ KEY idx_material_stock (material_stock_id),
+ KEY idx_batch_state (batch_id, stock_state, status),
+ KEY idx_location_state (warehouse_id, location_id, area_id, stock_state, status),
+ KEY idx_bag_code_id (bag_code_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES搴撳瓨琚嬬爜鏄庣粏';
diff --git a/sql/mysql/mes_wm_product_sales_add_columns.sql b/sql/mysql/mes_wm_product_sales_add_columns.sql
new file mode 100644
index 0000000..04f072d
--- /dev/null
+++ b/sql/mysql/mes_wm_product_sales_add_columns.sql
@@ -0,0 +1,12 @@
+-- MES 閿�鍞嚭搴撳崟琛ㄧ粨鏋勪慨鏀�
+-- 鏍规嵁 MesWmProductSalesDO 琛ュ厖缂哄け瀛楁
+-- 璇存槑锛氫慨澶嶆煡璇㈡姤閿� Unknown column 'client_name'锛屽悓鏃惰ˉ鍏� outbound_time銆乷utbound_user_id
+
+-- 1. 缁忛攢鍟嗗悕绉板揩鐓�
+ALTER TABLE mes_wm_product_sales ADD COLUMN client_name VARCHAR(128) DEFAULT NULL COMMENT '缁忛攢鍟嗗悕绉板揩鐓�' AFTER client_id;
+
+-- 2. 瀹為檯鍑哄簱鏃堕棿
+ALTER TABLE mes_wm_product_sales ADD COLUMN outbound_time DATETIME DEFAULT NULL COMMENT '瀹為檯鍑哄簱鏃堕棿';
+
+-- 3. 鎵ц鍑哄簱鎿嶄綔浜篒D
+ALTER TABLE mes_wm_product_sales ADD COLUMN outbound_user_id BIGINT DEFAULT NULL COMMENT '鎵ц鍑哄簱鎿嶄綔浜篒D';
\ No newline at end of file
diff --git a/sql/mysql/mes_wm_qualified_warehouse.sql b/sql/mysql/mes_wm_qualified_warehouse.sql
new file mode 100644
index 0000000..29379d1
--- /dev/null
+++ b/sql/mysql/mes_wm_qualified_warehouse.sql
@@ -0,0 +1,85 @@
+-- =====================================================================
+-- 鏂板缓鍚堟牸浠撳簱 + 浠撳簱绫诲瀷 + 璐ㄦ鍏ュ悎鏍煎簱鏀归��
+--
+-- 1) mes_wm_warehouse 澧炲姞 type 瀛楁锛�10 鏆傚瓨搴� / 20 鍚堟牸搴擄級
+-- 2) 鐜版湁浠撳簱鍒嗙被锛氳櫄鎷熺嚎杈逛粨搴�=10锛堟殏瀛樺簱锛夛紝浜у搧搴�/鐗╂枡搴�=20锛堝悎鏍煎簱锛�
+-- 3) 鏂板缓"鎴愬搧鍚堟牸搴�"(type=20) + 涓�涓簱鍖� + 涓�涓簱浣�
+-- 4) 铏氭嫙浠撳簱涓� stock_state=20 鐨勫悎鏍煎簱瀛樿縼绉诲埌鏂板悎鏍煎簱
+--
+-- 璇存槑锛氭湰鑴氭湰骞傜瓑锛屽彲閲嶅鎵ц锛涙棤绉熸埛瀛楁銆�
+-- =====================================================================
+
+-- 1) 澧炲姞浠撳簱绫诲瀷瀛楁锛圡ySQL 涓嶆敮鎸� ALTER ADD COLUMN IF NOT EXISTS锛屽厛鏌ュ瓨鍦ㄦ�э級
+SET @type_exists = (
+ SELECT COUNT(*)
+ FROM information_schema.columns
+ WHERE table_schema = DATABASE()
+ AND table_name = 'mes_wm_warehouse'
+ AND column_name = 'type'
+);
+SET @type_sql = IF(
+ @type_exists = 0,
+ 'ALTER TABLE mes_wm_warehouse ADD COLUMN type tinyint NOT NULL DEFAULT 10 COMMENT ''浠撳簱绫诲瀷锛�10鏆傚瓨搴擄紝20鍚堟牸搴�'' AFTER frozen',
+ 'SELECT 1'
+);
+PREPARE type_stmt FROM @type_sql;
+EXECUTE type_stmt;
+DEALLOCATE PREPARE type_stmt;
+
+-- 2) 鐜版湁浠撳簱鍒嗙被
+UPDATE mes_wm_warehouse SET type = 10 WHERE code = 'WIP_VIRTUAL_WAREHOUSE' AND deleted = 0;
+UPDATE mes_wm_warehouse SET type = 20 WHERE code IN ('1212', 'WHS000001') AND deleted = 0;
+
+-- 3) 鏂板缓"鎴愬搧鍚堟牸搴�"锛坱ype=20锛�
+SET @wh_exists = (
+ SELECT COUNT(*) FROM mes_wm_warehouse WHERE code = 'FG_QUALIFIED_WH' AND deleted = 0
+);
+INSERT INTO mes_wm_warehouse (code, name, frozen, type, remark)
+SELECT 'FG_QUALIFIED_WH', '鎴愬搧鍚堟牸搴�', 0, 20, '璐ㄦ鍚堟牸鐩存帴鍏ュ簱鐨勭洰鏍囦粨搴擄紙type=20 鍚堟牸搴擄級'
+WHERE @wh_exists = 0;
+SET @wh_id = (SELECT id FROM mes_wm_warehouse WHERE code = 'FG_QUALIFIED_WH' AND deleted = 0 LIMIT 1);
+
+-- 鏂板缓"鎴愬搧鍚堟牸搴撳尯"
+SET @loc_exists = (
+ SELECT COUNT(*) FROM mes_wm_warehouse_location WHERE code = 'FG_QUALIFIED_WH_LOC' AND deleted = 0
+);
+INSERT INTO mes_wm_warehouse_location (code, name, warehouse_id, frozen, remark)
+SELECT 'FG_QUALIFIED_WH_LOC', '鎴愬搧鍚堟牸搴撳尯', @wh_id, 0, '璐ㄦ鍚堟牸鍏ュ簱榛樿搴撳尯'
+WHERE @loc_exists = 0;
+SET @loc_id = (SELECT id FROM mes_wm_warehouse_location WHERE code = 'FG_QUALIFIED_WH_LOC' AND deleted = 0 LIMIT 1);
+
+-- 鏂板缓"鎴愬搧鍚堟牸搴撲綅"
+SET @area_exists = (
+ SELECT COUNT(*) FROM mes_wm_warehouse_area WHERE code = 'FG_QUALIFIED_WH_AREA' AND deleted = 0
+);
+INSERT INTO mes_wm_warehouse_area (code, name, location_id, frozen, remark)
+SELECT 'FG_QUALIFIED_WH_AREA', '鎴愬搧鍚堟牸搴撲綅', @loc_id, 0, '璐ㄦ鍚堟牸鍏ュ簱榛樿搴撲綅'
+WHERE @area_exists = 0;
+SET @area_id = (SELECT id FROM mes_wm_warehouse_area WHERE code = 'FG_QUALIFIED_WH_AREA' AND deleted = 0 LIMIT 1);
+
+-- 4) 杩佺Щ铏氭嫙浠撳簱鍚堟牸搴撳瓨鍒版柊鍚堟牸搴�
+-- 4.1 鑻ユ柊鍚堟牸搴撳凡瀛樺湪鍚� (item_id, batch_id, vendor_id) 鐨� state=20 璁板綍锛屽厛鏁伴噺绱姞鍚堝苟
+UPDATE mes_wm_material_stock t
+JOIN mes_wm_material_stock s
+ ON s.warehouse_id = 3 AND s.stock_state = 20 AND s.deleted = 0
+ AND t.warehouse_id = @wh_id AND t.stock_state = 20 AND t.deleted = 0
+ AND t.item_id = s.item_id
+ AND IFNULL(t.batch_id, 0) = IFNULL(s.batch_id, 0)
+ AND IFNULL(t.vendor_id, 0) = IFNULL(s.vendor_id, 0)
+SET t.quantity = t.quantity + s.quantity,
+ t.reserved_quantity = t.reserved_quantity + s.reserved_quantity,
+ t.frozen_quantity = t.frozen_quantity + s.frozen_quantity;
+
+-- 4.2 鍒犻櫎宸插悎骞跺埌鏂板悎鏍煎簱鐨勬簮璁板綍锛堣櫄鎷熶粨搴撲腑锛�
+DELETE s FROM mes_wm_material_stock s
+JOIN mes_wm_material_stock t
+ ON s.warehouse_id = 3 AND s.stock_state = 20 AND s.deleted = 0
+ AND t.warehouse_id = @wh_id AND t.stock_state = 20 AND t.deleted = 0
+ AND t.item_id = s.item_id
+ AND IFNULL(t.batch_id, 0) = IFNULL(s.batch_id, 0)
+ AND IFNULL(t.vendor_id, 0) = IFNULL(s.vendor_id, 0);
+
+-- 4.3 鍏朵綑鍚堟牸搴撳瓨鐩存帴鏀逛粨搴�/搴撳尯/搴撲綅
+UPDATE mes_wm_material_stock
+SET warehouse_id = @wh_id, location_id = @loc_id, area_id = @area_id
+WHERE warehouse_id = 3 AND stock_state = 20 AND deleted = 0;
diff --git a/sql/mysql/mes_wm_transaction_bag_code.sql b/sql/mysql/mes_wm_transaction_bag_code.sql
new file mode 100644
index 0000000..4b974c9
--- /dev/null
+++ b/sql/mysql/mes_wm_transaction_bag_code.sql
@@ -0,0 +1,17 @@
+SET @exists_bag_code_id = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'mes_wm_transaction' AND column_name = 'bag_code_id');
+SET @sql_bag_code_id = IF(@exists_bag_code_id = 0, 'ALTER TABLE mes_wm_transaction ADD COLUMN bag_code_id BIGINT NULL COMMENT ''鐢熶骇琚嬬爜ID'' AFTER material_stock_id', 'SELECT 1');
+PREPARE stmt FROM @sql_bag_code_id;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+SET @exists_bag_code = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'mes_wm_transaction' AND column_name = 'bag_code');
+SET @sql_bag_code = IF(@exists_bag_code = 0, 'ALTER TABLE mes_wm_transaction ADD COLUMN bag_code VARCHAR(64) NULL COMMENT ''琚嬬爜'' AFTER bag_code_id', 'SELECT 1');
+PREPARE stmt FROM @sql_bag_code;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+SET @exists_bag_code_index = (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'mes_wm_transaction' AND index_name = 'idx_bag_code');
+SET @sql_bag_code_index = IF(@exists_bag_code_index = 0, 'ALTER TABLE mes_wm_transaction ADD KEY idx_bag_code (bag_code)', 'SELECT 1');
+PREPARE stmt FROM @sql_bag_code_index;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
diff --git a/sql/mysql/wls_sales_outbound_menu_extract.sql b/sql/mysql/wls_sales_outbound_menu_extract.sql
new file mode 100644
index 0000000..6df47c8
--- /dev/null
+++ b/sql/mysql/wls_sales_outbound_menu_extract.sql
@@ -0,0 +1,25 @@
+-- =============================================
+-- 鍑哄簱娴侀�氱鐞嗚彍鍗曟彁鍙栬剼鏈�
+-- 灏�"閿�鍞粨搴�"(602479) 鎻愬彇涓轰竴绾ц彍鍗�"鍑哄簱娴侀�氱鐞�"
+-- 鍘熺粨鏋勶細浠撳偍鐗╂祦(5780) -> 閿�鍞粨搴�(602479) -> 鍙戣揣閫氱煡/閿�鍞嚭搴�/閿�鍞��璐�
+-- =============================================
+
+-- 1. 鎻愬彇涓轰竴绾ц彍鍗�
+-- 璇存槑锛氶《绾�"钀ラ攢绠$悊"(2617) 宸插崰鐢� path=sale锛屾晠鏀圭敤 sales-outbound 閬垮厤璺敱鍐茬獊
+UPDATE system_menu SET
+ parent_id = 0,
+ name = '鍑哄簱娴侀�氱鐞�',
+ path = 'sales-outbound',
+ sort = 10 -- 鏀惧湪浠撳偍鐗╂祦(sort=9)涔嬪悗
+WHERE id = 602479 AND deleted = b'0';
+
+-- =============================================
+-- 璇存槑锛�
+-- 1. 瀛愯彍鍗�(鍙戣揣閫氱煡 5867 / 閿�鍞嚭搴� 5970 / 閿�鍞��璐� 5847) 鏃犻渶鏀瑰姩锛�
+-- 鍓嶇鍔ㄦ�佽矾鐢变細鑷姩鎷兼帴涓� /sales-outbound/sales-notice 绛夎矾寰�
+-- 2. 椤剁骇鐩綍鑿滃崟鐢卞墠绔嚜鍔ㄦ覆鏌撲负 BasicLayout锛宑omponent 瀛楁鏃犻渶濉啓
+-- 3. 濡傞渶鎭㈠锛屾墽琛屼互涓嬪弽鍚戣剼鏈細
+-- =============================================
+
+-- 鍙嶅悜鑴氭湰锛堝闇�鎭㈠锛夛細
+-- UPDATE system_menu SET parent_id = 5780, name = '閿�鍞粨搴�', path = 'sale', sort = 5 WHERE id = 602479;
diff --git a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/returnobj/AfterSaleReturnServiceImpl.java b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/returnobj/AfterSaleReturnServiceImpl.java
index ed5fcd6..e820f5d 100644
--- a/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/returnobj/AfterSaleReturnServiceImpl.java
+++ b/yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/service/returnobj/AfterSaleReturnServiceImpl.java
@@ -130,8 +130,6 @@
MesWmReturnSalesCreateReqDTO mesReqDTO = new MesWmReturnSalesCreateReqDTO();
mesReqDTO.setCode(returnDO.getNo());
mesReqDTO.setName("鍞悗閫�璐�-" + returnDO.getNo());
- mesReqDTO.setSaleOrderId(returnDO.getSaleOrderId());
- mesReqDTO.setSalesOrderCode(ticket != null ? ticket.getSaleOrderNo() : null);
mesReqDTO.setClientId(returnDO.getCustomerId());
mesReqDTO.setReturnDate(LocalDate.now());
mesReqDTO.setReturnReason(returnDO.getReturnReason());
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
index 3cacd73..43748cd 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
@@ -21,9 +21,6 @@
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi;
import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
-import cn.iocoder.yudao.module.mes.api.mps.MesProMpsApi;
-import cn.iocoder.yudao.module.mes.api.productsales.MesWmProductSalesLineApi;
-import cn.iocoder.yudao.module.mes.api.salesnotice.MesWmSalesNoticeApi;
import cn.iocoder.yudao.module.mes.api.wms.MesWmStockApi;
import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@@ -63,12 +60,6 @@
private MdmItemApi mdmItemApi;
@Resource
private AdminUserApi adminUserApi;
- @Resource
- private MesWmSalesNoticeApi salesNoticeApi;
- @Resource
- private MesWmProductSalesLineApi productSalesLineApi;
- @Resource
- private MesProMpsApi mpsApi;
@Resource
private StorageAttachmentApi storageAttachmentApi;
@Resource
@@ -155,14 +146,11 @@
// 2. 鎵归噺鏌ヨ鍏宠仈鏁版嵁
Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(
convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId));
- Map<Long, String> batchCodeMap = productSalesLineApi.getBatchCodesBySaleOrderItemIds(
- convertSet(saleOrderItemList, ErpSaleOrderItemDO::getId));
Map<Long, MdmUnitMeasureRespDTO> unitMeasureMap = mdmUnitMeasureApi.getUnitMeasureMap(
convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductUnitId));
// 3. 杞崲璁㈠崟椤�
List<ErpSaleOrderRespVO.Item> itemVOList = BeanUtils.toBean(saleOrderItemList, ErpSaleOrderRespVO.Item.class, item -> {
item.setStockCount(mesWmStockApi.getStockQuantity(item.getProductId()));
- item.setBatchCode(batchCodeMap.get(item.getId()));
MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem ->
item.setProductName(mdmItem.getName()).setProductBarCode(mdmItem.getBarCode())
.setProductSpecification(mdmItem.getSpecification()));
@@ -213,54 +201,13 @@
// 1.4 绠$悊鍛樹俊鎭�
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(pageResult.getList(), saleOrder -> Long.parseLong(saleOrder.getCreator())));
- // 1.5 鍙戣揣閫氱煡鍗曚俊鎭�
- Map<Long, Boolean> salesNoticeMap = salesNoticeApi.checkSalesNoticeBySaleOrderIds(
- convertSet(pageResult.getList(), ErpSaleOrderDO::getId));
- // 1.6 鍑哄簱鎵瑰彿
- Map<Long, String> batchCodeMap = productSalesLineApi.getBatchCodesBySaleOrderItemIds(
- convertSet(saleOrderItemList, ErpSaleOrderItemDO::getId));
- // 1.7 璁¢噺鍗曚綅
+ // 1.5 璁¢噺鍗曚綅
Map<Long, MdmUnitMeasureRespDTO> unitMeasureMap = mdmUnitMeasureApi.getUnitMeasureMap(
convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductUnitId));
- // 1.8 妫�鏌ユ槸鍚﹀彲浠ョ敓鎴愬彂璐ч�氱煡鍗曪紙闇�瑕佺敓浜х殑鏄庣粏瀵瑰簲鐨� MPS 鏄惁宸插畬鎴愶級
- // 绛涢�夊嚭闇�瑕佺敓浜х殑鏄庣粏ID
- List<Long> needProductionItemIds = saleOrderItemList.stream()
- .filter(item -> item.getNeedProduction() != null && item.getNeedProduction() == 1)
- .map(ErpSaleOrderItemDO::getId)
- .toList();
- Map<Long, Boolean> canCreateSalesNoticeMap = new java.util.HashMap<>();
- if (!needProductionItemIds.isEmpty()) {
- // 鎸夎鍗曞垎缁勬槑缁咺D
- Map<Long, List<Long>> orderItemIdsMap = new java.util.HashMap<>();
- for (ErpSaleOrderItemDO item : saleOrderItemList) {
- orderItemIdsMap.computeIfAbsent(item.getOrderId(), k -> new java.util.ArrayList<>())
- .add(item.getId());
- }
- // 妫�鏌ユ瘡涓鍗�
- for (Map.Entry<Long, List<Long>> entry : orderItemIdsMap.entrySet()) {
- List<Long> itemIds = entry.getValue().stream()
- .filter(id -> {
- ErpSaleOrderItemDO item = saleOrderItemList.stream()
- .filter(i -> i.getId().equals(id))
- .findFirst().orElse(null);
- return item != null && item.getNeedProduction() != null && item.getNeedProduction() == 1;
- }
- ).toList();
- if (itemIds.isEmpty()) {
- canCreateSalesNoticeMap.put(entry.getKey(), true);
- } else {
- canCreateSalesNoticeMap.put(entry.getKey(), mpsApi.checkCanCreateSalesNotice(itemIds));
- }
- }
- } else {
- // 娌℃湁闇�瑕佺敓浜х殑鏄庣粏锛岄兘鍙互鐢熸垚鍙戣揣閫氱煡鍗�
- pageResult.getList().forEach(order -> canCreateSalesNoticeMap.put(order.getId(), true));
- }
// 2. 寮�濮嬫嫾鎺�
return BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class, saleOrder -> {
saleOrder.setItems(BeanUtils.toBean(saleOrderItemMap.get(saleOrder.getId()), ErpSaleOrderRespVO.Item.class,
item -> {
- item.setBatchCode(batchCodeMap.get(item.getId()));
MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem ->
item.setProductName(mdmItem.getName()).setProductBarCode(mdmItem.getBarCode())
.setProductSpecification(mdmItem.getSpecification()));
@@ -270,10 +217,6 @@
saleOrder.setProductNames(CollUtil.join(saleOrder.getItems(), "锛�", ErpSaleOrderRespVO.Item::getProductName));
MapUtils.findAndThen(customerMap, saleOrder.getCustomerId(), supplier -> saleOrder.setCustomerName(supplier.getName()));
MapUtils.findAndThen(userMap, Long.parseLong(saleOrder.getCreator()), user -> saleOrder.setCreatorName(user.getNickname()));
- // 璁剧疆鏄惁宸茬敓鎴愬彂璐ч�氱煡鍗�
- saleOrder.setHasSalesNotice(salesNoticeMap.getOrDefault(saleOrder.getId(), false));
- // 璁剧疆鏄惁鍙互鐢熸垚鍙戣揣閫氱煡鍗曪細宸茬敓鎴愬彂璐ч�氱煡鍗曟椂涓嶆樉绀烘寜閽�
- saleOrder.setCanCreateSalesNotice(!saleOrder.getHasSalesNotice() && canCreateSalesNoticeMap.getOrDefault(saleOrder.getId(), true));
// 璁剧疆鏄惁鏈夐渶瑕佺敓浜х殑鏄庣粏
boolean hasNeedProduction = saleOrder.getItems().stream()
.anyMatch(item -> item.getNeedProduction() != null && item.getNeedProduction() == 1);
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
index dd38717..73e35e7 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
@@ -104,18 +104,10 @@
@Schema(description = "鍑哄簱鐘舵��", example = "0")
private Integer outStatus;
- // ========== 鍙戣揣閫氱煡 ==========
-
- @Schema(description = "鏄惁宸茬敓鎴愬彂璐ч�氱煡鍗�", example = "false")
- private Boolean hasSalesNotice;
-
- @Schema(description = "鏄惁鍙互鐢熸垚鍙戣揣閫氱煡鍗曪紙鏈夐渶瑕佺敓浜т笖鏈畬鎴愮殑鏄庣粏鏃朵负 false锛�", example = "true")
- private Boolean canCreateSalesNotice;
+ // ========== 鐢熶骇鍏宠仈 ==========
@Schema(description = "鏄惁鏈夐渶瑕佺敓浜х殑鏄庣粏锛�0=鍚� 1=鏄級", example = "1")
private Integer needProduction;
-
- // ========== 鐢熶骇鍏宠仈 ==========
@Schema(description = "鐢熶骇鐘舵�侊細0-鏈畬鎴愶紝1-宸插畬鎴�", example = "1")
private Integer productionStatus;
@@ -163,11 +155,6 @@
@Schema(description = "鍏宠仈鐨� MPS 缂栧彿", example = "1024")
private Long mpsId;
-
- // ========== 鍑哄簱鎵瑰彿 ==========
-
- @Schema(description = "鍑哄簱鎵瑰彿", example = "B2026001銆丅2026002")
- private String batchCode;
// ========== 鍏宠仈瀛楁 ==========
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApi.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApi.java
deleted file mode 100644
index 42d7636..0000000
--- a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApi.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.mes.api.productsales;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * MES 閿�鍞嚭搴撳崟琛� API 鎺ュ彛
- *
- * @author 瓒呯骇绠$悊鍛�
- */
-public interface MesWmProductSalesLineApi {
-
- /**
- * 鏍规嵁閿�鍞鍗曟槑缁� ID 鍒楄〃鏌ヨ鍑哄簱鎵瑰彿
- *
- * @param saleOrderItemIds 閿�鍞鍗曟槑缁� ID 鍒楄〃
- * @return Map<閿�鍞鍗曟槑缁咺D, 鎵瑰彿涓茶仈瀛楃涓�>
- */
- Map<Long, String> getBatchCodesBySaleOrderItemIds(Collection<Long> saleOrderItemIds);
-
-}
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/returnsales/dto/MesWmReturnSalesCreateReqDTO.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/returnsales/dto/MesWmReturnSalesCreateReqDTO.java
index ce7e494..bdc8482 100644
--- a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/returnsales/dto/MesWmReturnSalesCreateReqDTO.java
+++ b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/returnsales/dto/MesWmReturnSalesCreateReqDTO.java
@@ -20,12 +20,6 @@
@Schema(description = "閫�璐у崟鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鍞悗閫�璐�")
private String name;
- @Schema(description = "閿�鍞鍗� ID", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO202603010001")
- private String salesOrderCode;
-
@Schema(description = "瀹㈡埛 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long clientId;
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApi.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApi.java
deleted file mode 100644
index b6c5825..0000000
--- a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApi.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.mes.api.salesnotice;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * MES 鍙戣揣閫氱煡鍗� API 鎺ュ彛
- *
- * @author 瓒呯骇绠$悊鍛�
- */
-public interface MesWmSalesNoticeApi {
-
- /**
- * 鏍规嵁閿�鍞鍗� ID 鍒楄〃妫�鏌ユ槸鍚﹀凡鐢熸垚鍙戣揣閫氱煡鍗�
- *
- * @param saleOrderIds 閿�鍞鍗� ID 鍒楄〃
- * @return Map<閿�鍞鍗旾D, 鏄惁宸茬敓鎴愬彂璐ч�氱煡鍗�>
- */
- Map<Long, Boolean> checkSalesNoticeBySaleOrderIds(Collection<Long> saleOrderIds);
-
-}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApiImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApiImpl.java
deleted file mode 100644
index 005e87e..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/productsales/MesWmProductSalesLineApiImpl.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package cn.iocoder.yudao.module.mes.api.productsales;
-
-import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesLineMapper;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * MES 閿�鍞嚭搴撳崟琛� API 瀹炵幇绫�
- *
- * @author 瓒呯骇绠$悊鍛�
- */
-@Service
-@Validated
-public class MesWmProductSalesLineApiImpl implements MesWmProductSalesLineApi {
-
- @Resource
- private MesWmProductSalesLineMapper productSalesLineMapper;
-
- @Override
- public Map<Long, String> getBatchCodesBySaleOrderItemIds(Collection<Long> saleOrderItemIds) {
- return productSalesLineMapper.selectBatchCodesBySaleOrderItemIds(saleOrderItemIds);
- }
-
-}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApiImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApiImpl.java
deleted file mode 100644
index 943fb7b..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/salesnotice/MesWmSalesNoticeApiImpl.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package cn.iocoder.yudao.module.mes.api.salesnotice;
-
-import cn.iocoder.yudao.module.mes.dal.mysql.wm.salesnotice.MesWmSalesNoticeMapper;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * MES 鍙戣揣閫氱煡鍗� API 瀹炵幇绫�
- *
- * @author 瓒呯骇绠$悊鍛�
- */
-@Service
-@Validated
-public class MesWmSalesNoticeApiImpl implements MesWmSalesNoticeApi {
-
- @Resource
- private MesWmSalesNoticeMapper salesNoticeMapper;
-
- @Override
- public Map<Long, Boolean> checkSalesNoticeBySaleOrderIds(Collection<Long> saleOrderIds) {
- if (saleOrderIds == null || saleOrderIds.isEmpty()) {
- return Collections.emptyMap();
- }
- // 鏌ヨ宸插瓨鍦ㄧ殑閿�鍞鍗� ID
- List<Long> existingSaleOrderIds = salesNoticeMapper.selectExistingSaleOrderIds(saleOrderIds);
- // 鏋勫缓杩斿洖缁撴灉
- Map<Long, Boolean> result = new HashMap<>();
- for (Long saleOrderId : saleOrderIds) {
- result.put(saleOrderId, existingSaleOrderIds.contains(saleOrderId));
- }
- return result;
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/home/vo/MesBagCodeHomeSummaryRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/home/vo/MesBagCodeHomeSummaryRespVO.java
index cf6c323..4bb5491 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/home/vo/MesBagCodeHomeSummaryRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/home/vo/MesBagCodeHomeSummaryRespVO.java
@@ -37,6 +37,25 @@
@Schema(description = "鎵樼洏鐮佹�绘暟", requiredMode = Schema.RequiredMode.REQUIRED, example = "800")
private Long palletCount;
+ // ========== 鍑哄簱娴侀�� ==========
+
+ @Schema(description = "鍙戣揣閫氱煡鍗曟暟锛坢es_wm_sales_notice锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+ private Long salesNoticeCount;
+
+ @Schema(description = "閿�鍞嚭搴撳崟鏁帮紙mes_wm_product_sales锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+ private Long productSalesCount;
+
+ @Schema(description = "閿�鍞��璐у崟鏁帮紙mes_wm_return_sales锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ private Long returnSalesCount;
+
+ // ========== 浠撳偍棰勮 / 璐ㄩ噺 ==========
+
+ @Schema(description = "鏈鐞嗗簱瀛橀璀︽暟锛坢es_wm_stock_warning.status=10锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "3")
+ private Long stockWarningPendingCount;
+
+ @Schema(description = "寰呰瘎瀹′笉鍚堟牸鍝佸崟鏁帮紙mes_qc_ncr.status=0锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+ private Long ncrPendingCount;
+
// ========== 鐘舵�佸垎甯� ==========
@Schema(description = "鎵规鐘舵�佸垎甯�")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/MesProScanEventController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/MesProScanEventController.java
index 4566021..f3dfe25 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/MesProScanEventController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/MesProScanEventController.java
@@ -23,7 +23,7 @@
@RestController @RequestMapping("/mes/pro/scan-in")
public class MesProScanEventController {
@Resource private MesProScanEventService service;
- @PostMapping("/inbound") @PreAuthorize("@ss.hasPermission('mes:pro-scan-in:inbound')") @Operation(summary = "琚嬬爜鎵爜鍏ュ簱")
+ @PostMapping("/inbound") @PreAuthorize("@ss.hasPermission('mes:pro-scan-in:inbound')") @Operation(summary = "杩芥函鐮佹壂鐮佸叆搴擄紙琚嬬爜/鎵樼洏鐮�/鎵规鐮侊級")
public CommonResult<MesProScanEventRespVO> inbound(@Valid @RequestBody MesProScanEventCreateReqVO req) {
return success(BeanUtils.toBean(service.createInbound(req), MesProScanEventRespVO.class));
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventCreateReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventCreateReqVO.java
index 99ded7b..c6c2565 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventCreateReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventCreateReqVO.java
@@ -8,9 +8,19 @@
@Data
public class MesProScanEventCreateReqVO {
@NotBlank private String eventId;
+ /**
+ * 鎵爜鍐呭锛堣鐮� / 鎵樼洏鐮� / 鎵规鐮佺殑鐮佸�硷紝鍚复鏃剁爜锛�
+ */
@NotBlank private String bagCode;
+ /**
+ * 鎵爜绫诲瀷锛欱AG 琚嬬爜 / PALLET 鎵樼洏鐮� / BATCH 鎵规鐮侊紝榛樿 BAG
+ */
+ private String scanType;
@NotNull @DecimalMin("0.000001") private BigDecimal quantity;
- @NotBlank private String deviceCode;
+ /**
+ * 璁惧缂栫爜锛堜笉鍐嶅繀濉紝浜х嚎鎵爜浠ヤ骇绾�+搴撳尯搴撲綅瀹氫綅锛�
+ */
+ @Size(max = 64) private String deviceCode;
private String lineCode;
@NotNull private Long locationId;
@NotNull private Long areaId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventRespVO.java
index 18ca711..2cfb498 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/scan/vo/MesProScanEventRespVO.java
@@ -10,6 +10,7 @@
private Long id;
private String eventId;
private String bagCode;
+ private String scanType;
private String batchCode;
private BigDecimal quantity;
private String deviceCode;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java
index 2d35909..3bbd79e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java
@@ -1,6 +1,10 @@
package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO;
import cn.iocoder.yudao.module.mes.service.qc.seedquality.MesQcSeedQualityService;
import io.swagger.v3.oas.annotations.Operation;
@@ -16,6 +20,13 @@
@RestController @RequestMapping("/mes/qc/seed-quality") @Validated
public class MesQcSeedQualityController {
@Resource private MesQcSeedQualityService service;
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱绉嶅瓙璐ㄦ璁板綍鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:query')")
+ public CommonResult<PageResult<MesQcSeedQualityRespVO>> getQualityPage(@Valid MesQcSeedQualityPageReqVO pageReqVO) {
+ return success(BeanUtils.toBean(service.getQualityPage(pageReqVO), MesQcSeedQualityRespVO.class));
+ }
+
@PostMapping("/submit") @Operation(summary = "鎻愪氦绉嶅瓙璐ㄦ")
@PreAuthorize("@ss.hasPermission('mes:qc-seed-quality:submit')")
public CommonResult<Long> submit(@Valid @RequestBody MesQcSeedQualitySubmitReqVO reqVO) { return success(service.submit(reqVO)); }
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityPageReqVO.java
new file mode 100644
index 0000000..2645d67
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityPageReqVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 绉嶅瓙璐ㄦ璁板綍鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class MesQcSeedQualityPageReqVO extends PageParam {
+
+ @Schema(description = "璐ㄦ琚嬬爜")
+ private String code;
+
+ @Schema(description = "鐢熶骇鎵规")
+ private String batchCode;
+
+ @Schema(description = "妫�楠岀粨鏋滐細1鍚堟牸 2涓嶅悎鏍�")
+ private Integer result;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java
new file mode 100644
index 0000000..6102954
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualityRespVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - MES 绉嶅瓙璐ㄦ璁板綍 Response VO")
+@Data
+public class MesQcSeedQualityRespVO {
+
+ private Long id;
+ private String code;
+ private Long itemId;
+ private Long batchId;
+ private String batchCode;
+ private Integer result;
+ private String reason;
+ private Long inspectorId;
+ private LocalDateTime inspectedAt;
+ private LocalDateTime createTime;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java
index d3b0978..1d8d9d3 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/vo/MesQcSeedQualitySubmitReqVO.java
@@ -9,10 +9,11 @@
@Data
public class MesQcSeedQualitySubmitReqVO {
@NotBlank private String code;
- @NotNull private Long itemId;
private String batchCode;
@NotEmpty @Valid private List<Indicator> indicators;
private String reason;
+ /** 鐩爣鍚堟牸搴撶紪鍙凤紙璐ㄦ鍚堟牸鍚庡叆璇ヤ粨搴擄級锛屽繀椤绘槸浠撳簱绫诲瀷涓哄悎鏍煎簱(20)鐨勪粨搴� */
+ @NotNull private Long qualifiedWarehouseId;
@Data public static class Indicator {
@NotBlank private String code;
@NotNull @DecimalMin("0") private BigDecimal value;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/batch/MesTraceBatchController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/batch/MesTraceBatchController.java
new file mode 100644
index 0000000..4ce1163
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/trace/batch/MesTraceBatchController.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.mes.controller.admin.trace.batch;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.mes.controller.pub.trace.vo.MesProTracePublicRespVO;
+import cn.iocoder.yudao.module.mes.service.trace.MesProTracePublicService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.constraints.NotBlank;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "绠$悊鍚庡彴 - MES 鎵规杩芥函")
+@RestController
+@RequestMapping("/mes/trace/batch")
+@Validated
+public class MesTraceBatchController {
+
+ @Resource
+ private MesProTracePublicService traceService;
+
+ @GetMapping("/detail")
+ @Operation(summary = "鏌ヨ缁熶竴鎵规杩芥函璇︽儏")
+ @Parameter(name = "code", description = "鎵规鐮併�佷复鏃舵壒娆$爜銆佽鐮佹垨鎵樼洏鐮�", required = true,
+ example = "BAG-202608280001")
+ @PreAuthorize("@ss.hasPermission('mes:trace-batch:query')")
+ public CommonResult<MesProTracePublicRespVO> getBatchTraceDetail(
+ @RequestParam("code") @NotBlank(message = "杩芥函鐮佷笉鑳戒负绌�") String code) {
+ return success(traceService.queryTrace(code));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java
index 26cb544..6c23287 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java
@@ -14,6 +14,9 @@
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockBagPageReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockBagRespVO;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmStockSummaryRespVO;
import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi;
import cn.iocoder.yudao.module.srm.api.supplier.dto.SrmSupplierRespDTO;
@@ -21,6 +24,7 @@
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
@@ -72,6 +76,8 @@
private MesWmWarehouseAreaService areaService;
@Resource
private SrmSupplierApi srmSupplierApi;
+ @Resource
+ private MesWmMaterialStockBagMapper materialStockBagMapper;
@GetMapping("/get")
@Operation(summary = "鑾峰緱搴撳瓨璁板綍")
@@ -92,6 +98,17 @@
@Valid MesWmMaterialStockPageReqVO pageReqVO) {
PageResult<MesWmMaterialStockDO> pageResult = materialStockService.getMaterialStockPage(pageReqVO);
return success(new PageResult<>(buildRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ @GetMapping("/bag-details")
+ @Operation(summary = "鏌ヨ搴撳瓨琚嬬爜鏄庣粏")
+ @PreAuthorize("@ss.hasPermission('mes:wm-material-stock:query')")
+ public CommonResult<PageResult<MesWmMaterialStockBagRespVO>> getMaterialStockBagDetails(
+ @Valid MesWmMaterialStockBagPageReqVO pageReqVO) {
+ PageResult<MesWmMaterialStockBagRespVO> result = new PageResult<>();
+ PageResult<cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO> page =
+ materialStockBagMapper.selectPage(pageReqVO);
+ return success(new PageResult<>(BeanUtils.toBean(page.getList(), MesWmMaterialStockBagRespVO.class), page.getTotal()));
}
@PutMapping("/update-frozen")
@@ -179,6 +196,9 @@
convertSet(list, MesWmMaterialStockDO::getLocationId));
Map<Long, MesWmWarehouseAreaDO> areaMap = areaService.getWarehouseAreaMap(
convertSet(list, MesWmMaterialStockDO::getAreaId));
+ Map<Long, Long> bagCountMap = materialStockBagMapper.selectListByMaterialStockIds(
+ convertSet(list, MesWmMaterialStockDO::getId)).stream()
+ .collect(Collectors.groupingBy(MesWmMaterialStockBagDO::getMaterialStockId, Collectors.counting()));
Map<Long, SrmSupplierRespDTO> vendorMap = srmSupplierApi.getSupplierList(
convertSet(list, MesWmMaterialStockDO::getVendorId)).getCheckedData().stream()
.collect(Collectors.toMap(SrmSupplierRespDTO::getId, s -> s));
@@ -197,6 +217,8 @@
area -> vo.setAreaName(area.getName()));
MapUtils.findAndThen(vendorMap, vo.getVendorId(),
vendor -> vo.setVendorName(vendor.getName()));
+ vo.setBagCount(bagCountMap.getOrDefault(vo.getId(), 0L));
+ vo.setBagDetailSupported(bagCountMap.containsKey(vo.getId()));
// 璁$畻鍙敤閲� = 鍦ㄥ簱鏁伴噺 - 鍐荤粨鏁伴噺 - 鍗犵敤閲�
BigDecimal quantity = vo.getQuantity() != null ? vo.getQuantity() : BigDecimal.ZERO;
BigDecimal frozenQty = vo.getFrozenQuantity() != null ? vo.getFrozenQuantity() : BigDecimal.ZERO;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagPageReqVO.java
new file mode 100644
index 0000000..7b6c868
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagPageReqVO.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Schema(description = "绠$悊鍚庡彴 - 搴撳瓨琚嬬爜鏄庣粏鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class MesWmMaterialStockBagPageReqVO extends PageParam {
+
+ @Schema(description = "搴撳瓨姹囨�昏褰旾D", requiredMode = Schema.RequiredMode.REQUIRED)
+ private Long materialStockId;
+
+ @Schema(description = "琚嬬爜")
+ private String bagCode;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagRespVO.java
new file mode 100644
index 0000000..e1b8041
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockBagRespVO.java
@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo;
+
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - 搴撳瓨琚嬬爜鏄庣粏 Response VO")
+@Data
+public class MesWmMaterialStockBagRespVO {
+ private Long id;
+ private Long materialStockId;
+ private Long bagCodeId;
+ private String bagCode;
+ private Long itemId;
+ private Long batchId;
+ private String batchCode;
+ private Long warehouseId;
+ private Long locationId;
+ private Long areaId;
+ private Integer stockState;
+ private Integer status;
+ private BigDecimal quantity;
+ private Boolean frozen;
+ private LocalDateTime inboundTime;
+ private LocalDateTime outboundTime;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java
index 8be7fce..cc8d0b6 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java
@@ -12,6 +12,9 @@
@Schema(description = "浠撳簱缂栧彿")
private Long warehouseId;
+ @Schema(description = "浠撳簱绫诲瀷锛�10鏆傚瓨搴擄紝20鍚堟牸搴擄紙鎸夌被鍨嬭繃婊や粨搴擄紝涓� warehouseId 浜岄�変竴锛�", example = "20")
+ private Integer warehouseType;
+
@Schema(description = "搴撳尯缂栧彿")
private Long locationId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java
index 6549016..c4b9862 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java
@@ -39,6 +39,9 @@
@Schema(description = "浠撳簱缂栧彿", example = "1")
private Long warehouseId;
+ @Schema(description = "浠撳簱绫诲瀷锛�10鏆傚瓨搴擄紝20鍚堟牸搴擄紙鎸夌被鍨嬭繃婊や粨搴擄紝涓� warehouseId 浜岄�変竴锛�", example = "20")
+ private Integer warehouseType;
+
@Schema(description = "搴撳尯缂栧彿", example = "1")
private Long locationId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java
index 5cec30c..c3d901e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java
@@ -46,6 +46,12 @@
@ExcelProperty("鎵规鍙�")
private String batchCode;
+ @Schema(description = "褰撳墠琚嬬爜鏁伴噺", example = "10")
+ private Long bagCount;
+
+ @Schema(description = "鏄惁瀛樺湪琚嬬爜鏄庣粏", example = "true")
+ private Boolean bagDetailSupported;
+
@Schema(description = "浠撳簱缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long warehouseId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java
index a3f44a6..885e7fd 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java
@@ -42,10 +42,6 @@
@ExcelProperty("鍑哄簱鎿嶄綔浜�")
private String outboundUserName;
- @Schema(description = "閿�鍞鍗曞彿", example = "SO2026030001")
- @ExcelProperty("閿�鍞鍗曞彿")
- private String salesOrderCode;
-
@Schema(description = "鍑哄簱鏃ユ湡")
@ExcelProperty("鍑哄簱鏃ユ湡")
private LocalDateTime salesDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java
index 1c94e13..996c873 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java
@@ -26,9 +26,6 @@
@NotNull(message = "瀹㈡埛涓嶈兘涓虹┖")
private Long clientId;
- @Schema(description = "閿�鍞鍗曞彿", example = "SO2026030001")
- private String salesOrderCode;
-
@Schema(description = "鍑哄簱鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "鍑哄簱鏃ユ湡涓嶈兘涓虹┖")
private LocalDateTime salesDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesPageReqVO.java
index 1008ffc..f581a93 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesPageReqVO.java
@@ -26,12 +26,6 @@
@Schema(description = "閫�璐у崟鍚嶇О", example = "閿�鍞��璐�")
private String name;
- @Schema(description = "閿�鍞鍗� ID", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO202603010001")
- private String salesOrderCode;
-
@Schema(description = "瀹㈡埛 ID", example = "1")
private Long clientId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesRespVO.java
index 8d50c3c..dbd8d3f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesRespVO.java
@@ -24,12 +24,6 @@
@Schema(description = "閫�璐у崟鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "閿�鍞��璐�")
private String name;
- @Schema(description = "閿�鍞鍗� ID", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO202603010001")
- private String salesOrderCode;
-
@Schema(description = "瀹㈡埛 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long clientId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesSaveReqVO.java
index b77d34f..a267c62 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/MesWmReturnSalesSaveReqVO.java
@@ -27,12 +27,6 @@
@NotBlank(message = "閫�璐у崟鍚嶇О涓嶈兘涓虹┖")
private String name;
- @Schema(description = "閿�鍞鍗� ID", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO202603010001")
- private String salesOrderCode;
-
@Schema(description = "瀹㈡埛 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "瀹㈡埛 ID 涓嶈兘涓虹┖")
private Long clientId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/MesWmSalesNoticeController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/MesWmSalesNoticeController.java
index 2bf826e..17e2662 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/MesWmSalesNoticeController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/MesWmSalesNoticeController.java
@@ -111,14 +111,6 @@
return success(true);
}
- @PostMapping("/generate-from-sale-order")
- @Operation(summary = "浠庨攢鍞鍗曠敓鎴愬彂璐ч�氱煡鍗�")
- @PreAuthorize("@ss.hasPermission('mes:wm-sales-notice:create')")
- public CommonResult<Long> generateFromSaleOrder(@RequestBody Map<String, Long> params) {
- Long saleOrderId = params.get("saleOrderId");
- return success(salesNoticeService.generateSalesNoticeFromSaleOrder(saleOrderId));
- }
-
@PostMapping("/generate-product-sales")
@Operation(summary = "浠庡彂璐ч�氱煡鍗曠敓鎴愰攢鍞嚭搴撳崟")
@Parameter(name = "id", description = "鍙戣揣閫氱煡鍗曠紪鍙�", required = true)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticePageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticePageReqVO.java
index f3ce710..80d4881 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticePageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticePageReqVO.java
@@ -18,9 +18,6 @@
@Schema(description = "閫氱煡鍗曞悕绉�", example = "娴嬭瘯鍙戣揣閫氱煡")
private String name;
- @Schema(description = "閿�鍞鍗曠紪鍙�", example = "SO202603010001")
- private String saleOrderCode;
-
@Schema(description = "瀹㈡埛缂栧彿", example = "1")
private Long clientId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeRespVO.java
index ad39bbd..53445d2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeRespVO.java
@@ -31,13 +31,6 @@
@ExcelProperty("瀹㈡埛鍚嶇О")
private String clientName;
- @Schema(description = "閿�鍞鍗旾D", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曞彿", example = "SO202603010001")
- @ExcelProperty("閿�鍞鍗曞彿")
- private String saleOrderCode;
-
@Schema(description = "鍙戣揣鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("鍙戣揣鏃ユ湡")
private LocalDateTime salesDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeSaveReqVO.java
index 4ffa6e2..444d3d9 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/MesWmSalesNoticeSaveReqVO.java
@@ -26,12 +26,6 @@
@NotNull(message = "瀹㈡埛缂栧彿涓嶈兘涓虹┖")
private Long clientId;
- @Schema(description = "閿�鍞鍗旾D", example = "1")
- private Long saleOrderId;
-
- @Schema(description = "閿�鍞鍗曞彿", example = "SO202603010001")
- private String saleOrderCode;
-
@Schema(description = "鍙戣揣鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "鍙戣揣鏃ユ湡涓嶈兘涓虹┖")
private LocalDateTime salesDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineRespVO.java
index 93201b1..3a3f837 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineRespVO.java
@@ -16,9 +16,6 @@
@Schema(description = "鍙戣揣閫氱煡鍗曠紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long noticeId;
- @Schema(description = "閿�鍞鍗曟槑缁咺D", example = "1")
- private Long saleOrderItemId;
-
@Schema(description = "鐗╂枡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long itemId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java
index 35af7ca..d6ba341 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java
@@ -18,9 +18,6 @@
@NotNull(message = "鍙戣揣閫氱煡鍗曠紪鍙蜂笉鑳戒负绌�")
private Long noticeId;
- @Schema(description = "閿�鍞鍗曟槑缁咺D", example = "1")
- private Long saleOrderItemId;
-
@Schema(description = "鐗╂枡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "鐗╂枡缂栧彿涓嶈兘涓虹┖")
private Long itemId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionPageReqVO.java
index 0cabd59..20b4b0f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionPageReqVO.java
@@ -26,6 +26,9 @@
@Schema(description = "鎵规鍙�", example = "BATCH001")
private String batchCode;
+ @Schema(description = "琚嬬爜", example = "BG202608180001")
+ private String bagCode;
+
@Schema(description = "浠撳簱ID", example = "1")
private Long warehouseId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java
index e40218c..3ec6568 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java
@@ -51,6 +51,12 @@
@Schema(description = "鎵规鍙�", example = "BATCH001")
private String batchCode;
+ @Schema(description = "琚嬬爜ID", example = "1")
+ private Long bagCodeId;
+
+ @Schema(description = "琚嬬爜", example = "BG202608180001")
+ private String bagCode;
+
// ========== 搴撳瓨浣嶇疆 ==========
@Schema(description = "浠撳簱ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehousePageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehousePageReqVO.java
index e6861e3..1b2e826 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehousePageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehousePageReqVO.java
@@ -21,4 +21,7 @@
@Schema(description = "鏄惁鍐荤粨", example = "false")
private Boolean frozen;
+ @Schema(description = "浠撳簱绫诲瀷锛�10鏆傚瓨搴� 20鍚堟牸搴�", example = "20")
+ private Integer type;
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseRespVO.java
index 6c85e3b..10edec2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseRespVO.java
@@ -40,6 +40,10 @@
@ExcelProperty("鏄惁鍐荤粨")
private Boolean frozen;
+ @Schema(description = "浠撳簱绫诲瀷锛�10鏆傚瓨搴� 20鍚堟牸搴�", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+ @ExcelProperty("浠撳簱绫诲瀷")
+ private Integer type;
+
@Schema(description = "澶囨敞", example = "澶囨敞")
@ExcelProperty("澶囨敞")
private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseSaveReqVO.java
index a05c861..ddfe51e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/warehouse/vo/MesWmWarehouseSaveReqVO.java
@@ -35,6 +35,10 @@
@NotNull(message = "鏄惁鍐荤粨涓嶈兘涓虹┖")
private Boolean frozen;
+ @Schema(description = "浠撳簱绫诲瀷锛�10鏆傚瓨搴� 20鍚堟牸搴�", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+ @NotNull(message = "浠撳簱绫诲瀷涓嶈兘涓虹┖")
+ private Integer type;
+
@Schema(description = "澶囨敞", example = "澶囨敞")
private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicRespVO.java
index 6f5d570..bf9329f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicRespVO.java
@@ -119,6 +119,44 @@
@Schema(description = "鍔犲伐娴佽浆锛堝彲閫夛級")
private List<MesWmBatchProcessTraceRespVO> processTraces;
+ @Schema(description = "杩芥函鏃堕棿绾�")
+ private List<TimelineVO> timeline;
+
+ @Schema(description = "杩芥函鍐崇瓥鎽樿")
+ private DecisionVO decision;
+
+ @Schema(description = "杩芥函鏃堕棿绾夸簨浠�")
+ @Data
+ public static class TimelineVO {
+ @Schema(description = "闃舵")
+ private String stage;
+ @Schema(description = "浜嬩欢绫诲瀷")
+ private String eventType;
+ @Schema(description = "浜嬩欢鍚嶇О")
+ private String eventName;
+ @Schema(description = "浜嬩欢鏃堕棿")
+ private LocalDateTime eventTime;
+ @Schema(description = "鏁伴噺")
+ private BigDecimal quantity;
+ @Schema(description = "鐘舵��")
+ private String status;
+ }
+
+ @Schema(description = "杩芥函鍐崇瓥鎽樿")
+ @Data
+ public static class DecisionVO {
+ @Schema(description = "璐ㄩ噺鏄惁瀛樺湪椋庨櫓")
+ private Boolean qualityRisk;
+ @Schema(description = "搴撳瓨鍏ュ簱鏁伴噺")
+ private BigDecimal inboundQuantity;
+ @Schema(description = "閿�鍞幓鍚戞暟閲�")
+ private Integer salesTargetCount;
+ @Schema(description = "娑堣垂鑰呮壂鐮佹鏁�")
+ private Long consumerScanCount;
+ @Schema(description = "椋庨櫓绛夌骇")
+ private String riskLevel;
+ }
+
@Schema(description = "鐢熶骇浜哄憳")
@Data
public static class WorkerVO {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java
index 50e4df7..7da62ad 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/bagcode/MesProBagCodeDO.java
@@ -29,6 +29,7 @@
private Long palletId;
private String palletCode;
private Integer status;
+ private Integer qcStatus;
private LocalDateTime printTime;
private LocalDateTime cancelTime;
private String cancelReason;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java
index 43024f1..dfeae62 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/pallet/MesProPalletDO.java
@@ -62,6 +62,14 @@
*/
private Integer bagCount;
/**
+ * 鏈�杩戝叆搴撴壂鐮佷簨浠剁紪鍙凤紙鏁存墭鎵爜鍏ュ簱鍚庡洖鍐欙紝鐢ㄤ簬闃查噸澶嶅叆搴擄級
+ */
+ private Long inboundEventId;
+ /**
+ * 鏈�杩戝叆搴撴椂闂�
+ */
+ private java.time.LocalDateTime inboundTime;
+ /**
* 鏄惁鑷姩鐢熸垚锛堟寜鏈夋晥琚嬬爜绱闃堝�肩敓鎴愶紝瀹归噺鍥哄畾涓洪槇鍊硷級
*/
private Boolean autoGenerated;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/scan/MesProScanEventDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/scan/MesProScanEventDO.java
index d0be21d..6bf1274 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/scan/MesProScanEventDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/scan/MesProScanEventDO.java
@@ -14,7 +14,14 @@
public class MesProScanEventDO extends BaseDO {
@TableId private Long id;
private String eventId;
+ /**
+ * 鎵爜鍐呭锛堣鐮� / 鎵樼洏鐮� / 鎵规鐮佺殑鐮佸�硷紝鍚复鏃剁爜锛�
+ */
private String bagCode;
+ /**
+ * 鎵爜绫诲瀷锛欱AG 琚嬬爜 / PALLET 鎵樼洏鐮� / BATCH 鎵规鐮�
+ */
+ private String scanType;
private Long bagCodeId;
private Long batchId;
private String batchCode;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java
index 0c79b74..1ca77b7 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/seedquality/MesQcSeedQualityDO.java
@@ -12,6 +12,8 @@
@TableId private Long id;
private String code;
private Long itemId;
+ /** 鐢熶骇鎵规 ID */
+ private Long batchId;
private String batchCode;
private Integer result;
private String reason;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java
index ac0e186..3f67ca8 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java
@@ -3,6 +3,7 @@
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO;
@@ -34,6 +35,12 @@
@TableId
private Long id;
/**
+ * 瀵瑰簲鐢熶骇鎵规 ID
+ *
+ * 鍏宠仈 {@link MesProBatchDO#getId()}
+ */
+ private Long proBatchId;
+ /**
* 鎵规缂栫爜
*/
private String code;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstockbag/MesWmMaterialStockBagDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstockbag/MesWmMaterialStockBagDO.java
new file mode 100644
index 0000000..fb40f0b
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstockbag/MesWmMaterialStockBagDO.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * MES 搴撳瓨琚嬬爜鏄庣粏 DO
+ */
+@TableName("mes_wm_material_stock_bag")
+@KeySequence("mes_wm_material_stock_bag_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MesWmMaterialStockBagDO extends BaseDO {
+
+ @TableId
+ private Long id;
+ private Long materialStockId;
+ private Long bagCodeId;
+ private String bagCode;
+ private Long itemId;
+ private Long batchId;
+ private String batchCode;
+ private Long vendorId;
+ private Long warehouseId;
+ private Long locationId;
+ private Long areaId;
+ private Integer stockState;
+ private Integer status;
+ private BigDecimal quantity;
+ private Boolean frozen;
+ private Long lastTransactionId;
+ private LocalDateTime inboundTime;
+ private LocalDateTime outboundTime;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java
index d266de7..211f40e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java
@@ -50,14 +50,6 @@
*/
private String clientName;
/**
- * 閿�鍞鍗旾D
- */
- private Long saleOrderId;
- /**
- * 閿�鍞鍗曞彿
- */
- private String salesOrderCode;
- /**
* 鍙戣揣閫氱煡鍗� ID
*
* 鍏宠仈 {@link MesWmSalesNoticeDO#getId()}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java
index f76011b..29fd0a7 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java
@@ -42,10 +42,6 @@
*/
private Long salesId;
/**
- * 閿�鍞鍗曟槑缁咺D
- */
- private Long saleOrderItemId;
- /**
* 鍙戣揣閫氱煡鍗曡ID
*
* 鍏宠仈 {@link MesWmSalesNoticeLineDO#getId()}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesDO.java
index aa3bb74..d26f69b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesDO.java
@@ -39,14 +39,6 @@
*/
private String name;
/**
- * 閿�鍞鍗� ID
- */
- private Long saleOrderId;
- /**
- * 閿�鍞鍗曠紪鍙�
- */
- private String salesOrderCode;
- /**
* 瀹㈡埛 ID
*
* 鍏宠仈 CRM 瀹㈡埛 {@link cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO#getId()}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeDO.java
index 4c69b80..a6d6c2d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeDO.java
@@ -42,14 +42,6 @@
*/
private Long clientId;
/**
- * 閿�鍞鍗旾D
- */
- private Long saleOrderId;
- /**
- * 閿�鍞鍗曞彿
- */
- private String saleOrderCode;
- /**
* 鍙戣揣鏃ユ湡
*/
private LocalDateTime salesDate;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeLineDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeLineDO.java
index 1219bf6..288cc75 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeLineDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/salesnotice/MesWmSalesNoticeLineDO.java
@@ -35,10 +35,6 @@
*/
private Long noticeId;
/**
- * 閿�鍞鍗曟槑缁咺D
- */
- private Long saleOrderItemId;
- /**
* 鐗╂枡缂栧彿
*
* 鍏宠仈 {@link MesMdItemDO#getId()}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java
index abfce45..8174699 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java
@@ -2,6 +2,9 @@
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
@@ -29,6 +32,28 @@
@TableId
private Long id;
/**
+ * 鐢熶骇鎵规 ID
+ *
+ * 鍏宠仈 {@link MesProBatchDO#getId()}
+ */
+ private Long proBatchId;
+ /**
+ * 琚嬬爜 ID
+ *
+ * 鍏宠仈 {@link MesProBagCodeDO#getId()}
+ */
+ private Long bagCodeId;
+ /**
+ * 鎵樼洏 ID
+ *
+ * 鍏宠仈 {@link MesProPalletDO#getId()}
+ */
+ private Long palletId;
+ /**
+ * 閿�鍞嚭搴撳崟 ID
+ */
+ private Long salesId;
+ /**
* 鎵规 UUID锛堢敤浜庢爣璁板悓涓�鎵规鐢熸垚鐨� SN 鐮侊級
*/
private String uuid;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java
index f574a36..b3cce53 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java
@@ -107,6 +107,10 @@
* 鍏宠仈 {@link MesWmBatchDO#getCode()}
*/
private String batchCode;
+ /** 琚嬬爜ID */
+ private Long bagCodeId;
+ /** 琚嬬爜 */
+ private String bagCode;
// ==================== 搴撳瓨浣嶇疆 ====================
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/warehouse/MesWmWarehouseDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/warehouse/MesWmWarehouseDO.java
index 0c8a9b2..b2f75da 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/warehouse/MesWmWarehouseDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/warehouse/MesWmWarehouseDO.java
@@ -62,6 +62,13 @@
*/
private Boolean frozen;
/**
+ * 浠撳簱绫诲瀷
+ *
+ * 鍏宠仈 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum}锛�
+ * 10 鏆傚瓨搴擄紙濡傝櫄鎷熺嚎杈逛粨搴擄紝瀛樻斁鎵爜鍏ュ簱寰呮/鏆傚瓨搴撳瓨锛夛紱20 鍚堟牸搴擄紙瀛樻斁璐ㄦ鍚堟牸銆佸彲鎷h揣搴撳瓨锛�
+ */
+ private Integer type;
+ /**
* 澶囨敞
*/
private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/home/MesBagCodeHomeStatisticsMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/home/MesBagCodeHomeStatisticsMapper.java
index e5a7643..5bb3749 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/home/MesBagCodeHomeStatisticsMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/home/MesBagCodeHomeStatisticsMapper.java
@@ -43,6 +43,23 @@
/** 缁熻鎵樼洏鐮佹�绘暟锛坢es_pro_pallet锛� */
Long selectPalletCount();
+ // ========== 鍑哄簱娴侀�� / 浠撳偍 / 璐ㄩ噺 ==========
+
+ /** 缁熻鍙戣揣閫氱煡鍗曟暟锛坢es_wm_sales_notice锛� */
+ Long selectSalesNoticeCount();
+
+ /** 缁熻閿�鍞嚭搴撳崟鏁帮紙mes_wm_product_sales锛� */
+ Long selectProductSalesCount();
+
+ /** 缁熻閿�鍞��璐у崟鏁帮紙mes_wm_return_sales锛� */
+ Long selectReturnSalesCount();
+
+ /** 缁熻鏈鐞嗗簱瀛橀璀︽暟锛坢es_wm_stock_warning.status=10锛� */
+ Long selectStockWarningPendingCount();
+
+ /** 缁熻寰呰瘎瀹′笉鍚堟牸鍝佸崟鏁帮紙mes_qc_ncr.status=0锛� */
+ Long selectNcrPendingCount();
+
// ========== 鐘舵�佸垎甯� ==========
/**
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java
index 0675ba6..c0ae4ce 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/bagcode/MesProBagCodeMapper.java
@@ -36,6 +36,30 @@
int markInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId,
@org.apache.ibatis.annotations.Param("deviceCode") String deviceCode, @org.apache.ibatis.annotations.Param("lineCode") String lineCode);
+ /** 鎵规鏁存壒鍏ュ簱鏃舵壒閲忔爣璁板叾涓嬫湭鍏ュ簱琚嬬爜锛堝箓绛夛級锛屼繚鎸佽鐮佷笌搴撳瓨鐘舵�佷竴鑷� */
+ @Update("UPDATE mes_pro_bag_code SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_line_code = #{lineCode}, update_time = NOW() "
+ + "WHERE deleted = 0 AND inbound_event_id IS NULL AND batch_id = #{batchId}")
+ int markInboundByBatchId(@Param("batchId") Long batchId, @Param("eventId") Long eventId,
+ @Param("lineCode") String lineCode);
+
+ /** 鏁存墭鍏ュ簱鏃舵壒閲忔爣璁版墭鐩樹笅鏈叆搴撹鐮侊紙骞傜瓑锛� */
+ @Update("UPDATE mes_pro_bag_code SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_line_code = #{lineCode}, update_time = NOW() "
+ + "WHERE deleted = 0 AND inbound_event_id IS NULL AND pallet_id = #{palletId}")
+ int markInboundByPalletId(@Param("palletId") Long palletId, @Param("eventId") Long eventId,
+ @Param("lineCode") String lineCode);
+
+ /**
+ * 鏇存柊琚嬬爜璐ㄦ鐘舵�侊紙绉嶅瓙璐ㄦ鍚堟牸/涓嶅悎鏍兼椂璁板綍璇ヨ缁撴灉锛�
+ *
+ * @param id 琚嬬爜缂栧彿
+ * @param qcStatus 璐ㄦ鐘舵�侊紙瑙� MesProBagCodeQcStatusEnum锛�
+ */
+ default void updateQcStatus(Long id, Integer qcStatus) {
+ update(null, new LambdaUpdateWrapper<MesProBagCodeDO>()
+ .eq(MesProBagCodeDO::getId, id)
+ .set(MesProBagCodeDO::getQcStatus, qcStatus));
+ }
+
default List<MesProBagCodeDO> selectListByUuid(String uuid) {
return selectList(MesProBagCodeDO::getUuid, uuid);
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/batch/MesProBatchMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/batch/MesProBatchMapper.java
index 5c3026e..e672278 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/batch/MesProBatchMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/batch/MesProBatchMapper.java
@@ -40,6 +40,12 @@
int markInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId,
@org.apache.ibatis.annotations.Param("deviceCode") String deviceCode, @org.apache.ibatis.annotations.Param("lineCode") String lineCode);
+ /** 鎵规鏁存壒鎵爜鍏ュ簱鍥炲啓锛氬叆搴撹鏁扮洿鎺ョ疆涓烘壒娆¤鏁帮紝骞傜瓑锛堝凡鏈夊叆搴撴爣璁扮殑涓嶅啀鏇存柊锛� */
+ @org.apache.ibatis.annotations.Update("UPDATE mes_pro_batch SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_line_code = #{lineCode}, inbound_bag_quantity = #{bagQuantity}, update_time = NOW() "
+ + "WHERE id = #{id} AND deleted = 0 AND inbound_event_id IS NULL")
+ int markBatchInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId,
+ @org.apache.ibatis.annotations.Param("lineCode") String lineCode, @org.apache.ibatis.annotations.Param("bagQuantity") Integer bagQuantity);
+
default PageResult<MesProBatchDO> selectPage(MesProBatchPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<MesProBatchDO>()
.likeIfPresent(MesProBatchDO::getCode, reqVO.getCode())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java
index cbbda3f..ab03c10 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/pallet/MesProPalletMapper.java
@@ -64,6 +64,11 @@
void markOutbound(@Param("id") Long id, @Param("salesId") Long salesId,
@Param("outboundTime") java.time.LocalDateTime outboundTime);
+ /** 鏁存墭鎵爜鍏ュ簱鍥炲啓锛氬箓绛夛紙宸叉湁鍏ュ簱鏍囪鐨勪笉鍐嶆洿鏂帮級锛岀敤浜庨槻閲嶅鍏ュ簱 */
+ @org.apache.ibatis.annotations.Update("UPDATE mes_pro_pallet SET inbound_event_id = #{eventId}, inbound_time = NOW(), update_time = NOW() "
+ + "WHERE id = #{id} AND deleted = 0 AND inbound_event_id IS NULL")
+ int markInbound(@Param("id") Long id, @Param("eventId") Long eventId);
+
@org.apache.ibatis.annotations.Update("UPDATE mes_pro_pallet SET sales_id = NULL, outbound_time = NULL, update_time = NOW() "
+ "WHERE id = #{id} AND deleted = 0")
void clearOutbound(@Param("id") Long id);
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedQualityMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedQualityMapper.java
index 314133b..98e3ea2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedQualityMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/seedquality/MesQcSeedQualityMapper.java
@@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedQualityDO;
import org.apache.ibatis.annotations.Mapper;
@@ -9,6 +11,15 @@
@Mapper
public interface MesQcSeedQualityMapper extends BaseMapperX<MesQcSeedQualityDO> {
+
+ default PageResult<MesQcSeedQualityDO> selectPage(MesQcSeedQualityPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<MesQcSeedQualityDO>()
+ .likeIfPresent(MesQcSeedQualityDO::getCode, reqVO.getCode())
+ .likeIfPresent(MesQcSeedQualityDO::getBatchCode, reqVO.getBatchCode())
+ .eqIfPresent(MesQcSeedQualityDO::getResult, reqVO.getResult())
+ .orderByDesc(MesQcSeedQualityDO::getInspectedAt)
+ .orderByDesc(MesQcSeedQualityDO::getId));
+ }
default MesQcSeedQualityDO selectByCode(String code) {
return selectOne(new LambdaQueryWrapperX<MesQcSeedQualityDO>().eq(MesQcSeedQualityDO::getCode, code));
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
index cc2413d..d3a7a25 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
@@ -6,6 +6,7 @@
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
@@ -22,13 +23,15 @@
default PageResult<MesWmMaterialStockDO> selectPage(MesWmMaterialStockPageReqVO reqVO,
Collection<Long> itemTypeIds,
Collection<Long> itemIds,
- Long virtualWarehouseId) {
+ Long virtualWarehouseId,
+ Collection<Long> warehouseIds) {
LambdaQueryWrapperX<MesWmMaterialStockDO> wrapper = new LambdaQueryWrapperX<MesWmMaterialStockDO>()
.inIfPresent(MesWmMaterialStockDO::getItemTypeId, itemTypeIds)
.inIfPresent(MesWmMaterialStockDO::getItemId, itemIds)
.likeIfPresent(MesWmMaterialStockDO::getBatchCode, reqVO.getBatchCode())
.eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId())
.eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId())
+ .inIfPresent(MesWmMaterialStockDO::getWarehouseId, warehouseIds)
.eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId())
.eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId())
.eqIfPresent(MesWmMaterialStockDO::getVendorId, reqVO.getVendorId())
@@ -149,9 +152,10 @@
}
/**
- * 鎸夌粍鍚堥敭鏌ヨ搴撳瓨璁板綍锛堝拷鐣ヤ緵搴斿晢缁村害锛�
+ * 鎸夌粍鍚堥敭鏌ヨ搴撳瓨璁板綍锛堝拷鐣ヤ緵搴斿晢缁村害锛屼粎鍚堟牸搴擄級
*
- * 鐢ㄤ簬绉诲簱鍦烘櫙锛氱Щ搴撴椂灏嗗簱瀛樺悎骞跺埌鐩爣搴撲綅宸叉湁搴撳瓨锛屼笉鍖哄垎渚涘簲鍟�
+ * 鐢ㄤ簬绉诲簱鍦烘櫙锛氱Щ搴撴椂灏嗗悎鏍煎簱瀛樺悎骞跺埌鐩爣搴撲綅宸叉湁鍚堟牸搴撳瓨锛屼笉鍖哄垎渚涘簲鍟�
+ * 鍙尮閰嶅悎鏍煎簱(20)锛岄伩鍏嶅皢绉诲叆鏁伴噺鍚堝苟鍒板悓鎵规鐨勬殏瀛樺簱璁板綍
*/
default MesWmMaterialStockDO selectByCompositeKeyIgnoreVendor(Long itemId, Long warehouseId, Long locationId,
Long areaId, Long batchId) {
@@ -159,7 +163,8 @@
.eq(MesWmMaterialStockDO::getItemId, itemId)
.eq(MesWmMaterialStockDO::getWarehouseId, warehouseId)
.eq(MesWmMaterialStockDO::getLocationId, locationId)
- .eq(MesWmMaterialStockDO::getAreaId, areaId);
+ .eq(MesWmMaterialStockDO::getAreaId, areaId)
+ .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.QUALIFIED.getState());
// batchId=null 鏃剁簿纭尮閰� is null
if (batchId != null) {
wrapper.eq(MesWmMaterialStockDO::getBatchId, batchId);
@@ -170,9 +175,41 @@
return selectOne(wrapper);
}
+ /**
+ * 鎸夌粍鍚堥敭鏌ヨ鍚堟牸搴撳簱瀛樿褰曪紙鐢ㄤ簬鍑哄簱浜嬪姟鍖归厤锛�
+ *
+ * 鍚屾壒娆″彲鑳藉悓鏃跺瓨鍦ㄦ殏瀛樺簱(10)涓庡悎鏍煎簱(20)涓ゆ潯璁板綍锛堢瀛愯川妫�鎸夎鎷嗘暟閲忥級锛�
+ * 鍑哄簱蹇呴』鍙粠鍚堟牸搴撳尮閰嶏紝閬垮厤鎵e埌鏈川妫�鐨勬殏瀛樺簱瀛樸��
+ */
+ default MesWmMaterialStockDO selectQualifiedByCompositeKey(Long itemId, Long warehouseId, Long locationId,
+ Long areaId, Long batchId, Long vendorId) {
+ LambdaQueryWrapperX<MesWmMaterialStockDO> wrapper = new LambdaQueryWrapperX<MesWmMaterialStockDO>()
+ .eq(MesWmMaterialStockDO::getItemId, itemId)
+ .eq(MesWmMaterialStockDO::getWarehouseId, warehouseId)
+ .eq(MesWmMaterialStockDO::getLocationId, locationId)
+ .eq(MesWmMaterialStockDO::getAreaId, areaId)
+ .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.QUALIFIED.getState());
+ // batchId=null 鏃剁簿纭尮閰� is null
+ if (batchId != null) {
+ wrapper.eq(MesWmMaterialStockDO::getBatchId, batchId);
+ } else {
+ wrapper.isNull(MesWmMaterialStockDO::getBatchId);
+ }
+ if (vendorId != null) {
+ wrapper.eq(MesWmMaterialStockDO::getVendorId, vendorId);
+ }
+ wrapper.last("ORDER BY quantity DESC LIMIT 1");
+ return selectOne(wrapper);
+ }
+
default List<MesWmMaterialStockDO> selectList(MesWmMaterialStockListReqVO reqVO) {
+ return selectList(reqVO, null);
+ }
+
+ default List<MesWmMaterialStockDO> selectList(MesWmMaterialStockListReqVO reqVO, Collection<Long> warehouseIds) {
return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
.eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId())
+ .inIfPresent(MesWmMaterialStockDO::getWarehouseId, warehouseIds)
.eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId())
.eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId())
.eqIfPresent(MesWmMaterialStockDO::getItemId, reqVO.getItemId())
@@ -197,6 +234,36 @@
.orderByAsc(MesWmMaterialStockDO::getReceiptTime));
}
+ /**
+ * 鎸夌墿鏂�/鎵规鏌ヨ鍚堟牸搴撳簱瀛樿褰曪紙浠� stock_state=20锛屼笖浠呴檺鍚堟牸浠撳簱锛�
+ *
+ * <p>鍚屾壒娆″彲鑳藉悓鏃跺瓨鍦ㄦ殏瀛樺簱(10)涓庡悎鏍煎簱(20)涓ゆ潯璁板綍锛堢瀛愯川妫�鎸夎鎷嗘暟閲忥級锛�
+ * 閿�鍞嚭搴撻�夊簱瀛樺彧鑳戒粠鍚堟牸搴撹褰曚腑閫夛紝鏉滅粷閫変腑鏈川妫�鐨勬殏瀛樺簱瀛橈紱
+ * 鍚屾椂闄愬畾鍚堟牸浠撳簱锛坱ype=20锛夛紝閬垮厤浠庢殏瀛樹粨搴撲腑璇�夊悎鏍兼�佸簱瀛樸��</p>
+ */
+ default List<MesWmMaterialStockDO> selectQualifiedListByItemAndBatch(Long itemId, Long batchId,
+ Collection<Long> qualifiedWarehouseIds) {
+ return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
+ .eq(MesWmMaterialStockDO::getItemId, itemId)
+ .eqIfPresent(MesWmMaterialStockDO::getBatchId, batchId)
+ .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.QUALIFIED.getState())
+ .in(MesWmMaterialStockDO::getWarehouseId, qualifiedWarehouseIds)
+ .gt(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO)
+ .orderByAsc(MesWmMaterialStockDO::getReceiptTime));
+ }
+
+ /**
+ * 鎸変粨搴撴壒娆℃煡璇㈠叏閮ㄥ簱瀛樿褰曪紙鍚殏瀛樺簱涓庡悎鏍煎簱锛宷uantity>0锛�
+ *
+ * <p>鐢ㄤ簬绉嶅瓙璐ㄦ鎸夎鐮佹祦杞細瀹氫綅璇ユ壒娆℃殏瀛樺簱璁板綍鎵e噺 1 琚嬶紝浠ュ強瀹氫綅/鏂板缓鍚堟牸搴撹褰曠疮鍔� 1 琚嬨��</p>
+ */
+ default List<MesWmMaterialStockDO> selectStockListByBatchId(Long batchId) {
+ return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
+ .eq(MesWmMaterialStockDO::getBatchId, batchId)
+ .gt(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO)
+ .orderByAsc(MesWmMaterialStockDO::getReceiptTime));
+ }
+
default List<MesWmMaterialStockDO> selectListByItemIds(Collection<Long> itemIds) {
if (itemIds == null || itemIds.isEmpty()) {
return java.util.Collections.emptyList();
@@ -207,18 +274,16 @@
}
/**
- * 鎸夋壒娆″彿鏇存柊搴撳瓨鐘舵�侊紙鐢ㄤ簬绉嶅瓙璐ㄦ鍚堟牸鍚庯紝灏嗘殏瀛樺簱鏁存壒杞负鍚堟牸搴擄級
+ * 缁熻鎵规鍦ㄦ殏瀛樺簱涓殑搴撳瓨璁板綍鏁帮紙鐢ㄤ簬绉嶅瓙璐ㄦ鍓嶆牎楠岃鐮�/鎵规鏄惁澶勪簬寰呰川妫�鐘舵�侊級
*
- * @param batchId 浠撳簱鎵规ID
- * @param toState 鐩爣搴撳瓨鐘舵��
- * @param fromState 鍘熷簱瀛樼姸鎬侊紙闄愬畾鍙洿鏂拌鐘舵�佺殑璁板綍锛�
- * @return 褰卞搷琛屾暟
+ * @param batchId 浠撳簱鎵规ID
+ * @return 鏆傚瓨搴撳簱瀛樿褰曟暟
*/
- default int updateStockStateByBatchId(Long batchId, Integer toState, Integer fromState) {
- return update(new MesWmMaterialStockDO().setStockState(toState),
- new LambdaUpdateWrapper<MesWmMaterialStockDO>()
- .eq(MesWmMaterialStockDO::getBatchId, batchId)
- .eq(MesWmMaterialStockDO::getStockState, fromState));
+ default Long selectTempStockCountByBatchId(Long batchId) {
+ return selectCount(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
+ .eq(MesWmMaterialStockDO::getBatchId, batchId)
+ .eq(MesWmMaterialStockDO::getStockState, MesWmStockStateEnum.TEMP.getState())
+ .gt(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO));
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstockbag/MesWmMaterialStockBagMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstockbag/MesWmMaterialStockBagMapper.java
new file mode 100644
index 0000000..d1727b5
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstockbag/MesWmMaterialStockBagMapper.java
@@ -0,0 +1,82 @@
+package cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockBagPageReqVO;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper
+public interface MesWmMaterialStockBagMapper extends BaseMapperX<MesWmMaterialStockBagDO> {
+
+ default PageResult<MesWmMaterialStockBagDO> selectPage(MesWmMaterialStockBagPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getMaterialStockId, reqVO.getMaterialStockId())
+ .likeIfPresent(MesWmMaterialStockBagDO::getBagCode, reqVO.getBagCode())
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .orderByAsc(MesWmMaterialStockBagDO::getInboundTime));
+ }
+
+ default MesWmMaterialStockBagDO selectByBagCode(String bagCode) {
+ return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getBagCode, bagCode)
+ .orderByDesc(MesWmMaterialStockBagDO::getId)
+ .last("LIMIT 1"));
+ }
+
+ default MesWmMaterialStockBagDO selectByBagCodeId(Long bagCodeId) {
+ return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getBagCodeId, bagCodeId)
+ .orderByDesc(MesWmMaterialStockBagDO::getId)
+ .last("LIMIT 1"));
+ }
+
+ default MesWmMaterialStockBagDO selectOneActiveByMaterialStockId(Long materialStockId) {
+ return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getMaterialStockId, materialStockId)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .last("LIMIT 1"));
+ }
+
+ default MesWmMaterialStockBagDO selectActiveByBagCode(String bagCode) {
+ return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getBagCode, bagCode)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .last("LIMIT 1"));
+ }
+
+ default MesWmMaterialStockBagDO selectActiveByBagCodeId(Long bagCodeId) {
+ return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getBagCodeId, bagCodeId)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .last("LIMIT 1"));
+ }
+
+ default List<MesWmMaterialStockBagDO> selectActiveListByItemAndBatch(Long itemId, Long batchId, Integer stockState) {
+ return selectList(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getItemId, itemId)
+ .eqIfPresent(MesWmMaterialStockBagDO::getBatchId, batchId)
+ .eqIfPresent(MesWmMaterialStockBagDO::getStockState, stockState)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .eq(MesWmMaterialStockBagDO::getFrozen, false)
+ .orderByAsc(MesWmMaterialStockBagDO::getInboundTime));
+ }
+
+ default List<MesWmMaterialStockBagDO> selectListByMaterialStockIds(Collection<Long> materialStockIds) {
+ return selectList(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .in(MesWmMaterialStockBagDO::getMaterialStockId, materialStockIds)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .orderByAsc(MesWmMaterialStockBagDO::getInboundTime));
+ }
+
+ default List<MesWmMaterialStockBagDO> selectListByMaterialStockId(Long materialStockId) {
+ return selectList(new LambdaQueryWrapperX<MesWmMaterialStockBagDO>()
+ .eq(MesWmMaterialStockBagDO::getMaterialStockId, materialStockId)
+ .eq(MesWmMaterialStockBagDO::getStatus, 1)
+ .orderByAsc(MesWmMaterialStockBagDO::getInboundTime));
+ }
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java
index 1659343..3dd15dc 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java
@@ -7,7 +7,6 @@
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
-import java.util.Map;
/**
* MES 閿�鍞嚭搴撳崟琛� Mapper
@@ -31,26 +30,6 @@
.eqIfPresent(MesWmProductSalesLineDO::getSalesId, reqVO.getSalesId())
.inIfPresent(MesWmProductSalesLineDO::getSalesId, reqVO.getSalesIds())
.orderByDesc(MesWmProductSalesLineDO::getId));
- }
-
- /**
- * 鏍规嵁閿�鍞鍗曟槑缁� ID 鍒楄〃鏌ヨ鍑哄簱琛岋紝鎸� saleOrderItemId 鍒嗙粍杩斿洖鎵瑰彿
- */
- default Map<Long, String> selectBatchCodesBySaleOrderItemIds(java.util.Collection<Long> saleOrderItemIds) {
- if (saleOrderItemIds == null || saleOrderItemIds.isEmpty()) {
- return java.util.Collections.emptyMap();
- }
- List<MesWmProductSalesLineDO> lines = selectList(new LambdaQueryWrapperX<MesWmProductSalesLineDO>()
- .in(MesWmProductSalesLineDO::getSaleOrderItemId, saleOrderItemIds));
- return lines.stream()
- .filter(l -> l.getBatchCode() != null && !l.getBatchCode().isEmpty())
- .collect(java.util.stream.Collectors.groupingBy(
- MesWmProductSalesLineDO::getSaleOrderItemId,
- java.util.LinkedHashMap::new,
- java.util.stream.Collectors.collectingAndThen(
- java.util.stream.Collectors.mapping(MesWmProductSalesLineDO::getBatchCode,
- java.util.stream.Collectors.toSet()),
- codes -> String.join("銆�", codes))));
}
default void updateQualityStatusByIds(List<Long> ids, Integer qualityStatus) {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnsales/MesWmReturnSalesMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnsales/MesWmReturnSalesMapper.java
index 988d14d..c25314f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnsales/MesWmReturnSalesMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnsales/MesWmReturnSalesMapper.java
@@ -22,7 +22,6 @@
return selectPage(reqVO, new LambdaQueryWrapperX<MesWmReturnSalesDO>()
.likeIfPresent(MesWmReturnSalesDO::getCode, reqVO.getCode())
.likeIfPresent(MesWmReturnSalesDO::getName, reqVO.getName())
- .likeIfPresent(MesWmReturnSalesDO::getSalesOrderCode, reqVO.getSalesOrderCode())
.eqIfPresent(MesWmReturnSalesDO::getClientId, reqVO.getClientId())
.eqIfPresent(MesWmReturnSalesDO::getStatus, reqVO.getStatus())
.betweenIfPresent(MesWmReturnSalesDO::getReturnDate, reqVO.getReturnDate())
@@ -36,7 +35,6 @@
LambdaQueryWrapperX<MesWmReturnSalesDO> wrapper = new LambdaQueryWrapperX<MesWmReturnSalesDO>()
.likeIfPresent(MesWmReturnSalesDO::getCode, reqVO.getCode())
.likeIfPresent(MesWmReturnSalesDO::getName, reqVO.getName())
- .likeIfPresent(MesWmReturnSalesDO::getSalesOrderCode, reqVO.getSalesOrderCode())
.eqIfPresent(MesWmReturnSalesDO::getClientId, reqVO.getClientId())
.eqIfPresent(MesWmReturnSalesDO::getStatus, reqVO.getStatus())
.betweenIfPresent(MesWmReturnSalesDO::getReturnDate, reqVO.getReturnDate())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/salesnotice/MesWmSalesNoticeMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/salesnotice/MesWmSalesNoticeMapper.java
index 23f7af4..088bd2b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/salesnotice/MesWmSalesNoticeMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/salesnotice/MesWmSalesNoticeMapper.java
@@ -8,7 +8,6 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeDO;
import org.apache.ibatis.annotations.Mapper;
-import java.util.Collection;
import java.util.List;
/**
@@ -21,7 +20,6 @@
return selectPage(reqVO, new LambdaQueryWrapperX<MesWmSalesNoticeDO>()
.likeIfPresent(MesWmSalesNoticeDO::getCode, reqVO.getCode())
.likeIfPresent(MesWmSalesNoticeDO::getName, reqVO.getName())
- .likeIfPresent(MesWmSalesNoticeDO::getSaleOrderCode, reqVO.getSaleOrderCode())
.eqIfPresent(MesWmSalesNoticeDO::getClientId, reqVO.getClientId())
.eqIfPresent(MesWmSalesNoticeDO::getStatus, reqVO.getStatus())
.orderByDesc(MesWmSalesNoticeDO::getId));
@@ -38,7 +36,6 @@
LambdaQueryWrapperX<MesWmSalesNoticeDO> wrapper = new LambdaQueryWrapperX<MesWmSalesNoticeDO>()
.likeIfPresent(MesWmSalesNoticeDO::getCode, reqVO.getCode())
.likeIfPresent(MesWmSalesNoticeDO::getName, reqVO.getName())
- .likeIfPresent(MesWmSalesNoticeDO::getSaleOrderCode, reqVO.getSaleOrderCode())
.eqIfPresent(MesWmSalesNoticeDO::getClientId, reqVO.getClientId())
.eqIfPresent(MesWmSalesNoticeDO::getStatus, reqVO.getStatus())
.orderByDesc(MesWmSalesNoticeDO::getId);
@@ -55,19 +52,6 @@
default MesWmSalesNoticeDO selectByCode(String code) {
return selectOne(MesWmSalesNoticeDO::getCode, code);
- }
-
- default MesWmSalesNoticeDO selectBySaleOrderId(Long saleOrderId) {
- return selectOne(MesWmSalesNoticeDO::getSaleOrderId, saleOrderId);
- }
-
- /**
- * 鏌ヨ宸插瓨鍦ㄥ彂璐ч�氱煡鍗曠殑閿�鍞鍗� ID 鍒楄〃
- */
- default List<Long> selectExistingSaleOrderIds(Collection<Long> saleOrderIds) {
- return selectObjs(new LambdaQueryWrapperX<MesWmSalesNoticeDO>()
- .select(MesWmSalesNoticeDO::getSaleOrderId)
- .in(MesWmSalesNoticeDO::getSaleOrderId, saleOrderIds));
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java
index 878347e..1d18be0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transaction/MesWmTransactionMapper.java
@@ -17,6 +17,7 @@
return selectPage(reqVO, new LambdaQueryWrapperX<MesWmTransactionDO>()
.eqIfPresent(MesWmTransactionDO::getItemId, reqVO.getItemId())
.likeIfPresent(MesWmTransactionDO::getBatchCode, reqVO.getBatchCode())
+ .likeIfPresent(MesWmTransactionDO::getBagCode, reqVO.getBagCode())
.eqIfPresent(MesWmTransactionDO::getWarehouseId, reqVO.getWarehouseId())
.eqIfPresent(MesWmTransactionDO::getLocationId, reqVO.getLocationId())
.eqIfPresent(MesWmTransactionDO::getAreaId, reqVO.getAreaId())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/warehouse/MesWmWarehouseMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/warehouse/MesWmWarehouseMapper.java
index 2353b9e..3a3cfc1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/warehouse/MesWmWarehouseMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/warehouse/MesWmWarehouseMapper.java
@@ -21,9 +21,16 @@
.likeIfPresent(MesWmWarehouseDO::getCode, reqVO.getCode())
.likeIfPresent(MesWmWarehouseDO::getName, reqVO.getName())
.eqIfPresent(MesWmWarehouseDO::getFrozen, reqVO.getFrozen())
+ .eqIfPresent(MesWmWarehouseDO::getType, reqVO.getType())
.orderByDesc(MesWmWarehouseDO::getId));
}
+ default List<MesWmWarehouseDO> selectListByType(Integer type) {
+ return selectList(new LambdaQueryWrapperX<MesWmWarehouseDO>()
+ .eq(MesWmWarehouseDO::getType, type)
+ .orderByAsc(MesWmWarehouseDO::getId));
+ }
+
default MesWmWarehouseDO selectByCode(String code) {
return selectOne(MesWmWarehouseDO::getCode, code);
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
index 1d17581..392cd33 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -455,6 +455,8 @@
ErrorCode WM_WAREHOUSE_HAS_WORKSTATION = new ErrorCode(1_040_700_004, "浠撳簱宸茶宸ヤ綔绔欏紩鐢紝鏃犳硶鍒犻櫎");
ErrorCode WM_WAREHOUSE_HAS_MATERIAL_STOCK = new ErrorCode(1_040_700_005, "浠撳簱涓嬫湁搴撳瓨璁板綍锛屾棤娉曞垹闄�");
ErrorCode WM_WAREHOUSE_IS_VIRTUAL = new ErrorCode(1_040_700_006, "铏氭嫙浠撳簱涓嶅厑璁告搷浣�");
+ ErrorCode WM_WAREHOUSE_TYPE_NOT_QUALIFIED = new ErrorCode(1_040_700_007, "鎵�閫変粨搴撲笉鏄悎鏍煎簱");
+ ErrorCode WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED = new ErrorCode(1_040_700_008, "鏈厤缃悎鏍煎簱锛岃鍏堝湪浠撳簱绠$悊涓垱寤哄苟璁剧疆浠撳簱绫诲瀷涓哄悎鏍煎簱");
// ========== MES 浠撳簱绠$悊-搴撳尯锛�1-040-701-000锛� ==========
ErrorCode WM_WAREHOUSE_LOCATION_NOT_EXISTS = new ErrorCode(1_040_701_000, "搴撳尯涓嶅瓨鍦�");
@@ -496,6 +498,12 @@
ErrorCode WM_MATERIAL_STOCK_SELECTION_MISMATCH = new ErrorCode(1_040_703_014, "搴撳瓨璁板綍涓庢彁浜ょ殑鐗╂枡銆佹壒娆℃垨搴撲綅淇℃伅涓嶄竴鑷�");
ErrorCode WM_MATERIAL_STOCK_QUANTITY_INVALID = new ErrorCode(1_040_703_015, "璋冩暣鏁伴噺涓嶈兘涓虹┖鎴栭浂");
ErrorCode WM_MATERIAL_STOCK_FROZEN = new ErrorCode(1_040_703_016, "搴撳瓨璁板綍宸插喕缁擄紝鏃犳硶绉诲簱");
+ ErrorCode WM_MATERIAL_STOCK_NOT_QUALIFIED = new ErrorCode(1_040_703_017, "闈炲悎鏍煎簱瀛樹笉鍙嚭搴�");
+ ErrorCode WM_MATERIAL_STOCK_BAG_NOT_EXISTS = new ErrorCode(1_040_703_018, "搴撳瓨琚嬬爜鏄庣粏涓嶅瓨鍦�");
+ ErrorCode WM_MATERIAL_STOCK_BAG_DUPLICATE = new ErrorCode(1_040_703_019, "琚嬬爜({})宸插湪搴擄紝绂佹閲嶅鍏ュ簱");
+ ErrorCode WM_MATERIAL_STOCK_BAG_NOT_ACTIVE = new ErrorCode(1_040_703_020, "琚嬬爜({})涓嶅湪搴撴垨宸插嚭搴�/鎶ュ簾锛屾棤娉曟搷浣�");
+ ErrorCode WM_MATERIAL_STOCK_BAG_REQUIRED = new ErrorCode(1_040_703_021, "璇ョ墿鏂欏惎鐢ㄨ鐮佺鐞嗭紝蹇呴』鎼哄甫琚嬬爜");
+ ErrorCode WM_MATERIAL_STOCK_BAG_INSUFFICIENT = new ErrorCode(1_040_703_022, "鍦ㄥ簱琚嬬爜鏄庣粏鏁伴噺涓嶈冻锛屾棤娉曞嚭搴�");
// ========== MES 浠撳簱绠$悊-鍒拌揣閫氱煡鍗曪紙1-040-704-000锛� ==========
ErrorCode WM_ARRIVAL_NOTICE_NOT_EXISTS = new ErrorCode(1_040_704_000, "鍒拌揣閫氱煡鍗曚笉瀛樺湪");
@@ -727,6 +735,8 @@
ErrorCode WM_PRODUCT_SALES_SCAN_STOCK_NOT_FOUND = new ErrorCode(1_040_714_105, "鎵弿鎵规鍦ㄥ悎鏍煎簱涓湭鎵惧埌瀵瑰簲搴撳瓨璁板綍");
ErrorCode WM_PRODUCT_SALES_SCAN_NO_MATCH_LINE = new ErrorCode(1_040_714_106, "鍑哄簱鍗曚腑娌℃湁涓庤鐗╂枡/鎵规鍖归厤鐨勮");
ErrorCode WM_PRODUCT_SALES_SCAN_BAG_ALREADY_SCANNED = new ErrorCode(1_040_714_107, "璇ヨ鐮佸凡鎵弿鍑哄簱锛岃鍕块噸澶嶆壂鎻�");
+ ErrorCode WM_PRODUCT_SALES_SCAN_BAG_NOT_QUALIFIED = new ErrorCode(1_040_714_108, "璇ヨ鐮佹湭璐ㄦ鍚堟牸锛岀姝㈠嚭搴�");
+ ErrorCode WM_PRODUCT_SALES_SCAN_PALLET_NOT_ALL_QUALIFIED = new ErrorCode(1_040_714_109, "鎵樼洏涓嬪瓨鍦ㄦ湭璐ㄦ琚嬬爜锛岀姝㈡暣鎵樺嚭搴�");
// ========== MES 浠撳簱绠$悊-鏉傞」鍑哄簱鍗曪紙1-040-715-000锛� ==========
ErrorCode WM_MISC_ISSUE_NOT_EXISTS = new ErrorCode(1_040_715_000, "鏉傞」鍑哄簱鍗曚笉瀛樺湪");
@@ -760,9 +770,6 @@
ErrorCode WM_SALES_NOTICE_LINE_NOT_EXISTS = new ErrorCode(1_040_720_010, "鍙戣揣閫氱煡鍗曡涓嶅瓨鍦�");
ErrorCode WM_SALES_NOTICE_LINE_EMPTY = new ErrorCode(1_040_720_011, "鍙戣揣閫氱煡鍗曡涓虹┖锛屼笉鑳芥彁浜�");
ErrorCode WM_SALES_NOTICE_LINE_NOT_MATCH = new ErrorCode(1_040_720_012, "鍙戣揣閫氱煡鍗曡涓嶅睘浜庢寚瀹氱殑鍙戣揣閫氱煡鍗�");
- ErrorCode WM_SALES_NOTICE_SALE_ORDER_NOT_EXISTS = new ErrorCode(1_040_720_013, "閿�鍞鍗曚笉瀛樺湪");
- ErrorCode WM_SALES_NOTICE_SALE_ORDER_ITEM_EMPTY = new ErrorCode(1_040_720_014, "閿�鍞鍗曟槑缁嗕负绌�");
- ErrorCode WM_SALES_NOTICE_ALREADY_EXISTS = new ErrorCode(1_040_720_015, "璇ラ攢鍞鍗曞凡鐢熸垚鍙戣揣閫氱煡鍗曪紝涓嶈兘閲嶅鐢熸垚");
// ========== MES 浠撳簱绠$悊-鏉$爜閰嶇疆锛�1-040-730-000锛� ==========
ErrorCode WM_BARCODE_CONFIG_NOT_EXISTS = new ErrorCode(1_040_730_000, "鏉$爜閰嶇疆涓嶅瓨鍦�");
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
index b089810..26e6ab1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
@@ -18,6 +18,7 @@
public static final int QC_IPQC = 2; // 杩囩▼妫�楠岋細MesQcIpqcDO
public static final int QC_OQC = 3; // 鍑鸿揣妫�楠岋細MesQcOqcDO
public static final int QC_RQC = 4; // 閫�璐ф楠岋細MesQcRqcDO
+ public static final int QC_SEED_QUALITY = 5; // 绉嶅瓙璐ㄦ锛歁esQcSeedQualityDO锛堝惈鏆傚瓨鍑哄簱/鍚堟牸鍏ュ簱/鎶ュ簾锛�
// ========== WM 浠撳簱妯″潡 [100, 200) ==========
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProBagCodeQcStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProBagCodeQcStatusEnum.java
new file mode 100644
index 0000000..2713dc8
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProBagCodeQcStatusEnum.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.mes.enums.pro;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * MES 琚嬬爜锛堜竴琚嬩竴鐮侊級璐ㄦ鐘舵�佹灇涓�
+ *
+ * <p>璁板綍姣忚鐨勭瀛愯川妫�缁撴灉锛岄攢鍞嚭搴撴壂琚嬬爜鏃舵牎楠岃琚嬪凡璐ㄦ鍚堟牸銆�</p>
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Getter
+@AllArgsConstructor
+public enum MesProBagCodeQcStatusEnum implements ArrayValuable<Integer> {
+
+ UNCHECKED(10, "鏈川妫�"),
+ QUALIFIED(20, "璐ㄦ鍚堟牸"),
+ UNQUALIFIED(30, "璐ㄦ涓嶅悎鏍�");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProBagCodeQcStatusEnum::getStatus).toArray(Integer[]::new);
+
+ /**
+ * 鐘舵��
+ */
+ private final Integer status;
+ /**
+ * 鐘舵�佸悕绉�
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMaterialStockBagStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMaterialStockBagStatusEnum.java
new file mode 100644
index 0000000..bf6bd86
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMaterialStockBagStatusEnum.java
@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.module.mes.enums.wm;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum MesWmMaterialStockBagStatusEnum {
+ ACTIVE(1, "鍦ㄥ簱"),
+ OUT(2, "宸插嚭搴�"),
+ SCRAPPED(3, "宸叉姤搴�");
+
+ private final Integer status;
+ private final String name;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmWarehouseTypeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmWarehouseTypeEnum.java
new file mode 100644
index 0000000..d0cd8f9
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmWarehouseTypeEnum.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.mes.enums.wm;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * MES 浠撳簱绫诲瀷
+ *
+ * 涓� {@link MesWmStockStateEnum} 璇箟瀵归綈锛氭殏瀛樺簱瀛樻斁寰呮/鏆傚瓨搴撳瓨锛屽悎鏍煎簱瀛樻斁璐ㄦ鍚堟牸銆佸彲鎷h揣搴撳瓨銆�
+ */
+@Getter
+@AllArgsConstructor
+public enum MesWmWarehouseTypeEnum {
+
+ TEMP(10, "鏆傚瓨搴�"),
+ QUALIFIED(20, "鍚堟牸搴�");
+
+ private final Integer type;
+ private final String name;
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/home/MesBagCodeHomeStatisticsServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/home/MesBagCodeHomeStatisticsServiceImpl.java
index 4a14ca7..0282554 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/home/MesBagCodeHomeStatisticsServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/home/MesBagCodeHomeStatisticsServiceImpl.java
@@ -42,7 +42,16 @@
summary.setBagCodeCount(getCount(homeStatisticsMapper.selectBagCodeCount()));
summary.setPalletCount(getCount(homeStatisticsMapper.selectPalletCount()));
- // 3. 鐘舵�佸垎甯�
+ // 3. 鍑哄簱娴侀��
+ summary.setSalesNoticeCount(getCount(homeStatisticsMapper.selectSalesNoticeCount()));
+ summary.setProductSalesCount(getCount(homeStatisticsMapper.selectProductSalesCount()));
+ summary.setReturnSalesCount(getCount(homeStatisticsMapper.selectReturnSalesCount()));
+
+ // 4. 浠撳偍棰勮 / 璐ㄩ噺
+ summary.setStockWarningPendingCount(getCount(homeStatisticsMapper.selectStockWarningPendingCount()));
+ summary.setNcrPendingCount(getCount(homeStatisticsMapper.selectNcrPendingCount()));
+
+ // 5. 鐘舵�佸垎甯�
summary.setBatchStatusList(toStatusList(homeStatisticsMapper.selectBatchCountGroupByStatus()));
summary.setBagCodeStatusList(toStatusList(homeStatisticsMapper.selectBagCodeCountGroupByStatus()));
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java
index 6ee0402..4657035 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/scan/MesProScanEventServiceImpl.java
@@ -5,11 +5,13 @@
import cn.iocoder.yudao.module.mes.controller.admin.pro.scan.vo.MesProScanEventPageReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.scan.MesProScanEventDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.scan.MesProScanEventMapper;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
import cn.iocoder.yudao.module.mes.enums.MesProScanEventStatusEnum;
@@ -20,47 +22,102 @@
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+@Slf4j
@Service
@Validated
public class MesProScanEventServiceImpl implements MesProScanEventService {
@Resource private MesProScanEventMapper eventMapper;
@Resource private MesProBagCodeMapper bagCodeMapper;
@Resource private MesProBatchMapper batchMapper;
+ @Resource private MesProPalletMapper palletMapper;
@Resource private MesWmTransactionService transactionService;
@Resource private MesWmWarehouseService warehouseService;
@Resource private MesWmBatchService mesWmBatchService;
+
+ /** 鎵爜绫诲瀷锛氳鐮侊紙榛樿锛� */
+ private static final String SCAN_TYPE_BAG = "BAG";
+ /** 鎵爜绫诲瀷锛氭墭鐩樼爜锛堟寜鎵樼洏宸茶琚嬫暟鏁存墭鍏ュ簱锛� */
+ private static final String SCAN_TYPE_PALLET = "PALLET";
+ /** 鎵爜绫诲瀷锛氭壒娆$爜锛堟寜鎵规琚嬫暟鏁存壒鍏ュ簱锛� */
+ private static final String SCAN_TYPE_BATCH = "BATCH";
@Override
@Transactional(rollbackFor = Exception.class)
public MesProScanEventDO createInbound(MesProScanEventCreateReqVO req) {
MesProScanEventDO existing = eventMapper.selectByEventIdForUpdate(req.getEventId());
if (existing != null) {
- if (!req.getBagCode().equals(existing.getBagCode()) || !req.getDeviceCode().equals(existing.getDeviceCode())) {
+ boolean contentMatch = req.getBagCode().equals(existing.getBagCode())
+ && (req.getDeviceCode() == null || req.getDeviceCode().equals(existing.getDeviceCode()));
+ if (!contentMatch) {
return failed(existing, "MES_SCAN_EVENT_ID_CONFLICT", "浜嬩欢鍙峰凡瀛樺湪浣嗗唴瀹逛笉涓�鑷�");
}
return existing;
}
+ String scanType = (req.getScanType() == null || req.getScanType().isBlank()) ? SCAN_TYPE_BAG : req.getScanType();
MesProScanEventDO event = new MesProScanEventDO();
- event.setEventId(req.getEventId()).setBagCode(req.getBagCode()).setQuantity(req.getQuantity())
- .setDeviceCode(req.getDeviceCode()).setLineCode(req.getLineCode()).setRemark(req.getRemark())
- .setStatus(MesProScanEventStatusEnum.FAILED).setReceivedTime(LocalDateTime.now());
+ event.setEventId(req.getEventId()).setBagCode(req.getBagCode()).setScanType(scanType)
+ .setQuantity(req.getQuantity()).setDeviceCode(req.getDeviceCode()).setLineCode(req.getLineCode())
+ .setRemark(req.getRemark()).setStatus(MesProScanEventStatusEnum.FAILED).setReceivedTime(LocalDateTime.now());
eventMapper.insert(event);
- MesProBagCodeDO bag = bagCodeMapper.selectByCodeForUpdate(req.getBagCode());
- if (bag == null) return failed(event, "MES_SCAN_BAG_NOT_EXISTS", "琚嬬爜涓嶅瓨鍦�");
- event.setBagCodeId(bag.getId());
- if (bag.getInboundEventId() != null) return failed(event, "MES_SCAN_BAG_ALREADY_INBOUND", "琚嬬爜宸插叆搴�");
- MesProBatchDO batch = batchMapper.selectByIdForUpdate(bag.getBatchId());
- if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "鐢熶骇鎵规涓嶅瓨鍦�");
- event.setBatchId(batch.getId()).setBatchCode(batch.getCode()).setItemId(batch.getItemId());
+ // 1. 鎸夋壂鐮佺被鍨嬭В鏋愭壂鐮佺洰鏍囦笌鍏ュ簱鏁伴噺锛堟墭鐩樻寜宸茶琚嬫暟銆佹壒娆℃寜鎵规琚嬫暟鏁存壒/鏁存墭鍏ュ簱锛�
+ Long targetId;
+ Long batchId;
+ BigDecimal quantity;
+ MesProBatchDO batch;
+ // 鍗曡鎵爜鍏ュ簱鏃朵紶閫掕鐮侊紝渚涘簱瀛樿鐮佹槑缁嗗湪鍏ュ簱绗竴鏃堕棿寤虹珛锛涙墭鐩�/鎵规鏁存壒鍏ュ簱涓烘壒閲忥紝涓嶉�愯寤烘槑缁�
+ Long bagCodeId = null;
+ String bagCode = null;
+ if (SCAN_TYPE_PALLET.equals(scanType)) {
+ MesProPalletDO pallet = palletMapper.selectByCode(req.getBagCode());
+ if (pallet == null) {
+ pallet = palletMapper.selectByTempCode(req.getBagCode());
+ }
+ if (pallet == null) return failed(event, "MES_SCAN_PALLET_NOT_EXISTS", "鎵樼洏鐮佷笉瀛樺湪");
+ if (pallet.getInboundEventId() != null) return failed(event, "MES_SCAN_PALLET_ALREADY_INBOUND", "鎵樼洏宸插叆搴�");
+ batch = batchMapper.selectByIdForUpdate(pallet.getBatchId());
+ if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "鐢熶骇鎵规涓嶅瓨鍦�");
+ batchId = batch.getId();
+ targetId = pallet.getId();
+ quantity = pallet.getBagCount() != null && pallet.getBagCount() > 0
+ ? BigDecimal.valueOf(pallet.getBagCount())
+ : BigDecimal.valueOf(bagCodeMapper.selectCountByPalletId(pallet.getId()));
+ } else if (SCAN_TYPE_BATCH.equals(scanType)) {
+ batch = batchMapper.selectByCode(req.getBagCode());
+ if (batch == null) {
+ batch = batchMapper.selectByTempCode(req.getBagCode());
+ }
+ if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "鐢熶骇鎵规涓嶅瓨鍦�");
+ if (batch.getInboundEventId() != null) return failed(event, "MES_SCAN_BATCH_ALREADY_INBOUND", "鎵规宸叉暣鎵瑰叆搴�");
+ batchId = batch.getId();
+ targetId = batch.getId();
+ quantity = batch.getBagQuantity() != null && batch.getBagQuantity() > 0
+ ? BigDecimal.valueOf(batch.getBagQuantity())
+ : BigDecimal.valueOf(bagCodeMapper.selectCountByBatchId(batch.getId()));
+ } else {
+ MesProBagCodeDO bag = bagCodeMapper.selectByCodeForUpdate(req.getBagCode());
+ if (bag == null) return failed(event, "MES_SCAN_BAG_NOT_EXISTS", "琚嬬爜涓嶅瓨鍦�");
+ event.setBagCodeId(bag.getId());
+ bagCodeId = bag.getId();
+ bagCode = req.getBagCode();
+ if (bag.getInboundEventId() != null) return failed(event, "MES_SCAN_BAG_ALREADY_INBOUND", "琚嬬爜宸插叆搴�");
+ batch = batchMapper.selectByIdForUpdate(bag.getBatchId());
+ if (batch == null) return failed(event, "MES_SCAN_BATCH_NOT_EXISTS", "鐢熶骇鎵规涓嶅瓨鍦�");
+ batchId = batch.getId();
+ targetId = bag.getId();
+ quantity = req.getQuantity();
+ }
+ event.setBatchId(batchId).setBatchCode(batch.getCode()).setItemId(batch.getItemId());
MesWmWarehouseDO warehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE);
if (warehouse == null) return failed(event, "MES_SCAN_WIP_WAREHOUSE_NOT_EXISTS", "WIP铏氭嫙浠撲笉瀛樺湪");
event.setWarehouseId(warehouse.getId()).setLocationId(req.getLocationId()).setAreaId(req.getAreaId());
@@ -72,19 +129,31 @@
}
Long txId = transactionService.createTransaction(new MesWmTransactionSaveReqDTO()
.setType(MesWmTransactionTypeEnum.IN.getType()).setBizType(MesBizTypeConstants.WM_PRODUCT_PRODUCE)
- .setBizId(batch.getId()).setBizCode(batch.getCode()).setBizLineId(bag.getId())
- .setItemId(batch.getItemId()).setQuantity(req.getQuantity())
+ .setBizId(batchId).setBizCode(batch.getCode()).setBizLineId(targetId)
+ .setItemId(batch.getItemId()).setQuantity(quantity)
.setBatchId(wmBatch.getId()).setBatchCode(batch.getCode())
+ .setBagCodeId(bagCodeId).setBagCode(bagCode)
.setWarehouseId(warehouse.getId()).setLocationId(req.getLocationId()).setAreaId(req.getAreaId())
.setReceiptTime(LocalDateTime.now()).setCheckFlag(true)
.setStockState(MesWmStockStateEnum.TEMP.getState()));
event.setTransactionId(txId).setStatus(MesProScanEventStatusEnum.SUCCESS).setEventTime(LocalDateTime.now());
eventMapper.updateById(event);
- bagCodeMapper.markInbound(bag.getId(), event.getId(), req.getDeviceCode(), req.getLineCode());
- batchMapper.markInbound(batch.getId(), event.getId(), req.getDeviceCode(), req.getLineCode());
+ // 2. 鍥炲啓鍏ュ簱鏍囪锛堟墭鐩�/鎵规鏁存墭/鏁存壒鍏ュ簱鏃跺悓姝ユ爣璁板叾涓嬫湭鍏ュ簱琚嬬爜锛屼繚鎸佺姸鎬佷竴鑷达級
+ if (SCAN_TYPE_PALLET.equals(scanType)) {
+ palletMapper.markInbound(targetId, event.getId());
+ bagCodeMapper.markInboundByPalletId(targetId, event.getId(), req.getLineCode());
+ } else if (SCAN_TYPE_BATCH.equals(scanType)) {
+ batchMapper.markBatchInbound(targetId, event.getId(), req.getLineCode(), batch.getBagQuantity());
+ bagCodeMapper.markInboundByBatchId(targetId, event.getId(), req.getLineCode());
+ } else {
+ bagCodeMapper.markInbound(targetId, event.getId(), req.getDeviceCode(), req.getLineCode());
+ batchMapper.markInbound(batchId, event.getId(), req.getDeviceCode(), req.getLineCode());
+ }
return event;
} catch (Exception ex) {
- return failed(event, "MES_SCAN_TRANSACTION_FAILED", "搴撳瓨浜嬪姟澶勭悊澶辫触");
+ log.error("[createInbound] 搴撳瓨浜嬪姟澶勭悊澶辫触锛宔ventId={}, bagCode={}, batchId={}, itemId={}",
+ req.getEventId(), req.getBagCode(), batchId, batch.getItemId(), ex);
+ throw ex;
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java
index 8fbf16c..ed096f1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityService.java
@@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.mes.service.qc.seedquality;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedQualityDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.MesQcSeedQualityIndicatorDO;
@@ -10,6 +12,8 @@
Long submit(MesQcSeedQualitySubmitReqVO reqVO);
+ PageResult<MesQcSeedQualityDO> getQualityPage(MesQcSeedQualityPageReqVO reqVO);
+
/**
* 鏍规嵁鎵规鍙锋煡璇㈣川妫�璁板綍锛堟寜妫�楠屾椂闂村�掑簭锛屽彇鏈�鏂帮級锛岀敤浜庡叕寮�婧簮銆�
* 绉嶅瓙璐ㄦ琛ㄦ湭鍒濆鍖栨椂杩斿洖绌哄垪琛紙瀹归敊锛屼笉褰卞搷杩芥函锛夈��
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
index 60b78c1..492d1d0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
@@ -1,41 +1,117 @@
package cn.iocoder.yudao.module.mes.service.qc.seedquality;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality.*;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.batch.MesWmBatchMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeQcStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum;
import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService;
-import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
-import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
+import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_WAREHOUSE_NOT_EXISTS;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_WAREHOUSE_TYPE_NOT_QUALIFIED;
@Service @Validated @Slf4j
public class MesQcSeedQualityServiceImpl implements MesQcSeedQualityService {
private static final Set<String> REQUIRED = Set.of("purity", "cleanliness", "germination_rate", "moisture");
@Resource private MesQcSeedQualityMapper qualityMapper;
@Resource private MesQcSeedQualityIndicatorMapper indicatorMapper;
+ @Resource private MesProBagCodeMapper bagCodeMapper;
@Resource private MesProBatchService proBatchService;
- @Resource private MesWmBatchService mesWmBatchService;
- @Resource private MesWmMaterialStockService materialStockService;
+ @Resource private MesWmBatchMapper mesWmBatchMapper;
+ @Resource private MesWmMaterialStockMapper materialStockMapper;
+ @Resource private MesWmMaterialStockBagMapper materialStockBagMapper;
+ @Resource private MesWmMaterialStockBagService materialStockBagService;
+ @Resource private MesWmTransactionService wmTransactionService;
+ @Resource private MesWmWarehouseService warehouseService;
+ @Resource private MesWmWarehouseLocationService warehouseLocationService;
+ @Resource private MesWmWarehouseAreaService warehouseAreaService;
+
+ @Override
+ public PageResult<MesQcSeedQualityDO> getQualityPage(MesQcSeedQualityPageReqVO reqVO) {
+ return qualityMapper.selectPage(reqVO);
+ }
@Override @Transactional(rollbackFor = Exception.class)
public Long submit(MesQcSeedQualitySubmitReqVO reqVO) {
if (reqVO.getIndicators().size() != 4) throw new IllegalArgumentException("蹇呴』鎻愪氦鍥涢」鎸囨爣");
if (qualityMapper.selectByCode(reqVO.getCode()) != null) throw new IllegalArgumentException("璇ヨ鐮佸凡璐ㄦ锛岀姝㈤噸澶嶆彁浜�");
+ // 绉嶅瓙璐ㄦ蹇呴』浠ヨ鐮侊紙鍗曡锛夋彁浜わ紝鐗╂枡淇℃伅鐢辫鐮佽嚜鍔ㄨВ鏋愶紝鍓嶇涓嶅啀鍗曠嫭閫夋嫨鐗╂枡
+ MesProBagCodeDO bag = bagCodeMapper.selectByCode(reqVO.getCode());
+ if (bag == null) {
+ throw new IllegalArgumentException("鏈В鏋愬埌鏈夋晥琚嬬爜锛岀瀛愯川妫�蹇呴』浠ヨ鐮佹彁浜�");
+ }
+ MesProBatchDO batch = resolveBatch(reqVO.getCode(), reqVO.getBatchCode());
+ if (batch == null || batch.getItemId() == null) {
+ throw new IllegalArgumentException("鏈牴鎹鐮佽В鏋愬埌鐗╂枡淇℃伅锛岃纭鎵爜鍐呭鎴栨壒娆″彿姝g‘");
+ }
+ // 琚嬬爜瀵瑰簲鎵规鐨勫簱瀛樺繀椤诲浜庢殏瀛樺簱锛堝緟璐ㄦ锛変腑锛屾墠鑳借繘琛岀瀛愯川妫�
+ MesWmBatchDO wmBatch = mesWmBatchMapper.selectByCode(batch.getCode());
+ if (wmBatch == null || materialStockMapper.selectTempStockCountByBatchId(wmBatch.getId()) == 0) {
+ throw new IllegalArgumentException("璇ヨ鐮�/鎵规瀵瑰簲鐨勫簱瀛樹笉鍦ㄦ殏瀛樺簱涓紝鏃犳硶杩涜璐ㄦ");
+ }
+ // 鏍¢獙鐩爣鍚堟牸搴擄細蹇呴』瀛樺湪涓斾粨搴撶被鍨嬩负鍚堟牸搴�(20)
+ if (warehouseService.getFirstQualifiedWarehouse() == null) {
+ throw exception(WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED);
+ }
+ MesWmWarehouseDO qualifiedWarehouse = warehouseService.getWarehouse(reqVO.getQualifiedWarehouseId());
+ if (qualifiedWarehouse == null) {
+ throw exception(WM_WAREHOUSE_NOT_EXISTS);
+ }
+ if (!MesWmWarehouseTypeEnum.QUALIFIED.getType().equals(qualifiedWarehouse.getType())) {
+ throw exception(WM_WAREHOUSE_TYPE_NOT_QUALIFIED);
+ }
+ // 瑙f瀽鍚堟牸搴撻粯璁ゅ簱鍖�/搴撲綅锛堝彇璇ヤ粨搴撲笅绗竴涓簱鍖恒�佸叾涓嬬涓�涓簱浣嶏紝鏈厤缃垯涓� null锛�
+ Long qualifiedLocationId = null;
+ Long qualifiedAreaId = null;
+ List<MesWmWarehouseLocationDO> locations = warehouseLocationService.getWarehouseLocationList(qualifiedWarehouse.getId());
+ if (CollUtil.isNotEmpty(locations)) {
+ qualifiedLocationId = locations.get(0).getId();
+ List<MesWmWarehouseAreaDO> areas = warehouseAreaService.getWarehouseAreaList(qualifiedLocationId);
+ if (CollUtil.isNotEmpty(areas)) {
+ qualifiedAreaId = areas.get(0).getId();
+ }
+ }
Set<String> codes = new HashSet<>();
boolean passed = true;
- MesQcSeedQualityDO quality = MesQcSeedQualityDO.builder().code(reqVO.getCode()).itemId(reqVO.getItemId())
- .batchCode(reqVO.getBatchCode()).reason(reqVO.getReason()).result(0)
+ MesQcSeedQualityDO quality = MesQcSeedQualityDO.builder().code(reqVO.getCode()).itemId(batch.getItemId())
+ .batchCode(batch.getCode()).reason(reqVO.getReason()).result(0)
.inspectedAt(LocalDateTime.now()).build();
qualityMapper.insert(quality);
for (MesQcSeedQualitySubmitReqVO.Indicator item : reqVO.getIndicators()) {
@@ -47,20 +123,151 @@
if (!codes.equals(REQUIRED)) throw new IllegalArgumentException("鍥涢」鎸囨爣涓嶅畬鏁�");
quality.setResult(passed ? 1 : 2);
qualityMapper.updateById(quality);
- // 璐ㄦ鍚堟牸 鈫� 搴撳瓨鏁存壒鐢辨殏瀛樺簱锛堝緟璐ㄦ锛夎浆涓哄悎鏍煎簱锛堟寮忓簱瀛橈級
+ // 鎸夎鐮佺矑搴︽祦杞簱瀛橈細閿佸畾璇ヨ鍦ㄦ殏瀛樺簱涓殑娲诲姩鏄庣粏锛岀姝㈡寜鎵规浠绘剰鎵e噺
+ MesWmMaterialStockBagDO stockBag = materialStockBagMapper.selectActiveByBagCode(bag.getCode());
+ MesWmMaterialStockDO tempStock = resolveTempStock(bag, wmBatch, stockBag);
+ // A. 鏆傚瓨鍑哄簱锛�-1锛夛細璇ヨ绂诲紑鏆傚瓨搴擄紝鍐欏叆璐ㄦ鏆傚瓨鍑哄簱浜嬪姟锛堣烦杩囪鐮佽嚜鍔ㄧ淮鎶わ紝鐢辫川妫�缁熶竴鎺у埗琚嬬爜鏈�缁堣惤鐐癸級
+ MesWmTransactionSaveReqDTO tempOutReq = new MesWmTransactionSaveReqDTO()
+ .setType(MesWmTransactionTypeEnum.OUT.getType())
+ .setBizType(MesBizTypeConstants.QC_SEED_QUALITY)
+ .setBizId(quality.getId())
+ .setBizCode(reqVO.getCode())
+ .setBizLineId(quality.getId())
+ .setItemId(batch.getItemId())
+ .setQuantity(BigDecimal.ONE.negate())
+ .setBatchId(tempStock.getBatchId())
+ .setBatchCode(tempStock.getBatchCode())
+ .setBagCodeId(bag.getId())
+ .setBagCode(bag.getCode())
+ .setWarehouseId(tempStock.getWarehouseId())
+ .setLocationId(tempStock.getLocationId())
+ .setAreaId(tempStock.getAreaId())
+ .setVendorId(tempStock.getVendorId())
+ .setMaterialStockId(tempStock.getId())
+ .setCheckFlag(true)
+ .setSkipBagManage(true);
+ Long tempOutTxId = wmTransactionService.createTransaction(tempOutReq);
if (passed) {
- MesProBatchDO proBatch = proBatchService.getBatchByCode(reqVO.getBatchCode());
- if (proBatch != null) {
- MesWmBatchDO wmBatch = mesWmBatchService.getOrCreateByProBatch(proBatch);
- if (wmBatch != null) {
- int updated = materialStockService.updateStockStateByBatchId(wmBatch.getId(),
- MesWmStockStateEnum.QUALIFIED.getState(), MesWmStockStateEnum.TEMP.getState());
- log.info("[submit][璐ㄦ鍚堟牸锛屾壒娆� {} 搴撳瓨鐢辨殏瀛樺簱杞悎鏍煎簱锛屽奖鍝� {} 鏉", reqVO.getBatchCode(), updated);
+ // B1. 璐ㄦ鍚堟牸 鈫� 璇ヨ杞叆鎿嶄綔鍛橀�夋嫨鐨勫悎鏍煎簱锛屽啓鍏ュ悎鏍煎叆搴撲簨鍔★紙璺宠繃琚嬬爜鑷姩缁存姢锛�
+ MesWmMaterialStockDO qualifiedStock = getOrCreateQualifiedStock(tempStock, qualifiedWarehouse.getId(), qualifiedLocationId, qualifiedAreaId);
+ MesWmTransactionSaveReqDTO qualInReq = new MesWmTransactionSaveReqDTO()
+ .setType(MesWmTransactionTypeEnum.IN.getType())
+ .setBizType(MesBizTypeConstants.QC_SEED_QUALITY)
+ .setBizId(quality.getId())
+ .setBizCode(reqVO.getCode())
+ .setBizLineId(quality.getId())
+ .setItemId(batch.getItemId())
+ .setQuantity(BigDecimal.ONE)
+ .setBatchId(qualifiedStock.getBatchId())
+ .setBatchCode(qualifiedStock.getBatchCode())
+ .setBagCodeId(bag.getId())
+ .setBagCode(bag.getCode())
+ .setWarehouseId(qualifiedStock.getWarehouseId())
+ .setLocationId(qualifiedStock.getLocationId())
+ .setAreaId(qualifiedStock.getAreaId())
+ .setVendorId(qualifiedStock.getVendorId())
+ .setMaterialStockId(qualifiedStock.getId())
+ .setCheckFlag(false)
+ .setStockState(MesWmStockStateEnum.QUALIFIED.getState())
+ .setSkipBagManage(true);
+ Long qualInTxId = wmTransactionService.createTransaction(qualInReq);
+ // B2. 鍚屾杩佺Щ琚嬬爜鏄庣粏鍒板悎鏍煎簱瀛樿惤鐐�
+ materialStockBagService.moveIn(qualInReq, qualifiedStock, qualInTxId);
+ bagCodeMapper.updateQcStatus(bag.getId(), MesProBagCodeQcStatusEnum.QUALIFIED.getStatus());
+ log.info("[submit][璐ㄦ鍚堟牸锛岃鐮� {} 鐢辨殏瀛樺簱杞悎鏍煎簱 {}]", bag.getCode(), qualifiedWarehouse.getName());
+ } else {
+ // C. 璐ㄦ涓嶅悎鏍� 鈫� 璇ヨ鎶ュ簾锛涙殏瀛樺嚭搴撲簨鍔″凡鎵e噺鏆傚瓨搴撳瓨锛屾爣璁拌鐮佹姤搴�
+ materialStockBagService.scrap(tempOutReq, tempOutTxId);
+ bagCodeMapper.updateQcStatus(bag.getId(), MesProBagCodeQcStatusEnum.UNQUALIFIED.getStatus());
+ log.info("[submit][璐ㄦ涓嶅悎鏍硷紝琚嬬爜 {} 鎶ュ簾]", bag.getCode());
+ }
+ return quality.getId();
+ }
+
+ /**
+ * 瀹氫綅璇ヨ鐨勬殏瀛樺簱瀛樻眹鎬昏褰曪紙鍙畾浣嶏紝涓嶆墸鍑忥紱鎵e噺鐢辫川妫�鏆傚瓨鍑哄簱浜嬪姟瀹屾垚锛夈��
+ * <p>
+ * 浼樺厛涓ユ牸鎸夎鐮侀攣瀹氬叾娲诲姩鏄庣粏瀵瑰簲鐨勬殏瀛樿褰曪紱鍘嗗彶鏃犳槑缁嗘椂鍥為��鎸夋壒娆″畾浣嶅苟琛ュ缓鏄庣粏銆�
+ */
+ private MesWmMaterialStockDO resolveTempStock(MesProBagCodeDO bag, MesWmBatchDO wmBatch, MesWmMaterialStockBagDO stockBag) {
+ if (stockBag != null && stockBag.getMaterialStockId() != null) {
+ MesWmMaterialStockDO stock = materialStockMapper.selectById(stockBag.getMaterialStockId());
+ if (stock != null && MesWmStockStateEnum.TEMP.getState().equals(stock.getStockState())) {
+ return stock;
+ }
+ }
+ MesWmMaterialStockDO tempStock = materialStockMapper.selectStockListByBatchId(wmBatch.getId()).stream()
+ .filter(s -> MesWmStockStateEnum.TEMP.getState().equals(s.getStockState()))
+ .max(Comparator.comparing(MesWmMaterialStockDO::getQuantity))
+ .orElse(null);
+ if (tempStock == null) {
+ throw new IllegalArgumentException("璇ユ壒娆℃殏瀛樺簱瀛樹笉瓒筹紝鏃犳硶璐ㄦ");
+ }
+ getOrCreateStockBag(bag, tempStock);
+ return tempStock;
+ }
+
+ /**
+ * 璐ㄦ鍚堟牸锛氬皢璐ㄦ閫氳繃鐨勯偅琚嬭浆鍏ユ搷浣滃憳閫夋嫨鐨勫悎鏍煎簱锛堝悓缁勫悎閿悎鏍煎簱璁板綍 +1锛屼笉瀛樺湪鍒欐柊寤猴級銆�
+ *
+ * @param tempStock 浠庢殏瀛樺簱鎵e噺鍚庤繑鍥炵殑鏆傚瓨璁板綍锛堟惡甯� item/batch/vendor 缁村害锛�
+ * @param qualifiedWarehouseId 鐩爣鍚堟牸搴撲粨搴撶紪鍙�
+ * @param qualifiedLocationId 鐩爣鍚堟牸搴撳簱鍖虹紪鍙凤紙鏈厤缃垯涓� null锛�
+ * @param qualifiedAreaId 鐩爣鍚堟牸搴撳簱浣嶇紪鍙凤紙鏈厤缃垯涓� null锛�
+ */
+ private MesWmMaterialStockBagDO getOrCreateStockBag(MesProBagCodeDO bag, MesWmMaterialStockDO tempStock) {
+ MesWmMaterialStockBagDO stockBag = materialStockBagMapper.selectByBagCode(bag.getCode());
+ if (stockBag != null) {
+ return stockBag;
+ }
+ stockBag = MesWmMaterialStockBagDO.builder().materialStockId(tempStock.getId())
+ .bagCodeId(bag.getId()).bagCode(bag.getCode()).itemId(tempStock.getItemId())
+ .batchId(tempStock.getBatchId()).batchCode(tempStock.getBatchCode()).vendorId(tempStock.getVendorId())
+ .warehouseId(tempStock.getWarehouseId()).locationId(tempStock.getLocationId()).areaId(tempStock.getAreaId())
+ .stockState(MesWmStockStateEnum.TEMP.getState()).status(1).quantity(BigDecimal.ONE)
+ .frozen(false).inboundTime(tempStock.getReceiptTime()).build();
+ materialStockBagMapper.insert(stockBag);
+ return stockBag;
+ }
+
+ private MesWmMaterialStockDO getOrCreateQualifiedStock(MesWmMaterialStockDO tempStock, Long qualifiedWarehouseId,
+ Long qualifiedLocationId, Long qualifiedAreaId) {
+ MesWmMaterialStockDO qualified = materialStockMapper.selectQualifiedByCompositeKey(
+ tempStock.getItemId(), qualifiedWarehouseId, qualifiedLocationId,
+ qualifiedAreaId, tempStock.getBatchId(), tempStock.getVendorId());
+ if (qualified != null) {
+ return qualified;
+ }
+ // 涓嶅瓨鍦ㄥ垯鏂板缓鍚堟牸搴撹褰曪紙浠撳簱/搴撳尯/搴撲綅閲囩敤鎵�閫夊悎鏍煎簱鐨勭淮搴︼紝鏁伴噺鐢辫川妫�鍏ュ簱浜嬪姟 +1锛�
+ MesWmMaterialStockDO newStock = MesWmMaterialStockDO.builder()
+ .itemId(tempStock.getItemId()).itemTypeId(tempStock.getItemTypeId())
+ .warehouseId(qualifiedWarehouseId).locationId(qualifiedLocationId).areaId(qualifiedAreaId)
+ .batchId(tempStock.getBatchId()).batchCode(tempStock.getBatchCode()).vendorId(tempStock.getVendorId())
+ .quantity(BigDecimal.ZERO).receiptTime(LocalDateTime.now())
+ .stockState(MesWmStockStateEnum.QUALIFIED.getState())
+ .frozen(false)
+ .build();
+ materialStockMapper.insert(newStock);
+ return newStock;
+ }
+
+ /**
+ * 鐢辫鐮佹垨鐢熶骇鎵规瑙f瀽鎵�灞炵敓浜ф壒娆★紙琚嬬爜浼樺厛锛屾壒娆$爜鍏煎涓存椂鐮侊級
+ */
+ private MesProBatchDO resolveBatch(String code, String batchCode) {
+ if (StrUtil.isNotBlank(code)) {
+ MesProBagCodeDO bag = bagCodeMapper.selectByCode(code);
+ if (bag != null && bag.getBatchId() != null) {
+ MesProBatchDO batch = proBatchService.getBatch(bag.getBatchId());
+ if (batch != null) {
+ return batch;
}
}
}
- // 搴撲綅鐢卞悗鍙伴厤缃湇鍔℃帴绠★紝褰撳墠鐗堟湰淇濈暀瀹¤闂幆锛岀姝㈠墠绔紶鍏ュ簱浣嶃��
- return quality.getId();
+ if (StrUtil.isNotBlank(batchCode)) {
+ return proBatchService.getBatchByCode(batchCode);
+ }
+ return null;
}
@Override
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
index 110c7b1..04ff12f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
@@ -38,6 +38,9 @@
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -212,6 +215,7 @@
fillAntiFake(resp, traceCode);
// 鍙�夋墿灞曞尯鍧楋紙鏈夋暟鎹墠杩斿洖锛�
fillOptionalModules(resp, batch);
+ fillTimelineAndDecision(resp);
return resp;
}
@@ -338,6 +342,47 @@
}
}
+ private void fillTimelineAndDecision(MesProTracePublicRespVO resp) {
+ List<MesProTracePublicRespVO.TimelineVO> timeline = new ArrayList<>();
+ if (resp.getProduceDate() != null) {
+ timeline.add(timeline("鐢熶骇", "BATCH_CREATED", "鐢熶骇鎵规寤虹珛", resp.getProduceDate(), null,
+ resp.getBatchStatusName()));
+ }
+ if (resp.getProcessTraces() != null) {
+ resp.getProcessTraces().forEach(item -> timeline.add(timeline("鍔犲伐", item.getEventType(),
+ item.getEventType() == null ? "宸ュ簭娴佽浆" : ("IN".equals(item.getEventType()) ? "宸ュ簭鎶曞叆" : "宸ュ簭浜у嚭"),
+ item.getEventTime(), item.getQuantity(), item.getQualityStatus() == null ? null : String.valueOf(item.getQualityStatus()))));
+ }
+ if (resp.getInbound() != null) {
+ timeline.add(timeline("浠撳偍", "INBOUND", "浠撳偍鍏ュ簱", resp.getInbound().getEventTime(),
+ resp.getInbound().getQuantity(), resp.getInbound().getStatus()));
+ }
+ if (resp.getSalesTargets() != null) {
+ resp.getSalesTargets().forEach(item -> timeline.add(timeline("閿�鍞�", "OUTBOUND", "閿�鍞嚭搴�",
+ item.getSalesDate(), item.getQuantity(), item.getQualityStatus() == null ? null : String.valueOf(item.getQualityStatus()))));
+ }
+ timeline.sort(Comparator.comparing(MesProTracePublicRespVO.TimelineVO::getEventTime,
+ Comparator.nullsLast(Comparator.naturalOrder())));
+ resp.setTimeline(timeline);
+
+ MesProTracePublicRespVO.DecisionVO decision = new MesProTracePublicRespVO.DecisionVO();
+ decision.setQualityRisk(resp.getQuality() != null && Integer.valueOf(2).equals(resp.getQuality().getResult()));
+ decision.setInboundQuantity(resp.getInbound() == null ? null : resp.getInbound().getQuantity());
+ decision.setSalesTargetCount(resp.getSalesTargets() == null ? 0 : resp.getSalesTargets().size());
+ decision.setConsumerScanCount(resp.getAntiFake() == null ? 0L : resp.getAntiFake().getScanCount());
+ decision.setRiskLevel(Boolean.TRUE.equals(decision.getQualityRisk()) ? "HIGH" : "NORMAL");
+ resp.setDecision(decision);
+ }
+
+ private MesProTracePublicRespVO.TimelineVO timeline(String stage, String eventType, String eventName,
+ java.time.LocalDateTime eventTime, BigDecimal quantity,
+ String status) {
+ MesProTracePublicRespVO.TimelineVO vo = new MesProTracePublicRespVO.TimelineVO();
+ vo.setStage(stage).setEventType(eventType).setEventName(eventName).setEventTime(eventTime)
+ .setQuantity(quantity).setStatus(status);
+ return vo;
+ }
+
// ==================== 鍚嶇О鏄犲皠 ====================
private String userName(Long userId) {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
index 313063f..f4ecec0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
@@ -423,13 +423,21 @@
if (proBatch == null || StrUtil.isBlank(proBatch.getCode())) {
return null;
}
- // 1. 澶嶇敤宸叉湁浠撳簱鎵规锛堝悓涓�鐢熶骇鎵规鍙凤級
- MesWmBatchDO existing = batchMapper.selectByCode(proBatch.getCode());
+ // 1. 浼樺厛鎸夌敓浜ф壒娆� ID 澶嶇敤锛屽吋瀹瑰巻鍙叉暟鎹啀鎸夋壒娆″彿鍖归厤
+ MesWmBatchDO existing = batchMapper.selectOne(MesWmBatchDO::getProBatchId, proBatch.getId());
+ if (existing == null) {
+ existing = batchMapper.selectByCode(proBatch.getCode());
+ }
if (existing != null) {
+ if (existing.getProBatchId() == null && proBatch.getId() != null) {
+ existing.setProBatchId(proBatch.getId());
+ batchMapper.updateById(existing);
+ }
return existing;
}
// 2. 鏂板缓浠撳簱鎵规锛氫互鐢熶骇鎵规鍙蜂綔涓轰粨搴撴壒娆″彿锛岃川閲忕姸鎬佺疆涓哄緟妫�楠�
MesWmBatchDO batch = MesWmBatchDO.builder()
+ .proBatchId(proBatch.getId())
.code(proBatch.getCode())
.itemId(proBatch.getItemId())
.produceDate(proBatch.getProduceDate())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
index 2e6a51f..8d9a29d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
@@ -132,6 +132,18 @@
List<MesWmMaterialStockDO> getMaterialStockListByItemAndBatch(Long itemId, Long batchId);
/**
+ * 鏌ヨ鐗╂枡/鎵规鐨勫悎鏍煎簱搴撳瓨璁板綍锛堜粎 stock_state=20锛�
+ *
+ * <p>鍚屾壒娆″彲鑳藉悓鏃跺瓨鍦ㄦ殏瀛樺簱涓庡悎鏍煎簱涓ゆ潯璁板綍锛堢瀛愯川妫�鎸夎鎷嗘暟閲忥級锛�
+ * 閿�鍞嚭搴撻�夊簱瀛樺繀椤讳粠鍚堟牸搴撹褰曚腑閫夛紝閬垮厤閫変腑鏈川妫�鐨勬殏瀛樺簱瀛樸��</p>
+ *
+ * @param itemId 鐗╂枡缂栧彿
+ * @param batchId 鎵规缂栧彿
+ * @return 鍚堟牸搴撳簱瀛樿褰曞垪琛�
+ */
+ List<MesWmMaterialStockDO> getQualifiedMaterialStockListByItemAndBatch(Long itemId, Long batchId);
+
+ /**
* 鏇存柊搴撳瓨鏁伴噺
*
* @param id 搴撳瓨璁板綍缂栧彿
@@ -165,16 +177,6 @@
* @return 浠撳簱姹囨�诲垪琛�
*/
List<MesWmStockSummaryRespVO> getStockSummaryByWarehouse(MesWmMaterialStockListReqVO reqVO);
-
- /**
- * 鎸変粨搴撴壒娆℃洿鏂板簱瀛樼姸鎬侊紙鐢ㄤ簬绉嶅瓙璐ㄦ鍚堟牸鍚庯紝灏嗘殏瀛樺簱鏁存壒杞负鍚堟牸搴擄級
- *
- * @param batchId 浠撳簱鎵规ID
- * @param toState 鐩爣搴撳瓨鐘舵��
- * @param fromState 鍘熷簱瀛樼姸鎬侊紙闄愬畾鍙洿鏂拌鐘舵�佺殑璁板綍锛�
- * @return 褰卞搷琛屾暟
- */
- int updateStockStateByBatchId(Long batchId, Integer toState, Integer fromState);
/**
* 搴撲綅娣锋斁瑙勫垯鏍¢獙
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
index 4318153..b3b7ec6 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
@@ -29,6 +29,9 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
+import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
import jakarta.annotation.Resource;
@@ -44,6 +47,7 @@
import java.util.function.Function;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -74,6 +78,11 @@
@Resource
@Lazy
private MesWmBatchService batchService;
+
+ @Resource
+ private MesWmMaterialStockBagMapper materialStockBagMapper;
+ @Resource
+ private MesWmMaterialStockBagService materialStockBagService;
@Override
public MesWmMaterialStockDO getMaterialStock(Long id) {
@@ -121,9 +130,27 @@
Assert.notNull(virtualWarehouse, "铏氭嫙浠撳簱锛圵IP_VIRTUAL_WAREHOUSE锛変笉瀛樺湪");
virtualWarehouseId = virtualWarehouse.getId();
}
+ // 1.4 瑙f瀽 warehouseType锛氳浆鎹负璇ョ被鍨嬩粨搴� warehouseIds锛堜笌 warehouseId / virtualFilter 骞跺瓨锛屼繚鐣欏吋瀹癸級
+ List<Long> warehouseIds = resolveWarehouseIdsByType(pageReqVO.getWarehouseType());
+ if (warehouseIds != null && warehouseIds.isEmpty()) {
+ return PageResult.empty();
+ }
// 2. 鍒嗛〉鏌ヨ
- return materialStockMapper.selectPage(pageReqVO, itemTypeIds, itemIds, virtualWarehouseId);
+ return materialStockMapper.selectPage(pageReqVO, itemTypeIds, itemIds, virtualWarehouseId, warehouseIds);
+ }
+
+ /**
+ * 灏嗕粨搴撶被鍨嬭В鏋愪负浠撳簱 id 闆嗗悎锛坵arehouseType 涓� null 鏃朵笉鍔犺繃婊わ紝杩斿洖 null锛�
+ *
+ * @param warehouseType 浠撳簱绫诲瀷锛岃 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum}
+ * @return 璇ョ被鍨嬩粨搴� id 闆嗗悎锛泈arehouseType 涓� null 杩斿洖 null锛涜绫诲瀷鏃犱粨搴撹繑鍥炵┖闆嗗悎
+ */
+ private List<Long> resolveWarehouseIdsByType(Integer warehouseType) {
+ if (warehouseType == null) {
+ return null;
+ }
+ return convertList(warehouseService.getWarehouseListByType(warehouseType), MesWmWarehouseDO::getId);
}
@Override
@@ -169,7 +196,11 @@
@Override
public List<MesWmMaterialStockDO> getMaterialStockList(MesWmMaterialStockListReqVO reqVO) {
- return materialStockMapper.selectList(reqVO);
+ List<Long> warehouseIds = resolveWarehouseIdsByType(reqVO.getWarehouseType());
+ if (warehouseIds != null && warehouseIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return materialStockMapper.selectList(reqVO, warehouseIds);
}
@Override
@@ -282,7 +313,17 @@
@Override
public MesWmMaterialStockDO getMaterialStockByCompositeKey(Long itemId, Long warehouseId, Long locationId, Long areaId,
Long batchId, Long vendorId) {
- return materialStockMapper.selectByCompositeKey(itemId, warehouseId, locationId, areaId, batchId, vendorId);
+ // 鍑哄簱/鍗犵敤鍙粠鍚堟牸搴撳尮閰嶏紝閬垮厤鎵e埌鍚屾壒娆$殑鏆傚瓨搴擄紙绉嶅瓙璐ㄦ鎸夎鎷嗘暟閲忓悗鍚屾壒娆″弻鐘舵�佸苟瀛橈級
+ return materialStockMapper.selectQualifiedByCompositeKey(itemId, warehouseId, locationId, areaId, batchId, vendorId);
+ }
+
+ @Override
+ public List<MesWmMaterialStockDO> getQualifiedMaterialStockListByItemAndBatch(Long itemId, Long batchId) {
+ List<Long> qualifiedWarehouseIds = warehouseService.getQualifiedWarehouseIds();
+ if (CollUtil.isEmpty(qualifiedWarehouseIds)) {
+ return Collections.emptyList();
+ }
+ return materialStockMapper.selectQualifiedListByItemAndBatch(itemId, batchId, qualifiedWarehouseIds);
}
@Override
@@ -302,11 +343,6 @@
@Override
public void updateMaterialStockState(Long id, Integer stockState) {
materialStockMapper.updateById(new MesWmMaterialStockDO().setId(id).setStockState(stockState));
- }
-
- @Override
- public int updateStockStateByBatchId(Long batchId, Integer toState, Integer fromState) {
- return materialStockMapper.updateStockStateByBatchId(batchId, toState, fromState);
}
@Override
@@ -356,7 +392,11 @@
|| ObjUtil.notEqual(stock.getAreaId(), areaId)) {
throw exception(WM_MATERIAL_STOCK_SELECTION_MISMATCH);
}
- // 3. 鏍¢獙搴撳瓨鏁伴噺鍏呰冻锛堝鏋滃墠绔紶浜� quantity锛屽垯蹇呴』淇濊瘉搴撳瓨鏁伴噺 >= quantity锛�
+ // 3. 鏍¢獙搴撳瓨璁板綍蹇呴』鏄悎鏍煎簱锛堟殏瀛樺簱瀛樻湭璐ㄦ锛屼笉鍙敤浜庡嚭搴�/鍗犵敤锛�
+ if (!MesWmStockStateEnum.QUALIFIED.getState().equals(stock.getStockState())) {
+ throw exception(WM_MATERIAL_STOCK_NOT_QUALIFIED);
+ }
+ // 4. 鏍¢獙搴撳瓨鏁伴噺鍏呰冻锛堝鏋滃墠绔紶浜� quantity锛屽垯蹇呴』淇濊瘉搴撳瓨鏁伴噺 >= quantity锛�
if (quantity != null && stock.getQuantity() != null && stock.getQuantity().compareTo(quantity) < 0) {
throw exception(WM_MATERIAL_STOCK_INSUFFICIENT);
}
@@ -592,6 +632,32 @@
.setRelatedTransactionId(outTransactionId)
.setCheckFlag(false);
wmTransactionService.createTransaction(inTransaction);
+
+ // 9. 鏁翠綅缃Щ搴撴椂锛岄�愯杩佺Щ琚嬬爜鏄庣粏浣嶇疆锛堟暟閲忕瓑浜庢簮搴撲綅娲诲姩琚嬫暟涓斾负鏁存暟鎵嶈涓烘暣浣嶇Щ搴擄級
+ MesWmMaterialStockDO finalTargetStock = materialStockMapper.selectByCompositeKeyIgnoreVendor(
+ sourceStock.getItemId(), reqVO.getToWarehouseId(), reqVO.getToLocationId(),
+ reqVO.getToAreaId(), sourceStock.getBatchId());
+ relocateBagsForMove(sourceStock, reqVO.getQuantity(), inTransaction, finalTargetStock);
+ }
+
+ /**
+ * 鏁翠綅绉诲簱锛氬皢婧愬簱浣嶇殑娲诲姩琚嬬爜鏄庣粏杩佺Щ鍒扮洰鏍囧簱浣嶃��
+ * <p>
+ * 浠呭綋绉诲簱鏁伴噺绛変簬婧愬簱浣嶆椿鍔ㄨ鏁颁笖涓烘暣鏁版椂鎵ц锛堟暣浣嶇疆鎼Щ锛夛紝灏嗘瘡琚嬫槑缁嗙殑搴撳瓨姹囨�汇�佷粨搴撱�佸簱鍖恒�佸簱浣�
+ * 鏇存柊涓虹洰鏍囦綅缃紱閮ㄥ垎绉诲簱/鏃犺鐮佹槑缁嗙殑鏃у簱瀛樹笉鍋氳鐮佽縼绉伙紝淇濇寔姹囨�诲簱瀛樺彉鍔ㄥ嵆鍙��
+ */
+ private void relocateBagsForMove(MesWmMaterialStockDO sourceStock, BigDecimal quantity,
+ MesWmTransactionSaveReqDTO moveInReq, MesWmMaterialStockDO targetStock) {
+ List<MesWmMaterialStockBagDO> bags = materialStockBagMapper.selectActiveListByItemAndBatch(
+ sourceStock.getItemId(), sourceStock.getBatchId(), sourceStock.getStockState());
+ if (CollUtil.isEmpty(bags) || targetStock == null || quantity == null
+ || quantity.compareTo(BigDecimal.valueOf(bags.size())) != 0) {
+ return;
+ }
+ for (MesWmMaterialStockBagDO bag : bags) {
+ moveInReq.setBagCodeId(bag.getBagCodeId()).setBagCode(bag.getBagCode());
+ materialStockBagService.moveIn(moveInReq, targetStock, null);
+ }
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagService.java
new file mode 100644
index 0000000..ce3eb1d
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagService.java
@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.module.mes.service.wm.materialstockbag;
+
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
+
+/**
+ * MES 搴撳瓨琚嬬爜鏄庣粏 Service 鎺ュ彛
+ *
+ * 缁熶竴灏佽琚嬬爜搴撳瓨鏄庣粏鐨勫缓绔嬨�佽縼绉汇�佸嚭搴撱�佹姤搴熼�昏緫锛屼緵鎵�鏈夊甫琚嬬爜鐨勫簱瀛樺彉鍔ㄥ叆鍙e鐢ㄣ��
+ * 姣忎釜琚嬬爜鍦ㄥ悓涓�鏃堕棿鍙湁涓�鏉″湪搴撴槑缁嗭紙鍞竴绾︽潫 bag_code锛夛紝娴佽浆閫氳繃鏇存柊鏄庣粏浣嶇疆/鐘舵�佸疄鐜般��
+ */
+public interface MesWmMaterialStockBagService {
+
+ /**
+ * 鍏ュ簱锛氬缓绔嬫垨婵�娲绘椿鍔ㄨ鐮佹槑缁嗐��
+ * <p>
+ * 琚嬬爜棣栨鍏ュ簱鏃舵柊寤烘槑缁嗭紱宸插嚭搴�/宸叉姤搴熺殑琚嬬爜鍐嶆鍏ュ簱鏃舵縺娲讳负鍦ㄥ簱骞舵洿鏂颁綅缃紱宸插湪搴撳垯瑙嗕负閲嶅鍏ュ簱鎶涘嚭寮傚父銆�
+ *
+ * @param reqDTO 浜嬪姟璇锋眰
+ * @param stock 鐩爣搴撳瓨姹囨�昏褰�
+ * @param transactionId 鏈瑪浜嬪姟 ID
+ * @return 琚嬬爜鏄庣粏
+ */
+ MesWmMaterialStockBagDO inbound(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO stock, Long transactionId);
+
+ /**
+ * 鍑哄簱锛氬皢鎸囧畾琚嬬爜鏄庣粏缃负宸插嚭搴撱��
+ *
+ * @param reqDTO 浜嬪姟璇锋眰锛堥渶鎼哄甫 bagCode/bagCodeId锛�
+ * @param transactionId 鏈瑪浜嬪姟 ID
+ */
+ void outbound(MesWmTransactionSaveReqDTO reqDTO, Long transactionId);
+
+ /**
+ * 绉诲叆/杩佺Щ锛氭洿鏂版椿鍔ㄨ鐮佹槑缁嗙殑浣嶇疆涓庡簱瀛樼姸鎬侊紙绉诲簱銆佽皟鎷ㄣ�佽川妫�鍚堟牸杩佺Щ锛夈��
+ *
+ * @param reqDTO 浜嬪姟璇锋眰锛堥渶鎼哄甫 bagCode锛�
+ * @param targetStock 鐩爣搴撳瓨姹囨�昏褰�
+ * @param transactionId 鏈瑪浜嬪姟 ID
+ */
+ void moveIn(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO targetStock, Long transactionId);
+
+ /**
+ * 鎶ュ簾锛氬皢鎸囧畾琚嬬爜鏄庣粏缃负鎶ュ簾銆�
+ *
+ * @param reqDTO 浜嬪姟璇锋眰锛堥渶鎼哄甫 bagCode锛�
+ * @param transactionId 鏈瑪浜嬪姟 ID
+ */
+ void scrap(MesWmTransactionSaveReqDTO reqDTO, Long transactionId);
+
+ /**
+ * 鏍规嵁搴撳瓨姹囨�� ID 鏌ヨ鍦ㄥ簱琚嬬爜鏄庣粏銆�
+ *
+ * @param materialStockId 搴撳瓨姹囨�� ID
+ * @return 琚嬬爜鏄庣粏锛堟棤鍒� null锛�
+ */
+ MesWmMaterialStockBagDO getActiveByMaterialStockId(Long materialStockId);
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagServiceImpl.java
new file mode 100644
index 0000000..3929602
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstockbag/MesWmMaterialStockBagServiceImpl.java
@@ -0,0 +1,165 @@
+package cn.iocoder.yudao.module.mes.service.wm.materialstockbag;
+
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmMaterialStockBagStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
+
+/**
+ * MES 搴撳瓨琚嬬爜鏄庣粏 Service 瀹炵幇绫�
+ *
+ * 琚嬬爜鏄庣粏鐢熷懡鍛ㄦ湡锛氶娆″叆搴撳缓绔嬶紙ACTIVE锛夆啋 绉诲簱/璐ㄦ杩佺Щ浣嶇疆鐘舵�� 鈫� 鍑哄簱/鎶ュ簾缁撴潫锛圤UT/SCRAPPED锛夈��
+ * 鍞竴绾︽潫 bag_code 淇濊瘉姣忎釜琚嬬爜浠呬竴鏉℃槑缁嗭紝澶嶇敤鍚屼竴琛屽畬鎴愬叏鐢熷懡鍛ㄦ湡娴佽浆銆�
+ */
+@Service
+@Validated
+public class MesWmMaterialStockBagServiceImpl implements MesWmMaterialStockBagService {
+
+ @Resource
+ private MesWmMaterialStockBagMapper materialStockBagMapper;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public MesWmMaterialStockBagDO inbound(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO stock, Long transactionId) {
+ String bagCode = reqDTO.getBagCode();
+ if (StrUtil.isBlank(bagCode)) {
+ throw exception(WM_MATERIAL_STOCK_BAG_REQUIRED);
+ }
+ // 1. 鏌ヨ璇ヨ鐮佹棦鏈夋槑缁嗭細浼樺厛鎸� bagCodeId锛屽叾娆℃寜 bagCode
+ MesWmMaterialStockBagDO existing = materialStockBagMapper.selectByBagCode(bagCode);
+ if (existing == null && reqDTO.getBagCodeId() != null) {
+ existing = materialStockBagMapper.selectByBagCodeId(reqDTO.getBagCodeId());
+ }
+ if (existing != null) {
+ // 2. 宸插湪搴� 鈫� 閲嶅鍏ュ簱锛岀姝�
+ if (MesWmMaterialStockBagStatusEnum.ACTIVE.getStatus().equals(existing.getStatus())) {
+ throw exception(WM_MATERIAL_STOCK_BAG_DUPLICATE, bagCode);
+ }
+ // 3. 宸插嚭搴�/鎶ュ簾 鈫� 閲嶆柊婵�娲诲苟鏇存柊浣嶇疆
+ return reactivate(existing, reqDTO, stock, transactionId);
+ }
+ // 4. 棣栨鍏ュ簱 鈫� 鏂板缓鏄庣粏
+ MesWmMaterialStockBagDO bag = MesWmMaterialStockBagDO.builder()
+ .materialStockId(stock.getId())
+ .bagCodeId(reqDTO.getBagCodeId())
+ .bagCode(bagCode)
+ .itemId(stock.getItemId())
+ .batchId(stock.getBatchId())
+ .batchCode(stock.getBatchCode())
+ .vendorId(stock.getVendorId())
+ .warehouseId(stock.getWarehouseId())
+ .locationId(stock.getLocationId())
+ .areaId(stock.getAreaId())
+ .stockState(ObjUtil.defaultIfNull(reqDTO.getStockState(), stock.getStockState()))
+ .status(MesWmMaterialStockBagStatusEnum.ACTIVE.getStatus())
+ .quantity(BigDecimal.ONE)
+ .frozen(false)
+ .lastTransactionId(transactionId)
+ .inboundTime(LocalDateTime.now())
+ .build();
+ materialStockBagMapper.insert(bag);
+ return bag;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void outbound(MesWmTransactionSaveReqDTO reqDTO, Long transactionId) {
+ MesWmMaterialStockBagDO bag = requireActiveBag(reqDTO);
+ MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO();
+ update.setId(bag.getId());
+ update.setStatus(MesWmMaterialStockBagStatusEnum.OUT.getStatus());
+ update.setStockState(MesWmStockStateEnum.OUT.getState());
+ update.setLastTransactionId(transactionId);
+ update.setOutboundTime(LocalDateTime.now());
+ materialStockBagMapper.updateById(update);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void moveIn(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO targetStock, Long transactionId) {
+ MesWmMaterialStockBagDO bag = requireActiveBag(reqDTO);
+ MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO();
+ update.setId(bag.getId());
+ update.setMaterialStockId(targetStock.getId());
+ update.setWarehouseId(targetStock.getWarehouseId());
+ update.setLocationId(targetStock.getLocationId());
+ update.setAreaId(targetStock.getAreaId());
+ update.setStockState(ObjUtil.defaultIfNull(reqDTO.getStockState(), targetStock.getStockState()));
+ update.setLastTransactionId(transactionId);
+ materialStockBagMapper.updateById(update);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void scrap(MesWmTransactionSaveReqDTO reqDTO, Long transactionId) {
+ MesWmMaterialStockBagDO bag = requireActiveBag(reqDTO);
+ MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO();
+ update.setId(bag.getId());
+ update.setStatus(MesWmMaterialStockBagStatusEnum.SCRAPPED.getStatus());
+ update.setStockState(MesWmStockStateEnum.OUT.getState());
+ update.setQuantity(BigDecimal.ZERO);
+ update.setLastTransactionId(transactionId);
+ update.setOutboundTime(LocalDateTime.now());
+ materialStockBagMapper.updateById(update);
+ }
+
+ @Override
+ public MesWmMaterialStockBagDO getActiveByMaterialStockId(Long materialStockId) {
+ return materialStockBagMapper.selectOneActiveByMaterialStockId(materialStockId);
+ }
+
+ /**
+ * 鏌ヨ鎸囧畾琚嬬爜鐨勬椿鍔ㄦ槑缁嗭紝涓嶅瓨鍦ㄦ垨宸插嚭搴�/鎶ュ簾鍒欐姏寮傚父銆�
+ */
+ private MesWmMaterialStockBagDO requireActiveBag(MesWmTransactionSaveReqDTO reqDTO) {
+ MesWmMaterialStockBagDO bag = null;
+ if (reqDTO.getBagCodeId() != null) {
+ bag = materialStockBagMapper.selectActiveByBagCodeId(reqDTO.getBagCodeId());
+ }
+ if (bag == null && StrUtil.isNotBlank(reqDTO.getBagCode())) {
+ bag = materialStockBagMapper.selectActiveByBagCode(reqDTO.getBagCode());
+ }
+ if (bag == null) {
+ String code = StrUtil.blankToDefault(reqDTO.getBagCode(), String.valueOf(reqDTO.getBagCodeId()));
+ throw exception(WM_MATERIAL_STOCK_BAG_NOT_ACTIVE, code);
+ }
+ return bag;
+ }
+
+ private MesWmMaterialStockBagDO reactivate(MesWmMaterialStockBagDO existing, MesWmTransactionSaveReqDTO reqDTO,
+ MesWmMaterialStockDO stock, Long transactionId) {
+ MesWmMaterialStockBagDO update = new MesWmMaterialStockBagDO();
+ update.setId(existing.getId());
+ update.setMaterialStockId(stock.getId());
+ update.setItemId(stock.getItemId());
+ update.setBatchId(stock.getBatchId());
+ update.setBatchCode(stock.getBatchCode());
+ update.setVendorId(stock.getVendorId());
+ update.setWarehouseId(stock.getWarehouseId());
+ update.setLocationId(stock.getLocationId());
+ update.setAreaId(stock.getAreaId());
+ update.setStockState(ObjUtil.defaultIfNull(reqDTO.getStockState(), stock.getStockState()));
+ update.setStatus(MesWmMaterialStockBagStatusEnum.ACTIVE.getStatus());
+ update.setQuantity(BigDecimal.ONE);
+ update.setFrozen(false);
+ update.setLastTransactionId(transactionId);
+ update.setInboundTime(LocalDateTime.now());
+ update.setOutboundTime(null);
+ materialStockBagMapper.updateById(update);
+ return existing;
+ }
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java
index a54a1eb..628720f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java
@@ -27,6 +27,7 @@
import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesLineMapper;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeQcStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmSalesNoticeStatusEnum;
@@ -43,8 +44,6 @@
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService;
-import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi;
-import cn.iocoder.yudao.module.erp.api.sale.enums.ErpSaleOrderOutStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
@@ -104,9 +103,6 @@
@Resource
private MesTraceIntegrityService integrityService;
-
- @Resource
- private ErpSaleOrderApi saleOrderApi;
@Override
public Long createProductSales(MesWmProductSalesSaveReqVO createReqVO) {
@@ -242,6 +238,15 @@
if (pallet != null && pallet.getBatchId() == null) {
throw exception(PRO_PALLET_NOT_BIND_BATCH);
}
+ // 绉嶅瓙璐ㄦ鎸夎鐮佺矑搴︽祦杞悗锛屽嚭搴撳彧鍏佽宸茶川妫�鍚堟牸鐨勮鐮�/鎵樼洏
+ if (pallet != null) {
+ List<MesProBagCodeDO> palletBags = bagCodeService.getBagCodeListByPalletId(pallet.getId());
+ if (palletBags.stream().anyMatch(b -> !MesProBagCodeQcStatusEnum.QUALIFIED.getStatus().equals(b.getQcStatus()))) {
+ throw exception(WM_PRODUCT_SALES_SCAN_PALLET_NOT_ALL_QUALIFIED);
+ }
+ } else if (!MesProBagCodeQcStatusEnum.QUALIFIED.getStatus().equals(bag.getQcStatus())) {
+ throw exception(WM_PRODUCT_SALES_SCAN_BAG_NOT_QUALIFIED);
+ }
Long codeId = pallet != null ? pallet.getId() : bag.getId();
MesWmProductSalesDetailDO existed = pallet != null
? productSalesDetailMapper.selectBySalesIdAndPalletCodeId(reqVO.getSalesId(), codeId)
@@ -270,7 +275,8 @@
if (quantity == null) {
quantity = line.getQuantity();
}
- List<MesWmMaterialStockDO> stocks = materialStockService.getMaterialStockListByItemAndBatch(batch.getItemId(), wmBatch.getId());
+ // 鍙粠鍚堟牸搴撹褰曚腑閫夊簱瀛橈紙鍚屾壒娆℃殏瀛樺簱璁板綍涓嶅彲鍑哄簱锛�
+ List<MesWmMaterialStockDO> stocks = materialStockService.getQualifiedMaterialStockListByItemAndBatch(batch.getItemId(), wmBatch.getId());
BigDecimal outboundQuantity = quantity;
MesWmMaterialStockDO stock = stocks.stream().filter(item -> item.getQuantity().compareTo(outboundQuantity) >= 0).findFirst().orElse(null);
if (stock == null) {
@@ -338,12 +344,6 @@
// 鎵ц鎷h揣锛堝緟鎷h揣 鈫� 寰呭~鍐欒繍鍗曪級
productSalesMapper.updateById(new MesWmProductSalesDO()
.setId(id).setStatus(MesWmProductSalesStatusEnum.SHIPPING.getStatus()));
-
- // 鍥炲啓 ERP 閿�鍞鍗曞嚭搴撶姸鎬佷负"閮ㄥ垎鍑哄簱"锛堣〃绀哄凡鎷h揣/鍗犵敤锛�
- if (sales.getSaleOrderId() != null) {
- saleOrderApi.updateOrderOutStatusTo(sales.getSaleOrderId(),
- ErpSaleOrderOutStatusEnum.PART_OUT.getStatus());
- }
}
@Override
@@ -392,10 +392,7 @@
updateSalesNoticeOutCount(sales);
}
- // 6. 鍥炲啓 ERP 閿�鍞鍗曠殑鍑哄簱鏁伴噺鍜岀姸鎬�
- updateErpSaleOrderOutCount(sales);
-
- // 7. 鍥炲啓琚嬬爜/鎵樼洏鍑哄簱鍘诲悜锛堜緵绐滆揣绋芥煡瀹氫綅缁忛攢鍟嗗湴鍖猴級锛屽苟鐢熸垚鍑哄簱瀹屾暣鎬ф憳瑕�
+ // 6. 鍥炲啓琚嬬爜/鎵樼洏鍑哄簱鍘诲悜锛堜緵绐滆揣绋芥煡瀹氫綅缁忛攢鍟嗗湴鍖猴級锛屽苟鐢熸垚鍑哄簱瀹屾暣鎬ф憳瑕�
List<MesWmProductSalesDetailDO> outDetails = productSalesDetailService.getProductSalesDetailListBySalesId(id);
for (MesWmProductSalesDetailDO detail : outDetails) {
if (detail.getBagCodeId() != null) {
@@ -425,43 +422,13 @@
}
}
- /**
- * 鍥炲啓 ERP 閿�鍞鍗曠殑鍑哄簱鏁伴噺鍜岀姸鎬�
- */
- private void updateErpSaleOrderOutCount(MesWmProductSalesDO sales) {
- // 鑾峰彇鍑哄簱鍗曡
- List<MesWmProductSalesLineDO> lines = productSalesLineService.getProductSalesLineListBySalesId(sales.getId());
- if (CollUtil.isEmpty(lines)) {
- return;
- }
- // 鐢ㄤ簬瀛樺偍閿�鍞鍗� ID锛岄伩鍏嶉噸澶嶆洿鏂�
- Long saleOrderId = null;
- // 閬嶅巻琛岋紝鎸� saleOrderItemId 鏇存柊鍑哄簱鏁伴噺
- for (MesWmProductSalesLineDO line : lines) {
- if (line.getSaleOrderItemId() != null && line.getQuantity() != null) {
- saleOrderApi.updateOrderItemOutCount(line.getSaleOrderItemId(), line.getQuantity());
- // 鑾峰彇閿�鍞鍗� ID锛堜粠绗竴涓湁鏁堢殑鏄庣粏椤硅幏鍙栵級
- if (saleOrderId == null) {
- cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderItemRespDTO itemDTO =
- saleOrderApi.getSaleOrderItem(line.getSaleOrderItemId()).getCheckedData();
- if (itemDTO != null && itemDTO.getOrderId() != null) {
- saleOrderId = itemDTO.getOrderId();
- }
- }
- }
- }
- // 鏇存柊閿�鍞鍗曠殑鍑哄簱鐘舵��
- if (saleOrderId != null) {
- saleOrderApi.updateOrderOutStatus(saleOrderId);
- }
- }
-
private void createTransactionList(MesWmProductSalesDO sales) {
List<MesWmProductSalesDetailDO> details = productSalesDetailService.getProductSalesDetailListBySalesId(sales.getId());
wmTransactionService.createTransactionList(convertList(details, detail -> new MesWmTransactionSaveReqDTO()
.setType(MesWmTransactionTypeEnum.OUT.getType()).setItemId(detail.getItemId())
.setQuantity(detail.getQuantity().negate()) // 鍑哄簱鏁伴噺涓鸿礋鏁�
.setBatchId(detail.getBatchId()).setBatchCode(detail.getBatchCode())
+ .setBagCodeId(detail.getBagCodeId()) // 琚嬬爜鍨嬫槑缁嗗嚭搴撴椂缃鐮佸凡鍑哄簱锛涙墭鐩樺瀷鏄庣粏涓嶉�愯澶勭悊
.setWarehouseId(detail.getWarehouseId()).setLocationId(detail.getLocationId()).setAreaId(detail.getAreaId())
.setBizType(MesBizTypeConstants.WM_PRODUCT_SALES).setBizId(sales.getId())
.setBizCode(sales.getCode()).setBizLineId(detail.getLineId())
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java
index 7f40f15..fed11df 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java
@@ -7,16 +7,19 @@
import cn.iocoder.yudao.module.mes.controller.admin.wm.salesnotice.vo.line.MesWmSalesNoticeLinePageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.salesnotice.vo.line.MesWmSalesNoticeLineSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.salesnotice.MesWmSalesNoticeLineMapper;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
+import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -38,6 +41,8 @@
private MesWmSalesNoticeService salesNoticeService;
@Resource
private MesWmBatchService batchService;
+ @Resource
+ private MesWmMaterialStockService materialStockService;
@Resource
private MesMdmItemService mdmItemService;
@@ -118,12 +123,36 @@
}
private void validateLineSaveData(MesWmSalesNoticeLineSaveReqVO reqVO) {
- // 鏍¢獙鐖跺崟鎹瓨鍦ㄤ笖涓鸿崏绋跨姸鎬�
validateNoticeStatusDraft(reqVO.getNoticeId());
- // 鏍¢獙鐗╂枡瀛樺湪
- if (reqVO.getItemId() != null) {
- mdmItemService.validateItemExistsAndEnable(reqVO.getItemId());
+ mdmItemService.validateItemExistsAndEnable(reqVO.getItemId());
+
+ MesWmBatchDO batch = resolveBatch(reqVO);
+ if (batch == null) {
+ throw exception(WM_MATERIAL_STOCK_NOT_EXISTS);
}
+ if (ObjUtil.notEqual(batch.getItemId(), reqVO.getItemId())) {
+ throw exception(WM_MATERIAL_STOCK_NOT_EXISTS);
+ }
+ BigDecimal qualifiedQuantity = materialStockService
+ .getQualifiedMaterialStockListByItemAndBatch(reqVO.getItemId(), batch.getId()).stream()
+ .map(MesWmMaterialStockDO::getQuantity)
+ .filter(quantity -> quantity != null)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ if (qualifiedQuantity.compareTo(reqVO.getQuantity()) < 0) {
+ throw exception(WM_MATERIAL_STOCK_INSUFFICIENT);
+ }
+ reqVO.setBatchId(batch.getId());
+ reqVO.setBatchCode(batch.getCode());
+ }
+
+ private MesWmBatchDO resolveBatch(MesWmSalesNoticeLineSaveReqVO reqVO) {
+ if (reqVO.getBatchId() != null) {
+ return batchService.getBatch(reqVO.getBatchId());
+ }
+ if (StrUtil.isNotBlank(reqVO.getBatchCode())) {
+ return batchService.getBatchByCode(reqVO.getBatchCode());
+ }
+ return null;
}
/**
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeService.java
index be5338c..18e1cd2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeService.java
@@ -89,14 +89,6 @@
}
/**
- * 浠庨攢鍞鍗曠敓鎴愬彂璐ч�氱煡鍗�
- *
- * @param saleOrderId 閿�鍞鍗旾D
- * @return 鍙戣揣閫氱煡鍗旾D
- */
- Long generateSalesNoticeFromSaleOrder(Long saleOrderId);
-
- /**
* 瀹屾垚鍙戣揣閫氱煡鍗曪紙鍑哄簱瀹屾垚鍚庤皟鐢級
* 绱姞鍑哄簱鏁伴噺骞惰绠楀嚭搴撶姸鎬�
*
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeServiceImpl.java
index a233210..115bebf 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeServiceImpl.java
@@ -18,10 +18,6 @@
import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi;
-import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi;
-import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderItemRespDTO;
-import cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderRespDTO;
-import cn.iocoder.yudao.module.erp.api.sale.enums.ErpSaleOrderOutStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -53,8 +49,6 @@
@Resource
private CrmCustomerApi customerApi;
- @Resource
- private ErpSaleOrderApi saleOrderApi;
@Resource
private MesMdAutoCodeRecordService autoCodeRecordService;
@@ -125,7 +119,7 @@
@Transactional(rollbackFor = Exception.class)
public void submitSalesNotice(Long id) {
// 1.1 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
- MesWmSalesNoticeDO notice = validateSalesNoticeExistsAndDraft(id);
+ validateSalesNoticeExistsAndDraft(id);
// 1.2 妫�鏌ユ槸鍚︽湁琛岄」鐩�
List<MesWmSalesNoticeLineDO> lines = salesNoticeLineService.getSalesNoticeLineListByNoticeId(id);
if (CollUtil.isEmpty(lines)) {
@@ -135,12 +129,6 @@
// 2. 鏇存柊鐘舵�侊細鑽夌 鈫� 寰呭嚭搴�
salesNoticeMapper.updateById(new MesWmSalesNoticeDO()
.setId(id).setStatus(APPROVED.getStatus()));
-
- // 3. 鍥炲啓 ERP 閿�鍞鍗曞嚭搴撶姸鎬佷负"宸查鐣�"
- if (notice.getSaleOrderId() != null) {
- saleOrderApi.updateOrderOutStatusTo(notice.getSaleOrderId(),
- ErpSaleOrderOutStatusEnum.RESERVED.getStatus());
- }
}
@Override
@@ -188,54 +176,6 @@
if (ObjUtil.notEqual(id, notice.getId())) {
throw exception(WM_SALES_NOTICE_CODE_DUPLICATE);
}
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Long generateSalesNoticeFromSaleOrder(Long saleOrderId) {
- // 1. 鏍¢獙鏄惁宸茬敓鎴愯繃鍙戣揣閫氱煡鍗曪紙闃叉閲嶅鐢熸垚锛�
- MesWmSalesNoticeDO existNotice = salesNoticeMapper.selectBySaleOrderId(saleOrderId);
- if (existNotice != null) {
- throw exception(WM_SALES_NOTICE_ALREADY_EXISTS);
- }
-
- // 2. 鑾峰彇閿�鍞鍗曚俊鎭�
- ErpSaleOrderRespDTO saleOrder = saleOrderApi.getSaleOrder(saleOrderId).getCheckedData();
- if (saleOrder == null) {
- throw exception(WM_SALES_NOTICE_SALE_ORDER_NOT_EXISTS);
- }
-
- // 3. 鑾峰彇閿�鍞鍗曟槑缁�
- List<ErpSaleOrderItemRespDTO> saleOrderItems = saleOrderApi.getSaleOrderItemList(saleOrderId).getCheckedData();
- if (CollUtil.isEmpty(saleOrderItems)) {
- throw exception(WM_SALES_NOTICE_SALE_ORDER_ITEM_EMPTY);
- }
-
- // 4. 鐢熸垚鍙戣揣閫氱煡鍗曠紪鐮�
- String code = autoCodeRecordService.generateAutoCode("SALESNOTICE_CODE", null);
-
- // 5. 鍒涘缓鍙戣揣閫氱煡鍗曚富琛�
- MesWmSalesNoticeDO notice = new MesWmSalesNoticeDO();
- notice.setCode(code);
- notice.setName("閿�鍞鍗昜" + saleOrder.getNo() + "]鍙戣揣閫氱煡");
- notice.setClientId(saleOrder.getCustomerId());
- notice.setSaleOrderId(saleOrderId);
- notice.setSaleOrderCode(saleOrder.getNo());
- notice.setSalesDate(java.time.LocalDateTime.now());
- notice.setStatus(PREPARE.getStatus());
- salesNoticeMapper.insert(notice);
-
- // 6. 閬嶅巻鏄庣粏鍒涘缓鍙戣揣閫氱煡鍗曡
- for (ErpSaleOrderItemRespDTO saleOrderItem : saleOrderItems) {
- MesWmSalesNoticeLineDO line = new MesWmSalesNoticeLineDO();
- line.setNoticeId(notice.getId());
- line.setSaleOrderItemId(saleOrderItem.getId());
- line.setItemId(saleOrderItem.getProductId());
- line.setQuantity(saleOrderItem.getCount());
- salesNoticeLineService.createSalesNoticeLine(line);
- }
-
- return notice.getId();
}
@Override
@@ -350,8 +290,6 @@
productSales.setCode(code);
productSales.setName("鍙戣揣閫氱煡鍗昜" + notice.getCode() + "]鍑哄簱");
productSales.setClientId(notice.getClientId());
- productSales.setSaleOrderId(notice.getSaleOrderId());
- productSales.setSalesOrderCode(notice.getSaleOrderCode());
productSales.setNoticeId(noticeId);
productSales.setSalesDate(notice.getSalesDate());
// 鏀惰揣淇℃伅浠庡彂璐ч�氱煡鍗曞甫鍏�
@@ -365,7 +303,6 @@
for (MesWmSalesNoticeLineDO noticeLine : noticeLines) {
MesWmProductSalesLineDO salesLine = new MesWmProductSalesLineDO();
salesLine.setSalesId(productSales.getId());
- salesLine.setSaleOrderItemId(noticeLine.getSaleOrderItemId());
salesLine.setNoticeLineId(noticeLine.getId());
salesLine.setItemId(noticeLine.getItemId());
salesLine.setQuantity(noticeLine.getQuantity());
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java
index fd75003..eb43c7e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java
@@ -16,6 +16,7 @@
import cn.iocoder.yudao.module.mes.dal.mysql.wm.transaction.MesWmTransactionMapper;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
@@ -23,6 +24,7 @@
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
+import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -57,6 +59,9 @@
private MesWmWarehouseLocationService locationService;
@Resource
private MesWmWarehouseAreaService areaService;
+
+ @Resource
+ private MesWmMaterialStockBagService materialStockBagService;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -127,11 +132,20 @@
materialStockService.updateMaterialStockQuantity(materialStock.getId(), reqDTO.getQuantity(), checkFlag);
MesWmMaterialStockDO updatedStock = materialStockService.getMaterialStock(materialStock.getId());
BigDecimal newQuantity = updatedStock.getQuantity();
- // 搴撳瓨鐘舵�侊細鏄惧紡鎸囧畾浼樺厛锛堝鎵爜鍏ユ殏瀛樺簱锛夛紝鍚﹀垯鎸夋暟閲忚嚜鍔ㄥ垽瀹氾紙鈮�0 宸插嚭搴擄紝>0 鍚堟牸搴擄級
+ // 搴撳瓨鐘舵�侊細鏄惧紡鎸囧畾浼樺厛锛堝鎵爜鍏ユ殏瀛樺簱锛夛紝鍚﹀垯鑷姩鍒ゅ畾鈥斺�斺墹0 宸插嚭搴擄紱
+ // >0 鏃朵粎鐩爣浠撳簱涓哄悎鏍煎簱(20)鎵嶇疆鍚堟牸鎬侊紝鍚﹀垯淇濇寔鏆傚瓨鎬�(10)锛�
+ // 閬垮厤鐩樼偣/璋冩暣/璋冩嫧绛夋搷浣滄妸鏆傚瓨浠撳簱搴撳瓨缈绘垚鍚堟牸鎬�
Integer stockState = reqDTO.getStockState();
if (stockState == null) {
- stockState = newQuantity.signum() <= 0
- ? MesWmStockStateEnum.OUT.getState() : MesWmStockStateEnum.QUALIFIED.getState();
+ if (newQuantity.signum() <= 0) {
+ stockState = MesWmStockStateEnum.OUT.getState();
+ } else {
+ MesWmWarehouseDO warehouse = warehouseService.getWarehouse(reqDTO.getWarehouseId());
+ boolean qualifiedWarehouse = warehouse != null
+ && MesWmWarehouseTypeEnum.QUALIFIED.getType().equals(warehouse.getType());
+ stockState = qualifiedWarehouse
+ ? MesWmStockStateEnum.QUALIFIED.getState() : MesWmStockStateEnum.TEMP.getState();
+ }
}
materialStockService.updateMaterialStockState(updatedStock.getId(), stockState);
@@ -139,14 +153,46 @@
MesWmTransactionDO transaction = MesWmTransactionDO.builder()
.type(reqDTO.getType()).quantity(reqDTO.getQuantity()).transactionTime(LocalDateTime.now())
.itemId(reqDTO.getItemId()).batchId(reqDTO.getBatchId()).batchCode(reqDTO.getBatchCode())
+ .bagCodeId(reqDTO.getBagCodeId()).bagCode(reqDTO.getBagCode())
.warehouseId(reqDTO.getWarehouseId()).locationId(reqDTO.getLocationId()).areaId(reqDTO.getAreaId())
.bizType(reqDTO.getBizType()).bizId(reqDTO.getBizId()).bizCode(reqDTO.getBizCode()).bizLineId(reqDTO.getBizLineId())
.materialStockId(materialStock.getId()).relatedTransactionId(reqDTO.getRelatedTransactionId())
.build();
transactionMapper.insert(transaction);
+ // 4. 甯﹁鐮佹椂锛屽悓姝ョ淮鎶ゅ簱瀛樿鐮佹槑缁嗭紙鍏ュ簱寤虹珛/婵�娲汇�佸嚭搴撶疆宸插嚭搴撱�佺Щ鍏ヨ縼绉汇�佹姤搴燂級
+ boolean skipBagManage = ObjUtil.defaultIfNull(reqDTO.getSkipBagManage(), false);
+ if (!skipBagManage && (StrUtil.isNotBlank(reqDTO.getBagCode()) || reqDTO.getBagCodeId() != null)) {
+ handleStockBag(reqDTO, materialStock, transaction.getId(), transactionType);
+ }
return transaction.getId();
}
+ /**
+ * 鎸変簨鍔$被鍨嬬淮鎶よ鐮佹槑缁嗭紝淇濊瘉姹囨�诲簱瀛樸�佽鐮佹槑缁嗐�佷簨鍔℃祦姘翠笁鑰呬竴鑷淬��
+ */
+ private void handleStockBag(MesWmTransactionSaveReqDTO reqDTO, MesWmMaterialStockDO materialStock,
+ Long transactionId, MesWmTransactionTypeEnum transactionType) {
+ switch (transactionType) {
+ case MOVE_IN:
+ // 绉诲叆/璋冩嫧/璐ㄦ杩佺Щ锛氭洿鏂版槑缁嗕綅缃笌鐘舵��
+ materialStockBagService.moveIn(reqDTO, materialStock, transactionId);
+ break;
+ case IN:
+ case ADJUST_IN:
+ // 鍏ュ簱/鐩樼泩锛氬缓绔嬫垨婵�娲绘槑缁�
+ materialStockBagService.inbound(reqDTO, materialStock, transactionId);
+ break;
+ case MOVE_OUT:
+ case OUT:
+ case ADJUST_OUT:
+ // 绉诲嚭/鍑哄簱/鐩樹簭锛氱疆涓哄凡鍑哄簱
+ materialStockBagService.outbound(reqDTO, transactionId);
+ break;
+ default:
+ break;
+ }
+ }
+
@Override
@Transactional(rollbackFor = Exception.class)
public void createTransactionList(List<MesWmTransactionSaveReqDTO> reqDTOs) {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java
index 39a7693..6ac1ead 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java
@@ -69,6 +69,10 @@
* 鎵规鍙�
*/
private String batchCode;
+ /** 琚嬬爜ID */
+ private Long bagCodeId;
+ /** 琚嬬爜 */
+ private String bagCode;
// ===== 搴撳瓨浣嶇疆 =====
@@ -128,4 +132,12 @@
*/
private Integer stockState;
+ /**
+ * 鏄惁璺宠繃琚嬬爜鏄庣粏鑷姩缁存姢锛堥粯璁� false锛夈��
+ * <p>
+ * 璐ㄦ绛夐渶瑕佽嚜琛屾帶鍒惰鐮佺敓鍛藉懆鏈燂紙濡傛殏瀛樺嚭搴撲笌鍚堟牸鍏ュ簱鎴愬鍙戠敓銆佽鐮佷粎鍦ㄦ渶缁堣惤鐐硅縼绉伙級鐨勫満鏅紝
+ * 鍦ㄥ啓浜嬪姟鏃剁疆 true锛岄伩鍏� createTransaction 鎸夊崟绗斾簨鍔$被鍨嬭嚜鍔ㄧ疆宸插嚭搴�/杩佺Щ锛屽鑷磋鐮佺姸鎬侀敊涔便��
+ */
+ private Boolean skipBagManage;
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseService.java
index c038d5a..d983b1c 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseService.java
@@ -90,4 +90,26 @@
*/
MesWmWarehouseDO getWarehouseByCode(String code);
+ /**
+ * 鎸変粨搴撶被鍨嬭幏寰椾粨搴撳垪琛紙鎸� id 鍗囧簭锛�
+ *
+ * @param type 浠撳簱绫诲瀷锛岃 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum}
+ * @return 浠撳簱鍒楄〃
+ */
+ List<MesWmWarehouseDO> getWarehouseListByType(Integer type);
+
+ /**
+ * 鑾峰緱鍚堟牸搴擄紙type=QUALIFIED锛夌殑缂栧彿闆嗗悎锛岀敤浜庢寜浠撳簱绫诲瀷杩囨护鍚堟牸搴撳瓨
+ *
+ * @return 鍚堟牸浠撳簱 id 闆嗗悎
+ */
+ List<Long> getQualifiedWarehouseIds();
+
+ /**
+ * 鑾峰緱绗竴涓悎鏍煎簱锛坱ype=QUALIFIED锛屾寜 id 鍗囧簭锛�
+ *
+ * @return 鍚堟牸浠撳簱锛屾湭閰嶇疆杩斿洖 null
+ */
+ MesWmWarehouseDO getFirstQualifiedWarehouse();
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java
index bd85c14..5ca72bd 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java
@@ -9,6 +9,7 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseMapper;
import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum;
import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService;
import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
@@ -22,6 +23,7 @@
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
/**
@@ -175,6 +177,7 @@
if (MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE.equals(code)) {
MesWmWarehouseDO newWarehouse = MesWmWarehouseDO.builder()
.code(code).name("铏氭嫙绾胯竟浠撳簱").frozen(false)
+ .type(MesWmWarehouseTypeEnum.TEMP.getType())
.remark("绯荤粺鑷姩鍒濆鍖栫殑铏氭嫙绾胯竟浠撳簱锛堢敤浜庣敓浜ф姤宸ヤ笌鍦ㄥ埗鍝佺鐞嗚В鑰︼級")
.build();
warehouseMapper.insert(newWarehouse);
@@ -183,4 +186,21 @@
return null;
}
+ @Override
+ public List<MesWmWarehouseDO> getWarehouseListByType(Integer type) {
+ return warehouseMapper.selectListByType(type);
+ }
+
+ @Override
+ public List<Long> getQualifiedWarehouseIds() {
+ return convertList(getWarehouseListByType(MesWmWarehouseTypeEnum.QUALIFIED.getType()),
+ MesWmWarehouseDO::getId);
+ }
+
+ @Override
+ public MesWmWarehouseDO getFirstQualifiedWarehouse() {
+ List<MesWmWarehouseDO> list = getWarehouseListByType(MesWmWarehouseTypeEnum.QUALIFIED.getType());
+ return CollUtil.isNotEmpty(list) ? list.get(0) : null;
+ }
+
}
diff --git a/yudao-module-mes/src/main/resources/mapper/home/MesBagCodeHomeStatisticsMapper.xml b/yudao-module-mes/src/main/resources/mapper/home/MesBagCodeHomeStatisticsMapper.xml
index 8e19a64..b59a960 100644
--- a/yudao-module-mes/src/main/resources/mapper/home/MesBagCodeHomeStatisticsMapper.xml
+++ b/yudao-module-mes/src/main/resources/mapper/home/MesBagCodeHomeStatisticsMapper.xml
@@ -62,6 +62,45 @@
WHERE deleted = 0
</select>
+ <!-- ========== 鍑哄簱娴侀�� / 浠撳偍 / 璐ㄩ噺 ========== -->
+
+ <!-- 缁熻鍙戣揣閫氱煡鍗曟暟锛坢es_wm_sales_notice锛� -->
+ <select id="selectSalesNoticeCount" resultType="java.lang.Long">
+ SELECT COUNT(*)
+ FROM mes_wm_sales_notice
+ WHERE deleted = 0
+ </select>
+
+ <!-- 缁熻閿�鍞嚭搴撳崟鏁帮紙mes_wm_product_sales锛� -->
+ <select id="selectProductSalesCount" resultType="java.lang.Long">
+ SELECT COUNT(*)
+ FROM mes_wm_product_sales
+ WHERE deleted = 0
+ </select>
+
+ <!-- 缁熻閿�鍞��璐у崟鏁帮紙mes_wm_return_sales锛� -->
+ <select id="selectReturnSalesCount" resultType="java.lang.Long">
+ SELECT COUNT(*)
+ FROM mes_wm_return_sales
+ WHERE deleted = 0
+ </select>
+
+ <!-- 缁熻鏈鐞嗗簱瀛橀璀︽暟锛坢es_wm_stock_warning.status=10锛� -->
+ <select id="selectStockWarningPendingCount" resultType="java.lang.Long">
+ SELECT COUNT(*)
+ FROM mes_wm_stock_warning
+ WHERE deleted = 0
+ AND status = 10
+ </select>
+
+ <!-- 缁熻寰呰瘎瀹′笉鍚堟牸鍝佸崟鏁帮紙mes_qc_ncr.status=0锛� -->
+ <select id="selectNcrPendingCount" resultType="java.lang.Long">
+ SELECT COUNT(*)
+ FROM mes_qc_ncr
+ WHERE deleted = 0
+ AND status = 0
+ </select>
+
<!-- ========== 鐘舵�佸垎甯� ========== -->
<!-- 鎸夌姸鎬佺粺璁℃壒娆℃暟閲� -->
--
Gitblit v1.9.3