chen.lin
1 天以前 b003a49794f49a329e2702918ecfc8d14b371d0d
云仓WMS接口流程
13个文件已添加
122个文件已修改
2909 ■■■■■ 已修改文件
rsf-admin/src/i18n/en.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/zh.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/deliveryItem/DeliveryItemCreate.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/deliveryItem/DeliveryItemEdit.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/deliveryItem/DeliveryItemList.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/deliveryItem/DeliveryItemPanel.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/histories/asnOrderLog/AsnOrderItemLogList.jsx 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/histories/asnOrderLog/AsnOrderLogListBase.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/histories/asnOrderLog/AsnOrderLogShow.jsx 264 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/histories/asnOrderLog/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/histories/taskLog/TaskItemLogList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/histories/waitPakinLog/WaitPakinItemLogList.jsx 89 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/histories/waitPakinLog/WaitPakinLogEdit.jsx 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/histories/waitPakinLog/WaitPakinLogList.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/histories/waitPakinLog/WaitPakinLogShow.jsx 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/histories/waitPakinLog/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locItem/LocItemCreate.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locItem/LocItemEdit.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locItem/LocItemList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locItem/LocItemPanel.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/locPreview/LocPreviewItems.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/AsnCreateByPoModal.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/AsnOrderItemCreate.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/AsnOrderItemEdit.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/AsnOrderList.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/AsnOrderModal.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/AsnOrderPanel.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/OrderPrintPreview.jsx 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/POItemModal.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/check/CheckOrderItemList.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/check/CheckOrderList.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/check/CheckOrderModal.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/check/CheckOrderPub.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/check/CheckPreviewTable.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/check/checkDiff/CheckDiffList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/check/checkDiffItem/CheckDiffItemList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/delivery/DeliveryItemCreate.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/delivery/DeliveryItemEdit.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/delivery/DeliveryItemList.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/delivery/DeliveryList.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutOrderList.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutOrderModal.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutStockPublic.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/purchase/PurchaseItemCreate.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/purchase/PurchaseItemEdit.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/purchase/PurchaseItemList.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/purchase/PurchaseList.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/purchase/PurchasePanel.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/qlyInspect/QlyIsptItemResult.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/stock/OrderItemList.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/stock/OrderList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/transfer/TransferItemList.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/transfer/TransferOrders.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/wave/WaveItemList.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/wave/WaveList.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/wave/WavePanel.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/statistics/deadTime/LocItemDeadList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/statistics/inStockItem/InStockItemList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/statistics/inStockNum/InStockNumList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/statistics/outStockItem/OutStockItemList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/statistics/outStockNum/OutStockNumList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/statistics/stockManage/WarehouseHistories.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/statistics/stockManage/WarehouseStockList.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/statistics/stockStatisticNum/stockStatisticList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/stockItem/StockItemList.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/stockManage/locRevise/ReviseLogItemList.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/task/TaskItemList.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/task/TaskPanel.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/waitPakin/WaitPakinEdit.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/waitPakin/WaitPakinItemList.jsx 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/waitPakin/WaitPakinList.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/warehouseAreasItem/WarehouseIsptResult.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/utils/common.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/config/GlobalExceptionHandler.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/dto/OrderDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ErpOpParams.java 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ExMsgCallbackParams.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/FlexibleDateDeserializer.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/FlexibleTimestampDeserializer.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ReportDataParam.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/service/impl/WmsErpServiceImpl.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/ReportDataParam.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrderParams.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrdersItem.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/TaskInParam.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/PdaCheckOrderController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/PdaOutStockController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/InspectDetlDto.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/params/ExMsgParams.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/AgvServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/MobileServiceImpl.java 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaCheckOrderServiceImpl.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java 341 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/event/DictDataChangedEvent.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/utils/QuantityUtils.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaitPakinController.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaitPakinLogController.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/AsnOrderLog.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/BasContainer.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/ReviseLog.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/TaskItem.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WaitPakin.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WaitPakinLog.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WkOrder.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WkOrderItem.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/AsnOrderTemplate.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/OutStockTemplate.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/PurchaseTemplate.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/TransferTemplate.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/AsnExceStatus.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/listener/OrderWorkTypeRefreshListener.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/ScheduleJobs.java 291 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OrderTypeDictService.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OrderWorkTypeService.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderLogServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OrderTypeDictServiceImpl.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OrderWorkTypeServiceImpl.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaitPakinServiceImpl.java 168 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/DictDataServiceImpl.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
version/db/man_asn_order_add_8_3_fields.sql 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
version/db/out_stock_order_log_menu.sql 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
version/db/sys_order_type_dict.sql 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
version/db/sys_order_work_type_dict.sql 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
version/db/wave_menu.sql 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/en.js
@@ -599,7 +599,7 @@
            },
            asnOrder: {
                code: "Code",
                poCode: "poCode",
                poCode: "Internal Code",
                poId: "poId",
                type: "Type",
                wkType: "wkType",
@@ -786,7 +786,7 @@
            },
            asnOrderLog: {
                code: "code",
                poCode: "poCode",
                poCode: "Internal Code",
                poId: "poId",
                type: "type",
                wkType: "wkType",
@@ -802,7 +802,7 @@
                asnCode: "asnCode",
                platItemId: "platItemId",
                poDetlId: "poDetlId",
                poCode: "poCode",
                poCode: "Internal Code",
                fieldsIndex: "fieldsIndex",
                matnrId: "matnrId",
                matnrCode: "matnrCode",
@@ -928,6 +928,7 @@
            },
            waitPakin: {
                code: "code",
                asnCodes: "Inbound Order No.",
                ansId: "ansId",
                asnCode: "asnCode",
                barcode: "barcode",
rsf-admin/src/i18n/zh.js
@@ -472,7 +472,7 @@
                name: "名称",
                flagLogic: "虚拟库位",
                fucAtrrs: "功能属性",
                barcode: "容器码",
                barcode: "料箱码",
                startChannel: "起始巷道",
                unit: "单位",
                size: "长/宽/高",
@@ -652,7 +652,7 @@
            },
            asnOrder: {
                code: "WMS单号",
                poCode: "PO编码",
                poCode: "单据内码",
                poId: "PO标识",
                type: "单据类型",
                wkType: "业务类型",
@@ -666,7 +666,7 @@
            },
            outStock: {
                code: "出库单号",
                poCode: "DO单号",
                poCode: "单据内码",
                poId: "DO标识",
                type: "类型",
                wkType: "业务类型",
@@ -681,7 +681,7 @@
            },
            checkOrder: {
                code: "盘点单号",
                poCode: "DO单号",
                poCode: "单据内码",
                poId: "DO标识",
                type: "单据类型",
                checkType: '盘点类型',
@@ -765,7 +765,7 @@
            transferOrder: {
                code: '单号',
                poCode: '调拔单',
                poCode: '单据内码',
                type: '单据类型',
                wkType: '调拔类型',
                anfme: '调拔数量',
@@ -824,7 +824,7 @@
            outStockItem: {
                orderId: "主单标识",
                orderCode: "单号",
                poCode: 'DO单号',
                poCode: '单据内码',
                poDetlId: "平台明细ID",
                poDetlCode: "DO单",
                matnrId: "物料标识",
@@ -849,7 +849,7 @@
            },
            asnOrderLog: {
                code: "编码",
                poCode: "PO编码",
                poCode: "单据内码",
                poId: "PO标识",
                type: "单据类型",
                wkType: "业务类型",
@@ -863,6 +863,7 @@
            asnOrderItemLog: {
                orderId: "主单标识",
                orderCode: "主单编码",
                poCode: "单据内码",
                platItemId: "erp标识",
                poDetlId: "PO单标识",
                poDetlCode: "PO单编码",
@@ -972,9 +973,10 @@
            },
            waitPakin: {
                code: "编码",
                asnCodes: "入库通知单号",
                ansId: "收货通知单号",
                asnCode: "收货通知单编码",
                barcode: "容器码",
                barcode: "料箱码",
                flagDefect: "不良品",
                anfme: "数量",
                ioStatus: "状态",
@@ -999,7 +1001,7 @@
                matnrId: "物料id",
                matnrCode: "物料编码",
                asnId: "收货通知单号",
                asnCode: "收货通知单编码",
                asnCode: "入库通知单号",
                asnItemId: "收货通知单明细id",
                trackCode: "条形码",
                isptResult: '质检状态',
@@ -1013,7 +1015,7 @@
            waitPakinLog: {
                pakinId: "组托Id",
                code: "编码",
                barcode: "容器码",
                barcode: "料箱码",
                anfme: "数量",
                ioStatus: "状态",
            },
@@ -1397,9 +1399,13 @@
            true: '正常',
            false: '禁用',
        },
        notification: {
            deleted: '删除成功 |||| %{smart_count} 项 删除成功',
        },
        message: {
            delete_title: '删除 %{name} #%{id}',
            delete_content: '您确定要删除此项吗?',
            loading: '请稍候',
        },
        action: {
            search: '搜索',
@@ -1432,6 +1438,7 @@
        },
        page: {
            empty_with_filters: '使用当前过滤条件未找到结果。',
            loading: '加载中',
        },
        navigation: {
            no_results: '没有找到数据',
rsf-admin/src/page/deliveryItem/DeliveryItemCreate.jsx
@@ -91,6 +91,7 @@
                                        autoFocus
                                    />
                                </Grid>
                                {/* 现品票号已注释
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.deliveryItem.platItemId"
@@ -98,6 +99,7 @@
                                        parse={v => v}
                                    />
                                </Grid>
                                */}
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.deliveryItem.matnrCode"
rsf-admin/src/page/deliveryItem/DeliveryItemEdit.jsx
@@ -70,6 +70,7 @@
                                autoFocus
                            />
                        </Stack>
                        {/* 现品票号已注释
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.deliveryItem.platItemId"
@@ -77,6 +78,7 @@
                                parse={v => v}
                            />
                        </Stack>
                        */}
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.deliveryItem.matnrCode"
rsf-admin/src/page/deliveryItem/DeliveryItemList.jsx
@@ -64,7 +64,7 @@
    <DateInput label='common.time.before' source="timeEnd" alwaysOn />,
    <NumberInput source="deliveryId" label="table.field.deliveryItem.deliveryId" />,
    <TextInput source="platItemId" label="table.field.deliveryItem.platItemId" />,
    // 现品票号已注释 <TextInput source="platItemId" label="table.field.deliveryItem.platItemId" />,
    <TextInput source="matnrCode" label="table.field.deliveryItem.matnrCode" />,
    <TextInput source="matnrName" label="table.field.deliveryItem.matnrName" />,
    <TextInput source="fieldsIndex" label="table.field.deliveryItem.fieldsIndex" />,
@@ -130,12 +130,12 @@
                >
                    <NumberField source="id" />
                    <NumberField source="deliveryId" label="table.field.deliveryItem.deliveryId" />
                    <TextField source="platItemId" label="table.field.deliveryItem.platItemId" />
                    {/* 现品票号已注释 <TextField source="platItemId" label="table.field.deliveryItem.platItemId" /> */}
                    <TextField source="matnrCode" label="table.field.deliveryItem.matnrCode" />
                    <TextField source="matnrName" label="table.field.deliveryItem.matnrName" />
                    <TextField source="fieldsIndex" label="table.field.deliveryItem.fieldsIndex" />
                    <TextField source="unit" label="table.field.deliveryItem.unit" />
                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" />
                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="qty" label="table.field.deliveryItem.qty" />
                    <NumberField source="nromQty" label="table.field.deliveryItem.nromQty" />
                    <NumberField source="printQty" label="table.field.deliveryItem.printQty" />
rsf-admin/src/page/deliveryItem/DeliveryItemPanel.jsx
@@ -46,12 +46,14 @@
                                property={record.deliveryId}
                            />
                        </Grid>
                        {/* 现品票号已注释
                        <Grid item xs={6}>
                            <PanelTypography
                                title="table.field.deliveryItem.platItemId" 
                                property={record.platItemId}
                            />
                        </Grid>
                        */}
                        <Grid item xs={6}>
                            <PanelTypography
                                title="table.field.deliveryItem.matnrCode" 
rsf-admin/src/page/histories/asnOrderLog/AsnOrderItemLogList.jsx
@@ -43,6 +43,9 @@
import * as Common from '@/utils/common';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    width: '100%',
    '& .RaDatagrid-tableWrapper': { width: '100%' },
    '& .MuiTable-root': { width: '100%' },
    '& .css-1vooibu-MuiSvgIcon-root': {
        height: '.9em'
    },
@@ -67,7 +70,7 @@
    <NumberInput source="orderId" label="table.field.asnOrderItemLog.orderId" />,
    <TextInput source="orderCode" label="table.field.asnOrderItemLog.orderCode" />,
    <TextInput source="platItemId" label="table.field.asnOrderItemLog.platItemId" />,
    // 现品票号已注释 <TextInput source="platItemId" label="table.field.asnOrderItemLog.platItemId" />,
    <NumberInput source="poDetlId" label="table.field.asnOrderItemLog.poDetlId" />,
    <TextInput source="poCode" label="table.field.asnOrderItemLog.poCode" />,
    <TextInput source="fieldsIndex" label="table.field.asnOrderItemLog.fieldsIndex" />,
@@ -122,13 +125,15 @@
                resource="asnOrderItemLog"
                sx={{
                    flexGrow: 1,
                    width: '100%',
                    minWidth: 0,
                    transition: (theme) =>
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.asnOrderItemLog"}
                title={"menu.asnOrderItem"}
                empty={false}
                filters={filters}
                filter={{ logId }}
@@ -146,30 +151,25 @@
                    preferenceKey='asnOrderItemLog'
                    bulkActionButtons={false}
                    rowClick={(id, resource, record) => false}
                    omit={['id', 'orderId', 'poDetlId', 'poCode', 'qrcode', 'packName', 'createTime', 'memo', 'fieldsIndex', 'matnrId', 'splrCode', 'status', 'createBy$']}
                    omit={['id', 'asnId', 'orderId', 'poDetlId', 'poCode', 'qrcode', 'packName', 'createTime', 'memo', 'fieldsIndex', 'matnrId', 'splrCode', 'status', 'createBy$', 'platItemId', 'trackCode']}
                >
                    <NumberField source="id" />
                    <NumberField source="asnId" label="table.field.asnOrderItemLog.orderId" />
                    <TextField source="asnCode" label="table.field.asnOrderItemLog.orderCode" />
                    <TextField source="platItemId" label="table.field.asnOrderItemLog.platItemId" />
                    <NumberField source="poDetlId" label="table.field.asnOrderItemLog.poDetlId" />
                    <TextField source="poCode" label="table.field.asnOrderItemLog.poCode" />
                    <TextField source="fieldsIndex" label="table.field.asnOrderItemLog.fieldsIndex" />
                    <TextField source="matnrId" label="table.field.asnOrderItemLog.matnrId" />
                    <TextField source="matnrCode" label="table.field.asnOrderItemLog.matnrCode" />
                    <TextField source="maktx" label="table.field.asnOrderItemLog.maktx" />
                    <NumberField source="anfme" label="table.field.asnOrderItemLog.anfme" />
                    <NumberField source="purQty" label="table.field.asnOrderItemLog.purQty" />
                    <TextField source="purUnit" label="table.field.asnOrderItemLog.purUnit" />
                    <NumberField source="qty" label="table.field.asnOrderItemLog.qty" />
                    <TextField source="splrCode" label="table.field.asnOrderItemLog.splrCode" />
                    <TextField source="splrBatch" label="table.field.asnOrderItemLog.splrBatch" />
                    <TextField source="splrName" label="table.field.asnOrderItemLog.splrName" />
                    <TextField source="qrcode" label="table.field.asnOrderItemLog.qrcode" />
                    <TextField source="trackCode" label="table.field.asnOrderItemLog.trackCode" />
                    <TextField source="packName" label="table.field.asnOrderItemLog.packName" />
                    {/*<TextField source="ntyStatus$" label="table.field.asnOrderItemLog.ntyStatus" sortable={false} />*/}
                    <NumberField source="asnId" label="table.field.asnOrderItem.orderId" />
                    <TextField source="asnCode" label="table.field.asnOrderItem.orderCode" />
                    <NumberField source="poDetlId" label="table.field.asnOrderItem.poDetlId" />
                    <TextField source="poCode" label="table.field.asnOrderItem.poCode" />
                    <TextField source="matnrCode" label="table.field.asnOrderItem.matnrCode" />
                    <TextField source="maktx" label="table.field.asnOrderItem.maktx" />
                    <TextField source="splrBatch" label="table.field.asnOrderItem.splrBatch" />
                    <NumberField source="anfme" label="table.field.asnOrderItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="qty" label="table.field.asnOrderItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="stockUnit" label="table.field.asnOrderItem.stockUnit" />
                    <NumberField source="purQty" label="table.field.asnOrderItem.purQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="purUnit" label="table.field.asnOrderItem.purUnit" />
                    <TextField source="splrCode" label="table.field.asnOrderItem.splrCode" />
                    <TextField source="splrName" label="table.field.asnOrderItem.splrName" />
                    <TextField source="updateBy$" label="common.field.updateBy" />
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
                    <TextField source="createBy$" label="common.field.createBy" />
                    <DateField source="createTime" label="common.field.createTime" showTime />
                    <TextField source="memo" label="common.field.memo" sortable={false} />
rsf-admin/src/page/histories/asnOrderLog/AsnOrderLogListBase.jsx
@@ -33,10 +33,8 @@
}));
/**
 * 入库/出库历史单列表共用骨架,仅 type 与标题由外部传入。
 * 入库历史单:typeFilter="in", listTitle="menu.asnOrderLog"
 * 出库历史单:typeFilter="out", listTitle="menu.outStockOrderLog"
 * 后端接口均为 asnOrderLog(出库由 dataProvider 映射),参数 filter.type 不同。
 */
export default function AsnOrderLogListBase({ typeFilter, listTitle }) {
    const [createDialog, setCreateDialog] = useState(false);
@@ -100,8 +98,8 @@
                    <NumberField source="poId" label="table.field.asnOrderLog.poId" />
                    <TextField source="type$" label="table.field.asnOrderLog.type" />
                    <TextField source="wkType$" label="table.field.asnOrderLog.wkType" />
                    <NumberField source="anfme" label="table.field.asnOrderLog.anfme" />
                    <NumberField source="qty" label="table.field.asnOrderLog.qty" />
                    <NumberField source="anfme" label="table.field.asnOrderLog.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="qty" label="table.field.asnOrderLog.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="logisNo" label="table.field.asnOrderLog.logisNo" />
                    <DateField source="arrTime" label="table.field.asnOrderLog.arrTime" showTime />
                    <TextField source="rleStatus$" label="table.field.asnOrderLog.rleStatus" sortable={false} />
rsf-admin/src/page/histories/asnOrderLog/AsnOrderLogShow.jsx
@@ -1,158 +1,150 @@
import { BooleanField, DateField, NumberField, ReferenceField, Show, SimpleShowLayout, TextField ,DateInput,
    SelectInput,required,useTranslate,
    useRecordContext,} from 'react-admin';
import { Stack, Grid, Box, Typography, Card } from '@mui/material';
import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
import EditBaseAside from "../../components/EditBaseAside";
import React from "react";
import { Show, useTranslate, useRecordContext, DateField } from 'react-admin';
import { Stack, Grid, Box, Typography, TextField as MuiTextField, Card, CardContent } from '@mui/material';
import AccessTimeIcon from '@mui/icons-material/AccessTime';
import CustomerTopToolBar from "../../components/EditTopToolBar";
import AsnOrderItemLogList from "./AsnOrderItemLogList";
const AsnOrderLogDetailWithItems = () => {
    const record = useRecordContext();
/** 只读输入框样式,与 Edit 页 Filled 白底一致,用于 Show 头部 */
const readOnlyInputSx = {
    "& .MuiFormLabel-root.MuiInputLabel-root.Mui-disabled": {
        bgcolor: 'white',
        WebkitTextFillColor: "rgba(0, 0, 0)"
    },
    "& .MuiInputBase-input.MuiFilledInput-input.Mui-disabled": {
        bgcolor: 'white',
        WebkitTextFillColor: "rgba(0, 0, 0)"
    },
    "& .MuiFilledInput-root.MuiInputBase-sizeSmall": {
        bgcolor: 'white',
    }
};
const ShowField = ({ source, labelKey, value }) => {
    const translate = useTranslate();
    if (!record?.id) return null;
    return (
        <>
            <Grid item xs={24} md={16} sx={{ marginTop: '1em', width: '100%' }}>
                <Typography variant="h6" gutterBottom>
                    {translate('common.edit.title.common')}
                </Typography>
            </Grid>
            <AsnOrderItemLogList logId={record.id} />
        </>
        <MuiTextField
            size="small"
            variant="filled"
            label={translate(labelKey)}
            value={value ?? ''}
            disabled
            sx={{ width: 130, minWidth: 110, flexShrink: 0, ...readOnlyInputSx }}
            InputProps={{ readOnly: true }}
        />
    );
};
const Aa = () =>{
/**
 * 入库/出库历史单查看详情:单列平铺(主要 → 更多 → 物料详情),无右侧 aside,占满整页宽度。
 * Show 页无 Form 上下文,用 MUI TextField 只读样式复刻 Edit 头部视觉效果。
 */
const AsnOrderLogShow = () => {
    const translate = useTranslate();
    return(
        <>
        <Show
            redirect="list"
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
            title="入库历史单详情"
            sx={{
                width: '100% !important',
                maxWidth: 'none !important',
                '& > div': { maxWidth: 'none !important', width: '100% !important' },
                '& .RaShow-main': { maxWidth: 'none !important', width: '100% !important', minWidth: 0 },
                '& .RaShow-card': { maxWidth: 'none !important', width: '100% !important' },
                '& .MuiPaper-root': { maxWidth: 'none !important', width: '100% !important' },
                '& [class*="RaShow"]': { maxWidth: 'none !important', width: '100% !important' },
            }}
            >
            <SimpleShowLayout
            shouldUnregister
            warnWhenUnsavedChanges
            mode="onTouched"
            defaultValues={{}}
            >
            <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, pt: 1, width: '100%', minWidth: 0 }}>
                <Grid container spacing={2}>
                    <Grid item xs={12} md>
                        <Card variant="outlined" sx={{ height: '100%' }}>
                            <CardContent sx={{ py: 1, '&:last-child': { pb: 1.5 } }}>
                                <MainSection />
                            </CardContent>
                        </Card>
                    </Grid>
                    <Grid item xs={12} md="auto">
                        <Card variant="outlined" sx={{ height: '100%' }}>
                            <CardContent>
                                <MoreSection />
                            </CardContent>
                        </Card>
                    </Grid>
                </Grid>
                <Card variant="outlined" sx={{ flex: '1 1 auto', minHeight: 0, display: 'flex', flexDirection: 'column' }}>
                    <CardContent sx={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, '&:last-child': { pb: 2 } }}>
                        <Box sx={{ width: '100%', minWidth: 0, overflowX: 'auto', flex: 1 }}>
                            <AsnOrderItemLogList />
                        </Box>
                    </CardContent>
                </Card>
            </Box>
        </Show>
    );
};
    
                <Grid sx={{
                    "& .MuiInputBase-input": {
                        bgcolor: "white"
                    }
                }} container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}>
                    <Grid item xs={24} md={12}>
/** 更多:创建时间、修改时间,与 EditBaseAside 内容一致,放在主内容区单列展示 */
const MoreSection = () => {
    const translate = useTranslate();
    const record = useRecordContext();
    if (!record) return null;
    return (
        <Box>
                    <Typography variant="h6" gutterBottom>
                {translate('common.edit.side.title')}
            </Typography>
            <Grid container rowSpacing={2} columnSpacing={1}>
                <Grid item xs={12} display="flex" gap={1}>
                    <AccessTimeIcon fontSize="small" color="disabled" />
                    <Box flexGrow={1}>
                        <Typography variant="body2">{translate('common.field.createTime')}</Typography>
                        <DateField record={record} source="createTime" showTime />
                    </Box>
                </Grid>
                <Grid item xs={12} display="flex" gap={1}>
                    <AccessTimeIcon fontSize="small" color="disabled" />
                    <Box flexGrow={1}>
                        <Typography variant="body2">{translate('common.field.updateTime')}</Typography>
                        <DateField record={record} source="updateTime" showTime />
                    </Box>
                </Grid>
            </Grid>
        </Box>
    );
};
const MainSection = () => {
    const translate = useTranslate();
    const record = useRecordContext();
    if (!record) return null;
    const rleStatusText = record.rleStatus === 1 ? '已释放' : (record.rleStatus === 0 ? '正常' : (record.rleStatus$ ?? ''));
    const arrTime = record.arrTime ? (typeof record.arrTime === 'string' ? record.arrTime : new Date(record.arrTime).toLocaleString('zh-CN')) : '';
    const numOpt = { minimumFractionDigits: 2, maximumFractionDigits: 2 };
    return (
        <Box sx={{ pt: 0.3, width: '100%' }}>
            <Grid container sx={{ width: '100%', maxWidth: '100%' }} rowSpacing={1} columnSpacing={1}>
                <Grid item xs={12}>
                    <Typography variant="h6" gutterBottom sx={{ mb: 1 }}>
                        {translate('common.edit.title.main')}
                    </Typography>                        
                        <Stack display="flax" justifyContent="space-between" flexWrap="wrap" direction='row' gap={2} >
                            <Grid item  display="flex" gap={1} minWidth={150}>
                                <Box flexGrow={1}>
                                    <Typography variant="body2" >
                                        {translate('table.field.asnOrderLog.code')}
                                    </Typography>
                                    <TextField source="code" label="id"/>
                                </Box>
                            </Grid>
                            <Grid item  display="flex" gap={1} minWidth={150}>
                                <Box flexGrow={1}>
                                    <Typography variant="body2" sx={{fontSize: 20}}>
                                        {translate('table.field.asnOrderLog.poCode')}
                                    </Typography>
                                    <TextField source="poCode" label="poCode"/>
                                </Box>
                            </Grid>
                            <Grid item  display="flex" gap={1} minWidth={150}>
                                <Box flexGrow={1}>
                                    <Typography variant="body2" sx={{fontSize: 20}}>
                                        {translate('table.field.asnOrderLog.poId')}
                                    </Typography>
                                    <NumberField source="poId" label="poId"/>
                                </Box>
                            </Grid>
                            <Grid item  display="flex" gap={1} minWidth={150}>
                                <Box flexGrow={1}>
                                    <Typography variant="body2" sx={{fontSize: 20}}>
                                        {translate('table.field.asnOrderLog.type')}
                                    </Typography>
                                    <TextField source="type$" label="type"/>
                                </Box>
                            </Grid>
                            <Grid item  display="flex" gap={1} minWidth={150}>
                                <Box flexGrow={1}>
                                    <Typography variant="body2" sx={{fontSize: 20}}>
                                        {translate('table.field.asnOrderLog.wkType')}
                                    </Typography>
                                    <TextField source="wkType$" label="type"/>
                                </Box>
                            </Grid>
                        </Stack>
                        <Stack display="flax" justifyContent="space-between"  flexWrap="wrap" direction='row' gap={2} sx={{mt:5 }}>
                        <Grid item  display="flex" gap={1} minWidth={150}>
                                <Box flexGrow={1}>
                                    <Typography variant="body2" sx={{fontSize: 20}}>
                                        {translate('table.field.asnOrderLog.anfme')}
                                    </Typography>
                                    <TextField source="anfme" label="id"/>
                                </Box>
                            </Grid>
                            <Grid item  display="flex" gap={1} minWidth={150}>
                                <Box flexGrow={1}>
                                    <Typography variant="body2" sx={{fontSize: 20}}>
                                        {translate('table.field.asnOrderLog.qty')}
                                    </Typography>
                                    <TextField source="qty" label="poCode"/>
                                </Box>
                            </Grid>
                            <Grid item  display="flex" gap={1} minWidth={150}>
                                <Box flexGrow={1}>
                                    <Typography variant="body2" sx={{fontSize: 20}}>
                                        {translate('table.field.asnOrderLog.logisNo')}
                                    </Typography>
                                    <NumberField source="logisNo" label="poId"/>
                                </Box>
                            </Grid>
                            <Grid item  display="flex" gap={1} minWidth={150}>
                                <Box flexGrow={1}>
                                    <Typography variant="body2" sx={{fontSize: 20}}>
                                        {translate('table.field.asnOrderLog.arrTime')}
                                    </Typography>
                                    <DateField source="arrTime" label="type" showTime/>
                                </Box>
                            </Grid>
                            {/* 质检上报状态
                            <Grid item  display="flex" gap={1} minWidth={150}>
                                <Box flexGrow={1}>
                                    <Typography variant="body2" sx={{fontSize: 20}}>
                                        {translate('table.field.asnOrderLog.ntyStatus')}
                                    </Typography>
                                    <TextField source="ntyStatus$" label="type"/>
                                </Box>
                            </Grid>
                            */}
                    <Stack direction="row" gap={1} flexWrap="wrap" useFlexGap>
                        <ShowField source="code" labelKey="table.field.asnOrder.code" value={record.code} />
                        <ShowField source="poCode" labelKey="table.field.asnOrder.poCode" value={record.poCode} />
                        <ShowField source="type" labelKey="table.field.asnOrder.type" value={record.type$ ?? record.type} />
                        <ShowField source="wkType" labelKey="table.field.asnOrder.wkType" value={record.wkType$ ?? record.wkType} />
                    {/*</Stack>*/}
                    {/*<Stack direction="row" gap={1} flexWrap="wrap" useFlexGap sx={{ mt: 1 }}>*/}
                        <ShowField source="logisNo" labelKey="table.field.asnOrder.logisNo" value={record.logisNo} />
                        <ShowField source="anfme" labelKey="table.field.asnOrder.anfme" value={record.anfme != null ? Number(record.anfme).toLocaleString('zh-CN', numOpt) : ''} />
                        <ShowField source="qty" labelKey="table.field.asnOrder.qty" value={record.qty != null ? Number(record.qty).toLocaleString('zh-CN', numOpt) : ''} />
                        <ShowField source="arrTime" labelKey="table.field.asnOrder.arrTime" value={arrTime} />
                        <ShowField source="rleStatus" labelKey="table.field.asnOrder.rleStatus" value={rleStatusText} />
                        </Stack>
                    </Grid>
                </Grid>
                <AsnOrderLogDetailWithItems />
            </SimpleShowLayout>
        </Show>
        </>
        </Box>
       ); 
}
};
const AsnorderlogShow = () => (
    <Aa />
);
export default AsnorderlogShow
export default AsnOrderLogShow;
rsf-admin/src/page/histories/asnOrderLog/index.jsx
@@ -7,12 +7,12 @@
import AsnOrderLogList from "./AsnOrderLogList";
import AsnOrderLogEdit from "./AsnOrderLogEdit";
import  AsnorderlogShow  from "./AsnOrderLogShow";
import AsnOrderLogShow from "./AsnOrderLogShow";
export default {
    list: AsnOrderLogList,
    edit: AsnOrderLogEdit,
    show: AsnorderlogShow,
    show: AsnOrderLogShow,
    recordRepresentation: (record) => {
        return `${record.id}`
    }
rsf-admin/src/page/histories/taskLog/TaskItemLogList.jsx
@@ -156,7 +156,7 @@
                <TextField source="maktx" label="table.field.taskItemLog.maktx" />,
                <TextField source="matnrCode" label="table.field.taskItemLog.matnrCode" />,
                <TextField source="unit" label="table.field.taskItemLog.unit" />,
                <NumberField source="anfme" label="table.field.taskItemLog.anfme" />,
                <NumberField source="anfme" label="table.field.taskItemLog.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="batch" label="table.field.taskItemLog.batch" />,
                <TextField source="spec" label="table.field.taskItemLog.spec" />,
                <TextField source="model" label="table.field.taskItemLog.model" />,
rsf-admin/src/page/histories/waitPakinLog/WaitPakinItemLogList.jsx
@@ -1,46 +1,24 @@
import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
import { useNavigate } from 'react-router-dom';
import React, { useState } from "react";
import {
    List,
    DatagridConfigurable,
    SearchInput,
    TopToolbar,
    SelectColumnsButton,
    EditButton,
    FilterButton,
    CreateButton,
    ExportButton,
    BulkDeleteButton,
    WrapperField,
    useRecordContext,
    useTranslate,
    useNotify,
    useListContext,
    FunctionField,
    TextField,
    NumberField,
    DateField,
    BooleanField,
    ReferenceField,
    TextInput,
    DateTimeInput,
    DateInput,
    SelectInput,
    NumberInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    DeleteButton,
    useGetRecordId,
} from 'react-admin';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles'; import EmptyData from "../../components/EmptyData";
import MyCreateButton from "../../components/MyCreateButton";
import MyExportButton from '../../components/MyExportButton';
import { Box } from '@mui/material';
import { styled } from '@mui/material/styles';
import PageDrawer from "../../components/PageDrawer";
import MyField from "../../components/MyField";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
import { PAGE_DRAWER_WIDTH, DEFAULT_ITEM_PAGE_SIZE } from '@/config/setting';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
@@ -49,8 +27,6 @@
    '& .RaDatagrid-row': {
        cursor: 'auto'
    },
    '& .column-name': {
    },
    '& .opt': {
        width: 200
    },
@@ -58,23 +34,14 @@
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <ReferenceInput source="pakinId" label="table.field.waitPakinItemLog.pakinId" reference="waitPakin">
        <AutocompleteInput label="table.field.waitPakinItemLog.pakinId" optionText="id" filterToQuery={(val) => ({ id: val })} />
    </ReferenceInput>,
    <NumberInput source="pakinItemId" label="table.field.waitPakinItemLog.pakinItemId" />,
    <NumberInput source="asnId" label="table.field.waitPakinItemLog.asnId" />,
    <TextInput source="asnCode" label="table.field.waitPakinItemLog.asnCode" />,
    <NumberInput source="asnItemId" label="table.field.waitPakinItemLog.asnItemId" />,
    <TextInput source="trackCode" label="table.field.waitPakinItemLog.trackCode" />,
    <NumberInput source="pakinId" label="table.field.waitPakinItemLog.pakinId" />,
    <TextInput source="maktx" label="table.field.waitPakinItemLog.maktx" />,
    <ReferenceInput source="matnrId" label="table.field.waitPakinItemLog.matnrId" reference="matnr">
        <AutocompleteInput label="table.field.waitPakinItemLog.matnrId" optionText="unit" filterToQuery={(val) => ({ unit: val })} />
    </ReferenceInput>,
    <NumberInput source="matnrId" label="table.field.waitPakinItemLog.matnrId" />,
    <TextInput source="matnrCode" label="table.field.waitPakinItemLog.matnrCode" />,
    <TextInput source="asnCode" label="table.field.waitPakinItem.asnCode" />,
    <NumberInput source="anfme" label="table.field.waitPakinItemLog.anfme" />,
    <NumberInput source="workQty" label="table.field.waitPakinItemLog.workQty" />,
    <TextInput source="unit" label="table.field.waitPakinItemLog.unit" />,
    <TextInput source="fieldsIndex" label="table.field.waitPakinItemLog.fieldsIndex" />,
    <NumberInput source="qty" label="table.field.waitPakinItemLog.qty" />,
    <TextInput source="batch" label="table.field.waitPakinItemLog.batch" />,
    <TextInput label="common.field.memo" source="memo" />,
@@ -87,11 +54,9 @@
        ]}
        resettable
    />,
]
];
const WaitPakinItemLogList = () => {
    const translate = useTranslate();
    const [createDialog, setCreateDialog] = useState(false);
    const [drawerVal, setDrawerVal] = useState(false);
    const recordId = useGetRecordId();
@@ -107,7 +72,7 @@
                        }),
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.waitPakinItemLog"}
                title={"menu.waitPakinItem"}
                empty={false}
                filters={filters}
                filter={{ logId: recordId }}
@@ -116,42 +81,32 @@
                    <TopToolbar>
                        <FilterButton />
                        <SelectColumnsButton preferenceKey='waitPakinItemLog' />
                        <MyExportButton />
                        {/* <MyExportButton /> 与组托通知档保持一致,不展示导出 */}
                    </TopToolbar>
                )}
                perPage={DEFAULT_PAGE_SIZE}
                perPage={DEFAULT_ITEM_PAGE_SIZE}
            >
                <StyledDatagrid
                    preferenceKey='waitPakinItemLog'
                    bulkActionButtons={false}
                    rowClick={ false}
                    omit={['id', 'createTime', 'createBy', 'memo', 'pakinId', 'pakinItemId', 'asnId' ,'asnItemId', 'createBy$', 'fieldsIndex']}
                    omit={['id', 'logId', 'pakinId', 'pakinItemId', 'asnId', 'asnItemId', 'createTime', 'matnrId', 'createBy', 'memo', 'fieldsIndex']}
                >
                    <NumberField source="id" />
                    <ReferenceField source="pakinId" label="table.field.waitPakinItemLog.pakinId" reference="waitPakin" link={false} sortable={false}>
                        <TextField source="id" />
                    </ReferenceField>
                    <NumberField source="pakinItemId" label="table.field.waitPakinItemLog.pakinItemId" />
                    <NumberField source="asnId" label="table.field.waitPakinItemLog.asnId" />
                    <TextField source="asnCode" label="table.field.waitPakinItemLog.asnCode" />
                    <NumberField source="asnItemId" label="table.field.waitPakinItemLog.asnItemId" />
                    <TextField source="trackCode" label="table.field.waitPakinItemLog.trackCode" />
                    <TextField source="maktx" label="table.field.waitPakinItemLog.maktx" />
                    <ReferenceField source="matnrId" label="table.field.waitPakinItemLog.matnrId" reference="matnr" link={false} sortable={false}>
                        <TextField source="unit" />
                    </ReferenceField>
                    <TextField source="matnrCode" label="table.field.waitPakinItemLog.matnrCode" />
                    <NumberField source="anfme" label="table.field.waitPakinItemLog.anfme" />
                    <NumberField source="workQty" label="table.field.waitPakinItemLog.workQty" />
                    <TextField source="unit" label="table.field.waitPakinItemLog.unit" />
                    <TextField source="fieldsIndex" label="table.field.waitPakinItemLog.fieldsIndex" />
                    <NumberField source="qty" label="table.field.waitPakinItemLog.qty" />
                    <TextField source="batch" label="table.field.waitPakinItemLog.batch" />
                    <TextField source="matnrCode" label="table.field.waitPakinItem.matnrCode" />
                    <TextField source="maktx" label="table.field.waitPakinItem.maktx" />
                    <TextField source="batch" label="table.field.waitPakinItem.batch" />
                    <NumberField source="matnrId" label="table.field.waitPakinItem.matnrId" />
                    <NumberField source="anfme" label="table.field.waitPakinItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="unit" label="table.field.waitPakinItem.unit" />
                    <TextField source="asnCode" label="table.field.waitPakinItem.asnCode" />
                    <NumberField source="workQty" label="table.field.waitPakinItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="qty" label="table.field.waitPakinItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="fieldsIndex" label="table.field.waitPakinItem.fieldsIndex" />
                    <TextField source="updateBy$" label="common.field.updateBy" />
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
                    <TextField source="createBy$" label="common.field.createBy"  />
                    <DateField source="createTime" label="common.field.createTime" showTime />
                    <BooleanField source="statusBool" label="common.field.status" sortable={false} />
                    <TextField source="memo" label="common.field.memo" sortable={false} />
                </StyledDatagrid>
            </List>
rsf-admin/src/page/histories/waitPakinLog/WaitPakinLogEdit.jsx
@@ -2,45 +2,17 @@
import {
    Edit,
    SimpleForm,
    FormDataConsumer,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    SaveButton,
    Toolbar,
    Labeled,
    NumberField,
    required,
    useRecordContext,
    DeleteButton,
} from 'react-admin';
import { useWatch, useFormContext } from "react-hook-form";
import { useFormContext } from "react-hook-form";
import { Stack, Grid, Box, Typography } from '@mui/material';
import * as Common from '@/utils/common';
import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
import { EDIT_MODE } from '@/config/setting';
import EditBaseAside from "../../components/EditBaseAside";
import CustomerTopToolBar from "../../components/EditTopToolBar";
import MemoInput from "../../components/MemoInput";
import StatusSelectInput from "../../components/StatusSelectInput";
import WaitPakinItemLogList from "./WaitPakinItemLogList";
const FormToolbar = () => {
    const { getValues } = useFormContext();
    return (
        <Toolbar sx={{ justifyContent: 'end' }}>
            <></>
            {/* <SaveButton />
            <DeleteButton mutationMode="optimistic" /> */}
        </Toolbar>
    )
}
const WaitPakinLogEdit = () => {
    const translate = useTranslate();
@@ -54,44 +26,45 @@
                aside={<EditBaseAside />}
            >
                <SimpleForm
                    sx={{
                        '& .MuiInputBase-input.MuiFilledInput-input.Mui-disabled': {
                            bgcolor: "white",
                            color: "black",
                            '-webkit-text-fill-color': "rgba(0, 0, 0)"
                        },
                        '& .MuiFormLabel-root.MuiInputLabel-root.Mui-disabled': {
                            color: 'rgba(0, 0, 0, 0.77)'
                        }
                    }}
                    shouldUnregister
                    warnWhenUnsavedChanges
                    toolbar={<FormToolbar />}
                    toolbar={<></>}
                    mode="onTouched"
                    defaultValues={{}}
                >
                    <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}>
                        <Grid item xs={24} md={12} sx={{
                            "& .MuiFormLabel-root.MuiInputLabel-root.Mui-disabled": {
                                bgcolor: 'white',
                                WebkitTextFillColor: "rgba(0, 0, 0)"
                            },
                            "& .MuiInputBase-input.MuiFilledInput-input.Mui-disabled": {
                                bgcolor: 'white',
                                WebkitTextFillColor: "rgba(0, 0, 0)"
                            }
                        }}>
                    <Grid container width={{ xs: '100%', xl: '100%' }}>
                        <Grid item xs={24} md={12}>
                            <Typography variant="h6" gutterBottom>
                                {translate('common.edit.title.main')}
                            </Typography>
                            <Stack direction='row' gap={2}>
                                <NumberInput
                                    label="table.field.waitPakinLog.pakinId"
                                    source="pakinId"
                                    readOnly
                                    autoFocus
                                />
                                <TextInput
                                    label="table.field.waitPakinLog.code"
                                    source="code"
                                    readOnly
                                    parse={v => v}
                                    autoFocus
                                />
                                <TextInput
                                    label="table.field.waitPakin.asnCodes"
                                    source="asnCodes"
                                    readOnly
                                    parse={v => v}
                                />
                                <TextInput
                                    label="table.field.waitPakinLog.barcode"
                                    source="barcode"
                                    readOnly
                                    source="barcode"
                                    parse={v => v}
                                />
                                <NumberInput
@@ -101,13 +74,12 @@
                                />
                                <SelectInput
                                    label="table.field.waitPakinLog.ioStatus"
                                    source="ioStatus"
                                    readOnly
                                    source="ioStatus"
                                    choices={[
                                        { id: 0, name: '待入库' },
                                        { id: 1, name: ' 入库中' },
                                    ]}
                                    validate={required()}
                                />
                            </Stack>
                        </Grid>
rsf-admin/src/page/histories/waitPakinLog/WaitPakinLogList.jsx
@@ -7,6 +7,7 @@
    TopToolbar,
    SelectColumnsButton,
    EditButton,
    ShowButton,
    FilterButton,
    CreateButton,
    ExportButton,
@@ -53,6 +54,10 @@
        width: 200
    },
}));
const ViewDetailButton = () => (
    <ShowButton label="查看详情" />
);
const filters = [
    <SearchInput source="condition" alwaysOn />,
@@ -112,7 +117,7 @@
                <StyledDatagrid
                    preferenceKey='waitPakinLog'
                    bulkActionButtons={false}
                    rowClick={'edit'}
                    rowClick={false}
                    expand={false}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo','statusBool']}
@@ -121,7 +126,7 @@
                    <NumberField source="pakinId" label="table.field.waitPakinLog.pakinId" />
                    <TextField source="code" label="table.field.waitPakinLog.code" />
                    <TextField source="barcode" label="table.field.waitPakinLog.barcode" />
                    <NumberField source="anfme" label="table.field.waitPakinLog.anfme" />
                    <NumberField source="anfme" label="table.field.waitPakinLog.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="ioStatus$" label="table.field.waitPakinLog.ioStatus" sortable={false} />
                    <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}>
                        <TextField source="nickname" />
@@ -133,6 +138,9 @@
                    <DateField source="createTime" label="common.field.createTime" showTime />
                    <BooleanField source="statusBool" label="common.field.status" sortable={false} />
                    <TextField source="memo" label="common.field.memo" sortable={false} />
                    <WrapperField cellClassName="opt" label="common.field.opt">
                        <ViewDetailButton />
                    </WrapperField>
                </StyledDatagrid>
            </List>
            <PageDrawer
rsf-admin/src/page/histories/waitPakinLog/WaitPakinLogShow.jsx
New file
@@ -0,0 +1,39 @@
import React from "react";
import {
    Show,
    TextField,
    NumberField,
} from 'react-admin';
import { Box, Typography, Stack, Grid } from '@mui/material';
import { useTranslate } from 'react-admin';
import WaitPakinItemLogList from "./WaitPakinItemLogList";
/**
 * 组托历史档查看详情:与组托通知档查看详情保持一致(主信息布局 + 明细列/omit 一致),仅展示无编辑。
 */
const WaitPakinLogShow = () => {
    const translate = useTranslate();
    return (
        <Show actions={false} title="组托历史档详情">
            <Box sx={{ pt: 1 }}>
                <Grid container width={{ xs: '100%', xl: '100%' }}>
                    <Grid item xs={24} md={12}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.main')}
                        </Typography>
                        <Stack direction="row" gap={2} flexWrap="wrap" useFlexGap>
                            <TextField source="code" label="table.field.waitPakinLog.code" />
                            <TextField source="asnCodes" label="table.field.waitPakin.asnCodes" />
                            <TextField source="barcode" label="table.field.waitPakinLog.barcode" />
                            <NumberField source="anfme" label="table.field.waitPakinLog.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                            <TextField source="ioStatus$" label="table.field.waitPakinLog.ioStatus" />
                        </Stack>
                    </Grid>
                </Grid>
            </Box>
            <WaitPakinItemLogList />
        </Show>
    );
};
export default WaitPakinLogShow;
rsf-admin/src/page/histories/waitPakinLog/index.jsx
@@ -1,18 +1,13 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    ListGuesser,
    EditGuesser,
    ShowGuesser,
} from "react-admin";
import React from "react";
import WaitPakinLogList from "./WaitPakinLogList";
import WaitPakinLogEdit from "./WaitPakinLogEdit";
import WaitPakinLogShow from "./WaitPakinLogShow";
export default {
    list: WaitPakinLogList,
    edit: WaitPakinLogEdit,
    show: ShowGuesser,
    show: WaitPakinLogShow,
    recordRepresentation: (record) => {
        return `${record.id}`
        return record?.code != null ? record.code : `${record?.id ?? ''}`;
    }
};
rsf-admin/src/page/locItem/LocItemCreate.jsx
@@ -137,6 +137,7 @@
                                        parse={v => v}
                                    />
                                </Grid>
                                {/* 现品票号已注释
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.locItem.platItemId"
@@ -144,6 +145,7 @@
                                        parse={v => v}
                                    />
                                </Grid>
                                */}
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.locItem.platOrderCode"
rsf-admin/src/page/locItem/LocItemEdit.jsx
@@ -116,6 +116,7 @@
                                parse={v => v}
                            />
                        </Stack>
                        {/* 现品票号已注释
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.locItem.platItemId"
@@ -123,6 +124,7 @@
                                parse={v => v}
                            />
                        </Stack>
                        */}
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.locItem.platOrderCode"
rsf-admin/src/page/locItem/LocItemList.jsx
@@ -163,7 +163,7 @@
                <TextField source="maktx" label="table.field.locItem.maktx" />,
                <TextField source="matnrCode" label="table.field.locItem.matnrCode" />,
                <TextField source="unit" label="table.field.locItem.unit" />,
                <NumberField source="anfme" label="table.field.locItem.anfme" options={{ maximumFractionDigits: 6 }} />,
                <NumberField source="anfme" label="table.field.locItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="batch" label="table.field.locItem.batch" />,
                <NumberField source="splrId" label="table.field.locItem.splrId" />,
                <TextField source="spec" label="table.field.locItem.spec" />,
rsf-admin/src/page/locItem/LocItemPanel.jsx
@@ -88,12 +88,14 @@
                                property={record.maktx}
                            />
                        </Grid>
                        {/* 现品票号已注释
                        <Grid item xs={6}>
                            <PanelTypography
                                title="table.field.locItem.platItemId" 
                                property={record.platItemId}
                            />
                        </Grid>
                        */}
                        <Grid item xs={6}>
                            <PanelTypography
                                title="table.field.locItem.platOrderCode" 
rsf-admin/src/page/locPreview/LocPreviewItems.jsx
@@ -172,9 +172,9 @@
                <TextField source="batch" label="table.field.locItem.batch" />,
                <TextField source="trackCode" label="table.field.locItem.trackCode" />,
                <TextField source="unit" label="table.field.locItem.unit" />,
                <NumberField source="anfme" label="table.field.locItem.anfme" />,
                <NumberField source="workQty" label="table.field.locItem.workQty" />,
                <NumberField source="qty" label="table.field.locItem.qty" />,
                <NumberField source="anfme" label="table.field.locItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <NumberField source="workQty" label="table.field.locItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <NumberField source="qty" label="table.field.locItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="splrBatch" label="table.field.locItem.splrBatch" />,
                <TextField source="fieldsIndex" label="table.field.locItem.fieldsIndex" />,
            ]
rsf-admin/src/page/orders/asnOrder/AsnCreateByPoModal.jsx
@@ -175,8 +175,8 @@
                                    <TextField source="type$" label="table.field.purchase.type" />
                                    <TextField source="wkType$" label="table.field.purchase.wkType" />
                                    <TextField source="source" label="table.field.purchase.source" />
                                    <NumberField source="anfme" label="table.field.purchase.anfme" options={{ maximumFractionDigits: 6 }} />
                                    <NumberField source="qty" label="table.field.purchase.qty" options={{ maximumFractionDigits: 6 }} />
                                    <NumberField source="anfme" label="table.field.purchase.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <NumberField source="qty" label="table.field.purchase.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <TextField source="channel" label="table.field.purchase.channel" />
                                    <TextField source="platCode" label="table.field.purchase.platCode" />
                                    <DateField source="preArr" label="table.field.purchase.preArr" showTime />
rsf-admin/src/page/orders/asnOrder/AsnOrderItemCreate.jsx
@@ -172,11 +172,13 @@
                                        source="barcode"
                                        parse={v => v}
                                    />
                                    {/* 包装已注释
                                    <TextInput
                                        label="table.field.asnOrderItem.packName"
                                        source="packName"
                                        parse={v => v}
                                    />
                                    */}
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
rsf-admin/src/page/orders/asnOrder/AsnOrderItemEdit.jsx
@@ -177,11 +177,13 @@
                                        parse={v => v}
                                        readOnly
                                    />
                                    {/* 包装已注释
                                    <TextInput
                                        label="table.field.asnOrderItem.packName"
                                        source="packName"
                                        parse={v => v}
                                    />
                                    */}
                                </Stack>
                            </Grid>
                        </Grid>
rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx
@@ -83,7 +83,7 @@
  <TextInput source="splrName" label="table.field.asnOrderItem.splrName" />,
  <TextInput source="qrcode" label="table.field.asnOrderItem.qrcode" />,
  <TextInput source="trackCode" label="table.field.asnOrderItem.barcode" />,
  <TextInput source="packName" label="table.field.asnOrderItem.packName" />,
  // <TextInput source="packName" label="table.field.asnOrderItem.packName" />, // 包装已注释
  <TextInput label="common.field.memo" source="memo" />,
  <SelectInput
    label="common.field.status"
@@ -180,7 +180,7 @@
        <TextField source="orderCode" label="table.field.asnOrderItem.orderCode" />,
        <TextField source="poDetlId" label="table.field.asnOrderItem.poDetlId" />,
        <TextField source="poDetlCode" label="table.field.asnOrderItem.poDetlCode" />,
        <TextField source="platItemId" label="table.field.asnOrderItem.platItemId" />,
        // <TextField source="platItemId" label="table.field.asnOrderItem.platItemId" />, // 现品票号已注释
        <TextField source="matnrId" label="table.field.asnOrderItem.matnrId" />,
        <TextField source="matnrCode" label="table.field.asnOrderItem.matnrCode" />,
        <TextField source="maktx" label="table.field.asnOrderItem.maktx" />,
@@ -190,17 +190,17 @@
        <TextField source="projectCode" label="table.field.asnOrderItem.projectCode" />,
        <TextField source="spec" label="table.field.asnOrderItem.spec" />,
        <TextField source="model" label="table.field.asnOrderItem.model" />,
        <NumberField source="anfme" label="table.field.asnOrderItem.anfme" options={{ maximumFractionDigits: 6 }} />,
        <NumberField source="qty" label="table.field.asnOrderItem.qty" options={{ maximumFractionDigits: 6 }} />,
        <NumberField source="anfme" label="table.field.asnOrderItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
        <NumberField source="qty" label="table.field.asnOrderItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
        <TextField source="stockUnit" label="table.field.asnOrderItem.stockUnit" />,
        <NumberField source="purQty" label="table.field.asnOrderItem.purQty" options={{ maximumFractionDigits: 6 }} />,
        <NumberField source="purQty" label="table.field.asnOrderItem.purQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
        <TextField source="purUnit" label="table.field.asnOrderItem.purUnit" />,
        <TextField source="splrCode" label="table.field.asnOrderItem.splrCode" />,
        <TextField source="splrName" label="table.field.asnOrderItem.splrName" />,
        <TextField source="isptResult$" label="table.field.asnOrderItem.isptResult" />,
        // <TextField source="isptResult$" label="table.field.asnOrderItem.isptResult" />, // 质检已注释
        <TextField source="qrcode" label="table.field.asnOrderItem.qrcode" />,
        <TextField source="trackCode" label="table.field.asnOrderItem.barcode" />,
        <TextField source="packName" label="table.field.asnOrderItem.packName" />,
        // <TextField source="packName" label="table.field.asnOrderItem.packName" />, // 包装已注释
      ]
      const fields = data.map(el => <TextField key={el.fields} source={`extendFields.[${el.fields}]`} label={el.fieldsAlise} />)
      const lastArr = [
@@ -238,7 +238,7 @@
          preferenceKey='asnOrderItem'
          bulkActionButtons={false}
          rowClick={(id, resource, record) => false}
          omit={['id', 'orderId', 'orderCode', 'poDetlId', 'poDetlCode', 'matnrId', 'spec', 'model', 'purQty', 'purUnit', 'qrcode', 'trackCode', 'splrCode', 'platWorkCode', 'projectCode']}
          omit={['id', 'orderId', 'orderCode', 'poDetlId', 'poDetlCode', 'matnrId', 'spec', 'model', 'purQty', 'purUnit', 'qrcode', 'trackCode', 'splrCode', 'platWorkCode', 'projectCode', 'platItemId', 'isptResult$', 'packName']}
        >
          {columns.map((column) => column)}
        </StyledDatagrid>}
rsf-admin/src/page/orders/asnOrder/AsnOrderList.jsx
@@ -138,8 +138,8 @@
        actions={(
          <TopToolbar>
            <FilterButton />
            <MyCreateButton onClick={() => { setCreateDialog(true); setmodalType(0) }} />
            <CreateByPoButton setPoCreate={setPoCreate} />
            {/* <MyCreateButton onClick={() => { setCreateDialog(true); setmodalType(0) }} /> 添加按钮暂不使用 */}
            {/* <CreateByPoButton setPoCreate={setPoCreate} /> 通过PO单创建暂不使用 */}
            <SelectColumnsButton preferenceKey='asnOrder' />
            <ImportButton value={'asnOrderItem'} />
            <MyExportButton />
@@ -152,7 +152,7 @@
          preferenceKey='asnOrder'
          bulkActionButtons={
            <>
              <InspectionsButton />
              {/* <InspectionsButton /> 报检按钮暂不使用 */}
              <MyExportButton />
              {/* <BtnBulkExport></BtnBulkExport> */}
            </>}
@@ -166,8 +166,8 @@
          <NumberField source="poId" label="table.field.asnOrder.poId" />
          <TextField source="type$" label="table.field.asnOrder.type" />
          <TextField cellClassName="wkType" source="wkType$" label="table.field.asnOrder.wkType" />
          <NumberField source="anfme" label="table.field.asnOrder.anfme" options={{ maximumFractionDigits: 6 }} />
          <NumberField source="qty" label="table.field.asnOrder.qty" options={{ maximumFractionDigits: 6 }} />
          <NumberField source="anfme" label="table.field.asnOrder.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
          <NumberField source="qty" label="table.field.asnOrder.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
          <DateField source="arrTime" label="table.field.asnOrder.arrTime" showTime />
          <TextField source="rleStatus$" label="table.field.asnOrder.rleStatus" sortable={false} />
          <TextField source="logisNo" label="table.field.asnOrder.logisNo" />
@@ -180,7 +180,7 @@
          <WrapperField cellClassName="opt" label="common.field.opt" >
            <EditButton label="toolbar.detail"></EditButton>
            <MyButton setCreateDialog={setCreateDialog} setmodalType={setmodalType} />
            <InspectionButton />
            {/* <InspectionButton /> 报检按钮暂不使用 */}
            <CompleteButton />
            <ODeleteButton />
            <PrintButton setPrintOrder={setPrintOrder} setSelect={setSelect} />
rsf-admin/src/page/orders/asnOrder/AsnOrderModal.jsx
@@ -544,14 +544,15 @@
            ),
            headerClassName: "custom",
        },
        {
            field: 'platItemId',
            headerName: translate('table.field.asnOrderItem.platItemId') + "*",
            minWidth: 100,
            flex: 1,
            editable: true,
            headerClassName: "custom",
        },
        // 现品票号已注释
        // {
        //     field: 'platItemId',
        //     headerName: translate('table.field.asnOrderItem.platItemId') + "*",
        //     minWidth: 100,
        //     flex: 1,
        //     editable: true,
        //     headerClassName: "custom",
        // },
        {
            field: 'splrBatch',
            headerName: translate('table.field.asnOrderItem.splrBatch'),
rsf-admin/src/page/orders/asnOrder/AsnOrderPanel.jsx
@@ -116,10 +116,7 @@
            field: 'prodTime',
            headerName: translate('table.field.asnOrderItem.prodTime')
        },
        {
            field: 'packName',
            headerName: translate('table.field.asnOrderItem.packName')
        },
        // { field: 'packName', headerName: translate('table.field.asnOrderItem.packName') }, // 包装已注释
        {
            field: 'action',
            headerName: '操作',
rsf-admin/src/page/orders/asnOrder/OrderPrintPreview.jsx
@@ -143,11 +143,11 @@
            <Grid container spacing={2} sx={{ justifyContent: 'space-between', }}>
                <Grid item md={2}>
                    <Box sx={{ display: 'flex', justifyContent: 'start' }}>
                        <Typography>ASN单:</Typography>
                        <Typography>单号:</Typography>
                        <Typography>{record?.code}</Typography>
                    </Box>
                    <Box sx={{ display: 'flex', justifyContent: 'start' }}>
                        <Typography>PO单:</Typography>
                        <Typography>单据内码:</Typography>
                        <Typography>{record?.poCode}</Typography>
                    </Box>
                    <Box sx={{ display: 'flex', justifyContent: 'start' }}>
@@ -203,18 +203,18 @@
                <TextField source="orderCode" label="table.field.asnOrderItem.orderCode" />,
                <TextField source="poDetlId" label="table.field.asnOrderItem.poDetlId" />,
                <TextField source="poDetlCode" label="table.field.asnOrderItem.poDetlCode" />,
                <TextField source="platItemId" label="table.field.asnOrderItem.platItemId" />,
                // <TextField source="platItemId" label="table.field.asnOrderItem.platItemId" />, // 现品票号已注释
                <TextField source="matnrId" label="table.field.asnOrderItem.matnrId" />,
                <TextField source="matnrCode" label="table.field.asnOrderItem.matnrCode" />,
                <TextField source="maktx" label="table.field.asnOrderItem.maktx" />,
                <TextField source="splrBatch" label="table.field.asnOrderItem.splrBatch" />,
                <NumberField source="anfme" label="table.field.asnOrderItem.anfme" options={{ maximumFractionDigits: 6 }} />,
                <NumberField source="qty" label="table.field.asnOrderItem.qty" options={{ maximumFractionDigits: 6 }} />,
                <NumberField source="purQty" label="table.field.asnOrderItem.purQty" options={{ maximumFractionDigits: 6 }} />,
                <NumberField source="anfme" label="table.field.asnOrderItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <NumberField source="qty" label="table.field.asnOrderItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <NumberField source="purQty" label="table.field.asnOrderItem.purQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                // <TextField source="splrName" label="table.field.asnOrderItem.splrName" />,
                <TextField source="isptResult$" label="table.field.asnOrderItem.isptResult" />,
                // <TextField source="isptResult$" label="table.field.asnOrderItem.isptResult" />, // 质检已注释
                // <TextField source="trackCode" label="table.field.asnOrderItem.barcode" />,
                <TextField source="packName" label="table.field.asnOrderItem.packName" />,
                // <TextField source="packName" label="table.field.asnOrderItem.packName" />, // 包装已注释
            ]
            const fields = data.map(el => <TextField key={el.fields} source={`extendFields.[${el.fields}]`} label={el.fieldsAlise} />)
            const lastArr = [
rsf-admin/src/page/orders/asnOrder/POItemModal.jsx
@@ -263,14 +263,15 @@
            ),
            headerClassName: "custom",
        },
        {
            field: 'platItemId',
            headerName: translate('table.field.asnOrderItem.platItemId') + "*",
            minWidth: 100,
            flex: 1,
            editable: true,
            headerClassName: "custom",
        },
        // 现品票号已注释
        // {
        //     field: 'platItemId',
        //     headerName: translate('table.field.asnOrderItem.platItemId') + "*",
        //     minWidth: 100,
        //     flex: 1,
        //     editable: true,
        //     headerClassName: "custom",
        // },
        {
            field: 'anfme',
            headerName: translate('table.field.asnOrderItem.anfme') + "*",
rsf-admin/src/page/orders/check/CheckOrderItemList.jsx
@@ -135,9 +135,9 @@
            <TextField source="matnrCode" label="table.field.checkOrderItem.matnrCode" />
            <TextField source="maktx" label="table.field.checkOrderItem.maktx" />
            <TextField source="platOrderCode" label="table.field.checkOrderItem.platOrderCode" />
            <NumberField source="anfme" label="table.field.checkOrderItem.anfme" />
            <NumberField source="workQty" label="table.field.checkOrderItem.workQty" />
            <NumberField source="qty" label="table.field.checkOrderItem.qty" />
            <NumberField source="anfme" label="table.field.checkOrderItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
            <NumberField source="workQty" label="table.field.checkOrderItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
            <NumberField source="qty" label="table.field.checkOrderItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
            <TextField source="stockUnit" label="table.field.checkOrderItem.stockUnit" />
            <TextField source="splrBatch" label="table.field.checkOrderItem.splrBatch" />
            <TextField source="splrCode" label="table.field.checkOrderItem.splrCode" />
rsf-admin/src/page/orders/check/CheckOrderList.jsx
@@ -151,9 +151,9 @@
          {/* <TextField source="type$" label="table.field.checkOrder.type" /> */}
          <TextField cellClassName="wkType" source="wkType$" label="table.field.checkOrder.type" />
          <TextField  source="checkType$" label="table.field.checkOrder.checkType" />
          <NumberField source="anfme" label="table.field.checkOrder.anfme" />
          <NumberField source="workQty" label="table.field.checkOrder.workQty" />
          <NumberField source="qty" label="table.field.checkOrder.qty" />
          <NumberField source="anfme" label="table.field.checkOrder.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
          <NumberField source="workQty" label="table.field.checkOrder.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
          <NumberField source="qty" label="table.field.checkOrder.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
          <DateField source="arrTime" label="table.field.checkOrder.arrTime" />
          <TextField source="updateBy$" label="common.field.updateBy" />
          <DateField source="updateTime" label="common.field.updateTime" showTime />
rsf-admin/src/page/orders/check/CheckOrderModal.jsx
@@ -234,8 +234,8 @@
                                    <TextField source="matnrCode" label="table.field.deliveryItem.matnrCode" />
                                    <TextField source="maktx" label="table.field.deliveryItem.matnrName" />
                                    <TextField source="unit" label="table.field.deliveryItem.unit" />
                                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" />
                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" />
                                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <TextField source="splrName" label="table.field.deliveryItem.splrName" />
                                    <TextField source="splrBatch" label="table.field.deliveryItem.splrBatch" />
                                    <TextField source="updateBy$" label="common.field.updateBy" />
rsf-admin/src/page/orders/check/CheckOrderPub.jsx
@@ -201,9 +201,9 @@
                                    <TextField source="orderCode" label="table.field.checkOrderItem.orderCode" />
                                    <TextField source="matnrCode" label="table.field.checkOrderItem.matnrCode" />
                                    <TextField source="maktx" label="table.field.checkOrderItem.maktx" />
                                    <NumberField source="anfme" label="table.field.checkOrderItem.anfme" />
                                    <NumberField source="workQty" label="table.field.checkOrderItem.workQty" />
                                    <NumberField source="qty" label="table.field.checkOrderItem.qty" />
                                    <NumberField source="anfme" label="table.field.checkOrderItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <NumberField source="workQty" label="table.field.checkOrderItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <NumberField source="qty" label="table.field.checkOrderItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <TextField source="stockUnit" label="table.field.checkOrderItem.stockUnit" />
                                    <TextField source="splrName" label="table.field.checkOrderItem.splrName" />
                                </StyledDatagrid>
rsf-admin/src/page/orders/check/CheckPreviewTable.jsx
@@ -36,7 +36,7 @@
    const baseColumns = [
        { field: 'locCode', headerName: '库位', width: 110 },
        { field: 'barcode', headerName: '容器', width: 120 },
        { field: 'barcode', headerName: '料箱码', width: 120 },
        { field: 'matnrCode', headerName: '物料编码', width: 120 },
        { field: 'batch', headerName: '批次', width: 90 },
        { field: 'unit', headerName: '单位', width: 60 },
rsf-admin/src/page/orders/check/checkDiff/CheckDiffList.jsx
@@ -133,7 +133,7 @@
                    <TextField source="checkType$" label="table.field.checkDiff.checkType" sortable={false} />
                    <NumberField source="areaId" label="table.field.checkDiff.areaId" />
                    <TextField source="areaName" label="table.field.checkDiff.areaName" />
                    <NumberField source="anfme" label="table.field.checkDiff.anfme" />
                    <NumberField source="anfme" label="table.field.checkDiff.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="checkQty" label="table.field.checkDiff.checkQty" />
                    {/* <NumberField source="exceStatus" label="table.field.checkDiff.exceStatus" /> */}
                    <NumberField source="updateBy$" label="common.field.updateBy" />
rsf-admin/src/page/orders/check/checkDiffItem/CheckDiffItemList.jsx
@@ -144,7 +144,7 @@
                    <TextField source="model" label="table.field.checkDiffItem.model" />
                    <TextField source="barcode" label="table.field.checkDiffItem.barcode" />
                    <TextField source="batch" label="table.field.checkDiffItem.batch" />
                    <NumberField source="anfme" label="table.field.checkDiffItem.anfme" />
                    <NumberField source="anfme" label="table.field.checkDiffItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="checkQty" label="table.field.checkDiffItem.checkQty" />
                    <CheckDiffField source="diffQty" label="table.field.checkDiffItem.diffQty" />
                    <TextField source="reason" label="table.field.checkDiffItem.reason" />
rsf-admin/src/page/orders/delivery/DeliveryItemCreate.jsx
@@ -96,11 +96,13 @@
                                    />
                                </Grid>
                                <Grid item xs={12} display="flex" gap={1}>
                                    {/* 现品票号已注释
                                    <TextInput
                                        label="table.field.deliveryItem.platItemId"
                                        source="platItemId"
                                        parse={v => v}
                                    />
                                    */}
                                    <TextInput
                                        label="table.field.deliveryItem.matnrCode"
                                        source="matnrCode"
rsf-admin/src/page/orders/delivery/DeliveryItemEdit.jsx
@@ -106,11 +106,13 @@
                                            source="deliveryId"
                                            readOnly
                                        />
                                        {/* 现品票号已注释
                                        <TextInput
                                            label="table.field.deliveryItem.platItemId"
                                            source="platItemId"
                                            parse={v => v}
                                        />
                                        */}
                                    </Stack>
                                    <Stack direction='row' gap={2}>
                                        <TextInput
rsf-admin/src/page/orders/delivery/DeliveryItemList.jsx
@@ -65,7 +65,7 @@
    <SearchInput source="condition" alwaysOn />,
    <DateInput label='common.time.after' source="timeStart" />,
    <DateInput label='common.time.before' source="timeEnd" />,
    <TextInput source="platItemId" label="table.field.deliveryItem.platItemId" />,
    // 现品票号已注释 <TextInput source="platItemId" label="table.field.deliveryItem.platItemId" />,
    <TextInput source="matnrCode" label="table.field.deliveryItem.matnrCode" />,
    <TextInput source="matnrName" label="table.field.deliveryItem.matnrName" />,
    <TextInput source="splrName" label="table.field.deliveryItem.splrName" />,
@@ -131,13 +131,13 @@
                >
                    <NumberField source="id" />
                    <NumberField source="deliveryId" label="table.field.deliveryItem.deliveryId" />
                    <TextField source="platItemId" label="table.field.deliveryItem.platItemId" />
                    {/* 现品票号已注释 <TextField source="platItemId" label="table.field.deliveryItem.platItemId" /> */}
                    <TextField source="matnrCode" label="table.field.deliveryItem.matnrCode" />
                    <TextField source="maktx" label="table.field.deliveryItem.matnrName" />
                    <TextField source="fieldsIndex" label="table.field.deliveryItem.fieldsIndex" />
                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" />
                    <NumberField source="workQty" label="table.field.deliveryItem.workQty" />
                    <NumberField source="qty" label="table.field.deliveryItem.qty" />
                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="workQty" label="table.field.deliveryItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="qty" label="table.field.deliveryItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="nromQty" label="table.field.deliveryItem.nromQty" />
                    <TextField source="unit" label="table.field.deliveryItem.unit" />
                    <TextField source="splrName" label="table.field.deliveryItem.splrName" />
rsf-admin/src/page/orders/delivery/DeliveryList.jsx
@@ -136,9 +136,9 @@
                    <TextField source="type$" label="table.field.delivery.type" />
                    <TextField source="wkType$" label="table.field.delivery.wkType" />
                    <TextField source="source" label="table.field.delivery.source" />
                    <NumberField source="anfme" label="table.field.delivery.anfme" />
                    <NumberField source="workQty" label="table.field.delivery.workQty" />
                    <NumberField source="qty" label="table.field.delivery.qty" />
                    <NumberField source="anfme" label="table.field.delivery.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="workQty" label="table.field.delivery.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="qty" label="table.field.delivery.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="platCode" label="table.field.delivery.platCode" />
                    <DateField source="startTime" label="table.field.delivery.startTime" showTime />
                    <DateField source="endTime" label="table.field.delivery.endTime" showTime />
rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx
@@ -181,10 +181,10 @@
        <TextField source="matnrCode" label="table.field.outStockItem.matnrCode" />,
        <TextField source="maktx" label="table.field.outStockItem.maktx" />,
        <TextField source="platOrderCode" label="table.field.outStockItem.platOrderCode" />,
        <NumberField source="anfme" label="table.field.outStockItem.anfme" options={{ maximumFractionDigits: 6 }} />,
        <NumberField source="purQty" label="table.field.outStockItem.purQty" options={{ maximumFractionDigits: 6 }} />,
        <NumberField source="workQty" label="table.field.outStockItem.workQty" options={{ maximumFractionDigits: 6 }} />,
        <NumberField source="qty" label="table.field.outStockItem.qty" options={{ maximumFractionDigits: 6 }} />,
        <NumberField source="anfme" label="table.field.outStockItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
        <NumberField source="purQty" label="table.field.outStockItem.purQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
        <NumberField source="workQty" label="table.field.outStockItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
        <NumberField source="qty" label="table.field.outStockItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
        <TextField source="stockUnit" label="table.field.outStockItem.stockUnit" />,
        <TextField source="splrBatch" label="table.field.outStockItem.splrBatch" />,
        <TextField source="purUnit" label="table.field.outStockItem.purUnit" />,
rsf-admin/src/page/orders/outStock/OutOrderList.jsx
@@ -195,8 +195,8 @@
        actions={(
          <TopToolbar>
            <FilterButton />
            <CreateByOrderButton setCreateDialog={setCreateDialog} />
            <MyCreateButton onClick={() => { setManualDialog(true); setmodalType(0) }} />
            {/* <CreateByOrderButton setCreateDialog={setCreateDialog} /> 通过单据创建暂不使用 */}
            {/* <MyCreateButton onClick={() => { setManualDialog(true); setmodalType(0) }} /> 添加按钮暂不使用 */}
            <SelectColumnsButton preferenceKey='outStock' />
            <ImportButton value={'outStockItem'} />
          </TopToolbar>
@@ -216,9 +216,9 @@
          <TextField source="poCode" label="table.field.outStock.poCode" />
          <TextField source="type$" label="table.field.outStock.type" />
          <TextField cellClassName="wkType" source="wkType$" label="table.field.outStock.wkType" />
          <NumberField source="anfme" label="table.field.outStock.anfme" options={{ maximumFractionDigits: 6 }} />
          <NumberField source="workQty" label="table.field.outStock.workQty" options={{ maximumFractionDigits: 6 }} />
          <NumberField source="qty" label="table.field.outStock.qty" options={{ maximumFractionDigits: 6 }} />
          <NumberField source="anfme" label="table.field.outStock.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
          <NumberField source="workQty" label="table.field.outStock.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
          <NumberField source="qty" label="table.field.outStock.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
          <TextField source="logisNo" label="table.field.outStock.logisNo" />
          <TextField source="rleStatus$" label="table.field.outStock.rleStatus" sortable={false} />
          <TextField source="updateBy$" label="common.field.updateBy" />
@@ -317,7 +317,7 @@
  )
}
/** 出库单执行状态:10=初始化(仅此状态显示编辑/详情) */
/** 出库单执行状态:10=初始化(仅此状态显示编辑);详情任意状态可查看 */
const OUT_STOCK_EXCE_STATUS_INIT = 10;
const OutOrderRowActions = ({ setCreateDialog, setmodalType, setDrawerVal, drawerVal, setSelect }) => {
@@ -325,12 +325,8 @@
  const isInit = record?.exceStatus === OUT_STOCK_EXCE_STATUS_INIT || record?.exceStatus === '10';
  return (
    <>
      {isInit && (
        <>
          <MyButton setCreateDialog={setCreateDialog} setmodalType={setmodalType} />
      {isInit && <MyButton setCreateDialog={setCreateDialog} setmodalType={setmodalType} />}
          <EditButton label="toolbar.detail" icon={(<DetailsIcon />)} />
        </>
      )}
      <PublicButton setDrawerVal={setDrawerVal} drawerVal={drawerVal} setSelect={setSelect} />
    </>
  );
rsf-admin/src/page/orders/outStock/OutOrderModal.jsx
@@ -270,8 +270,8 @@
                                    <TextField source="matnrCode" label="table.field.deliveryItem.matnrCode" />
                                    <TextField source="maktx" label="table.field.deliveryItem.matnrName" />
                                    <TextField source="unit" label="table.field.deliveryItem.unit" />
                                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" options={{ maximumFractionDigits: 6 }} />
                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" options={{ maximumFractionDigits: 6 }} />
                                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <TextField source="splrName" label="table.field.deliveryItem.splrName" />
                                    <TextField source="splrBatch" label="table.field.deliveryItem.splrBatch" />
                                    <TextField source="updateBy$" label="common.field.updateBy" />
rsf-admin/src/page/orders/outStock/OutStockPublic.jsx
@@ -338,9 +338,9 @@
                                    <TextField source="poCode" label="table.field.outStockItem.poCode" />
                                    <TextField source="matnrCode" label="table.field.outStockItem.matnrCode" />
                                    <TextField source="maktx" label="table.field.outStockItem.maktx" />
                                    <NumberField source="anfme" label="table.field.outStockItem.anfme" options={{ maximumFractionDigits: 6 }} />
                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" options={{ maximumFractionDigits: 6 }} />
                                    <NumberField source="qty" label="table.field.outStockItem.qty" options={{ maximumFractionDigits: 6 }} />
                                    <NumberField source="anfme" label="table.field.outStockItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <NumberField source="qty" label="table.field.outStockItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                                    <TextField source="stockUnit" label="table.field.outStockItem.stockUnit" />
                                    <TextField source="splrName" label="table.field.outStockItem.splrName" />
                                </StyledDatagrid>
@@ -393,7 +393,7 @@
    const baseColumns = [
        // { field: 'id', headerName: 'ID', width: 40 },
        { field: 'locCode', headerName: '库位', width: 110 },
        { field: 'barcode', headerName: '容器', width: 120 },
        { field: 'barcode', headerName: '料箱码', width: 120 },
        { field: 'matnrCode', headerName: '物料编码', width: 120 },
        { field: 'batch', headerName: '批次', width: 90 },
        { field: 'unit', headerName: '单位', width: 60 },
rsf-admin/src/page/orders/purchase/PurchaseItemCreate.jsx
@@ -92,6 +92,7 @@
                                        defaultValue={row.poId}
                                    />
                                </Grid>
                                {/* 现品票号已注释
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.purchaseItem.platItemId"
@@ -99,6 +100,7 @@
                                        parse={v => v}
                                    />
                                </Grid>
                                */}
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.purchaseItem.matnrCode"
rsf-admin/src/page/orders/purchase/PurchaseItemEdit.jsx
@@ -101,11 +101,13 @@
                                            source="purchaseId"
                                            defaultValue={record?.id}
                                        />
                                        {/* 现品票号已注释
                                        <TextInput
                                            label="table.field.purchaseItem.platItemId"
                                            source="platItemId"
                                            parse={v => v}
                                        />
                                        */}
                                        <TextInput
                                            label="table.field.purchaseItem.matnrCode"
                                            source="matnrCode"
rsf-admin/src/page/orders/purchase/PurchaseItemList.jsx
@@ -54,7 +54,7 @@
const filters = [
  <SearchInput source="condition" alwaysOn />,
  <NumberInput source="purchaseId" label="table.field.purchaseItem.purchaseId" />,
  <TextInput source="platItemId" label="table.field.purchaseItem.platItemId" />,
  // 现品票号已注释 <TextInput source="platItemId" label="table.field.purchaseItem.platItemId" />,
  <TextInput source="matnrCode" label="table.field.purchaseItem.matnrCode" />,
  <TextInput source="matnrName" label="table.field.purchaseItem.matnrName" />,
  <TextInput source="unit" label="table.field.purchaseItem.unit" />,
@@ -129,12 +129,12 @@
          >
            <NumberField source="id" />
            <NumberField source="purchaseId" label="table.field.purchaseItem.purchaseId" />
            <TextField source="platItemId" label="table.field.purchaseItem.platItemId" />
            {/* 现品票号已注释 <TextField source="platItemId" label="table.field.purchaseItem.platItemId" /> */}
            <TextField source="matnrCode" label="table.field.purchaseItem.matnrCode" />
            <TextField source="matnrName" label="table.field.purchaseItem.matnrName" />
            <TextField source="unit" label="table.field.purchaseItem.unit" />
            <NumberField source="anfme" label="table.field.purchaseItem.anfme" />
            <NumberField source="qty" label="table.field.purchaseItem.qty" />
            <NumberField source="anfme" label="table.field.purchaseItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
            <NumberField source="qty" label="table.field.purchaseItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
            <NumberField source="nromQty" label="table.field.purchaseItem.nromQty" />
            <NumberField source="asnQty" label="table.field.purchaseItem.asnQty" />
            <NumberField source="printQty" label="table.field.purchaseItem.printQty" />
rsf-admin/src/page/orders/purchase/PurchaseList.jsx
@@ -139,8 +139,8 @@
          <TextField source="type$" label="table.field.purchase.type" />
          <TextField source="wkType$" label="table.field.purchase.wkType" />
          <TextField source="source" label="table.field.purchase.source" />
          <NumberField source="anfme" label="table.field.purchase.anfme" />
          <NumberField source="qty" label="table.field.purchase.qty" />
          <NumberField source="anfme" label="table.field.purchase.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
          <NumberField source="qty" label="table.field.purchase.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
          {/* <NumberField source="workQty" label="table.field.purchase.workQty" /> */}
          <TextField source="channel" label="table.field.purchase.channel" />
          <TextField source="platCode" label="table.field.purchase.platCode" />
rsf-admin/src/page/orders/purchase/PurchasePanel.jsx
@@ -58,11 +58,12 @@
            label: 'table.field.purchaseItem.purchaseId',
            minWidth: 100
        },
        {
            id: 'platItemId',
            label: 'table.field.purchaseItem.platItemId',
            minWidth: 100
        },
        // 现品票号已注释
        // {
        //     id: 'platItemId',
        //     label: 'table.field.purchaseItem.platItemId',
        //     minWidth: 100
        // },
        {
            id: 'matnrCode',
            label: 'table.field.purchaseItem.matnrCode',
rsf-admin/src/page/orders/qlyInspect/QlyIsptItemResult.jsx
@@ -117,7 +117,7 @@
                        <TextField source="label" label="table.field.qlyIsptItem.label" />
                        <TextField source="splrBatch" label="table.field.qlyIsptItem.splrBatch" />
                        <NumberField source="dlyQty" label="table.field.qlyIsptItem.dlyQty" />
                        <NumberField source="anfme" label="table.field.qlyIsptItem.anfme" />
                        <NumberField source="anfme" label="table.field.qlyIsptItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                        <TextField source="splrName" label="table.field.qlyIsptItem.splrName" />
                        <NumberField source="isptResult$" label="table.field.qlyIsptItem.isptResult" />
                    </StyledDatagrid>
rsf-admin/src/page/orders/stock/OrderItemList.jsx
@@ -165,14 +165,14 @@
                <TextField source="matnrId" label="table.field.stockItem.matnrId" />,
                <TextField source="matnrCode" label="table.field.stockItem.matnrCode" />,
                <TextField source="maktx" label="table.field.stockItem.maktx" />,
                <NumberField source="anfme" label="table.field.stockItem.anfme" />,
                <NumberField source="anfme" label="table.field.stockItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="stockUnit" label="table.field.stockItem.stockUnit" />,
                <NumberField source="workQty" label="table.field.stockItem.workQty" />,
                <NumberField source="workQty" label="table.field.stockItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="locCode" label="table.field.loc.code" />,
                <TextField source="barcode" label="table.field.task.barcode" />,
                <NumberField source="purQty" label="table.field.stockItem.purQty" />,
                <NumberField source="purQty" label="table.field.stockItem.purQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="purUnit" label="table.field.stockItem.purUnit" />,
                <NumberField source="qty" label="table.field.stockItem.qty" />,
                <NumberField source="qty" label="table.field.stockItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="splrCode" label="table.field.stockItem.splrCode" />,
                <TextField source="batch" label="table.field.stockItem.batch" />,
                <TextField source="splrBatch" label="table.field.stockItem.splrBatch" />,
rsf-admin/src/page/orders/stock/OrderList.jsx
@@ -126,7 +126,7 @@
                    <TextField source="barcode" label="table.field.task.barcode" />,
                    <TextField source="type$" label="table.field.stock.type" />
                    <TextField source="wkType$" label="table.field.stock.wkType" />
                    <NumberField source="anfme" label="table.field.stock.anfme" />
                    <NumberField source="anfme" label="table.field.stock.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="updateBy$" label="common.field.updateBy" />
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
                    <TextField source="createBy$" label="common.field.createBy" />
rsf-admin/src/page/orders/transfer/TransferItemList.jsx
@@ -74,7 +74,7 @@
    <TextInput source="spec" label="table.field.transferItem.spec" />,
    <TextInput source="model" label="table.field.transferItem.model" />,
    <TextInput source="fieldsIndex" label="table.field.transferItem.fieldsIndex" />,
    <TextInput source="platItemId" label="table.field.transferItem.platItemId" />,
    // 现品票号已注释 <TextInput source="platItemId" label="table.field.transferItem.platItemId" />,
    <TextInput source="platOrderCode" label="table.field.transferItem.platOrderCode" />,
    <TextInput source="platWorkCode" label="table.field.transferItem.platWorkCode" />,
    <TextInput source="projectCode" label="table.field.transferItem.projectCode" />,
@@ -138,12 +138,12 @@
                    <TextField source="model" label="table.field.transferItem.model" />
                    <TextField source="batch" label="table.field.transferItem.batch" />
                    <TextField source="unit" label="table.field.transferItem.unit" />
                    <NumberField source="anfme" label="table.field.transferItem.anfme" />
                    <NumberField source="workQty" label="table.field.transferItem.workQty" />
                    <NumberField source="qty" label="table.field.transferItem.qty" />
                    <NumberField source="anfme" label="table.field.transferItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="workQty" label="table.field.transferItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="qty" label="table.field.transferItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="splrId" label="table.field.transferItem.splrId" />
                    <TextField source="fieldsIndex" label="table.field.transferItem.fieldsIndex" />
                    <TextField source="platItemId" label="table.field.transferItem.platItemId" />
                    {/* 现品票号已注释 <TextField source="platItemId" label="table.field.transferItem.platItemId" /> */}
                    <TextField source="platOrderCode" label="table.field.transferItem.platOrderCode" />
                    <TextField source="platWorkCode" label="table.field.transferItem.platWorkCode" />
                    <TextField source="projectCode" label="table.field.transferItem.projectCode" />
rsf-admin/src/page/orders/transfer/TransferOrders.jsx
@@ -85,9 +85,9 @@
                        <TextField source="poCode" label="table.field.transferOrder.poCode" />
                        <TextField source="type$" label="table.field.transferOrder.type" />
                        <TextField cellClassName="wkType" source="wkType$" label="table.field.transferOrder.wkType" />
                        <NumberField source="anfme" label="table.field.transferOrder.anfme" />
                        <NumberField source="workQty" label="table.field.transferOrder.workQty" />
                        <NumberField source="qty" label="table.field.transferOrder.qty" />
                        <NumberField source="anfme" label="table.field.transferOrder.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                        <NumberField source="workQty" label="table.field.transferOrder.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                        <NumberField source="qty" label="table.field.transferOrder.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                        <TextField source="createBy$" label="common.field.createBy" />
                        <TextField source="updateBy$" label="common.field.updateBy" />
                        <DateField source="createTime" label="common.field.createTime" showTime />
rsf-admin/src/page/orders/wave/ItemToTaskModal.jsx
@@ -138,9 +138,9 @@
                            <TextField source="unit" label="table.field.waveItem.unit" />
                            <TextField source="trackCode" label="table.field.waveItem.trackCode" />
                            <TextField source="fieldsIndex" label="table.field.waveItem.fieldsIndex" />
                            <NumberField source="anfme" label="table.field.waveItem.anfme" />
                            <NumberField source="workQty" label="table.field.waveItem.workQty" />
                            <NumberField source="qty" label="table.field.waveItem.qty" />
                            <NumberField source="anfme" label="table.field.waveItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                            <NumberField source="workQty" label="table.field.waveItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                            <NumberField source="qty" label="table.field.waveItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                            <NumberField source="stockQty" label="table.field.waveItem.stockQty" />
                            <WrapperField cellClassName="opt" label="table.field.waveItem.stockLocs">
                                <TagsField />
rsf-admin/src/page/orders/wave/WaveItemList.jsx
@@ -124,9 +124,9 @@
                    <TextField source="maktx" label="table.field.waveItem.matnrName" />
                    <TextField source="batch" label="table.field.waveItem.batch" />
                    <TextField source="splrBatch" label="table.field.waveItem.splrBatch" />
                    <NumberField source="anfme" label="table.field.waveItem.anfme" />
                    <NumberField source="anfme" label="table.field.waveItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="fieldsIndex" label="table.field.waveItem.fieldsIndex" />
                    <NumberField source="workQty" label="table.field.waveItem.workQty" />
                    <NumberField source="workQty" label="table.field.waveItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="unit" label="table.field.waveItem.unit" />
                    <TextField source="updateBy$" label="common.field.updateBy" />
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
rsf-admin/src/page/orders/wave/WaveList.jsx
@@ -157,9 +157,9 @@
                    <NumberField source="id" />
                    <TextField source="code" label="table.field.wave.code" />
                    <TextField source="type$" label="table.field.wave.type" sortable={false} />
                    <NumberField source="anfme" label="table.field.wave.anfme" />
                    <NumberField source="anfme" label="table.field.wave.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="groupQty" label="table.field.wave.groupQty" />
                    <NumberField source="workQty" label="table.field.wave.qty" />
                    <NumberField source="workQty" label="table.field.wave.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="orderNum" label="table.field.wave.orderNum" />
                    <DateField source="createTime" label="common.field.createTime" showTime />
                    <TextField source="updateBy$" label="common.field.updateBy" />
rsf-admin/src/page/orders/wave/WavePanel.jsx
@@ -78,7 +78,7 @@
                        <TextField source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />
                        <TextField source="spec" label="table.field.asnOrderItem.spec" />
                        <TextField source="model" label="table.field.asnOrderItem.model" />
                        <NumberField source="anfme" label="table.field.asnOrderItem.anfme" />
                        <NumberField source="anfme" label="table.field.asnOrderItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                        <TextField source="stockUnit" label="table.field.asnOrderItem.stockUnit" />
                        <TextField source="splrName" label="table.field.asnOrderItem.splrName" />
                    </StyledDatagrid>
rsf-admin/src/page/statistics/deadTime/LocItemDeadList.jsx
@@ -139,7 +139,7 @@
                    <NumberField source="matnrId" label="table.field.locItem.matnrId" />
                    <TextField source="matnrCode" label="table.field.locItem.matnrCode" />
                    <TextField source="maktx" label="table.field.locItem.maktx" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="batch" label="table.field.locItem.batch" />
                    <TextField source="trackCode" label="table.field.locItem.trackCode" />
                    <TextField source="unit" label="table.field.locItem.unit" />
rsf-admin/src/page/statistics/inStockItem/InStockItemList.jsx
@@ -128,7 +128,7 @@
                    <TextField source="locCode" label="table.field.stockStatistic.locCode" />
                    <TextField source="matnrCode" label="table.field.locItem.matnrCode" />
                    <TextField source="maktx" label="table.field.locItem.maktx" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="batch" label="table.field.locItem.batch" />
                    <TextField source="unit" label="table.field.locItem.unit" />
                    <TextField source="barcode" label="table.field.stockStatistic.barcode" />
rsf-admin/src/page/statistics/inStockNum/InStockNumList.jsx
@@ -128,7 +128,7 @@
                    <TextField source="dayTime" label="table.field.stockStatistic.dayTime" />
                    <TextField source="matnrCode" label="table.field.locItem.matnrCode" />
                    <TextField source="maktx" label="table.field.locItem.maktx" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="batch" label="table.field.locItem.batch" />
                    <TextField source="unit" label="table.field.locItem.unit" />
                </StyledDatagrid>
rsf-admin/src/page/statistics/outStockItem/OutStockItemList.jsx
@@ -128,7 +128,7 @@
                    <TextField source="locCode" label="table.field.stockStatistic.locCode" />
                    <TextField source="matnrCode" label="table.field.locItem.matnrCode" />
                    <TextField source="maktx" label="table.field.locItem.maktx" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="batch" label="table.field.locItem.batch" />
                    <TextField source="unit" label="table.field.locItem.unit" />
                    <TextField source="barcode" label="table.field.stockStatistic.barcode" />
rsf-admin/src/page/statistics/outStockNum/OutStockNumList.jsx
@@ -118,7 +118,7 @@
                    <TextField source="dayTime" label="table.field.stockStatistic.dayTime" />
                    <TextField source="matnrCode" label="table.field.locItem.matnrCode" />
                    <TextField source="maktx" label="table.field.locItem.maktx" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="batch" label="table.field.locItem.batch" />
                    <TextField source="unit" label="table.field.locItem.unit" />
                </StyledDatagrid>
rsf-admin/src/page/statistics/stockManage/WarehouseHistories.jsx
@@ -207,10 +207,10 @@
                <TextField source="matnrId" label="table.field.stockItem.matnrId" />,
                <TextField source="matnrCode" label="table.field.stockItem.matnrCode" />,
                <TextField source="maktx" label="table.field.stockItem.maktx" />,
                <NumberField source="anfme" label="table.field.stockItem.anfme" />,
                <NumberField source="anfme" label="table.field.stockItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="stockUnit" label="table.field.stockItem.stockUnit" />,
                <NumberField source="workQty" label="table.field.stockItem.workQty" />,
                <NumberField source="qty" label="table.field.stockItem.qty" />,
                <NumberField source="workQty" label="table.field.stockItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <NumberField source="qty" label="table.field.stockItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="splrCode" label="table.field.stockItem.splrCode" />,
                <TextField source="batch" label="table.field.stockItem.batch" />,
                <TextField source="splrBatch" label="table.field.stockItem.splrBatch" />,
rsf-admin/src/page/statistics/stockManage/WarehouseStockList.jsx
@@ -174,8 +174,8 @@
                <NumberField source="matnrId" label="table.field.warehouseStock.matnrId" />,
                <TextField source="matnrCode" label="table.field.warehouseStock.matnrCode" />,
                <TextField source="maktx" label="table.field.warehouseStock.maktx" />,
                <NumberField source="anfme" label="table.field.warehouseStock.anfme" />,
                <NumberField source="workQty" label="table.field.warehouseStock.qty" />,
                <NumberField source="anfme" label="table.field.warehouseStock.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <NumberField source="workQty" label="table.field.warehouseStock.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="spec" label="table.field.warehouseStock.spec" />,
                <TextField source="model" label="table.field.warehouseStock.model" />,
                <TextField source="warehouse$" label="table.field.warehouseStock.warehouse" />,
rsf-admin/src/page/statistics/stockStatisticNum/stockStatisticList.jsx
@@ -110,7 +110,7 @@
                    <NumberField source="count" label="table.field.stockStatistic.count" />
                    <TextField source="inAnfmeCount" label="table.field.stockStatistic.inAnfmeCount" />
                    <TextField source="outAnfmeCount" label="table.field.stockStatistic.outAnfmeCount" />
                    <NumberField source="anfme" label="table.field.stockStatistic.anfme" />
                    <NumberField source="anfme" label="table.field.stockStatistic.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="inAnfme" label="table.field.stockStatistic.inAnfme" />
                    <TextField source="outAnfme" label="table.field.stockStatistic.outAnfme" />
                </StyledDatagrid>
rsf-admin/src/page/stockItem/StockItemList.jsx
@@ -142,12 +142,12 @@
                    <NumberField source="matnrId" label="table.field.stockItem.matnrId" />
                    <TextField source="matnrCode" label="table.field.stockItem.matnrCode" />
                    <TextField source="maktx" label="table.field.stockItem.maktx" />
                    <NumberField source="anfme" label="table.field.stockItem.anfme" />
                    <NumberField source="anfme" label="table.field.stockItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="stockUnit" label="table.field.stockItem.stockUnit" />
                    <NumberField source="workQty" label="table.field.stockItem.workQty" />
                    <NumberField source="purQty" label="table.field.stockItem.purQty" />
                    <NumberField source="workQty" label="table.field.stockItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="purQty" label="table.field.stockItem.purQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="purUnit" label="table.field.stockItem.purUnit" />
                    <NumberField source="qty" label="table.field.stockItem.qty" />
                    <NumberField source="qty" label="table.field.stockItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="splrCode" label="table.field.stockItem.splrCode" />
                    <TextField source="batch" label="table.field.stockItem.batch" />
                    <TextField source="splrBatch" label="table.field.stockItem.splrBatch" />
rsf-admin/src/page/stockManage/locRevise/ReviseLogItemList.jsx
@@ -95,8 +95,8 @@
                    <TextField source="matnrCode" label="table.field.locItem.matnrCode" />
                    <TextField source="maktx" label="table.field.locItem.maktx" />
                    <TextField source="unit" label="table.field.locItem.unit" />
                    <NumberField source="anfme" label="table.field.locItem.anfme" options={{ maximumFractionDigits: 6 }} />
                    <NumberField source="reviseQty" label="table.field.locItem.reviseQty" options={{ maximumFractionDigits: 6 }} />
                    <NumberField source="anfme" label="table.field.locItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <NumberField source="reviseQty" label="table.field.locItem.reviseQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <CheckDiffField source="diffQty" label="table.field.locItem.diffQty" />
                    <TextField source="batch" label="table.field.locItem.batch" />
                    <TextField source="spec" label="table.field.locItem.spec" />
rsf-admin/src/page/task/TaskItemList.jsx
@@ -153,8 +153,8 @@
                <TextField source="maktx" label="table.field.taskItem.maktx" />,
                <TextField source="matnrCode" label="table.field.taskItem.matnrCode" />,
                <TextField source="unit" label="table.field.taskItem.unit" />,
                <NumberField source="anfme" label="table.field.taskItem.anfme" options={{ maximumFractionDigits: 6 }} />,
                <NumberField source="qty" label="table.field.taskItem.qty" options={{ maximumFractionDigits: 6 }} />,
                <NumberField source="anfme" label="table.field.taskItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <NumberField source="qty" label="table.field.taskItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />,
                <TextField source="platWorkCode" label="table.field.asnOrderItem.platWorkCode" />,
                <TextField source="projectCode" label="table.field.asnOrderItem.projectCode" />,
rsf-admin/src/page/task/TaskPanel.jsx
@@ -70,7 +70,7 @@
                        <TextField source="maktx" label="table.field.taskItem.maktx" />
                        <TextField source="matnrCode" label="table.field.taskItem.matnrCode" />
                        <TextField source="unit" label="table.field.taskItem.unit" />
                        <NumberField source="anfme" label="table.field.taskItem.anfme" options={{ maximumFractionDigits: 6 }} />
                        <NumberField source="anfme" label="table.field.taskItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                        <TextField source="batch" label="table.field.taskItem.batch" />
                        <TextField source="spec" label="table.field.taskItem.spec" />
                        <TextField source="model" label="table.field.taskItem.model" />
rsf-admin/src/page/waitPakin/WaitPakinEdit.jsx
@@ -71,6 +71,12 @@
                                    parse={v => v}
                                    autoFocus
                                />
                                <TextInput
                                    label="table.field.waitPakin.asnCodes"
                                    source="asnCodes"
                                    readOnly
                                    parse={v => v}
                                />
                                <SelectInput
                                    label="table.field.waitPakin.flagDefect"
                                    readOnly
rsf-admin/src/page/waitPakin/WaitPakinItemList.jsx
@@ -67,7 +67,8 @@
    <TextInput source="maktx" label="table.field.waitPakinItem.maktx" />,
    <NumberInput source="matnrId" label="table.field.waitPakinItem.matnrId" />,
    <TextInput source="matnrCode" label="table.field.waitPakinItem.matnrCode" />,
    <TextInput source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />,
    // <TextInput source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />, // 客户单号已注释
    <TextInput source="asnCode" label="table.field.waitPakinItem.asnCode" />,
    <TextInput source="platWorkCode" label="table.field.asnOrderItem.platWorkCode" />,
    <TextInput source="projectCode" label="table.field.asnOrderItem.projectCode" />,
    <NumberInput source="anfme" label="table.field.waitPakinItem.anfme" />,
@@ -161,17 +162,22 @@
                <TextField source="maktx" label="table.field.waitPakinItem.maktx" />,
                <TextField source="batch" label="table.field.waitPakinItem.batch" />,
                <NumberField source="matnrId" label="table.field.waitPakinItem.matnrId" />,
                <NumberField source="anfme" label="table.field.waitPakinItem.anfme" />,
                <NumberField source="anfme" label="table.field.waitPakinItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="unit" label="table.field.waitPakinItem.unit" />,
                <TextField source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />,
                // <TextField source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />, // 客户单号已注释
                <TextField source="asnCode" label="table.field.waitPakinItem.asnCode" />,
                <TextField source="platWorkCode" label="table.field.asnOrderItem.platWorkCode" />,
                <TextField source="projectCode" label="table.field.asnOrderItem.projectCode" />,
                <NumberField source="workQty" label="table.field.waitPakinItem.workQty" />,
                <NumberField source="qty" label="table.field.waitPakinItem.qty" />,
                <NumberField source="workQty" label="table.field.waitPakinItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <NumberField source="qty" label="table.field.waitPakinItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="fieldsIndex" label="table.field.waitPakinItem.fieldsIndex" />,
                <TextField source="isptResult$" label="table.field.waitPakinItem.isptResult" />,
                // <TextField source="isptResult$" label="table.field.waitPakinItem.isptResult" />, // 质检票号已注释
                // <TextField source="platItemId" label="table.field.waitPakinItem.platItemId" />, // 现品票号已注释
            ]
            const fields = data.map(el => <TextField key={el.fields} source={`extendFields.[${el.fields}]`} label={el.fieldsAlise} />)
            // 现品票号已注释:过滤掉 extendFields 中的现品票号(crushNo) 及别名为现品票号的字段
            const fields = data
                .filter(el => el.fields !== 'crushNo' && el.fieldsAlise !== '现品票号')
                .map(el => <TextField key={el.fields} source={`extendFields.[${el.fields}]`} label={el.fieldsAlise} />)
            const lastArr = [
                <TextField source="updateBy$" label="common.field.updateBy" />,
                <DateField source="updateTime" label="common.field.updateTime" showTime />,
@@ -203,7 +209,7 @@
                    preferenceKey='waitPakinItem'
                    bulkActionButtons={false}
                    rowClick={(id, resource, record) => false}
                    omit={['id', 'pakinId', 'createTime', 'matnrId', 'createBy', 'memo', 'fieldsIndex', 'platWorkCode', 'projectCode']}
                    omit={['id', 'pakinId', 'createTime', 'matnrId', 'createBy', 'memo', 'fieldsIndex', 'platWorkCode', 'projectCode', 'platOrderCode', 'isptResult$', 'platItemId']}
                >
                    {columns.map((column) => column)}
                </StyledDatagrid>}
rsf-admin/src/page/waitPakin/WaitPakinList.jsx
@@ -69,6 +69,7 @@
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <TextInput source="asnCode" label="table.field.waitPakin.asnCode" />,
    <TextInput source="code" label="table.field.waitPakin.code" />,
    <TextInput source="barcode" label="table.field.waitPakin.barcode" />,
    <NumberInput source="anfme" label="table.field.waitPakin.anfme" />,
@@ -168,7 +169,7 @@
                    preferenceKey='waitPakin'
                    bulkActionButtons={
                        <>
                            <CreateTaskButton />
                            {/* <CreateTaskButton /> 下发任务按钮暂不使用 */}
                            {/* <BulkDeleteButton mutationMode={OPERATE_MODE} /> */}
                        </>}
                    rowClick={false}
@@ -176,8 +177,9 @@
                >
                    <NumberField source="id" />
                    <TextField source="code" label="table.field.waitPakin.code" />
                    <TextField source="asnCodes" label="table.field.waitPakin.asnCodes" sortable={false} />
                    <TextField source="barcode" label="table.field.waitPakin.barcode" />
                    <NumberField source="anfme" label="table.field.waitPakin.anfme" />
                    <NumberField source="anfme" label="table.field.waitPakin.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                    <TextField source="ioStatus$" label="table.field.waitPakin.ioStatus" sortable={false} />
                    <TextField source="updateBy$" label="common.field.updateBy" />
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
@@ -186,7 +188,7 @@
                    <TextField source="memo" label="common.field.memo" sortable={false} />
                    <WrapperField cellClassName="opt" label="common.field.opt">
                        <EditButton label="toolbar.detail" sx={{ padding: '1px', fontSize: '.75rem' }} />
                        <CreateTaskRowButton />
                        {/* <CreateTaskRowButton /> 下发任务按钮暂不使用 */}
                        <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
                    </WrapperField>
                </StyledDatagrid>
rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx
@@ -186,9 +186,9 @@
                <TextField key="maktx" source="maktx" label="table.field.warehouseAreasItem.matnrName" />,
                <TextField key="matnrCode" source="matnrCode" label="table.field.warehouseAreasItem.matnrCode" />,
                <TextField key="trackCode" source="trackCode" label="table.field.warehouseAreasItem.barcode" />,
                <NumberField key="anfme" source="anfme" label="table.field.warehouseAreasItem.anfme" />,
                <NumberField key="workQty" source="workQty" label="table.field.warehouseAreasItem.workQty" />,
                <NumberField key="qty" source="qty" label="table.field.warehouseAreasItem.qty" />,
                <NumberField key="anfme" source="anfme" label="table.field.warehouseAreasItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <NumberField key="workQty" source="workQty" label="table.field.warehouseAreasItem.workQty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <NumberField key="qty" source="qty" label="table.field.warehouseAreasItem.qty" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />,
                <TextField source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />,
                <TextField source="platWorkCode" label="table.field.asnOrderItem.platWorkCode" />,
                <TextField source="projectCode" label="table.field.asnOrderItem.projectCode" />,
rsf-admin/src/page/warehouseAreasItem/WarehouseIsptResult.jsx
@@ -112,7 +112,7 @@
                        <TextField source="label" label="table.field.qlyIsptItem.label" />
                        <TextField source="splrBatch" label="table.field.qlyIsptItem.splrBatch" />
                        <NumberField source="dlyQty" label="table.field.qlyIsptItem.dlyQty" />
                        <NumberField source="anfme" label="table.field.qlyIsptItem.anfme" />
                        <NumberField source="anfme" label="table.field.qlyIsptItem.anfme" options={{ minimumFractionDigits: 2, maximumFractionDigits: 2 }} />
                        <TextField source="splrName" label="table.field.qlyIsptItem.splrName" />
                        <NumberField source="isptResult$" label="table.field.qlyIsptItem.isptResult" />
                    </StyledDatagrid>
rsf-admin/src/utils/common.js
@@ -1,13 +1,16 @@
/** 库存/数量显示:保留最多6位小数,去掉末尾多余的0(不强制补零) */
/** 前端数量显示:统一保留2位小数(仅展示,后端不变) */
export const formatQuantity = (value) => {
    if (value == null || value === '') return '0';
    if (value == null || value === '') return '0.00';
    const n = Number(value);
    if (Number.isNaN(n)) return '0';
    if (n < 0) return '0';
    return n % 1 === 0 ? String(n) : n.toFixed(6).replace(/\.?0+$/, '');
    if (Number.isNaN(n)) return '0.00';
    if (n < 0) return '0.00';
    return n.toFixed(2);
};
/** 用于 react-admin NumberField 的数量展示 options(2位小数) */
export const QTY_NUMBER_OPTIONS = { minimumFractionDigits: 2, maximumFractionDigits: 2 };
/** 校验最多 N 位小数,用于数量类字段;超过时返回错误信息并阻止提交 */
export const maxDecimalPlaces = (maxDecimals, message) => {
    const factor = Math.pow(10, maxDecimals);
rsf-open-api/src/main/java/com/vincent/rsf/openApi/config/GlobalExceptionHandler.java
@@ -28,10 +28,9 @@
    @ExceptionHandler(Exception.class)
    public ResponseEntity<CommonResponse> handleException(Exception e) {
        log.error("系统异常", e);
        String msg = e.getMessage() != null ? e.getMessage() : "系统异常";
        CommonResponse r = new CommonResponse();
        r.setCode(500);
        r.setMsg(msg);
        r.setMsg("系统异常");
        r.setData(ResultData.fail());
        return ResponseEntity.status(HttpStatus.OK).body(r);
    }
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/dto/OrderDto.java
@@ -17,9 +17,9 @@
    private String orderNo;
    /**
     * PO单号
     * 单据内码
     */
    @ApiModelProperty(value = "PO单号")
    @ApiModelProperty(value = "单据内码")
    private String poCode;
    /**
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ErpOpParams.java
@@ -1,11 +1,17 @@
package com.vincent.rsf.openApi.entity.params;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AccessLevel;
import lombok.Data;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;
/**
@@ -29,11 +35,27 @@
    @ApiModelProperty(value = "业务类型,如:采购入库单、销售出库单、调拨申请单等", required = true)
    private String wkType;
    @ApiModelProperty(value = "业务日期,时间戳精确到秒", required = true)
    private Long businessTime;
    @ApiModelProperty(value = "添加时间,支持 yyyy-MM-dd HH:mm:ss 或时间戳(秒/毫秒)")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Setter(AccessLevel.NONE)
    private Date businessTime;
    @ApiModelProperty(value = "创建日期,时间戳精确到秒", required = true)
    private Long createTime;
    @ApiModelProperty(value = "创建时间,支持 yyyy-MM-dd HH:mm:ss 或时间戳(秒/毫秒)")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Setter(AccessLevel.NONE)
    private Date createTime;
    @JsonDeserialize(using = FlexibleDateDeserializer.class)
    public void setBusinessTime(Date businessTime) {
        this.businessTime = businessTime;
    }
    @JsonDeserialize(using = FlexibleDateDeserializer.class)
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    @ApiModelProperty(value = "订单明细", required = true)
    private List<WmsOrderItemParam> orderItems;
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ExMsgCallbackParams.java
@@ -22,6 +22,6 @@
    @ApiModelProperty("机器人编码")
    private String robotCode;
    @ApiModelProperty("容器码")
    @ApiModelProperty("料箱码")
    private String zpallet;
}
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/FlexibleDateDeserializer.java
New file
@@ -0,0 +1,60 @@
package com.vincent.rsf.openApi.entity.params;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
/**
 * 支持时间戳(秒/毫秒)与字符串 "yyyy-MM-dd HH:mm:ss" 的 Date 反序列化,与 @JsonFormat 配合使用。
 */
public class FlexibleDateDeserializer extends JsonDeserializer<Date> {
    private static final long MS_THRESHOLD = 10_000_000_000L; // 大于此为毫秒
    private static final String PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static final TimeZone DEFAULT_TZ = TimeZone.getTimeZone("GMT+8");
    @Override
    public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonToken t = p.getCurrentToken();
        if (t == JsonToken.VALUE_NUMBER_INT || t == JsonToken.VALUE_NUMBER_FLOAT) {
            long v = p.getLongValue();
            long ms = v >= MS_THRESHOLD ? v : v * 1000;
            return new Date(ms);
        }
        if (t == JsonToken.VALUE_STRING) {
            String s = p.getText().trim();
            if (s.isEmpty()) return null;
            try {
                long v = Long.parseLong(s);
                long ms = v >= MS_THRESHOLD ? v : v * 1000;
                return new Date(ms);
            } catch (NumberFormatException ignored) {
            }
            try {
                SimpleDateFormat sdf = new SimpleDateFormat(PATTERN);
                sdf.setTimeZone(DEFAULT_TZ);
                sdf.setLenient(false);
                return sdf.parse(s);
            } catch (Exception ignored) {
            }
            if (s.length() >= 10 && s.charAt(4) == '-' && s.charAt(7) == '-') {
                try {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    sdf.setTimeZone(DEFAULT_TZ);
                    sdf.setLenient(false);
                    return sdf.parse(s.substring(0, 10));
                } catch (Exception ignored) {
                }
            }
            return null;
        }
        if (t == JsonToken.VALUE_NULL) return null;
        return (Date) ctxt.handleUnexpectedToken(Date.class, p);
    }
}
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/FlexibleTimestampDeserializer.java
New file
@@ -0,0 +1,64 @@
package com.vincent.rsf.openApi.entity.params;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
/**
 * 将 JSON 反序列化为 Unix 时间戳(秒,Long)。
 * 支持:数字(秒或毫秒)、字符串 "yyyy-MM-dd HH:mm:ss" 或 "yyyy-MM-dd"。
 */
public class FlexibleTimestampDeserializer extends JsonDeserializer<Long> {
    private static final long MS_THRESHOLD = 10_000_000_000L; // 大于此为毫秒
    private static final TimeZone DEFAULT_TZ = TimeZone.getTimeZone("GMT+8");
    @Override
    public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonToken t = p.getCurrentToken();
        if (t == JsonToken.VALUE_NUMBER_INT || t == JsonToken.VALUE_NUMBER_FLOAT) {
            long v = p.getLongValue();
            return v >= MS_THRESHOLD ? v / 1000 : v;
        }
        if (t == JsonToken.VALUE_STRING) {
            String s = p.getText().trim();
            if (s.isEmpty()) {
                return null;
            }
            try {
                long v = Long.parseLong(s);
                return v >= MS_THRESHOLD ? v / 1000 : v;
            } catch (NumberFormatException ignored) {
            }
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                sdf.setTimeZone(DEFAULT_TZ);
                sdf.setLenient(false);
                Date d = sdf.parse(s);
                return d != null ? d.getTime() / 1000 : null;
            } catch (Exception ignored) {
            }
            if (s.length() >= 10 && s.charAt(4) == '-' && s.charAt(7) == '-') {
                try {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    sdf.setTimeZone(DEFAULT_TZ);
                    sdf.setLenient(false);
                    Date d = sdf.parse(s.substring(0, 10));
                    return d != null ? d.getTime() / 1000 : null;
                } catch (Exception ignored) {
                }
            }
            return null;
        }
        if (t == JsonToken.VALUE_NULL) {
            return null;
        }
        return (Long) ctxt.handleUnexpectedToken(Long.class, p);
    }
}
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ReportDataParam.java
@@ -28,7 +28,7 @@
    @ApiModelProperty("采购退货单号/生产单号/")
    private String OrderNO;
    @ApiModelProperty("现品票号")
    @ApiModelProperty("现品票号(已废弃)")
    private String GoodsNO;
    @ApiModelProperty("盘点数量")
rsf-open-api/src/main/java/com/vincent/rsf/openApi/service/impl/WmsErpServiceImpl.java
@@ -136,6 +136,9 @@
            log.info("order/add 收到 operateType=3,走统一取消逻辑: {}", params.getOrderNo());
            return doCancel(params);
        }
        if (params.getOrderInternalCode() == null || params.getOrderInternalCode().trim().isEmpty()) {
            throw new CoolException("单据内码不能为空!!");
        }
        Map<String, Object> mapParams = toServerOrderMap(params);
        List<Map<String, Object>> maps = Collections.singletonList(mapParams);
        log.info("新增/修改单据,请求参数: {}", JSONArray.toJSONString(maps));
@@ -150,9 +153,12 @@
    private Map<String, Object> toServerOrderMap(ErpOpParams params) {
        Map<String, Object> m = new HashMap<>();
        m.put("orderNo", params.getOrderNo());
        m.put("orderInternalCode", params.getOrderInternalCode());
        m.put("stationId", params.getStationId());
        m.put("wkType", params.getWkType());
        m.put("type", params.getOrderType() != null ? String.valueOf(params.getOrderType()) : null);
        m.put("orderId", params.getOrderId());
        m.put("operateType", params.getOperateType());
        double anfmeSum = 0;
        if (params.getOrderItems() != null) {
            List<Map<String, Object>> items = params.getOrderItems().stream()
@@ -167,9 +173,9 @@
        }
        m.put("anfme", anfmeSum);
        if (params.getBusinessTime() != null) {
            m.put("arrTime", new Date(params.getBusinessTime() * 1000));
            m.put("arrTime", params.getBusinessTime());
        } else if (params.getCreateTime() != null) {
            m.put("arrTime", new Date(params.getCreateTime() * 1000));
            m.put("arrTime", params.getCreateTime());
        }
        return m;
    }
@@ -184,6 +190,10 @@
        m.put("model", item.getModel());
        m.put("unit", item.getUnit());
        m.put("batch", item.getBatch());
        m.put("planNo", item.getPlanNo());
        m.put("palletId", item.getPalletId());
        m.put("targetWareHouseId", item.getTargetWareHouseId());
        m.put("sourceWareHouseId", item.getSourceWareHouseId());
        return m;
    }
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/ReportDataParam.java
@@ -28,7 +28,7 @@
    @ApiModelProperty("采购退货单号/生产单号/")
    private String OrderNO;
    @ApiModelProperty("现品票号")
    @ApiModelProperty("现品票号(已废弃)")
    private String GoodsNO;
    @ApiModelProperty("盘点数量")
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrderParams.java
@@ -28,12 +28,21 @@
    @ApiModelProperty("单号")
    private String orderNo;
    @ApiModelProperty("单据内码,唯一标识")
    private String orderInternalCode;
    @ApiModelProperty("入/出库接驳站点")
    private String stationId;
    @ApiModelProperty("原库位")
    private String orgLoc;
    @ApiModelProperty("订单ID")
    private Long orderId;
    @ApiModelProperty("操作类型:1 新增;2 修改;3 取消")
    private Integer operateType;
    @ApiModelProperty("数量")
    private Double anfme;
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/SyncOrdersItem.java
@@ -57,6 +57,18 @@
    @ApiModelProperty("库存批次")
    private String batch;
    @ApiModelProperty("计划跟踪号")
    private String planNo;
    @ApiModelProperty("托盘码")
    private String palletId;
    @ApiModelProperty("建议入库仓库")
    private String targetWareHouseId;
    @ApiModelProperty("建议出库仓库")
    private String sourceWareHouseId;
    @ApiModelProperty("已收数量")
    private Double qty;
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/TaskInParam.java
@@ -16,8 +16,8 @@
    @ApiModelProperty("作业站点 or 来源站点")
    private String sourceStaNo; //作业站点 or 来源站点
    @ApiModelProperty("容器条码")
    private String barcode; //容器条码
    @ApiModelProperty("料箱码")
    private String barcode; //料箱码
    @ApiModelProperty("库位类型")
    private Integer locType1; //库位类型
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/PdaCheckOrderController.java
@@ -40,7 +40,7 @@
    @PreAuthorize("hasAuthority('manager:task:list')")
    @PostMapping("/getCheckTaskItemList2")
    @ApiOperation("查询盘点任务列表,直接扫容器码")
    @ApiOperation("查询盘点任务列表,直接扫料箱码")
    public R getCheckTaskItemList2(@RequestBody Map<String, String> map) {
        return pdaCheckOrderService.getCheckTaskItemList2(map.get("barcode"));
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/PdaOutStockController.java
@@ -51,7 +51,7 @@
    @PreAuthorize("hasAuthority('manager:task:list')")
    @PostMapping("/getContainerWaveList")
    @ApiOperation("根据容器码查询波次及出库单")
    @ApiOperation("根据料箱码查询波次及出库单")
    public R getContainerWaveList(@RequestBody Map<String, String> map) {
        return pdaOutStockService.getContainerWaveList(map);
    }
@@ -73,7 +73,7 @@
    @PreAuthorize("hasAuthority('manager:task:list')")
    @PostMapping("/saveWavePick")
    @ApiOperation("根据容器码查询波次及出库单")
    @ApiOperation("根据料箱码查询波次及出库单")
    public R saveWavePick(@RequestBody ContainerWaveParam containerWaveParam) {
        return pdaOutStockService.saveWavePick(containerWaveParam,getLoginUserId());
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/InspectDetlDto.java
@@ -16,7 +16,7 @@
    private String code;
    @ApiModelProperty("单号ID")
    private Long id;
    @ApiModelProperty("PO单号")
    @ApiModelProperty("单据内码")
    private String poCode;
    @ApiModelProperty("明细")
    private List<InspectItemDto> items;
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/params/ExMsgParams.java
@@ -21,6 +21,6 @@
    @ApiModelProperty("小车编号 ")
    private String robotCode;
    @ApiModelProperty("容器码")
    @ApiModelProperty("料箱码")
    private String zpallet;
}
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/AgvServiceImpl.java
@@ -220,7 +220,7 @@
    private BasStation checkStaStatus(String barcode, String sta) {
        if (Cools.isEmpty(barcode)) {
            throw new CoolException("容器码不能为空");
            throw new CoolException("料箱码不能为空");
        }
        if (Cools.isEmpty(sta)) {
            throw new CoolException("接驳位条码不能为空");
@@ -230,7 +230,7 @@
                .eq(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_DONE.val)
        );
        if (Cools.isEmpty(waitPakin)) {
            throw new CoolException("容器码未找到组托信息,请检查组托状态");
            throw new CoolException("料箱码未找到组托信息,请检查组托状态");
        }
        BasStation isBarcodeSta = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
                        .eq(BasStation::getBarcode, barcode)
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/MobileServiceImpl.java
@@ -14,6 +14,7 @@
import com.vincent.rsf.server.common.security.JwtSubject;
import com.vincent.rsf.server.common.utils.FieldsUtils;
import com.vincent.rsf.server.common.utils.JwtUtil;
import com.vincent.rsf.server.common.utils.QuantityUtils;
import com.vincent.rsf.server.manager.controller.params.GenerateTaskParams;
import com.vincent.rsf.server.manager.controller.params.IsptItemsParams;
import com.vincent.rsf.server.manager.controller.params.WaitPakinParam;
@@ -258,8 +259,9 @@
            throw new CoolException("数据错误:主单不存在!!");
        }
        //TODO /**收货数量累加,1. 会出超收情况 2. 会有收货不足情况*/
        Double rcptedQty = Math.round((wkOrder.getQty() + receiptQty) * 1000000) / 1000000.0;
        wkOrder.setQty(rcptedQty).setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_EXCE_ING.val);
        Double rcptedQty = QuantityUtils.add(wkOrder.getQty(), receiptQty);
        // 新顺序:未执行(组托)→任务执行中→已完成,不再设置执行中/收货完成
        wkOrder.setQty(rcptedQty); // .setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_EXCE_ING.val)
        if (!asnOrderMapper.updateById(wkOrder)) {
            throw new CoolException("已收货数量修改失败!!");
        }
@@ -306,14 +308,14 @@
                throw new CoolException("请输入正确的时间格式!!");
            }
            Double itemRcptQty = Math.round((dto.getReceiptQty() + orderItem.getQty()) * 1000000) / 1000000.0;
            Double itemRcptQty = QuantityUtils.add(dto.getReceiptQty(), orderItem.getQty());
            Boolean allowOver = false;
            if (!Objects.isNull(config)) {
                if (Boolean.parseBoolean(config.getVal())) {
                    allowOver = true;
                }
            }
            if (itemRcptQty.compareTo(orderItem.getAnfme()) > 0 && !allowOver) {
            if (QuantityUtils.compare(itemRcptQty, orderItem.getAnfme()) > 0 && !allowOver) {
                throw new CoolException("收货数量不能大于计划数量!!");
            }
@@ -350,18 +352,18 @@
            if (asnOrderItemMapper.updateById(orderItem) < 1) {
                throw new CoolException("通知单明细数量修改失败!!");
            }
            /**保存明细至收货区**/
            extracted(loginUserId, dto, areasItem, orderItem, wkOrder, matnr);
            // 收货区已停用,不再保存至收货区
            // extracted(loginUserId, dto, areasItem, orderItem, wkOrder, matnr);
        }
        WkOrder order = asnOrderMapper.getOne(new LambdaQueryWrapper<WkOrder>().eq(WkOrder::getCode, asnCode));
        if (order.getQty().compareTo(order.getAnfme()) >= 0.00) {
            order.setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_RECEIPT_DONE.val).setRleStatus(Short.valueOf("1"));
            if (!asnOrderMapper.updateById(order)) {
                throw new CoolException("订单状态修改失败!!");
            }
        }
        // 新顺序:未执行(组托)→任务执行中→已完成,不再设置收货完成
        // WkOrder order = asnOrderMapper.getOne(new LambdaQueryWrapper<WkOrder>().eq(WkOrder::getCode, asnCode));
        // if (order.getQty().compareTo(order.getAnfme()) >= 0.00) {
        //     order.setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_RECEIPT_DONE.val).setRleStatus(Short.valueOf("1"));
        //     if (!asnOrderMapper.updateById(order)) {
        //         throw new CoolException("订单状态修改失败!!");
        //     }
        // }
        return R.ok("收货成功!!");
    }
@@ -390,7 +392,7 @@
                .setUnit(orderItem.getStockUnit())
                .setStockUnit(orderItem.getStockUnit())
                .setBatch(StringUtils.isBlank(orderItem.getBatch()) ? SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_RECEIPT_BATCH, dto) : orderItem.getBatch())
                .setAnfme(dto.getReceiptQty())
                .setAnfme(QuantityUtils.roundToScale(dto.getReceiptQty()))
                .setSplrBatch(dto.getSplrBatch())
                .setMatnrCode(matnr.getCode())
                .setUpdateBy(loginUserId)
@@ -419,8 +421,7 @@
        if (!Objects.isNull(serviceOne)) {
            item.setId(serviceOne.getId());
            Double anfme = Math.round((item.getAnfme() + serviceOne.getAnfme()) * 1000000) / 1000000.0;
            item.setAnfme(anfme);
            item.setAnfme(QuantityUtils.add(item.getAnfme(), serviceOne.getAnfme()));
        }
        //未质检
@@ -511,11 +512,13 @@
     * @description 获取收货区
     * @time 2025/3/11 10:12
     */
    /** 收货区已停用,返回空列表 */
    @Override
    public R getReceiptAreas() {
        List<WarehouseAreas> areas = warehouseAreasService.list(new LambdaQueryWrapper<WarehouseAreas>()
                .eq(WarehouseAreas::getType, WarehouseAreaType.WAREHOUSE_AREA_RECEIPT.type));
        return R.ok(areas);
        // List<WarehouseAreas> areas = warehouseAreasService.list(new LambdaQueryWrapper<WarehouseAreas>()
        //         .eq(WarehouseAreas::getType, WarehouseAreaType.WAREHOUSE_AREA_RECEIPT.type));
        // return R.ok(areas);
        return R.ok(Collections.emptyList());
    }
    /**
@@ -552,7 +555,7 @@
//            throw new CoolException("票号不能为空!!");
//        }
//        if (Objects.isNull(code)) {
//            throw new CoolException("容器号不能为空!!");
//            throw new CoolException("料箱码不能为空!!");
//        }
//        BasContainer container = basContainerService.getOne(new LambdaQueryWrapper<BasContainer>().eq(BasContainer::getCode, barcode));
//        if (Objects.isNull(container)) {
@@ -620,34 +623,59 @@
            return R.ok(resultList);
        }
        
        //TODO 后续需根据策略配置,获取组拖数据。如:混装,按批次混装等
        LambdaQueryWrapper<WarehouseAreasItem> queryWrapper = new LambdaQueryWrapper<>();
        // 如果有ASN单号,则只查询该单号下的物料(ASN单号作为必须条件)
        // 收货区已停用:有ASN单号时从订单明细查可组托物料;可组盘数量 = 计划数量 - 已组托数量 - 已上架数量
        if (!Cools.isEmpty(asnCode)) {
            // ASN单号作为必须条件
            queryWrapper.eq(WarehouseAreasItem::getAsnCode, asnCode);
            // 如果同时有物料编码,则查询该ASN单号下的该物料
            if (!Cools.isEmpty(matnrCode)) {
                queryWrapper.eq(WarehouseAreasItem::getMatnrCode, matnrCode);
            WkOrder order = asnOrderMapper.getOne(new LambdaQueryWrapper<WkOrder>().eq(WkOrder::getCode, asnCode));
            if (order == null) {
                logger.info("未找到ASN单号: {}", asnCode);
                return R.ok(Collections.emptyList());
            }
            // 按明细汇总已组托数量(组托数量不会因改单而变)
            List<WaitPakinItem> pakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().eq(WaitPakinItem::getAsnId, order.getId()));
            Map<Long, Double> palletizedByItemId = pakinItems.stream()
                    .collect(Collectors.groupingBy(WaitPakinItem::getAsnItemId, Collectors.summingDouble(w -> w.getAnfme() != null ? w.getAnfme() : 0.0)));
            palletizedByItemId.replaceAll((k, v) -> QuantityUtils.roundToScale(v));
            LambdaQueryWrapper<WkOrderItem> itemWrapper = new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, order.getId());
            if (!Cools.isEmpty(matnrCode)) itemWrapper.eq(WkOrderItem::getMatnrCode, matnrCode);
            if (!Cools.isEmpty(batch)) itemWrapper.eq(WkOrderItem::getSplrBatch, batch);
            if (!Objects.isNull(fieldIndex)) itemWrapper.eq(WkOrderItem::getFieldsIndex, fieldIndex);
            if (!Cools.isEmpty(code)) itemWrapper.eq(WkOrderItem::getTrackCode, code);
            List<WkOrderItem> orderItems = asnOrderItemMapper.selectList(itemWrapper);
            List<WarehouseAreasItem> list = new ArrayList<>();
            for (WkOrderItem oi : orderItems) {
                Double anfme = QuantityUtils.roundToScale(oi.getAnfme() != null ? oi.getAnfme() : 0.0);
                Double qty = QuantityUtils.roundToScale(oi.getQty() != null ? oi.getQty() : 0.0);
                Double workQty = palletizedByItemId.getOrDefault(oi.getId(), 0.0); // 已组托数量
                if (QuantityUtils.compare(QuantityUtils.subtract(QuantityUtils.subtract(anfme, workQty), qty), 0.0) <= 0) continue; // 可组盘数量<=0 不返回
                WarehouseAreasItem v = new WarehouseAreasItem();
                v.setId(oi.getId());
                v.setAsnItemId(oi.getId());
                v.setAsnId(order.getId());
                v.setAsnCode(order.getCode());
                v.setAnfme(anfme);
                v.setQty(qty);
                v.setWorkQty(QuantityUtils.roundToScale(workQty));
                v.setMatnrCode(oi.getMatnrCode());
                v.setMaktx(oi.getMaktx());
                v.setSplrBatch(oi.getSplrBatch());
                v.setPlatItemId(oi.getPlatItemId());
                v.setStockUnit(oi.getStockUnit());
                v.setUnit(oi.getStockUnit());
                v.setMatnrId(oi.getMatnrId());
                v.setFieldsIndex(oi.getFieldsIndex());
                v.setTrackCode(oi.getTrackCode());
                if (oi.getFieldsIndex() != null) {
                    v.setExtendFields(FieldsUtils.getFields(oi.getFieldsIndex()));
                }
                list.add(v);
            }
            logger.info("=== 从订单明细查询可组托物料(收货区已停用)asnCode: {} 返回 {} 条", asnCode, list.size());
            return R.ok(list);
            }
            
            // 如果同时有批次,则查询该ASN单号下的该批次
            if (!Cools.isEmpty(batch)) {
                queryWrapper.eq(WarehouseAreasItem::getSplrBatch, batch);
            }
            // 如果同时有票号,则查询该ASN单号下的该票号
            if (!Objects.isNull(fieldIndex)) {
                queryWrapper.eq(WarehouseAreasItem::getFieldsIndex, fieldIndex);
            }
            // 如果同时有跟踪码,则查询该ASN单号下的该跟踪码
            if (!Cools.isEmpty(code)) {
                queryWrapper.eq(WarehouseAreasItem::getTrackCode, code);
            }
        } else {
        // 无ASN单号时按其他条件查(收货区已停用,此处仅保留兼容,通常无数据)
        LambdaQueryWrapper<WarehouseAreasItem> queryWrapper = new LambdaQueryWrapper<>();
        {
            // 没有ASN单号时,可以扫描任意物料组托,使用OR连接多个条件
            // 统计有效条件数量
            int conditionCount = 0;
@@ -1017,7 +1045,7 @@
            throw new CoolException("当前业务:" + SerialRuleCode.SYS_STOCK_CODE + ",编码规则不存在!!");
        }
        List<WkOrderItem> itemList = params.getItemList();
        double sum = itemList.stream().mapToDouble(WkOrderItem::getAnfme).sum();
        Double sum = QuantityUtils.roundToScale(itemList.stream().mapToDouble(WkOrderItem::getAnfme).sum());
        stock.setAnfme(sum)
                .setSourceId(order.getId())
                .setType(order.getType())
@@ -1202,14 +1230,14 @@
    @Override
    public R getUnItemByContainer(Map<String, Object> params) {
        if (Cools.isEmpty(params.get("barcode")) && Cools.isEmpty(params.get("code"))) {
            throw new CoolException("容器号与组托档编码不能全为空");
            throw new CoolException("料箱码与组托档编码不能全为空");
        }
        WaitPakin waitPakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>()
                .eq(!Cools.isEmpty(params.get("barcode")), WaitPakin::getBarcode, params.get("barcode"))
                .eq(!Cools.isEmpty(params.get("code")), WaitPakin::getCode, params.get("code"))
                .eq(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_DONE.val));
        if (Objects.isNull(waitPakin)) {
            return R.error("未找到该容器码的组托明细,请检查组托状态");
            return R.error("未找到该料箱码的组托明细,请检查组托状态");
        }
        List<WaitPakinItem> pakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>()
                .eq(WaitPakinItem::getPakinId, waitPakin.getId()));
@@ -1325,11 +1353,11 @@
                    .setMaktx(asnOrderItem.getMaktx())
                    .setFieldsIndex(asnOrderItem.getFieldsIndex())
                    .setBarcode(asnOrderItem.getTrackCode())
                    .setQty(asnOrderItem.getQty())
                    .setQty(QuantityUtils.roundToScale(asnOrderItem.getQty()))
                    .setStockUnit(asnOrderItem.getStockUnit())
                    .setPurUnit(asnOrderItem.getPurUnit())
                    .setPoCode(asnOrderItem.getPoCode())
                    .setAnfme(asnOrderItem.getAnfme())
                    .setAnfme(QuantityUtils.roundToScale(asnOrderItem.getAnfme()))
                    .setPurQty(asnOrderItem.getPurQty())
                    .setSplrBatch(asnOrderItem.getSplrBatch())
                    .setExtendFields(asnOrderItem.getExtendFields())
@@ -1360,7 +1388,7 @@
            if (Objects.isNull(stockItem)) {
                detlsDto.setStockQty(0.0);
            } else {
                Double anfme = Math.round((stockItem.getAnfme() + stockItem.getWorkQty()) * 1000000) / 1000000.0;
                Double anfme = QuantityUtils.add(stockItem.getAnfme(), stockItem.getWorkQty());
                detlsDto.setStockQty(anfme);
            }
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaCheckOrderServiceImpl.java
@@ -87,7 +87,7 @@
        lambdaQueryWrapper.eq(Task::getBarcode, barcode);
        Task task = taskService.getOne(lambdaQueryWrapper);
        if (null == task) {
            throw new CoolException("未找到容器号对应任务");
            throw new CoolException("未找到料箱码对应任务");
        }
        if (!task.getTaskStatus().equals(TaskStsType.AWAIT.id)) {
            return R.error("任务状态不是等待确认");
@@ -115,7 +115,7 @@
        }
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, params.getContainer()));
        if (null == task) {
            throw new CoolException("数据错误,未找到容器码对应盘点任务");
            throw new CoolException("数据错误,未找到料箱码对应盘点任务");
        }
        for (CheckDiffItem ckDiffItem : params.getCheckDiffItems()) {
            CheckDiffItem diffItem = new CheckDiffItem();
@@ -234,14 +234,14 @@
        lambdaQueryWrapper.eq(Task::getBarcode, barcode);
        Task task = taskService.getOne(lambdaQueryWrapper);
        if (null == task) {
            throw new CoolException("未找到容器号对应任务");
            throw new CoolException("未找到料箱码对应任务");
        }
        if (!task.getTaskStatus().equals(TaskStsType.AWAIT.id)) {
            return R.error("任务状态不是等待确认");
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        if (Cools.isEmpty(taskItems)) {
            throw new CoolException("未找到该容器码对应的任务明细");
            throw new CoolException("未找到该料箱码对应的任务明细");
        }
        String sourceCode = taskItems.stream().findFirst().map(TaskItem::getSourceCode).orElse(null);
        CheckDiff checkDiff = checkDiffService.getOne(new LambdaQueryWrapper<CheckDiff>().eq(CheckDiff::getOrderCode, sourceCode));
@@ -275,7 +275,7 @@
        lambdaQueryWrapper.eq(Task::getBarcode, barcode);
        Task task = taskService.getOne(lambdaQueryWrapper);
        if (null == task) {
            throw new CoolException("未找到容器号对应任务");
            throw new CoolException("未找到料箱码对应任务");
        }
        // 允许WAVE_SEED(199,等待确认/盘点中)和AWAIT(196,等待确认)两种状态
        if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id) 
@@ -284,7 +284,7 @@
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        if (Cools.isEmpty(taskItems)) {
            throw new CoolException("未找到该容器码对应的任务明细");
            throw new CoolException("未找到该料箱码对应的任务明细");
        }
        taskItems.forEach(taskItem -> {
            if (!Objects.isNull(taskItem.getFieldsIndex())) {
@@ -319,7 +319,7 @@
        lambdaQueryWrapper.eq(Task::getBarcode, barcode);
        Task task = taskService.getOne(lambdaQueryWrapper);
        if (null == task) {
            throw new CoolException("未找到容器号对应任务");
            throw new CoolException("未找到料箱码对应任务");
        }
        if (!task.getTaskStatus().equals(TaskStsType.AWAIT.id)) {
            return R.error("任务状态不是等待确认");
@@ -390,7 +390,7 @@
        lambdaQueryWrapper.eq(Task::getBarcode, barcode);
        Task task = taskService.getOne(lambdaQueryWrapper);
        if (null == task) {
            throw new CoolException("未找到容器号对应任务");
            throw new CoolException("未找到料箱码对应任务");
        }
        // 允许WAVE_SEED(199,等待确认/盘点中)和AWAIT(196,等待确认)两种状态
        if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id) 
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
@@ -104,7 +104,7 @@
                .last("limit 1");
        Task task = taskService.getOne(lambdaQueryWrapper);
        if (null == task) {
            throw new CoolException("未找到容器号对应任务");
            throw new CoolException("未找到料箱码对应任务");
        }
        // 允许 199(WAVE_SEED 播种中/待确认)或 196(AWAIT 等待确认),与盘点 PDA 逻辑一致
        if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)
@@ -163,7 +163,7 @@
                .orderByDesc(Task::getId)
                .last("limit 1"));
        if (null == task) {
            throw new CoolException("未找到容器号对应任务");
            throw new CoolException("未找到料箱码对应任务");
        }
        if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)) {
            return R.error("任务状态不是揀料狀態");
@@ -194,7 +194,7 @@
//            containerWaveDto.setTaskItem(taskItem);
//            Wave wave = waveService.getById(taskItem.getSourceId());
//            if (null == wave) {
//                throw new CoolException("未找到容器号对应波次");
//                throw new CoolException("未找到料箱码对应波次");
//            }
//            List<WaveOrderRela> waveOrderRelas = waveOrderRelaService.list(new LambdaQueryWrapper<WaveOrderRela>()
//                    .eq(WaveOrderRela::getWaveId, wave.getId()));
@@ -235,7 +235,7 @@
            return R.error("票号不能为空!!");
        }
        if (Objects.isNull(param.get("barcode"))) {
            return R.error("容器号不能为空!!");
            return R.error("料箱码不能为空!!");
        }
        if (Objects.isNull(param.get("orderId"))) {
            return R.error("订单ID不能为空!!");
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
@@ -19,6 +19,7 @@
import com.vincent.rsf.server.common.domain.BaseParam;
import com.vincent.rsf.server.common.domain.PageParam;
import com.vincent.rsf.server.common.utils.FieldsUtils;
import com.vincent.rsf.server.common.utils.QuantityUtils;
import com.vincent.rsf.server.manager.controller.dto.LocStockDto;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.enums.*;
@@ -79,6 +80,10 @@
    @Autowired
    private LocService locService;
    @Autowired
    private OrderWorkTypeService orderWorkTypeService;
    @Autowired
    private OrderTypeDictService orderTypeDictService;
    @Autowired
    private WarehouseAreasService warehouseAreasService;
    @Autowired
    private WarehouseService warehouseService;
@@ -104,6 +109,10 @@
    private DictTypeService dictTypeService;
    @Autowired
    private LocItemService locItemService;
    @Autowired
    private WaitPakinItemService waitPakinItemService;
    @Autowired
    private WarehouseAreasItemService warehouseAreasItemService;
    /**
@@ -408,11 +417,37 @@
    public R syncCheckOrder(List<SyncOrderParams> syncOrders, Long loginUserId) {
        if (!syncOrders.isEmpty()) {
            syncOrders.forEach(syncOrder -> {
                if (StringUtils.isBlank(syncOrder.getOrderInternalCode())) {
                    throw new CoolException("单据内码不能为空!!");
                }
                // 明细 lineId(对应 platItemId)不能为空,且同一订单内不能重复
                if (syncOrder.getOrderItems() != null) {
                    Set<String> lineIds = new HashSet<>();
                    for (SyncOrdersItem item : syncOrder.getOrderItems()) {
                        if (StringUtils.isBlank(item.getPlatItemId())) {
                            throw new CoolException("明细 lineId 不能为空!!");
                        }
                        String lineId = item.getPlatItemId().trim();
                        if (!lineIds.add(lineId)) {
                            throw new CoolException("同一订单内明细 lineId 不能重复:" + lineId);
                        }
                    }
                }
                WkOrder wkOrder = new WkOrder();
                DictData one = dictDataService.getOne(new LambdaQueryWrapper<DictData>().eq(DictData::getDictTypeCode, DictTypeCode.DICT_SYS_BUSINESS_TYPE)
                        .eq(DictData::getValue, syncOrder.getWkType()), false);
                if (Objects.isNull(one)) {
                // 兼容 wkType 传数字(类型码)或中文(显示名):先按 label 反查 type,否则按原值当 type
                String wkTypeInput = syncOrder.getWkType();
                String typeCode = StringUtils.isBlank(wkTypeInput) ? null : orderWorkTypeService.getTypeByLabel(wkTypeInput);
                if (typeCode == null) {
                    typeCode = wkTypeInput;
                }
                if (StringUtils.isBlank(typeCode) || orderWorkTypeService.getLabelByType(typeCode) == null) {
                    throw new CoolException("单据:" + syncOrder.getOrderNo() + ", 业务类型不存在!!");
                }
                // 订单类型:支持数字 1/2/3、中文「出库单」/「入库单」/「调拨单」或内部码 out/in/transfer(来自字典)
                String typeInput = syncOrder.getType();
                String resolvedOrderType = orderTypeDictService.resolveType(typeInput);
                if (typeInput != null && !typeInput.trim().isEmpty() && resolvedOrderType == null) {
                    throw new CoolException("单据:" + syncOrder.getOrderNo() + ", 订单类型不存在!!");
                }
                Loc serviceOne = null;
                if (!Objects.isNull(syncOrder.getOrgLoc())) {
@@ -421,42 +456,56 @@
                if (!Objects.isNull(serviceOne)) {
                    //TODO 添加调拔移库单功能
                } else {
                    // operateType=2 存在则修改、不存在则报错;operateType=1 存在则修改、不存在则新增
                    WkOrder order = asnOrderService.getOne(new LambdaQueryWrapper<WkOrder>()
                            .eq(!Objects.isNull(syncOrder.getOrderId()), WkOrder::getPoId, syncOrder.getOrderId())
                            .eq(WkOrder::getPoCode, syncOrder.getOrderNo()));
                            .eq(WkOrder::getPoCode, syncOrder.getOrderInternalCode()));
                    if (!Objects.isNull(order)) {
                        if (order.getExceStatus().equals(AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val) ||
                                order.getExceStatus().equals(AsnExceStatus.OUT_STOCK_STATUS_TASK_INIT.val)) {
                            /**删除单据明细*/
                            asnOrderItemService.remove(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, order.getId()));
                            /**删除主单*/
                            asnOrderService.removeById(order.getId());
                        } else {
                            throw new CoolException("单据已添加,不可执行修改或添加操作!!");
                        // 仅未执行状态可被 order/add 修改(入库未执行、出库任务初始)
                        List<Short> editableStatus = Arrays.asList(AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val, AsnExceStatus.OUT_STOCK_STATUS_TASK_INIT.val);
                        if (!editableStatus.contains(order.getExceStatus())) {
                            throw new CoolException("仅未执行状态的单据可修改!!");
                        }
                        // 存在则修改(1 和 2 均走此处),组托校验在 mergeOrderWithPakin/updateOrderNoPakin 内
                        long pakinCount = waitPakinItemService.count(new LambdaQueryWrapper<WaitPakinItem>()
                                .eq(WaitPakinItem::getAsnId, order.getId()));
                        if (pakinCount > 0) {
                            // 已组托:按 lineId(platItemId)合并,校验数量与删除
                            mergeOrderWithPakin(order, syncOrder, resolvedOrderType, typeCode, loginUserId);
                            // 收货区已停用 // syncReceiptAreaByOrder(order.getId());
                            return; // 本单已处理,跳过下方“新建主单+明细”
                        }
                        // 未组托:在原单上更新主单+明细,保留 exceStatus/qty/workQty,避免再次触发定时任务导致重复收货
                        updateOrderNoPakin(order, syncOrder, loginUserId);
                        // 收货区已停用 // syncReceiptAreaByOrder(order.getId());
                        return;
                    } else if (Integer.valueOf(2).equals(syncOrder.getOperateType())) {
                        // 仅 operateType=2 时要求单据必须存在
                        throw new CoolException("单据不存在,无法修改!!");
                    }
                    String rule = SerialRuleCode.SYS_ASN_ORDER;
                    if (syncOrder.getType().equals(OrderType.ORDER_OUT.type)) {
                    if (resolvedOrderType != null && resolvedOrderType.equals(OrderType.ORDER_OUT.type)) {
                        rule = SerialRuleCode.SYS_OUT_STOCK_CODE;
                    }
                    String ruleCode = SerialRuleUtils.generateRuleCode(rule, null);
                    wkOrder.setType(syncOrder.getType())
                            .setWkType(one.getValue())
                            .setAnfme(syncOrder.getAnfme())
                            .setPoCode(syncOrder.getOrderNo())
                    // 有 orderNo 则直接作为 WMS 单号 code,否则按规则生成;po_code 存单据内码(orderInternalCode 已校验非空)
                    String wmsCode = StringUtils.isNotBlank(syncOrder.getOrderNo()) ? syncOrder.getOrderNo() : SerialRuleUtils.generateRuleCode(rule, null);
                    String poCodeVal = syncOrder.getOrderInternalCode();
                    wkOrder.setType(resolvedOrderType != null ? resolvedOrderType : syncOrder.getType())
                            .setWkType(typeCode)
                            .setAnfme(QuantityUtils.roundToScale(syncOrder.getAnfme()))
                            .setPoCode(poCodeVal)
                            .setWorkQty(0.0)
                            .setQty(0.0)
                            .setPoId(syncOrder.getOrderId())
                            .setCode(ruleCode)
                            .setCode(wmsCode)
                            .setArrTime(syncOrder.getArrTime())
                            .setStationId(syncOrder.getStationId())
                            .setId(null)
                            .setCreateTime(new Date())
                            .setUpdateTime(new Date())
                            .setCreateBy(loginUserId)
                            .setUpdateBy(loginUserId);
                    if (syncOrder.getType().equals(OrderType.ORDER_OUT.type)){
                    if (resolvedOrderType != null && resolvedOrderType.equals(OrderType.ORDER_OUT.type)) {
                        wkOrder.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_INIT.val);
                    }
@@ -478,7 +527,7 @@
                    });
                    List<WkOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>()
                            .eq(WkOrderItem::getOrderId, wkOrder.getId()));
                    double sum = orderItems.stream().mapToDouble(WkOrderItem::getAnfme).sum();
                    Double sum = QuantityUtils.roundToScale(orderItems.stream().mapToDouble(WkOrderItem::getAnfme).sum());
                    wkOrder.setAnfme(sum);
                    if (!asnOrderService.updateById(wkOrder)) {
                        throw new CoolException("计划收货数量修改失败!!");
@@ -488,6 +537,203 @@
        }
        return R.ok();
    }
    /**
     * 已组托单据的修改合并:按 lineId(platItemId)匹配。
     * 规则:组托数量不会因改单而变;已组托 100 时,修改为 99 会报错,修改为 101 允许且多出的 1 可再组托。
     */
    private void mergeOrderWithPakin(WkOrder order, SyncOrderParams syncOrder, String resolvedOrderType, String typeCode, Long loginUserId) {
        if (syncOrder.getOrderItems() != null) {
            for (SyncOrdersItem it : syncOrder.getOrderItems()) {
                if (StringUtils.isBlank(it.getPlatItemId())) {
                    throw new CoolException("明细 lineId 不能为空!!");
                }
            }
        }
        List<WkOrderItem> existingItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, order.getId()));
        List<WaitPakinItem> pakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().eq(WaitPakinItem::getAsnId, order.getId()));
        Map<Long, Double> palletizedByItemId = pakinItems.stream()
                .collect(Collectors.groupingBy(WaitPakinItem::getAsnItemId, Collectors.summingDouble(w -> w.getAnfme() != null ? w.getAnfme() : 0.0)));
        palletizedByItemId.replaceAll((k, v) -> QuantityUtils.roundToScale(v));
        Map<String, SyncOrdersItem> incomingByLineId = new HashMap<>();
        if (syncOrder.getOrderItems() != null) {
            for (SyncOrdersItem it : syncOrder.getOrderItems()) {
                incomingByLineId.put(it.getPlatItemId().trim(), it);
            }
        }
        Set<String> existingLineIds = existingItems.stream()
                .map(e -> StringUtils.isNotBlank(e.getPlatItemId()) ? e.getPlatItemId().trim() : null)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        for (WkOrderItem existing : existingItems) {
            String lineId = StringUtils.isNotBlank(existing.getPlatItemId()) ? existing.getPlatItemId().trim() : null;
            double palletized = palletizedByItemId.getOrDefault(existing.getId(), 0.0);
            if (lineId == null || !incomingByLineId.containsKey(lineId)) {
                if (palletized > 0) {
                    throw new CoolException("该明细已组托,需解除组托后才能删除!!");
                }
            } else {
                SyncOrdersItem inc = incomingByLineId.get(lineId);
                Double newAnfme = QuantityUtils.roundToScale(inc.getAnfme() != null ? inc.getAnfme() : 0.0);
                // 已组托数量不变:改小(如 100 改为 99)报错;改大(如 100 改为 101)允许,多出的可再组托
                if (QuantityUtils.compare(newAnfme, palletized) < 0) {
                    throw new CoolException("该明细数量不能小于已组托数量(已组托 " + palletized + "),需解除组托后才能修改!!");
                }
            }
        }
        order.setAnfme(QuantityUtils.roundToScale(syncOrder.getAnfme() != null ? syncOrder.getAnfme() : 0.0));
        if (syncOrder.getArrTime() != null) {
            order.setArrTime(syncOrder.getArrTime());
        }
        if (StringUtils.isNotBlank(syncOrder.getStationId())) {
            order.setStationId(syncOrder.getStationId());
        }
        order.setUpdateBy(loginUserId);
        order.setUpdateTime(new Date());
        asnOrderService.updateById(order);
        for (WkOrderItem existing : existingItems) {
            String lineId = StringUtils.isNotBlank(existing.getPlatItemId()) ? existing.getPlatItemId().trim() : null;
            if (lineId == null || !incomingByLineId.containsKey(lineId)) {
                asnOrderItemService.removeById(existing.getId());
                continue;
            }
            SyncOrdersItem inc = incomingByLineId.get(lineId);
            existing.setAnfme(QuantityUtils.roundToScale(inc.getAnfme() != null ? inc.getAnfme() : existing.getAnfme()));
            existing.setMaktx(inc.getMaktx());
            existing.setSpec(inc.getSpec());
            existing.setModel(inc.getModel());
            existing.setStockUnit(inc.getUnit());
            existing.setBatch(inc.getBatch());
            existing.setPlanNo(inc.getPlanNo());
            existing.setPalletId(inc.getPalletId());
            existing.setUpdateBy(loginUserId);
            existing.setUpdateTime(new Date());
            asnOrderItemService.updateById(existing);
        }
        for (Map.Entry<String, SyncOrdersItem> e : incomingByLineId.entrySet()) {
            String key = e.getKey();
            if (!existingLineIds.contains(key)) {
                Map<String, Object> map = new ObjectMapper().convertValue(e.getValue(), Map.class);
                map.put("orderId", order.getId());
                map.put("poId", order.getPoId());
                map.put("poCode", order.getPoCode());
                map.put("order_code", order.getCode());
                map.put("matnrCode", e.getValue().getMatnr());
                map.put("platItemId", key);
                if (!asnOrderItemService.fieldsSave(map, loginUserId)) {
                    throw new CoolException("明细保存失败!!");
                }
            }
        }
        Double sum = QuantityUtils.roundToScale(asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, order.getId()))
                .stream().mapToDouble(WkOrderItem::getAnfme).sum());
        order.setAnfme(sum);
        asnOrderService.updateById(order);
    }
    /**
     * 未组托单据的修改:在原单上更新主单+明细(按 lineId 匹配),保留 exceStatus、qty、workQty,避免删单重建导致定时任务再次执行。
     */
    private void updateOrderNoPakin(WkOrder order, SyncOrderParams syncOrder, Long loginUserId) {
        if (syncOrder.getOrderItems() == null || syncOrder.getOrderItems().isEmpty()) {
            throw new CoolException("修改时明细不能为空!!");
        }
        Map<String, SyncOrdersItem> incomingByLineId = new HashMap<>();
        for (SyncOrdersItem it : syncOrder.getOrderItems()) {
            if (StringUtils.isBlank(it.getPlatItemId())) {
                throw new CoolException("明细 lineId 不能为空!!");
            }
            incomingByLineId.put(it.getPlatItemId().trim(), it);
        }
        List<WkOrderItem> existingItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, order.getId()));
        Set<String> existingLineIds = existingItems.stream()
                .map(e -> StringUtils.isNotBlank(e.getPlatItemId()) ? e.getPlatItemId().trim() : null)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        order.setAnfme(QuantityUtils.roundToScale(syncOrder.getAnfme() != null ? syncOrder.getAnfme() : 0.0));
        if (syncOrder.getArrTime() != null) {
            order.setArrTime(syncOrder.getArrTime());
        }
        if (StringUtils.isNotBlank(syncOrder.getStationId())) {
            order.setStationId(syncOrder.getStationId());
        }
        order.setUpdateBy(loginUserId);
        order.setUpdateTime(new Date());
        asnOrderService.updateById(order);
        for (WkOrderItem existing : existingItems) {
            String lineId = StringUtils.isNotBlank(existing.getPlatItemId()) ? existing.getPlatItemId().trim() : null;
            if (lineId == null || !incomingByLineId.containsKey(lineId)) {
                // 收货区已停用 // warehouseAreasItemService.remove(new LambdaQueryWrapper<WarehouseAreasItem>().eq(WarehouseAreasItem::getAsnItemId, existing.getId()));
                asnOrderItemService.removeById(existing.getId());
                continue;
            }
            SyncOrdersItem inc = incomingByLineId.get(lineId);
            existing.setAnfme(QuantityUtils.roundToScale(inc.getAnfme() != null ? inc.getAnfme() : existing.getAnfme()));
            existing.setMaktx(inc.getMaktx());
            existing.setSpec(inc.getSpec());
            existing.setModel(inc.getModel());
            existing.setStockUnit(inc.getUnit());
            existing.setBatch(inc.getBatch());
            existing.setPlanNo(inc.getPlanNo());
            existing.setPalletId(inc.getPalletId());
            existing.setUpdateBy(loginUserId);
            existing.setUpdateTime(new Date());
            asnOrderItemService.updateById(existing);
        }
        for (Map.Entry<String, SyncOrdersItem> e : incomingByLineId.entrySet()) {
            if (existingLineIds.contains(e.getKey())) {
                continue;
            }
            Map<String, Object> map = new ObjectMapper().convertValue(e.getValue(), Map.class);
            map.put("orderId", order.getId());
            map.put("poId", order.getPoId());
            map.put("poCode", order.getPoCode());
            map.put("order_code", order.getCode());
            map.put("matnrCode", e.getValue().getMatnr());
            map.put("platItemId", e.getKey());
            if (!asnOrderItemService.fieldsSave(map, loginUserId)) {
                throw new CoolException("明细保存失败!!");
            }
        }
        Double sum = QuantityUtils.roundToScale(asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, order.getId()))
                .stream().mapToDouble(WkOrderItem::getAnfme).sum());
        order.setAnfme(sum);
        asnOrderService.updateById(order);
    }
    /** 收货区已停用,方法整体注释
     * 订单修改后同步收货区:按 asnItemId 将收货区记录的 anfme 更新为订单明细的 anfme。
     */
//    private void syncReceiptAreaByOrder(Long orderId) {
//        List<WkOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, orderId));
//        if (orderItems.isEmpty()) {
//            return;
//        }
//        List<WarehouseAreasItem> areaItems = warehouseAreasItemService.list(new LambdaQueryWrapper<WarehouseAreasItem>().eq(WarehouseAreasItem::getAsnId, orderId));
//        Map<Long, Double> itemAnfme = orderItems.stream().collect(Collectors.toMap(WkOrderItem::getId, i -> i.getAnfme() != null ? i.getAnfme() : 0.0, (a, b) -> b));
//        for (WarehouseAreasItem area : areaItems) {
//            if (area.getAsnItemId() == null || !itemAnfme.containsKey(area.getAsnItemId())) {
//                continue;
//            }
//            Double anfme = itemAnfme.get(area.getAsnItemId());
//            if (area.getAnfme() != null && area.getAnfme().equals(anfme)) {
//                continue;
//            }
//            area.setAnfme(anfme);
//            warehouseAreasItemService.updateById(area);
//        }
//    }
    /**
     * @author Ryan
@@ -660,7 +906,7 @@
                            .eq(WkOrderItem::getMatnrCode, orderItem.getMatnr())
                            .eq(StringUtils.isNotEmpty(orderItem.getBatch()), WkOrderItem::getSplrBatch, orderItem.getBatch())
                            .eq(StringUtils.isNotEmpty(orderItem.getPlatItemId()), WkOrderItem::getPlatItemId, orderItem.getPlatItemId())
                            .set(WkOrderItem::getAnfme, orderItem.getAnfme()))) {
                            .set(WkOrderItem::getAnfme, QuantityUtils.roundToScale(orderItem.getAnfme())))) {
                        throw new CoolException("单据修改失败!!");
                    }
                } else {
@@ -673,7 +919,7 @@
                    }
                }
            });
            wkOrder.setAnfme(order.getAnfme());
            wkOrder.setAnfme(QuantityUtils.roundToScale(order.getAnfme()));
            if (!asnOrderService.updateById(wkOrder)) {
                throw new CoolException("主单据修改失败!!");
            }
@@ -691,31 +937,56 @@
    @Transactional(timeout = 60, rollbackFor = Exception.class)
    public R syncOrderDelete(List<SyncOrderParams> orders) {
        orders.forEach(order -> {
            // operateType=3:存在则判断是否可以取消;主要校验单据内码(orderInternalCode),orderNo 查到 1 条继续,查到多条则报错强调使用 orderInternalCode
            WkOrder wkOrder = null;
            if (StringUtils.isNotEmpty(order.getOrderInternalCode())) {
                wkOrder = asnOrderService.getOne(new LambdaQueryWrapper<WkOrder>()
                        .eq(WkOrder::getPoCode, order.getOrderInternalCode()));
            }
            if (wkOrder == null && StringUtils.isNotEmpty(order.getOrderNo())) {
                List<WkOrder> list = asnOrderService.list(new LambdaQueryWrapper<WkOrder>()
                        .eq(WkOrder::getCode, order.getOrderNo()));
                if (list.isEmpty()) {
                    throw new CoolException("单据不存在,无法取消!!");
                }
                if (list.size() > 1) {
                    throw new CoolException("单号对应多条单据,请使用单据内码(orderInternalCode)唯一指定后再取消!!");
                }
                wkOrder = list.get(0);
            }
            if (wkOrder == null) {
                throw new CoolException("单据不存在,无法取消!!请提供单据内码(orderInternalCode)或单号(orderNo)。");
            }
            final WkOrder finalWkOrder = wkOrder;
            // 已组托不可取消
            long pakinCount = waitPakinItemService.count(new LambdaQueryWrapper<WaitPakinItem>()
                    .eq(WaitPakinItem::getAsnId, finalWkOrder.getId()));
            if (pakinCount > 0) {
                throw new CoolException("单据已组托,仅未组托状态可取消,请先解除组托!!");
            }
            // 仅未执行状态可取消(入库未执行、出库任务初始)
            List<Short> list = Arrays.asList(AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val,
                    AsnExceStatus.OUT_STOCK_STATUS_TASK_INIT.val);
            WkOrder wkOrder = asnOrderService.getOne(new LambdaQueryWrapper<WkOrder>()
                    .in(WkOrder::getExceStatus, list)
                    .eq(WkOrder::getCode, order.getOrderNo()));
            if (Objects.isNull(wkOrder)) {
                throw new CoolException("订单:" + wkOrder.getCode() + ",当前状态,不可执行删除操作!!");
            if (!list.contains(finalWkOrder.getExceStatus())) {
                throw new CoolException("仅未执行状态的单据可取消!!");
            }
            order.getOrderItems().forEach(orderItem -> {
                if (!asnOrderItemService.remove(new LambdaQueryWrapper<WkOrderItem>()
                        .eq(WkOrderItem::getMatnrCode, orderItem.getMatnr())
                        .eq(StringUtils.isNotEmpty(orderItem.getBatch()), WkOrderItem::getSplrBatch, orderItem.getBatch())
                        .eq(StringUtils.isNotEmpty(orderItem.getPlatItemId()), WkOrderItem::getPlatItemId, orderItem.getPlatItemId())
                        .eq(WkOrderItem::getOrderCode, wkOrder.getCode()))) {
                        .eq(WkOrderItem::getOrderCode, finalWkOrder.getCode()))) {
                    throw new CoolException("单据明细删除失败!!");
                }
                List<WkOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, wkOrder.getId()));
                List<WkOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, finalWkOrder.getId()));
                if (orderItems.isEmpty()) {
                    if (!asnOrderService.removeById(wkOrder.getId())) {
                    if (!asnOrderService.removeById(finalWkOrder.getId())) {
                        throw new CoolException("单据删除失败!!");
                    }
                } else {
                    Double sum = orderItems.stream().mapToDouble(WkOrderItem::getAnfme).sum();
                    Double sum = QuantityUtils.roundToScale(orderItems.stream().mapToDouble(WkOrderItem::getAnfme).sum());
                    if (!asnOrderService.update(new LambdaUpdateWrapper<WkOrder>()
                            .eq(WkOrder::getId, wkOrder.getId())
                            .eq(WkOrder::getId, finalWkOrder.getId())
                            .set(WkOrder::getAnfme, sum))) {
                        throw new CoolException("主单数量修改失败!!");
                    }
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
@@ -45,7 +45,6 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
@@ -878,6 +877,7 @@
                        throw new CoolException("任务状态修改失败!!当前任务状态:" + task.getTaskStatus() + ",目标状态:" + TaskStsType.COMPLETE_IN.id);
                    }
                    log.info("入库任务状态更新成功 - 任务编码:{}", task.getTaskCode());
                    // 入库完整闭环由定时任务完成:TaskSchedules.completeInStock 扫描 COMPLETE_IN,执行库位/组托/上报云仓
                }
            } else if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)
@@ -920,33 +920,7 @@
                        throw new CoolException("任务状态修改失败!!当前任务状态:" + task.getTaskStatus() + ",目标状态:" + TaskStsType.COMPLETE_OUT.id);
                    }
                    log.info("出库任务状态更新成功 - 任务编码:{}", task.getTaskCode());
                    // 全版出库在RCS回调后处理库存并设置为199,等待PDA快速拣货确认后更新为200
                    if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) {
                        log.info("全版出库任务,开始处理库存并更新状态为199 - 任务编码:{}", task.getTaskCode());
                        try {
                            // 重新查询任务以获取最新状态(198)
                            task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getTaskCode, task.getTaskCode()));
                            // 调用completeTask处理库存(会设置为199)
                            List<Task> taskList = new ArrayList<>();
                            taskList.add(task);
                            taskService.completeTask(taskList);
                            // 重新查询任务以获取最新状态(199)
                            task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getTaskCode, task.getTaskCode()));
                            if (task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)) {
                                log.info("全版出库任务状态已更新为199(等待PDA快速拣货确认后更新为200) - 任务编码:{}", task.getTaskCode());
                            } else {
                                log.warn("全版出库任务状态更新为199失败 - 任务编码:{},当前状态:{}",
                                        task.getTaskCode(), task.getTaskStatus());
                            }
                        } catch (Exception e) {
                            log.error("全版出库任务处理失败 - 任务编码:{},错误:{}", task.getTaskCode(), e.getMessage(), e);
                            // 不抛出异常,避免影响RCS回调的正常返回
                        }
                    }
                    // 出库完整闭环(库存、出库单、9.1 上报云仓)由定时任务 TaskSchedules.complateOutStock 统一执行
                }
            }
        } else {
rsf-server/src/main/java/com/vincent/rsf/server/common/event/DictDataChangedEvent.java
New file
@@ -0,0 +1,20 @@
package com.vincent.rsf.server.common.event;
import org.springframework.context.ApplicationEvent;
/**
 * 字典数据变更事件,用于通知依赖该字典的缓存刷新(如订单业务类型)。
 */
public class DictDataChangedEvent extends ApplicationEvent {
    private final String dictTypeCode;
    public DictDataChangedEvent(Object source, String dictTypeCode) {
        super(source);
        this.dictTypeCode = dictTypeCode;
    }
    public String getDictTypeCode() {
        return dictTypeCode;
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/common/utils/QuantityUtils.java
@@ -66,7 +66,25 @@
    }
    /**
     * 统一舍入到 6 位小数后转 Double(用于存库/展示,避免浮点尾差)
     * 乘法:a * b,结果保留 6 位小数转 Double
     */
    public static Double multiply(Double a, Double b) {
        return toBigDecimal(a).multiply(toBigDecimal(b)).setScale(SCALE, ROUNDING).doubleValue();
    }
    /**
     * 除法:a / b,结果保留 6 位小数转 Double(b=0 时返回 0)
     */
    public static Double divide(Double a, Double b) {
        if (b == null || toBigDecimal(b).compareTo(BigDecimal.ZERO) == 0) {
            return 0.0;
        }
        return toBigDecimal(a).divide(toBigDecimal(b), SCALE, ROUNDING).doubleValue();
    }
    /**
     * 统一舍入到 6 位小数后转 Double(用于存库/展示、入参校验,避免浮点尾差)。
     * 所有 Double 写入实体或参与比较前建议经此方法或 add/subtract 做精度控制。
     */
    public static Double roundToScale(Double v) {
        if (v == null) {
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaitPakinController.java
@@ -52,26 +52,58 @@
    @PostMapping("/waitPakin/page")
    public R page(@RequestBody Map<String, Object> map) {
        BaseParam baseParam = buildParam(map, BaseParam.class);
        // 单据组托按单号查询:单号在明细表 asn_code,从 map 取出并移除,避免主表无此字段报错
        String asnCode = null;
        if (baseParam.getMap() != null && baseParam.getMap().containsKey("asnCode")) {
            Object v = baseParam.getMap().get("asnCode");
            if (v != null && StringUtils.isNotBlank(v.toString())) {
                asnCode = v.toString().trim();
            }
            baseParam.getMap().remove("asnCode");
        }
        PageParam<WaitPakin, BaseParam> pageParam = new PageParam<>(baseParam, WaitPakin.class);
        return R.ok().add(waitPakinService.page(pageParam, pageParam.buildWrapper(true)));
        com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<WaitPakin> qw = pageParam.buildWrapper(true);
        if (StringUtils.isNotBlank(asnCode)) {
            List<Long> pakinIds = waitPakinItemService.list(
                    new LambdaQueryWrapper<WaitPakinItem>()
                            .select(WaitPakinItem::getPakinId)
                            .like(WaitPakinItem::getAsnCode, asnCode))
                    .stream().map(WaitPakinItem::getPakinId).distinct().collect(Collectors.toList());
            if (pakinIds.isEmpty()) {
                qw.and(w -> w.apply("1 = 0"));
            } else {
                qw.in("id", pakinIds);
            }
        }
        Page<WaitPakin> page = waitPakinService.page(pageParam, qw);
        fillAsnCodes(page.getRecords());
        return R.ok().add(page);
    }
    @PreAuthorize("hasAuthority('manager:waitPakin:list')")
    @PostMapping("/waitPakin/list")
    public R list(@RequestBody Map<String, Object> map) {
        return R.ok().add(waitPakinService.list());
        List<WaitPakin> list = waitPakinService.list();
        fillAsnCodes(list);
        return R.ok().add(list);
    }
    @PreAuthorize("hasAuthority('manager:waitPakin:list')")
    @PostMapping({"/waitPakin/many/{ids}", "/waitPakins/many/{ids}"})
    public R many(@PathVariable Long[] ids) {
        return R.ok().add(waitPakinService.listByIds(Arrays.asList(ids)));
        List<WaitPakin> list = waitPakinService.listByIds(Arrays.asList(ids));
        fillAsnCodes(list);
        return R.ok().add(list);
    }
    @PreAuthorize("hasAuthority('manager:waitPakin:list')")
    @GetMapping("/waitPakin/{id}")
    public R get(@PathVariable("id") Long id) {
        return R.ok().add(waitPakinService.getById(id));
        WaitPakin one = waitPakinService.getById(id);
        if (one != null) {
            fillAsnCodes(Collections.singletonList(one));
        }
        return R.ok().add(one);
    }
    @PreAuthorize("hasAuthority('manager:waitPakin:save')")
@@ -143,7 +175,9 @@
    @PreAuthorize("hasAuthority('manager:waitPakin:list')")
    @PostMapping("/waitPakin/export")
    public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception {
        ExcelUtil.build(ExcelUtil.create(waitPakinService.list(), WaitPakin.class), response);
        List<WaitPakin> list = waitPakinService.list();
        fillAsnCodes(list);
        ExcelUtil.build(ExcelUtil.create(list, WaitPakin.class), response);
    }
@@ -160,4 +194,28 @@
        return  taskService.generateTasks(taskParams, getLoginUserId());
    }
    /**
     * 根据组托明细填充主档的关联入库通知单号(asnCodes),多个单号逗号分隔
     */
    private void fillAsnCodes(List<WaitPakin> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        List<Long> pakinIds = list.stream().map(WaitPakin::getId).collect(Collectors.toList());
        List<WaitPakinItem> items = waitPakinItemService.list(
                new LambdaQueryWrapper<WaitPakinItem>()
                        .in(WaitPakinItem::getPakinId, pakinIds)
                        .select(WaitPakinItem::getPakinId, WaitPakinItem::getAsnCode));
        Map<Long, String> asnCodesByPakinId = pakinIds.stream().collect(Collectors.toMap(
                pid -> pid,
                pid -> items.stream()
                        .filter(i -> pid.equals(i.getPakinId()) && i.getAsnCode() != null && !i.getAsnCode().trim().isEmpty())
                        .map(WaitPakinItem::getAsnCode)
                        .distinct()
                        .collect(Collectors.joining(","))));
        for (WaitPakin p : list) {
            p.setAsnCodes(asnCodesByPakinId.get(p.getId()));
        }
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaitPakinLogController.java
@@ -9,7 +9,9 @@
import com.vincent.rsf.server.common.domain.BaseParam;
import com.vincent.rsf.server.common.domain.KeyValVo;
import com.vincent.rsf.server.common.domain.PageParam;
import com.vincent.rsf.server.manager.entity.WaitPakinItemLog;
import com.vincent.rsf.server.manager.entity.WaitPakinLog;
import com.vincent.rsf.server.manager.service.WaitPakinItemLogService;
import com.vincent.rsf.server.manager.service.WaitPakinLogService;
import com.vincent.rsf.server.system.controller.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
@@ -18,37 +20,50 @@
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
@RestController
public class WaitPakinLogController extends BaseController {
    @Autowired
    private WaitPakinLogService waitPakinLogService;
    @Autowired
    private WaitPakinItemLogService waitPakinItemLogService;
    @PreAuthorize("hasAuthority('manager:waitPakinLog:list')")
    @PostMapping("/waitPakinLog/page")
    public R page(@RequestBody Map<String, Object> map) {
        BaseParam baseParam = buildParam(map, BaseParam.class);
        PageParam<WaitPakinLog, BaseParam> pageParam = new PageParam<>(baseParam, WaitPakinLog.class);
        return R.ok().add(waitPakinLogService.page(pageParam, pageParam.buildWrapper(true)));
        Page<WaitPakinLog> page = waitPakinLogService.page(pageParam, pageParam.buildWrapper(true));
        fillAsnCodesForLog(page.getRecords());
        return R.ok().add(page);
    }
    @PreAuthorize("hasAuthority('manager:waitPakinLog:list')")
    @PostMapping("/waitPakinLog/list")
    public R list(@RequestBody Map<String, Object> map) {
        return R.ok().add(waitPakinLogService.list());
        List<WaitPakinLog> list = waitPakinLogService.list();
        fillAsnCodesForLog(list);
        return R.ok().add(list);
    }
    @PreAuthorize("hasAuthority('manager:waitPakinLog:list')")
    @PostMapping({"/waitPakinLog/many/{ids}", "/waitPakinLogs/many/{ids}"})
    public R many(@PathVariable Long[] ids) {
        return R.ok().add(waitPakinLogService.listByIds(Arrays.asList(ids)));
        List<WaitPakinLog> list = waitPakinLogService.listByIds(Arrays.asList(ids));
        fillAsnCodesForLog(list);
        return R.ok().add(list);
    }
    @PreAuthorize("hasAuthority('manager:waitPakinLog:list')")
    @GetMapping("/waitPakinLog/{id}")
    public R get(@PathVariable("id") Long id) {
        return R.ok().add(waitPakinLogService.getById(id));
        WaitPakinLog one = waitPakinLogService.getById(id);
        if (one != null) {
            fillAsnCodesForLog(Collections.singletonList(one));
        }
        return R.ok().add(one);
    }
    @PreAuthorize("hasAuthority('manager:waitPakinLog:save')")
@@ -104,7 +119,33 @@
    @PreAuthorize("hasAuthority('manager:waitPakinLog:list')")
    @PostMapping("/waitPakinLog/export")
    public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception {
        ExcelUtil.build(ExcelUtil.create(waitPakinLogService.list(), WaitPakinLog.class), response);
        List<WaitPakinLog> list = waitPakinLogService.list();
        fillAsnCodesForLog(list);
        ExcelUtil.build(ExcelUtil.create(list, WaitPakinLog.class), response);
    }
    /**
     * 根据组托历史明细填充主档的关联入库通知单号(asnCodes),与组托通知档保持一致
     */
    private void fillAsnCodesForLog(List<WaitPakinLog> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        List<Long> logIds = list.stream().map(WaitPakinLog::getId).collect(Collectors.toList());
        List<WaitPakinItemLog> items = waitPakinItemLogService.list(
                new LambdaQueryWrapper<WaitPakinItemLog>()
                        .in(WaitPakinItemLog::getLogId, logIds)
                        .select(WaitPakinItemLog::getLogId, WaitPakinItemLog::getAsnCode));
        Map<Long, String> asnCodesByLogId = logIds.stream().collect(Collectors.toMap(
                logId -> logId,
                logId -> items.stream()
                        .filter(i -> logId.equals(i.getLogId()) && i.getAsnCode() != null && !i.getAsnCode().trim().isEmpty())
                        .map(WaitPakinItemLog::getAsnCode)
                        .distinct()
                        .collect(Collectors.joining(","))));
        for (WaitPakinLog p : list) {
            p.setAsnCodes(asnCodesByLogId.get(p.getId()));
        }
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/AsnOrderLog.java
@@ -53,9 +53,9 @@
    private String code;
    /**
     * PO单号
     * 单据内码
     */
    @ApiModelProperty(value= "PO单号")
    @ApiModelProperty(value= "单据内码")
    private String poCode;
    /**
@@ -195,7 +195,7 @@
//    AsnOrderLog asnOrderLog = new AsnOrderLog(
//            null,    // 编号
//            null,    // PO单号
//            null,    // 单据内码
//            null,    // PO单据标识
//            null,    // 单据类型[非空]
//            null,    // 业务类型[非空]
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/BasContainer.java
@@ -49,9 +49,9 @@
    private Long containerType;
    /**
     * 容器条码类型
     * 料箱条码类型
     */
    @ApiModelProperty(value= "容器条码类型")
    @ApiModelProperty(value= "料箱条码类型")
    private String codeType;
    @ApiModelProperty("是否满箱")
@@ -134,7 +134,7 @@
//    BasContainer basContainer = new BasContainer(
//            null,    // 容器类型
//            null,    // 容器条码类型
//            null,    // 料箱条码类型
//            null,    // 可入库区
//            null,    // 是否删除
//            null,    // 状态
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/ReviseLog.java
@@ -70,9 +70,9 @@
    private Integer type;
    /**
     * 容器码
     * 料箱码
     */
    @ApiModelProperty(value= "容器码")
    @ApiModelProperty(value= "料箱码")
    private String barcode;
    /**
@@ -187,7 +187,7 @@
//            null,    // 仓库ID
//            null,    // 库区ID
//            null,    // 类型
//            null,    // 容器码
//            null,    // 料箱码
//            null,    // 库位状态
//            null,    // 巷道
//            null,    // 排
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/TaskItem.java
@@ -183,7 +183,7 @@
    @ApiModelProperty(value= "添加人员")
    private Long createBy;
    /**现品票号*/
    /** 现品票号(已废弃,无此概念) */
    @TableField(exist = false)
    private String crushNo;
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WaitPakin.java
@@ -15,6 +15,7 @@
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -50,9 +51,9 @@
    private String code;
    /**
     * 容器码
     * 料箱码
     */
    @ApiModelProperty(value= "容器码")
    @ApiModelProperty(value= "料箱码")
    private String barcode;
    /**
@@ -126,6 +127,13 @@
    @ApiModelProperty(value= "备注")
    private String memo;
    /**
     * 关联的入库通知单号(多个用逗号分隔),仅查询展示用,不落库
     */
    @ApiModelProperty(value = "关联的入库通知单号,多个用逗号分隔")
    @TableField(exist = false)
    private String asnCodes;
    public WaitPakin() {}
    public WaitPakin(String code,String barcode,Double anfme,Short ioStatus,Integer status,Integer deleted,Integer tenantId,Long createBy,Date createTime,Long updateBy,Date updateTime,String memo) {
@@ -147,7 +155,7 @@
//            null,    // 编码
//            null,    // 订单ID
//            null,    // 订单编码
//            null,    // 容器码
//            null,    // 料箱码
//            null,    // 组拖数量
//            null,    // 组拖状态
//            null,    // 状态[非空]
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WaitPakinLog.java
@@ -11,6 +11,7 @@
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -51,9 +52,9 @@
    private String code;
    /**
     * 容器码
     * 料箱码
     */
    @ApiModelProperty(value= "容器码")
    @ApiModelProperty(value= "料箱码")
    private String barcode;
    /**
@@ -67,6 +68,13 @@
     */
    @ApiModelProperty(value= "组拖状态 0: 待入库   1:  入库中  ")
    private Short ioStatus;
    /**
     * 关联的入库通知单号(多个用逗号分隔),仅查询展示用,不落库
     */
    @ApiModelProperty(value = "关联的入库通知单号,多个用逗号分隔")
    @TableField(exist = false)
    private String asnCodes;
    /**
     * 状态 1: 正常  0: 冻结  
@@ -142,7 +150,7 @@
//    WaitPakinLog waitPakinLog = new WaitPakinLog(
//            null,    // 主单ID
//            null,    // 编码
//            null,    // 容器码
//            null,    // 料箱码
//            null,    // 组拖数量
//            null,    // 组拖状态[非空]
//            null,    // 状态[非空]
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WkOrder.java
@@ -50,9 +50,9 @@
    private String code;
    /**
     * PO单号
     * 单据内码
     */
    @ApiModelProperty(value = "PO单号")
    @ApiModelProperty(value = "单据内码")
    private String poCode;
    /**
@@ -61,6 +61,11 @@
    @ApiModelProperty(value = "PO单据标识")
    private Long poId;
    /** 入/出库接驳站点(8.3 stationId) */
    @ApiModelProperty(value = "接驳站点")
    @com.baomidou.mybatisplus.annotation.TableField("station_id")
    private String stationId;
    /**
     * 单据类型
     */
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/WkOrderItem.java
@@ -145,6 +145,23 @@
     */
    @ApiModelProperty("库存批次")
    private String batch;
    @ApiModelProperty("计划跟踪号(8.3 planNo)")
    @com.baomidou.mybatisplus.annotation.TableField("plan_no")
    private String planNo;
    @ApiModelProperty("托盘码(8.3 palletId)")
    @com.baomidou.mybatisplus.annotation.TableField("pallet_id")
    private String palletId;
    @ApiModelProperty("建议入库仓库(8.3 targetWareHouseId)")
    @com.baomidou.mybatisplus.annotation.TableField("target_ware_house_id")
    private String targetWareHouseId;
    @ApiModelProperty("建议出库仓库(8.3 sourceWareHouseId)")
    @com.baomidou.mybatisplus.annotation.TableField("source_ware_house_id")
    private String sourceWareHouseId;
    /**
     * 采购单位
     */
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/AsnOrderTemplate.java
@@ -34,10 +34,10 @@
    private String code;
    /**
     * PO单号
     * 单据内码
     */
    @Excel(name = "PO单号")
    @ApiModelProperty(value = "PO单号")
    @Excel(name = "单据内码")
    @ApiModelProperty(value = "单据内码")
    @ExcelComment(value = "poCode", example = "PO59755695")
    private String poCode;
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/OutStockTemplate.java
@@ -28,7 +28,7 @@
    private String code;
    /**
     * PO单号
     * 单据内码
     */
    @Excel(name = "DO单号")
    @ApiModelProperty(value = "DO单号")
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/PurchaseTemplate.java
@@ -17,8 +17,8 @@
    private static final long serialVersionUID = 1L;
    @Excel(name = "*PO单号")
    @ApiModelProperty(value= "*PO单号")
    @Excel(name = "*单据内码")
    @ApiModelProperty(value= "*单据内码")
    @ExcelComment(value = "poCode", example = "PO25413975")
    private String poCode;
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/TransferTemplate.java
@@ -14,10 +14,10 @@
    private String code;
    /**
     * PO单号
     * 单据内码
     */
    @Excel(name = "PO单号")
    @ApiModelProperty(value = "PO单号")
    @Excel(name = "单据内码")
    @ApiModelProperty(value = "单据内码")
    @ExcelComment(value = "poCode", example = "PO59755695")
    private String poCode;
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/AsnExceStatus.java
@@ -9,11 +9,14 @@
 */
public enum AsnExceStatus {
    //ASN执行状态状态
    // ASN/入库单执行状态(新顺序):未执行(组托) → 任务执行中 → 已完成
    ASN_EXCE_STATUS_UN_EXCE("0", "未执行"),
    /** @deprecated 已停用,新流程不再使用 */
    ASN_EXCE_STATUS_EXCE_ING("1", "执行中"),
    /** @deprecated 已停用,新流程不再使用 */
    ASN_EXCE_STATUS_RECEIPT_DONE("2", "收货完成"),
    ASN_EXCE_STATUS_TASK_EXCE("3", "任务执行中"),
    /** 已完成:整单全流程结束(收货+组托+上架/入库任务等),可归档历史、上报 ERP;由组托/任务定时或移历史时设置 */
    ASN_EXCE_STATUS_TASK_DONE("4", "已完成"),
    ASN_EXCE_STATUS_TASK_CANCEL("8", "取消"),
    ASN_EXCE_STATUS_TASK_CLOSE("9", "已关闭"),
rsf-server/src/main/java/com/vincent/rsf/server/manager/listener/OrderWorkTypeRefreshListener.java
New file
@@ -0,0 +1,36 @@
package com.vincent.rsf.server.manager.listener;
import com.vincent.rsf.server.common.event.DictDataChangedEvent;
import com.vincent.rsf.server.manager.service.OrderTypeDictService;
import com.vincent.rsf.server.manager.service.OrderWorkTypeService;
import com.vincent.rsf.server.system.constant.DictTypeCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
 * 字典数据变更时刷新订单业务类型、订单类型缓存,使配置改完立刻生效。
 */
@Slf4j
@Component
public class OrderWorkTypeRefreshListener {
    @Resource
    private OrderWorkTypeService orderWorkTypeService;
    @Resource
    private OrderTypeDictService orderTypeDictService;
    @EventListener
    public void onDictDataChanged(DictDataChangedEvent event) {
        if (DictTypeCode.DICT_ORDER_WORK_TYPE.equals(event.getDictTypeCode())) {
            orderWorkTypeService.refreshCache();
            log.debug("订单业务类型字典已变更,已刷新缓存");
        }
        if (DictTypeCode.DICT_SYS_ORDER_TYPE.equals(event.getDictTypeCode())) {
            orderTypeDictService.refreshCache();
            log.debug("订单类型字典已变更,已刷新缓存");
        }
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/ScheduleJobs.java
@@ -27,6 +27,7 @@
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@@ -68,160 +69,156 @@
    @Autowired
    private FieldsItemService fieldsItemService;
    /**
     * @author Ryan
     * @date 2025/5/9
     * @description: 直接组托开关为true,将收货单直接加入临时库存
     * @version 1.0
     */
    @Scheduled(cron = "0/25 * * * * ?")
    @Transactional(rollbackFor = Exception.class)
    public synchronized void IgnoreReceipt() {
        Config config = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.DIRECT_WAIT_PAKIN));
        if (Objects.isNull(config)) {
            return;
        }
        if (!Boolean.parseBoolean(config.getVal())) {
            return;
        }
        //自动收货单
        List<WkOrder> orders = asnOrderService.list(new LambdaQueryWrapper<WkOrder>()
                .eq(WkOrder::getType, OrderType.ORDER_IN.type)
                .eq(WkOrder::getExceStatus, AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val));
         if (!orders.isEmpty()) {
            for (WkOrder order : orders) {
                if (order.getWkType().equals(OrderWorkType.ORDER_WORK_TYPE_OTHER_TERANSFER.type)) {
                    WkOrder one = outStockService.getOne(new LambdaQueryWrapper<WkOrder>()
                            .eq(WkOrder::getPoCode, order.getPoCode())
                            .eq(WkOrder::getWkType, OrderWorkType.ORDER_WORK_TYPE_STOCK_TERANSFER.type));
                    if (Objects.isNull(one)) {
                        throw new CoolException("数据错误");
                    }
                    if (!one.getExceStatus().equals(AsnExceStatus.OUT_STOCK_STATUS_TASK_DONE.val)) {
                        continue;
                    }
                }
                List<WkOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, order.getId()));
                if (orderItems.isEmpty()) {
                    return;
                }
                List<WarehouseAreasItem> items = new ArrayList<>();
                for (WkOrderItem item : orderItems) {
                    WarehouseAreas one = warehouseAreasService.getOne(new LambdaQueryWrapper<WarehouseAreas>()
                            .eq(WarehouseAreas::getType, WarehouseAreasType.WAREHOUSE_AREAS_TYPE_RECEIPT.type), false);
                    Long areaId = Objects.isNull(one) ? null : one.getId();
                    String areaName = Objects.isNull(one) ? null : one.getName();
                    WarehouseAreasItem param = new WarehouseAreasItem();
                    BeanUtils.copyProperties(item, param);
                    param.setAreaId(one.getId())
                            .setAsnCode(order.getCode())
                            .setAreaId(areaId)
                            .setAreaName(areaName)
                            .setAsnId(order.getId());
                    items.add(param);
                    Matnr matnr = matnrService.getOne(new LambdaQueryWrapper<Matnr>().eq(Matnr::getId, item.getMatnrId()));
                    if (Objects.isNull(matnr)) {
                        throw new CoolException("物料不存在!!");
                    }
                    //更新收货区库存
                    try {
                        updateReceipt(one, item, order, matnr);
                    } catch (Exception e) {
                        throw new CoolException(e.getMessage());
                    }
                    if (!asnOrderItemService.update(new LambdaUpdateWrapper<WkOrderItem>().set(WkOrderItem::getQty, item.getAnfme()).eq(WkOrderItem::getId, item.getId()))) {
                        throw new CoolException("收货单明细完成数量修改失败!!");
                    }
                }
//                if (!warehouseAreasItemService.saveBatch(items)) {
//                    throw new CoolException("收货单保存至收货区执行失败!!");
//    /**
//     * @author Ryan
//     * @date 2025/5/9
//     * @description: 直接组托开关为true,将收货单直接加入临时库存
//     * @version 1.0
//     */
//    @Scheduled(cron = "0/25 * * * * ?")
//    @Transactional(rollbackFor = Exception.class)
//    public synchronized void IgnoreReceipt() {
//        Config config = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.DIRECT_WAIT_PAKIN));
//        if (Objects.isNull(config)) {
//            return;
//        }
//        if (!Boolean.parseBoolean(config.getVal())) {
//            return;
//        }
//        //自动收货单
//        List<WkOrder> orders = asnOrderService.list(new LambdaQueryWrapper<WkOrder>()
//                .eq(WkOrder::getType, OrderType.ORDER_IN.type)
//                .eq(WkOrder::getExceStatus, AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val));
//         if (!orders.isEmpty()) {
//            for (WkOrder order : orders) {
//                if (order.getWkType().equals(OrderWorkType.ORDER_WORK_TYPE_OTHER_TERANSFER.type)) {
//                    WkOrder one = outStockService.getOne(new LambdaQueryWrapper<WkOrder>()
//                            .eq(WkOrder::getPoCode, order.getPoCode())
//                            .eq(WkOrder::getWkType, OrderWorkType.ORDER_WORK_TYPE_STOCK_TERANSFER.type));
//                    if (Objects.isNull(one)) {
//                        throw new CoolException("数据错误");
//                    }
//                    if (!one.getExceStatus().equals(AsnExceStatus.OUT_STOCK_STATUS_TASK_DONE.val)) {
//                        continue;
//                    }
//                }
//
//                List<WkOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, order.getId()));
//                if (orderItems.isEmpty()) {
//                    return;
//                }
//                // 收货区已停用:不再写入收货区,仅更新单据状态与数量
////                List<WarehouseAreas> receiptAreas = warehouseAreasService.list(new LambdaQueryWrapper<WarehouseAreas>()
////                        .eq(WarehouseAreas::getType, WarehouseAreasType.WAREHOUSE_AREAS_TYPE_RECEIPT.type));
////                WarehouseAreas receiptArea = receiptAreas.isEmpty() ? null : receiptAreas.get(0);
////                List<WarehouseAreasItem> items = new ArrayList<>();
//                for (WkOrderItem item : orderItems) {
////                    Long areaId = receiptArea == null ? null : receiptArea.getId();
////                    String areaName = receiptArea == null ? null : receiptArea.getName();
////                    WarehouseAreasItem param = new WarehouseAreasItem();
////                    BeanUtils.copyProperties(item, param);
////                    param.setAsnCode(order.getCode()).setAsnId(order.getId());
////                    if (areaId != null) {
////                        param.setAreaId(areaId).setAreaName(areaName);
////                    }
////                    items.add(param);
////                    Matnr matnr = matnrService.getOne(new LambdaQueryWrapper<Matnr>().eq(Matnr::getId, item.getMatnrId()));
////                    if (Objects.isNull(matnr)) {
////                        throw new CoolException("物料不存在!!");
////                    }
////                    if (receiptArea != null) {
////                        try {
////                            updateReceipt(receiptArea, item, order, matnr);
////                        } catch (Exception e) {
////                            throw new CoolException(e.getMessage());
////                        }
////                    }
//                    if (!asnOrderItemService.update(new LambdaUpdateWrapper<WkOrderItem>().set(WkOrderItem::getQty, item.getAnfme()).eq(WkOrderItem::getId, item.getId()))) {
//                        throw new CoolException("收货单明细完成数量修改失败!!");
//                    }
//                }
////                if (!warehouseAreasItemService.saveBatch(items)) {
////                    throw new CoolException("收货单保存至收货区执行失败!!");
////                }
//
//                if (!asnOrderService.update(new LambdaUpdateWrapper<WkOrder>()
//                        .set(WkOrder::getQty, order.getAnfme())
//                        .set(WkOrder::getExceStatus, AsnExceStatus.ASN_EXCE_STATUS_RECEIPT_DONE.val)
//                        .eq(WkOrder::getId, order.getId()))) {
//                    throw new CoolException("收货单状态修改失败!!");
//                }
//            }
//        }
//                }
                if (!asnOrderService.update(new LambdaUpdateWrapper<WkOrder>()
                        .set(WkOrder::getQty, order.getAnfme())
                        .set(WkOrder::getExceStatus, AsnExceStatus.ASN_EXCE_STATUS_RECEIPT_DONE.val)
                        .eq(WkOrder::getId, order.getId()))) {
                    throw new CoolException("收货单状态修改失败!!");
                }
            }
        }
    }
    /**
    /** 收货区已停用,方法整体注释
     * @author Ryan
     * @date 2025/5/12
     * @description: 收货区库存更新
     * @version 1.0
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateReceipt(WarehouseAreas areasItem, WkOrderItem orderItem, WkOrder wkOrder, Matnr matnr) throws Exception {
        Companys companys = new Companys();
        if (StringUtils.isNoneBlank(orderItem.getSplrCode())) {
            companys = companysService.getOne(new LambdaQueryWrapper<Companys>().eq(Companys::getCode, orderItem.getSplrCode()));
        }
        WarehouseAreasItem item = new WarehouseAreasItem();
        item.setTrackCode(orderItem.getBarcode())
                .setAreaName(areasItem.getName())
                .setAreaId(areasItem.getId())
                .setAsnItemId(orderItem.getId())
                .setAsnCode(wkOrder.getCode())
                .setAsnId(wkOrder.getId())
                .setProdTime(orderItem.getProdTime())
                .setPlatItemId(orderItem.getPlatItemId())
                .setPlatOrderCode(orderItem.getPlatOrderCode())
                .setPlatWorkCode(orderItem.getPlatWorkCode())
                .setProjectCode(orderItem.getProjectCode())
                .setSplrId(companys.getId())
                //库存单位为最小单位
                .setUnit(orderItem.getStockUnit())
                .setStockUnit(orderItem.getStockUnit())
                .setMatnrCode(matnr.getCode())
                .setAnfme(orderItem.getAnfme())
                .setMatnrId(matnr.getId())
                .setIsptResult(orderItem.getIsptResult())
                .setMaktx(matnr.getName())
                .setSplrBatch(orderItem.getSplrBatch())
                .setWeight(matnr.getWeight())
                .setFieldsIndex(orderItem.getFieldsIndex())
                .setShipperId(matnr.getShipperId());
        WarehouseAreasItem warehousItem = warehouseAreasItemService.getOne(new LambdaQueryWrapper<WarehouseAreasItem>().eq(StringUtils.isNotBlank(orderItem.getFieldsIndex()), WarehouseAreasItem::getFieldsIndex, orderItem.getFieldsIndex()));
        if (!Objects.isNull(warehousItem)) {
            //相同票号,收货区不可新增相同票号数据
            FieldsItem fieldsItem = fieldsItemService.getOne(new LambdaQueryWrapper<FieldsItem>()
                    .eq(FieldsItem::getUuid, orderItem.getFieldsIndex()).last("LIMIT 1"));
            if (!Objects.isNull(fieldsItem)) {
                throw new CoolException("票号:" + fieldsItem.getValue() + "已在收货区,不可推送相当票号数据。请联系管理员!!" );
            }
        }
        LambdaQueryWrapper<WarehouseAreasItem> queryWrapper = new LambdaQueryWrapper<WarehouseAreasItem>()
                .eq(WarehouseAreasItem::getMatnrCode, orderItem.getMatnrCode())
                .eq(!Cools.isEmpty(orderItem.getFieldsIndex()), WarehouseAreasItem::getFieldsIndex, orderItem.getFieldsIndex())
                .eq(WarehouseAreasItem::getAsnCode, orderItem.getOrderCode())
                .eq(StringUtils.isNotBlank(orderItem.getSplrBatch()), WarehouseAreasItem::getSplrBatch, orderItem.getSplrBatch());
        if (Objects.isNull(orderItem.getIsptResult())) {
            queryWrapper.isNull(WarehouseAreasItem::getIsptResult);
        } else {
            queryWrapper.eq(WarehouseAreasItem::getIsptResult, orderItem.getIsptResult());
        }
        WarehouseAreasItem serviceOne = warehouseAreasItemService.getOne(queryWrapper);
        if (!Objects.isNull(serviceOne)) {
            item.setId(serviceOne.getId());
            Double anfme = Math.round((item.getAnfme() + serviceOne.getAnfme()) * 1000000) / 1000000.0;
            item.setAnfme(anfme);
        }
        //未质检
        if (!warehouseAreasItemService.saveOrUpdate(item)) {
            throw new CoolException("收货失败!!");
        }
    }
//    @Transactional(rollbackFor = Exception.class)
//    public void updateReceipt(WarehouseAreas areasItem, WkOrderItem orderItem, WkOrder wkOrder, Matnr matnr) throws Exception {
//        Companys companys = new Companys();
//        if (StringUtils.isNoneBlank(orderItem.getSplrCode())) {
//            companys = companysService.getOne(new LambdaQueryWrapper<Companys>().eq(Companys::getCode, orderItem.getSplrCode()));
//        }
//        WarehouseAreasItem item = new WarehouseAreasItem();
//        item.setTrackCode(orderItem.getBarcode())
//                .setAreaName(areasItem.getName())
//                .setAreaId(areasItem.getId())
//                .setAsnItemId(orderItem.getId())
//                .setAsnCode(wkOrder.getCode())
//                .setAsnId(wkOrder.getId())
//                .setProdTime(orderItem.getProdTime())
//                .setPlatItemId(orderItem.getPlatItemId())
//                .setPlatOrderCode(orderItem.getPlatOrderCode())
//                .setPlatWorkCode(orderItem.getPlatWorkCode())
//                .setProjectCode(orderItem.getProjectCode())
//                .setSplrId(companys.getId())
//                .setUnit(orderItem.getStockUnit())
//                .setStockUnit(orderItem.getStockUnit())
//                .setMatnrCode(matnr.getCode())
//                .setAnfme(orderItem.getAnfme())
//                .setMatnrId(matnr.getId())
//                .setIsptResult(orderItem.getIsptResult())
//                .setMaktx(matnr.getName())
//                .setSplrBatch(orderItem.getSplrBatch())
//                .setWeight(matnr.getWeight())
//                .setFieldsIndex(orderItem.getFieldsIndex())
//                .setShipperId(matnr.getShipperId());
//        List<WarehouseAreasItem> warehousList = StringUtils.isNotBlank(orderItem.getFieldsIndex())
//                ? warehouseAreasItemService.list(new LambdaQueryWrapper<WarehouseAreasItem>().eq(WarehouseAreasItem::getFieldsIndex, orderItem.getFieldsIndex()))
//                : Collections.emptyList();
//        WarehouseAreasItem warehousItem = warehousList.isEmpty() ? null : warehousList.get(0);
//        if (!Objects.isNull(warehousItem)) {
//            List<FieldsItem> fieldsList = fieldsItemService.list(new LambdaQueryWrapper<FieldsItem>()
//                    .eq(FieldsItem::getUuid, orderItem.getFieldsIndex()).last("LIMIT 1"));
//            FieldsItem fieldsItem = fieldsList.isEmpty() ? null : fieldsList.get(0);
//            if (!Objects.isNull(fieldsItem)) {
//                throw new CoolException("票号:" + fieldsItem.getValue() + "已在收货区,不可推送相当票号数据。请联系管理员!!" );
//            }
//        }
//        LambdaQueryWrapper<WarehouseAreasItem> queryWrapper = new LambdaQueryWrapper<WarehouseAreasItem>()
//                .eq(WarehouseAreasItem::getMatnrCode, orderItem.getMatnrCode())
//                .eq(!Cools.isEmpty(orderItem.getFieldsIndex()), WarehouseAreasItem::getFieldsIndex, orderItem.getFieldsIndex())
//                .eq(WarehouseAreasItem::getAsnCode, orderItem.getOrderCode())
//                .eq(StringUtils.isNotBlank(orderItem.getSplrBatch()), WarehouseAreasItem::getSplrBatch, orderItem.getSplrBatch());
//        if (Objects.isNull(orderItem.getIsptResult())) {
//            queryWrapper.isNull(WarehouseAreasItem::getIsptResult);
//        } else {
//            queryWrapper.eq(WarehouseAreasItem::getIsptResult, orderItem.getIsptResult());
//        }
//        List<WarehouseAreasItem> serviceList = warehouseAreasItemService.list(queryWrapper);
//        WarehouseAreasItem serviceOne = serviceList.isEmpty() ? null : serviceList.get(0);
//        if (!Objects.isNull(serviceOne)) {
//            item.setId(serviceOne.getId());
//            item.setAnfme(orderItem.getAnfme());
//        }
//        if (!warehouseAreasItemService.saveOrUpdate(item)) {
//            throw new CoolException("收货失败!!");
//        }
//    }
    /**
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java
@@ -104,10 +104,11 @@
    /**
     * @param
     * @return
     * 完成入库,更新库位明细、组托状态,并在此统一执行 9.1 入/出库结果上报云仓。
     * 与 RCS 回调形成闭环:RCS 上报任务结束后仅将任务状态置为 COMPLETE_IN(见 WcsServiceImpl.receiveExMsg),
     * 本定时任务扫描 COMPLETE_IN 并执行 complateInTask(库位、组托、9.1 上报云仓)。
     *
     * @author Ryan
     * @description 完成入库,更新库存
     * @time 2025/4/2 12:37
     */
    @Scheduled(cron = "0/3 * * * * ?")
@@ -122,10 +123,12 @@
    }
    /**
     * 完成出库任务,更新库位/出库单,并在此统一执行 9.1 入/出库结果上报云仓。
     * 与 RCS 回调形成闭环:RCS 上报 END 后仅将出库任务状态置为 COMPLETE_OUT(见 WcsServiceImpl.receiveExMsg),
     * 本定时任务扫描 COMPLETE_OUT 并执行 completeTask(扣库位、更新出库单、9.1 上报云仓)。
     *
     * @author Ryan
     * @date 2025/5/20
     * @description: 完成出库任务,更新库存
     * @version 1.0
     */
    @Scheduled(cron = "0/5 * * * * ?  ")
    @Transactional(rollbackFor = Exception.class)
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OrderTypeDictService.java
New file
@@ -0,0 +1,38 @@
package com.vincent.rsf.server.manager.service;
import com.vincent.rsf.server.system.entity.DictData;
import java.util.List;
/**
 * 订单类型字典:从字典表动态获取(出库单/入库单/调拨单等),兼容 API 的 1/2/3。
 */
public interface OrderTypeDictService {
    /**
     * 查询所有启用的订单类型(带缓存)
     */
    List<DictData> listAll();
    /**
     * 根据显示名称取类型编码,如 "出库单" -> "out"
     */
    String getTypeByLabel(String label);
    /**
     * 根据类型编码取显示名称,如 "out" -> "出库单"
     */
    String getLabelByType(String type);
    /**
     * 解析入参为内部类型编码。支持:数字 1/2/3、中文 "出库单"/"入库单"/"调拨单"、内部码 "out"/"in"/"transfer"
     */
    String resolveType(String input);
    /**
     * 解析 Integer 类型的 orderType(API 约定 1=出库 2=入库 3=调拨)
     */
    String resolveType(Integer orderType);
    void refreshCache();
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OrderWorkTypeService.java
New file
@@ -0,0 +1,31 @@
package com.vincent.rsf.server.manager.service;
import com.vincent.rsf.server.system.entity.DictData;
import java.util.List;
/**
 * 订单业务类型:从字典表动态获取与配置,替代/补充 OrderWorkType 枚举。
 */
public interface OrderWorkTypeService {
    /**
     * 查询所有启用的订单业务类型(带缓存,字典变更后需调用 refreshCache)
     */
    List<DictData> listAll();
    /**
     * 根据显示名称(label)取类型编码(value),如 "采购入库单" -> "1"
     */
    String getTypeByLabel(String label);
    /**
     * 根据类型编码(value)取显示名称(label),如 "1" -> "采购入库单"
     */
    String getLabelByType(String type);
    /**
     * 清除缓存,下次 listAll 时从数据库重新加载(字典数据变更后调用)
     */
    void refreshCache();
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderLogServiceImpl.java
@@ -50,7 +50,7 @@
        BeanUtils.copyProperties(orderLog, order);
        order.setId(orderLog.getAsnId())
                .setDeleted(0)
                .setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_EXCE_ING.val);
                .setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val); // 新顺序:不再使用执行中
        WkOrder wkOrder = asnOrderService.getOne(new LambdaQueryWrapper<WkOrder>().eq(WkOrder::getCode, orderLog.getCode()));
        if (!Objects.isNull(wkOrder)) {
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java
@@ -69,6 +69,8 @@
    private AsnOrderService asnOrderService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private WaitPakinItemService waitPakinItemService;
    @Override
    public boolean notifyInspect(List<WkOrder> orders) {
@@ -379,6 +381,12 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R removeOrders(List<Long> ids) {
        // 已组托不可删除,需先解除组托
        long palletizedCount = waitPakinItemService.count(new LambdaQueryWrapper<WaitPakinItem>()
                .in(WaitPakinItem::getAsnId, ids));
        if (palletizedCount > 0) {
            throw new CoolException("单据已组托,请先解除组托后再删除!!");
        }
        for (Long id : ids) {
            List<WkOrderItem> list = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>()
                    .eq(WkOrderItem::getOrderId, id));
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OrderTypeDictServiceImpl.java
New file
@@ -0,0 +1,98 @@
package com.vincent.rsf.server.manager.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.vincent.rsf.server.manager.enums.OrderType;
import com.vincent.rsf.server.manager.service.OrderTypeDictService;
import com.vincent.rsf.server.system.constant.DictTypeCode;
import com.vincent.rsf.server.system.entity.DictData;
import com.vincent.rsf.server.system.service.DictDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 订单类型:优先从字典表读取,兼容 API 数字 1/2/3 与枚举回退。
 */
@Slf4j
@Service
public class OrderTypeDictServiceImpl implements OrderTypeDictService {
    private static final Map<String, String> API_NUMERIC_MAP = new HashMap<>();
    static {
        API_NUMERIC_MAP.put("1", OrderType.ORDER_OUT.type);   // 出库单
        API_NUMERIC_MAP.put("2", OrderType.ORDER_IN.type);    // 入库单
        API_NUMERIC_MAP.put("3", OrderType.ORDER_TRANSFER.type); // 调拨单
    }
    @Resource
    private DictDataService dictDataService;
    private volatile List<DictData> cache;
    private static final Object CACHE_LOCK = new Object();
    @Override
    public List<DictData> listAll() {
        if (cache != null && !cache.isEmpty()) {
            return cache;
        }
        synchronized (CACHE_LOCK) {
            if (cache != null && !cache.isEmpty()) {
                return cache;
            }
            List<DictData> list = dictDataService.list(new LambdaQueryWrapper<DictData>()
                    .eq(DictData::getDictTypeCode, DictTypeCode.DICT_SYS_ORDER_TYPE)
                    .eq(DictData::getStatus, 1)
                    .orderByAsc(DictData::getSort));
            cache = list;
            return cache;
        }
    }
    @Override
    public String getTypeByLabel(String label) {
        if (label == null || label.isEmpty()) return null;
        for (DictData d : listAll()) {
            if (label.equals(d.getLabel())) return d.getValue();
        }
        return OrderType.getTypeVal(label);
    }
    @Override
    public String getLabelByType(String type) {
        if (type == null || type.isEmpty()) return null;
        for (DictData d : listAll()) {
            if (type.equals(d.getValue())) return d.getLabel();
        }
        return OrderType.getValType(type);
    }
    @Override
    public String resolveType(String input) {
        if (input == null) return null;
        String s = input.trim();
        if (s.isEmpty()) return null;
        if (API_NUMERIC_MAP.containsKey(s)) return API_NUMERIC_MAP.get(s);
        String byLabel = getTypeByLabel(s);
        if (byLabel != null) return byLabel;
        if (getLabelByType(s) != null) return s;
        return null;
    }
    @Override
    public String resolveType(Integer orderType) {
        if (orderType == null) return null;
        return API_NUMERIC_MAP.get(String.valueOf(orderType));
    }
    @Override
    public void refreshCache() {
        synchronized (CACHE_LOCK) {
            cache = null;
        }
        log.info("订单类型字典缓存已刷新");
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OrderWorkTypeServiceImpl.java
New file
@@ -0,0 +1,81 @@
package com.vincent.rsf.server.manager.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.vincent.rsf.server.manager.enums.OrderWorkType;
import com.vincent.rsf.server.manager.service.OrderWorkTypeService;
import com.vincent.rsf.server.system.constant.DictTypeCode;
import com.vincent.rsf.server.system.entity.DictData;
import com.vincent.rsf.server.system.service.DictDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
 * 订单业务类型:优先从字典表读取(可配置),无则回退到 OrderWorkType 枚举。
 */
@Slf4j
@Service
public class OrderWorkTypeServiceImpl implements OrderWorkTypeService {
    @Resource
    private DictDataService dictDataService;
    private volatile List<DictData> cache;
    private static final Object CACHE_LOCK = new Object();
    @Override
    public List<DictData> listAll() {
        if (cache != null && !cache.isEmpty()) {
            return cache;
        }
        synchronized (CACHE_LOCK) {
            if (cache != null && !cache.isEmpty()) {
                return cache;
            }
            List<DictData> list = dictDataService.list(new LambdaQueryWrapper<DictData>()
                    .eq(DictData::getDictTypeCode, DictTypeCode.DICT_ORDER_WORK_TYPE)
                    .eq(DictData::getStatus, 1)
                    .orderByAsc(DictData::getSort));
            cache = list;
            return cache;
        }
    }
    @Override
    public String getTypeByLabel(String label) {
        if (label == null || label.isEmpty()) {
            return null;
        }
        for (DictData d : listAll()) {
            if (label.equals(d.getLabel())) {
                return d.getValue();
            }
        }
        // 回退到枚举
        return OrderWorkType.getWorkType(label);
    }
    @Override
    public String getLabelByType(String type) {
        if (type == null || type.isEmpty()) {
            return null;
        }
        for (DictData d : listAll()) {
            if (type.equals(d.getValue())) {
                return d.getLabel();
            }
        }
        // 回退到枚举
        return OrderWorkType.getWorkDesc(type);
    }
    @Override
    public void refreshCache() {
        synchronized (CACHE_LOCK) {
            cache = null;
        }
        log.info("订单业务类型字典缓存已刷新");
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -467,16 +467,18 @@
        if (success.compareAndSet(false, true)) {
            Long loginUserId = SystemAuthUtils.getLoginUserId();
            for (Task task : tasks) {
                if (task.getTaskType().equals(TaskType.TASK_TYPE_IN.type)) {
                    //1.入库
                if (task.getTaskType().equals(TaskType.TASK_TYPE_IN.type) || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_IN.type)) {
                    //1.入库、54.并板再入库
                    complateInstock(task, loginUserId);
                } else if (task.getTaskType().equals(TaskType.TASK_TYPE_PICK_IN.type) || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
                    //53.拣料再入库
                    //57.盘点再入库
                    //53.拣料再入库、57.盘点再入库
                    pickComplateInStock(task, loginUserId);
                } else if (task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) {
                    //移库
                    //11.库格移载
                    moveInStock(task, loginUserId);
                } else if (task.getTaskType().equals(TaskType.TASK_TYPE_EMPITY_IN.type)) {
                    //10.空板入库:与普通入库共用一个完成逻辑(若有组托则更新组托/库位并上报云仓)
                    complateInstock(task, loginUserId);
                }
            }
        }
@@ -812,7 +814,11 @@
                .set(Task::getTaskStatus, TaskStsType.UPDATED_IN.id))) {
            throw new CoolException("任务状态修改失败!!");
        }
        // 9.1 入/出库结果上报:库格移载完成后通知云仓(与定时任务闭环一致)
        List<TaskItem> moveTaskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        if (!moveTaskItems.isEmpty()) {
            reportInOutResultToCloud(task, loc, moveTaskItems, null, true);
        }
    }
@@ -911,7 +917,8 @@
        if (!taskService.updateById(task)) {
            throw new CoolException("任务状态修改失败!!");
        }
        // 9.1 入/出库结果上报:拣料再入库/盘点再入库完成后通知云仓(与定时任务闭环一致)
        reportInOutResultToCloud(task, loc, taskItems, null, true);
    }
    /**
@@ -2222,10 +2229,10 @@
            List<TaskItem> items = orderMap.get(key);
            //保存入出库明细
            saveStockItems(items, task, pakinItem.getId(), pakinItem.getAsnCode(), pakinItem.getWkType(), pakinItem.getType(), loginUserId);
            //移出收货区库存, 修改组托状态(只有当source不为null时才需要移除收货区库存)
            if (Objects.nonNull(pakinItem.getSource())) {
                removeReceiptStock(pakinItem, loginUserId);
            }
            // 收货区已停用,不再移出收货区库存
            // if (Objects.nonNull(pakinItem.getSource())) {
            //     removeReceiptStock(pakinItem, loginUserId);
            // }
        });
        Set<Long> pkinItemIds = taskItems.stream().map(TaskItem::getSource).collect(Collectors.toSet());
@@ -2452,6 +2459,9 @@
            Date now = new Date();
            for (TaskItem item : taskItems) {
                String orderNo = isInbound ? sourceToOrderNo.get(item.getSource()) : (item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode());
                if (orderNo == null && isInbound) {
                    orderNo = item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode();
                }
                if (orderNo == null || item.getMatnrCode() == null) {
                    continue;
                }
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java
@@ -243,7 +243,7 @@
            throw new CoolException("出库单明细保存失败!!");
        }
        transfer.setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_EXCE_ING.val);
        transfer.setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val); // 新顺序:不再使用执行中
        if (!this.updateById(transfer)) {
            throw new CoolException("调拔单更新失败!!");
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaitPakinServiceImpl.java
@@ -11,6 +11,7 @@
import com.vincent.rsf.server.manager.mapper.MatnrMapper;
import com.vincent.rsf.server.manager.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vincent.rsf.server.common.utils.QuantityUtils;
import com.vincent.rsf.server.system.constant.SerialRuleCode;
import com.vincent.rsf.server.system.utils.SerialRuleUtils;
import org.apache.commons.lang3.StringUtils;
@@ -66,9 +67,9 @@
        WaitPakin pakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>()
                .eq(WaitPakin::getBarcode, waitPakin.getBarcode()));
        // 如果容器号已经组托过,提示已组托,请更换容器条码
        // 如果料箱码已经组托过,提示已组托,请更换料箱码
        if (!Objects.isNull(pakin)) {
            throw new CoolException("已组托,请更换容器条码");
            throw new CoolException("已组托,请更换料箱码");
        }
        List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, waitPakin.getBarcode()));
@@ -76,13 +77,13 @@
            throw new CoolException("当前料箱已有任务档在执行,不能再次组托!!");
        }
        
        // 检查容器号是否在库存中存在(通过库位表查询)
        // 检查料箱码是否在库存中存在(通过库位表查询)
        List<Loc> locs = locService.list(new LambdaQueryWrapper<Loc>().eq(Loc::getBarcode, waitPakin.getBarcode()));
        if (!locs.isEmpty()) {
            throw new CoolException("在库,请更换容器条码");
            throw new CoolException("在库,请更换料箱码");
        }
        double sum = waitPakin.getItems().stream().mapToDouble(PakinItem::getReceiptQty).sum();
        Double sum = QuantityUtils.roundToScale(waitPakin.getItems().stream().mapToDouble(PakinItem::getReceiptQty).sum());
        WaitPakin waitPakin1 = new WaitPakin();
        if (Objects.isNull(pakin)) {
@@ -144,47 +145,49 @@
                if (pakinItem1.getReceiptQty() == null || pakinItem1.getReceiptQty().compareTo(0.0) <= 0) {
                    throw new CoolException("组托数量不能小于等于零!!");
                }
                pakinItem.setAnfme(pakinItem1.getReceiptQty())
                pakinItem.setAnfme(QuantityUtils.roundToScale(pakinItem1.getReceiptQty()))
                        .setTrackCode(pakinItem1.getTrackCode());
            } else {
                // 有ASN单号,从收货区获取物料信息
                WarehouseAreasItem warehouseAreasItems = warehouseAreasItemService.getById(pakinItem1.getId());
                if (null == warehouseAreasItems) {
                    throw new CoolException("物料未送至收货区!!");
                // 收货区已停用:有ASN单号时从订单明细获取物料信息
                WkOrderItem orderItem = asnOrderItemService.getById(pakinItem1.getId());
                if (null == orderItem) {
                    throw new CoolException("订单明细不存在!!");
                }
                pakinItem.setAnfme(warehouseAreasItems.getAnfme())
                WkOrder order = asnOrderService.getById(orderItem.getOrderId());
                if (null == order) {
                    throw new CoolException("订单不存在!!");
                }
                pakinItem.setAnfme(QuantityUtils.roundToScale(orderItem.getAnfme()))
                        .setPakinId(waitPakin1.getId())
                        .setSource(warehouseAreasItems.getId())
                        .setAsnId(warehouseAreasItems.getAsnId())
                        .setAsnCode(warehouseAreasItems.getAsnCode())
                        .setAsnItemId(warehouseAreasItems.getAsnItemId())
                        .setIsptResult(warehouseAreasItems.getIsptResult())
                        .setPlatItemId(warehouseAreasItems.getPlatItemId())
                        .setPlatOrderCode(warehouseAreasItems.getPlatOrderCode())
                        .setPlatWorkCode(warehouseAreasItems.getPlatWorkCode())
                        .setProjectCode(warehouseAreasItems.getProjectCode())
                        .setBatch(warehouseAreasItems.getSplrBatch())
                        .setUnit(warehouseAreasItems.getStockUnit())
                        .setFieldsIndex(warehouseAreasItems.getFieldsIndex())
                        .setMatnrId(warehouseAreasItems.getMatnrId())
                        .setMaktx(warehouseAreasItems.getMaktx())
                        .setSource(null) // 收货区已停用,不关联收货区
                        .setAsnId(order.getId())
                        .setAsnCode(order.getCode())
                        .setAsnItemId(orderItem.getId())
                        .setIsptResult(orderItem.getIsptResult())
                        .setPlatItemId(orderItem.getPlatItemId())
                        .setPlatOrderCode(orderItem.getPlatOrderCode())
                        .setPlatWorkCode(orderItem.getPlatWorkCode())
                        .setProjectCode(orderItem.getProjectCode())
                        .setBatch(orderItem.getSplrBatch())
                        .setUnit(orderItem.getStockUnit())
                        .setFieldsIndex(orderItem.getFieldsIndex())
                        .setMatnrId(orderItem.getMatnrId())
                        .setMaktx(orderItem.getMaktx())
                        .setUpdateBy(userId)
                        .setCreateBy(userId)
                        .setMatnrCode(warehouseAreasItems.getMatnrCode());
                WkOrder order = asnOrderService.getById(warehouseAreasItems.getAsnId());
                if (!Objects.isNull(order)) {
                        .setMatnrCode(orderItem.getMatnrCode());
                    pakinItem.setType(null == order.getType() ? null : order.getType())
                            .setWkType(null == order.getWkType() ? null : Short.parseShort(order.getWkType()));
                }
                        .setWkType(StringUtils.isNotBlank(order.getWkType()) ? Short.parseShort(order.getWkType()) : null);
                for (PakinItem waitPakinItem : waitPakin.getItems()) {
                    if (waitPakinItem.getId().equals(warehouseAreasItems.getId())) {
                        if (waitPakinItem.getReceiptQty() > warehouseAreasItems.getAnfme() || waitPakinItem.getReceiptQty().compareTo(0.0) <= 0) {
                            throw new CoolException("组托数量不能大于收货数量且不能小于零!!");
                    if (waitPakinItem.getId().equals(orderItem.getId())) {
                        if (waitPakinItem.getReceiptQty() == null || waitPakinItem.getReceiptQty().compareTo(0.0) <= 0) {
                            throw new CoolException("组托数量不能小于等于零!!");
                        }
                        pakinItem.setAnfme(waitPakinItem.getReceiptQty())
                        if (QuantityUtils.compare(waitPakinItem.getReceiptQty(), orderItem.getAnfme()) > 0) {
                            throw new CoolException("组托数量不能大于计划数量!!");
                        }
                        pakinItem.setAnfme(QuantityUtils.roundToScale(waitPakinItem.getReceiptQty()))
                                .setTrackCode(waitPakinItem.getTrackCode());
                    }
                }
@@ -200,31 +203,22 @@
        List<WaitPakinItem> pakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().eq(WaitPakinItem::getPakinId, waitPakin1.getId()));
        Double waitSum = 0.0;
        if (!pakinItems.isEmpty()) {
            waitSum = pakinItems.stream().mapToDouble(WaitPakinItem::getAnfme).sum();
            waitSum = QuantityUtils.roundToScale(pakinItems.stream().mapToDouble(WaitPakinItem::getAnfme).sum());
        }
//        Double total = Math.round((sum + waitSum) * 100) / 100.0;
        for (WaitPakinItem pakinItem : items) {
            // 如果source为空(没有ASN单号,不在收货区),跳过收货区更新
            if (Objects.isNull(pakinItem.getSource())) {
                continue;
            }
            WarehouseAreasItem one = warehouseAreasItemService.getOne(new LambdaQueryWrapper<WarehouseAreasItem>()
                    .eq(WarehouseAreasItem::getId, pakinItem.getSource()));
            if (Objects.isNull(one)) {
                throw new CoolException("收货区数据错误!!");
            }
            Double workQty = Math.round((one.getWorkQty() + pakinItem.getAnfme()) * 1000000) / 1000000.0;
            Double qty = Math.round((workQty + one.getQty()) * 1000000) / 1000000.0;
            one.setWorkQty(workQty);
            if (qty.compareTo(one.getAnfme()) > 0) {
                throw new CoolException("组托数量不能大于收货数量!!");
            }
            if (!warehouseAreasItemService.saveOrUpdate(one)) {
                throw new CoolException("收货区执行数量修改失败!!");
            }
        }
        // 收货区已停用,不再更新收货区
        // for (WaitPakinItem pakinItem : items) {
        //     if (Objects.isNull(pakinItem.getSource())) continue;
        //     WarehouseAreasItem one = warehouseAreasItemService.getOne(new LambdaQueryWrapper<WarehouseAreasItem>()
        //             .eq(WarehouseAreasItem::getId, pakinItem.getSource()));
        //     if (Objects.isNull(one)) throw new CoolException("收货区数据错误!!");
        //     Double workQty = Math.round((one.getWorkQty() + pakinItem.getAnfme()) * 1000000) / 1000000.0;
        //     Double qty = Math.round((workQty + one.getQty()) * 1000000) / 1000000.0;
        //     one.setWorkQty(workQty);
        //     if (qty.compareTo(one.getAnfme()) > 0) throw new CoolException("组托数量不能大于收货数量!!");
        //     if (!warehouseAreasItemService.saveOrUpdate(one)) throw new CoolException("收货区执行数量修改失败!!");
        // }
        waitPakin1.setAnfme(waitSum);
        if (!this.updateById(waitPakin1)) {
@@ -265,21 +259,22 @@
//            if (!waitPakinItemService.removeByIds(ids)) {
//                throw new CoolException("组托明细解绑失败!!");
//            }
            List<Long> list2 = pakinItems.stream().map(WaitPakinItem::getSource).collect(Collectors.toList());
            List<WarehouseAreasItem> warehouseAreasItems = warehouseAreasItemService.listByIds(list2);
            // 收货区已停用:仅保留非空 source 用于兼容旧数据,不再更新收货区
            List<Long> list2 = pakinItems.stream().map(WaitPakinItem::getSource).filter(Objects::nonNull).collect(Collectors.toList());
            List<WarehouseAreasItem> warehouseAreasItems = list2.isEmpty() ? Collections.emptyList() : warehouseAreasItemService.listByIds(list2);
            for (int i1 = 0; i1 < pakinItems.size(); i1++) {
                for (PakinItem item : paramItems) {
                    if (item.getId().equals(pakinItems.get(i1).getId())) {
                        if (pakinItems.get(i1).getAnfme().compareTo(item.getReceiptQty()) > 0) {
                            if (item.getReceiptQty().compareTo(0.00) == 0) {
                        if (QuantityUtils.compare(pakinItems.get(i1).getAnfme(), item.getReceiptQty()) > 0) {
                            if (QuantityUtils.compare(item.getReceiptQty(), 0.00) == 0) {
                                throw new CoolException("解绑数量不能为零!!");
                            }
                            Double reslt = Math.round((pakinItems.get(i1).getAnfme() - pakinItems.get(i1).getWorkQty() - pakinItems.get(i1).getQty()) * 1000000) / 1000000.0;
                            if (item.getReceiptQty().compareTo(reslt) > 0) {
                            Double reslt = QuantityUtils.subtract(QuantityUtils.subtract(pakinItems.get(i1).getAnfme(), pakinItems.get(i1).getWorkQty()), pakinItems.get(i1).getQty());
                            if (QuantityUtils.compare(item.getReceiptQty(), reslt) > 0) {
                                throw new CoolException("解绑数量不能大于剩余可执行数!!");
                            }
                            Double anfme = Math.round((pakinItems.get(i1).getAnfme() - item.getReceiptQty()) * 1000000) / 1000000.0;
                            Double anfme = QuantityUtils.subtract(pakinItems.get(i1).getAnfme(), item.getReceiptQty());
                           pakinItems.get(i1).setAnfme(anfme);
                           if (!waitPakinItemService.updateById(pakinItems.get(i1))) {
                               throw new CoolException("组托明细数量修改失败!!");
@@ -289,28 +284,28 @@
                                throw new CoolException("组托明细删除失败!!");
                            }
                        }
                        for (int i = 0; i < warehouseAreasItems.size(); i++) {
                            if (warehouseAreasItems.get(i).getId().equals(pakinItems.get(i1).getSource())) {
                                double v = Math.round((warehouseAreasItems.get(i).getWorkQty() - item.getReceiptQty()) * 1000000) / 1000000.0;
                                warehouseAreasItems.get(i).setWorkQty(v);
                                if (!warehouseAreasItemService.updateById(warehouseAreasItems.get(i))) {
                                    throw new CoolException("收货区数量修改失败!!");
                                }
                            }
                        }
                        // 收货区已停用,不再回写收货区
                        // for (int i = 0; i < warehouseAreasItems.size(); i++) {
                        //     if (warehouseAreasItems.get(i).getId().equals(pakinItems.get(i1).getSource())) {
                        //         double v = Math.round((warehouseAreasItems.get(i).getWorkQty() - item.getReceiptQty()) * 1000000) / 1000000.0;
                        //         warehouseAreasItems.get(i).setWorkQty(v);
                        //         if (!warehouseAreasItemService.updateById(warehouseAreasItems.get(i))) {
                        //             throw new CoolException("收货区数量修改失败!!");
                        //         }
                        //     }
                        // }
                    }
                }
            }
            double anfmes = paramItems.stream().mapToDouble(PakinItem::getReceiptQty).sum();
            Double anfmes = QuantityUtils.roundToScale(paramItems.stream().mapToDouble(PakinItem::getReceiptQty).sum());
//            double anfmes = warehouseAreasItems.stream().mapToDouble(WarehouseAreasItem::getAnfme).sum();
            if (waitPakins.getAnfme().compareTo(anfmes) <= 0) {
            if (QuantityUtils.compare(waitPakins.getAnfme(), anfmes) <= 0) {
                if (!waitPakinService.removeById(waitPakins.getId())) {
                    throw new CoolException("组托删除失败!!");
                }
            } else {
                Double anfme = Math.round((waitPakins.getAnfme() - anfmes) * 1000000) / 1000000.0;
                waitPakins.setAnfme(anfme);
                waitPakins.setAnfme(QuantityUtils.subtract(waitPakins.getAnfme(), anfmes));
                if (!waitPakinService.updateById(waitPakins)) {
                    throw new CoolException("组托数据修改失败!!");
                }
@@ -338,28 +333,25 @@
                return R.error("组拖档有明细任务");
            }
            Set<Long> sourceIds = pakinItems.stream().map(WaitPakinItem::getSource).collect(Collectors.toSet());
            Set<Long> sourceIds = pakinItems.stream().map(WaitPakinItem::getSource).filter(Objects::nonNull).collect(Collectors.toSet());
            List<WarehouseAreasItem> areasItems = warehouseAreasItemService.list(new LambdaQueryWrapper<WarehouseAreasItem>()
                    .in(WarehouseAreasItem::getId, sourceIds));
            List<WarehouseAreasItem> areasItems = sourceIds.isEmpty() ? Collections.emptyList() : warehouseAreasItemService.list(new LambdaQueryWrapper<WarehouseAreasItem>().in(WarehouseAreasItem::getId, sourceIds));
            if (areasItems.isEmpty()) {
                return R.error("收货区数据不存在!!");
            }
            // 收货区已停用,仅兼容旧数据时回滚收货区数量
            if (!areasItems.isEmpty()) {
            Map<Long, List<WaitPakinItem>> listMap = pakinItems.stream().collect(Collectors.groupingBy(WaitPakinItem::getSource));
            for (WarehouseAreasItem item : areasItems) {
                List<WaitPakinItem> pakin = listMap.get(item.getId());
                if (Objects.isNull(pakin)) {
                    continue;
                }
                double sum = pakin.stream().mapToDouble(WaitPakinItem::getAnfme).sum();
                Double workQty = Math.round((item.getWorkQty() - sum) * 1000000) / 1000000.0;
                item.setWorkQty(workQty);
                    Double sum = QuantityUtils.roundToScale(pakin.stream().mapToDouble(WaitPakinItem::getAnfme).sum());
                    item.setWorkQty(QuantityUtils.subtract(item.getWorkQty(), sum));
                if (!warehouseAreasItemService.updateById(item)) {
                    throw new CoolException("收货区数据回滚失败!!");
                }
            }
            }
            Set<Long> pakinItemIds = pakinItems.stream().map(WaitPakinItem::getId).collect(Collectors.toSet());
rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java
@@ -98,4 +98,7 @@
    public final static String SYS_TRANSFER_TYPE = "sys_transfer_type";
    /**库存调整*/
    public final static String SYS_STOCK_REVISE_TYPE =  "sys_stock_revise_type";
    /** 订单业务类型(可界面配置,与 OrderWorkType 枚举对应) */
    public final static String DICT_ORDER_WORK_TYPE = "sys_order_work_type";
}
rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/DictDataServiceImpl.java
@@ -1,12 +1,55 @@
package com.vincent.rsf.server.system.service.impl;
import com.vincent.rsf.server.system.mapper.DictDataMapper;
import com.vincent.rsf.server.system.entity.DictData;
import com.vincent.rsf.server.system.service.DictDataService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vincent.rsf.server.common.event.DictDataChangedEvent;
import com.vincent.rsf.server.system.entity.DictData;
import com.vincent.rsf.server.system.mapper.DictDataMapper;
import com.vincent.rsf.server.system.service.DictDataService;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@Service("dictDataService")
public class DictDataServiceImpl extends ServiceImpl<DictDataMapper, DictData> implements DictDataService {
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;
    @Override
    public boolean save(DictData entity) {
        boolean result = super.save(entity);
        if (result && entity.getDictTypeCode() != null) {
            applicationEventPublisher.publishEvent(new DictDataChangedEvent(this, entity.getDictTypeCode()));
        }
        return result;
    }
    @Override
    public boolean updateById(DictData entity) {
        boolean result = super.updateById(entity);
        if (result && entity.getDictTypeCode() != null) {
            applicationEventPublisher.publishEvent(new DictDataChangedEvent(this, entity.getDictTypeCode()));
        }
        return result;
    }
    @Override
    public boolean removeByIds(Collection<? extends Serializable> list) {
        if (list == null || list.isEmpty()) {
            return true;
        }
        List<DictData> before = listByIds(list);
        boolean result = super.removeByIds(list);
        if (result && before != null) {
            for (String dictTypeCode : before.stream().map(DictData::getDictTypeCode).filter(c -> c != null).distinct().collect(Collectors.toList())) {
                applicationEventPublisher.publishEvent(new DictDataChangedEvent(this, dictTypeCode));
            }
        }
        return result;
    }
}
version/db/man_asn_order_add_8_3_fields.sql
New file
@@ -0,0 +1,15 @@
-- 8.3 接口未使用字段接入:主单 stationId;明细 planNo、palletId、targetWareHouseId、sourceWareHouseId
-- 单据内码用 po_code 存储(接口 orderInternalCode),不单独建 order_internal_code 字段
-- 若之前已执行过添加 order_internal_code,可先执行:ALTER TABLE man_asn_order DROP COLUMN order_internal_code;
-- 执行前请确认表 man_asn_order、man_asn_order_item 已存在
-- 主单 man_asn_order
ALTER TABLE `man_asn_order`
  ADD COLUMN `station_id` varchar(64) DEFAULT NULL COMMENT '入/出库接驳站点';
-- 明细 man_asn_order_item
ALTER TABLE `man_asn_order_item`
  ADD COLUMN `plan_no` varchar(64) DEFAULT NULL COMMENT '计划跟踪号' AFTER `batch`,
  ADD COLUMN `pallet_id` varchar(64) DEFAULT NULL COMMENT '托盘码' AFTER `plan_no`,
  ADD COLUMN `target_ware_house_id` varchar(64) DEFAULT NULL COMMENT '建议入库仓库' AFTER `pallet_id`,
  ADD COLUMN `source_ware_house_id` varchar(64) DEFAULT NULL COMMENT '建议出库仓库' AFTER `target_ware_house_id`;
version/db/out_stock_order_log_menu.sql
@@ -1,7 +1,7 @@
-- 出库历史单菜单:与「入库历史单」同级,共用 asnOrderLog 接口,仅前端 resource=outStockOrderLog、固定 type=out
-- 出库历史单菜单:与「入库历史单」同级,共用 asnOrderLog 接口,图标与出库通知单一致(HorizontalRule)
-- 执行前需已存在 component='asnOrderLog' 的菜单,否则本 INSERT 不会插入任何行
INSERT INTO `sys_menu` (`id`, `name`, `parent_id`, `parent_name`, `path`, `path_name`, `route`, `component`, `brief`, `code`, `type`, `authority`, `icon`, `sort`, `meta`, `tenant_id`, `status`, `deleted`, `create_time`, `create_by`, `update_time`, `update_by`, `memo`)
SELECT 52, 'menu.outStockOrderLog', m.parent_id, m.parent_name, CONCAT(IFNULL(m.path,''), ',52'), 'menu.outStockOrderLog', '/histories/outStockOrderLog', 'outStockOrderLog', NULL, NULL, 0, NULL, 'Outbox', 2, NULL, 1, 1, 0, NULL, NULL, NULL, NULL, NULL
SELECT 52, 'menu.outStockOrderLog', m.parent_id, m.parent_name, CONCAT(IFNULL(m.path,''), ',52'), 'menu.outStockOrderLog', '/histories/outStockOrderLog', 'outStockOrderLog', NULL, NULL, 0, NULL, 'HorizontalRule', 2, NULL, 1, 1, 0, NULL, NULL, NULL, NULL, NULL
FROM `sys_menu` m WHERE m.component = 'asnOrderLog' LIMIT 1;
-- 出库历史单列表权限(与入库历史单共用 manager:asnOrderLog:list,有该权限即可访问两个菜单)
version/db/sys_order_type_dict.sql
New file
@@ -0,0 +1,20 @@
-- 订单类型字典:1 出库单 2 入库单 3 调拨单 等,可在【系统-数据字典】中维护
-- value = 内部编码(out/in/transfer),label = 显示名称;API 的 orderType 1/2/3 在代码中映射为 out/in/transfer
INSERT INTO `sys_dict_type` (`code`, `name`, `description`, `status`, `deleted`, `tenant_id`, `create_by`, `create_time`, `update_by`, `update_time`, `memo`)
SELECT 'sys_order_type', '订单类型', '出库单/入库单/调拨单等,与 wk_order.type 对应', 1, 0, 1, NULL, NOW(), NULL, NOW(), NULL
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM sys_dict_type WHERE code = 'sys_order_type' LIMIT 1);
INSERT INTO `sys_dict_data` (`dict_type_id`, `dict_type_code`, `value`, `label`, `sort`, `status`, `deleted`, `tenant_id`, `create_by`, `create_time`, `update_by`, `update_time`, `memo`)
SELECT t.id, 'sys_order_type', v.val, v.lbl, v.srt, 1, 0, 1, NULL, NOW(), NULL, NOW(), NULL
FROM sys_dict_type t
CROSS JOIN (
  SELECT 'out' AS val, '出库单' AS lbl, 1 AS srt
  UNION ALL SELECT 'in', '入库单', 2
  UNION ALL SELECT 'transfer', '调拨单', 3
  UNION ALL SELECT 'revise', '库存调整', 4
  UNION ALL SELECT 'check', '盘点单', 5
) v
WHERE t.code = 'sys_order_type'
  AND NOT EXISTS (SELECT 1 FROM sys_dict_data d WHERE d.dict_type_code = 'sys_order_type' AND d.value = v.val LIMIT 1);
version/db/sys_order_work_type_dict.sql
New file
@@ -0,0 +1,22 @@
-- 订单业务类型字典:与 OrderWorkType 枚举对应,可在【系统-数据字典】中维护
-- 执行前请确认 sys_dict_type、sys_dict_data 表存在;表结构需含 create_by/create_time 等(与实体一致)
-- value = 类型编码(如 1、2),label = 显示名称(如 采购入库单)
-- 1. 字典类型(若已存在 sys_order_work_type 可跳过本段)
INSERT INTO `sys_dict_type` (`code`, `name`, `description`, `status`, `deleted`, `tenant_id`, `create_by`, `create_time`, `update_by`, `update_time`, `memo`)
SELECT 'sys_order_work_type', '订单业务类型', '入库/出库/调拨等业务类型,与 wk_order.wk_type 对应', 1, 0, 1, NULL, NOW(), NULL, NOW(), NULL
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM sys_dict_type WHERE code = 'sys_order_work_type' LIMIT 1);
-- 2. 字典数据(dict_type_id 取上一步类型的 id;若表结构为 id 自增可去掉 id 列)
INSERT INTO `sys_dict_data` (`dict_type_id`, `dict_type_code`, `value`, `label`, `sort`, `status`, `deleted`, `tenant_id`, `create_by`, `create_time`, `update_by`, `update_time`, `memo`)
SELECT t.id, 'sys_order_work_type', v.val, v.lbl, v.srt, 1, 0, 1, NULL, NOW(), NULL, NOW(), NULL
FROM sys_dict_type t
CROSS JOIN (
  SELECT '1' AS val, '采购入库单' AS lbl, 1 AS srt UNION ALL SELECT '2','生产入库单',2 UNION ALL SELECT '3','领料退回入库单',3 UNION ALL SELECT '4','销售退回入库单',4 UNION ALL SELECT '5','其它入库单',5
  UNION ALL SELECT '6','调拔入库单',6 UNION ALL SELECT '7','库存调整单',7 UNION ALL SELECT '8','调拔入库单(项目)',8 UNION ALL SELECT '11','销售出库单',11 UNION ALL SELECT '12','领料出库单',12
  UNION ALL SELECT '13','采购退回出库单',13 UNION ALL SELECT '14','其它出库单',14 UNION ALL SELECT '15','库存出库',15 UNION ALL SELECT '16','盘点出库',16 UNION ALL SELECT '17','调拔出库单',17
  UNION ALL SELECT '18','生产补料',18 UNION ALL SELECT '19','外发加工',19
) v
WHERE t.code = 'sys_order_work_type'
  AND NOT EXISTS (SELECT 1 FROM sys_dict_data d WHERE d.dict_type_code = 'sys_order_work_type' AND d.value = v.val LIMIT 1);
version/db/wave_menu.sql
New file
@@ -0,0 +1,37 @@
-- 波次管理菜单:若 sys_menu 中已存在 component='wave' 的菜单则跳过
-- 执行后需在【系统管理 -> 角色管理 -> 分配权限】中为对应角色勾选「波次管理」并保存,菜单才会在侧栏显示
INSERT INTO `sys_menu` (`name`, `parent_id`, `parent_name`, `path`, `path_name`, `route`, `component`, `brief`, `code`, `type`, `authority`, `icon`, `sort`, `meta`, `tenant_id`, `status`, `deleted`, `create_time`, `create_by`, `update_time`, `update_by`, `memo`)
SELECT 'menu.wave', 0, NULL, '', '', '/orders/wave', 'wave', NULL, NULL, 0, NULL, 'Waves', 0, NULL, 1, 1, 0, NOW(), NULL, NOW(), NULL, '波次管理'
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `component` = 'wave' AND `type` = 0 LIMIT 1);
-- 波次管理-列表查询权限(访问波次列表页和接口需要)
INSERT INTO `sys_menu` (`name`, `parent_id`, `path`, `path_name`, `route`, `component`, `type`, `authority`, `sort`, `tenant_id`, `status`, `deleted`)
SELECT 'Query 波次', m.id, CONCAT(IFNULL(m.path,''), ',', m.id), NULL, NULL, NULL, 1, 'manager:wave:list', 0, 1, 1, 0
FROM `sys_menu` m WHERE m.component = 'wave' AND m.type = 0 LIMIT 1;
-- 波次管理-保存权限
INSERT INTO `sys_menu` (`name`, `parent_id`, `path`, `type`, `authority`, `sort`, `tenant_id`, `status`, `deleted`)
SELECT 'Create 波次', m.id, CONCAT(IFNULL(m.path,''), ',', m.id), 1, 'manager:wave:save', 1, 1, 1, 0
FROM `sys_menu` m WHERE m.component = 'wave' AND m.type = 0 LIMIT 1;
-- 波次管理-更新权限
INSERT INTO `sys_menu` (`name`, `parent_id`, `path`, `type`, `authority`, `sort`, `tenant_id`, `status`, `deleted`)
SELECT 'Update 波次', m.id, CONCAT(IFNULL(m.path,''), ',', m.id), 1, 'manager:wave:update', 2, 1, 1, 0
FROM `sys_menu` m WHERE m.component = 'wave' AND m.type = 0 LIMIT 1;
-- 波次管理-删除权限
INSERT INTO `sys_menu` (`name`, `parent_id`, `path`, `type`, `authority`, `sort`, `tenant_id`, `status`, `deleted`)
SELECT 'Delete 波次', m.id, CONCAT(IFNULL(m.path,''), ',', m.id), 1, 'manager:wave:remove', 3, 1, 1, 0
FROM `sys_menu` m WHERE m.component = 'wave' AND m.type = 0 LIMIT 1;
-- 波次明细-列表权限(进入波次明细需 manager:waveItem:list,若接口有要求可再加)
INSERT INTO `sys_menu` (`name`, `parent_id`, `path`, `type`, `authority`, `sort`, `tenant_id`, `status`, `deleted`)
SELECT 'Query 波次明细', m.id, CONCAT(IFNULL(m.path,''), ',', m.id), 1, 'manager:waveItem:list', 4, 1, 1, 0
FROM `sys_menu` m WHERE m.component = 'wave' AND m.type = 0 LIMIT 1;
-- 波次明细-更新权限(下发任务等操作)
INSERT INTO `sys_menu` (`name`, `parent_id`, `path`, `type`, `authority`, `sort`, `tenant_id`, `status`, `deleted`)
SELECT 'Update 波次明细', m.id, CONCAT(IFNULL(m.path,''), ',', m.id), 1, 'manager:waveItem:update', 5, 1, 1, 0
FROM `sys_menu` m WHERE m.component = 'wave' AND m.type = 0 LIMIT 1;