Explorar o código

订单根据用户配置拆分出库任务

wudingsheng hai 3 semanas
pai
achega
947ac93f57

+ 98 - 144
imcs-admin-boot/imcs-business-biz/src/main/java/com/github/zuihou/business/operationManagementCenter/service/impl/OrderServiceImpl.java

@@ -510,111 +510,114 @@ public class OrderServiceImpl extends SuperServiceImpl<OrderMapper, Order> imple
                 // 建议放在 @Transactional(rollbackFor=Exception.class) 里,且“调用外部接口”可在事务外或用 REQUIRES_NEW 的日志事务
                 int box = (int) redisTemplate.opsForValue().get(CacheKey.PROPERTIES+oriBean.getZoneId()+CacheKey.BOX_CAPACITY);
                 if (Boolean.TRUE.equals(wmsFlag)) {
-                    // ====== 0) 参数与准备 ======
-                    final int BOX_CAPACITY = 10; // TODO: 从配置/参数表读取
-                    int priority = (oriBean.getPrority() == null ? 1 : oriBean.getPrority());
-                    Long zoneId = oriBean.getZoneId();
-
-                    // —— 预取,避免 N+1 —— //
-                    List<Long> receiveIds = productList.stream()
-                            .map(vo -> vo.getMeterialReceiveId())
-                            .filter(Objects::nonNull).distinct().collect(Collectors.toList());
-
-                    Map<Long, MMeterialReceiveLog> recvMap = mMeterialReceiveLogMapper.selectBatchIds(receiveIds)
-                            .stream().collect(Collectors.toMap(MMeterialReceiveLog::getId, x -> x));
-
-                    List<Long> meterialIds = recvMap.values().stream()
-                            .map(MMeterialReceiveLog::getMeterialId)
-                            .filter(Objects::nonNull).distinct().collect(Collectors.toList());
-
-                    Map<Long, MMeterial> meterialMap = mMeterialMapper.selectBatchIds(meterialIds)
-                            .stream().collect(Collectors.toMap(MMeterial::getId, x -> x));
-
-                    // —— 组装原始物料清单 —— //
-                    List<MatItem> srcList = new ArrayList<>();
-                    for (var vo : productList) {
-                        MMeterialReceiveLog recv = recvMap.get(vo.getMeterialReceiveId());
-                        if (recv == null) continue;
-                        MMeterial mm = meterialMap.get(recv.getMeterialId());
-                        if (mm == null) continue;
-
-                        srcList.add(new MatItem(
-                                mm.getId(),
-                                mm.getMeterialCode(),
-                                mm.getEquipmentName(),
-                                vo.getBomNum()
-                        ));
-                    }
-
-                    // ====== 1) 拆箱(保持物料顺序,单箱最多 BOX_CAPACITY 件) ======
-                    List<List<MatItem>> bins = splitByCapacity(srcList, BOX_CAPACITY);
+                    final int BOX_CAPACITY = box;
 
-                    // ====== 2) 为每个箱生成一条任务并落库,同时构建“批量下发”的 JSON ======
-                    cn.hutool.json.JSONArray orderArray = new cn.hutool.json.JSONArray();
-
-                    // 统一接口调用日志(一次请求)
                     ApiCallLog apiCallLog = new ApiCallLog();
                     long startTime = System.currentTimeMillis();
+
                     try {
-                        for (List<MatItem> bin : bins) {
-                            // 2.1 任务号
-                            String taskNo = codeRuleService.getBillCode(CodeRuleModule.CODE_RULE_WMS_OUT);
-
-                            // 2.2 WmsTransferTask
-                            WmsTransferTask wmsTransferTask = new WmsTransferTask();
-                            wmsTransferTask.setOrderId(oriBean.getId());
-                            wmsTransferTask.setOrderNo(oriBean.getOrderNo());
-                            wmsTransferTask.setStatus(0);
-                            wmsTransferTaskMapper.insert(wmsTransferTask);
-
-                            // 2.3 WmsAgvInfo
-                            WmsAgvInfo wmsAgvInfo = new WmsAgvInfo();
-                            wmsAgvInfo.setStatus(false);
-                            wmsAgvInfo.setOrderId(oriBean.getId());
-                            wmsAgvInfo.setPriority(priority);
-                            wmsAgvInfo.setTaskNo(taskNo);
-                            wmsAgvInfo.setTaskType("OUT");
-                            wmsAgvInfo.setWmsTransferTaskId(wmsTransferTask.getId());
-                            wmsAgvInfoMapper.insert(wmsAgvInfo);
-
-                            // 2.4 明细 + 下游 JSON 的 materialCodeList
-                            List<WmsAgvInfoDetail> detailList = new ArrayList<>(bin.size());
-                            cn.hutool.json.JSONArray materialArray = new cn.hutool.json.JSONArray();
-
-                            for (MatItem it : bin) {
-                                // DB 明细
+                        // 预取,避免 N+1
+                        List<Long> receiveIds = productList.stream()
+                                .map(vo -> vo.getMeterialReceiveId())
+                                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
+
+                        Map<Long, MMeterialReceiveLog> recvMap = receiveIds.isEmpty()
+                                ? Collections.emptyMap()
+                                : mMeterialReceiveLogMapper.selectBatchIds(receiveIds).stream()
+                                .collect(Collectors.toMap(MMeterialReceiveLog::getId, x -> x));
+
+                        List<Long> meterialIds = recvMap.values().stream()
+                                .map(MMeterialReceiveLog::getMeterialId)
+                                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
+
+                        Map<Long, MMeterial> meterialMap = meterialIds.isEmpty()
+                                ? Collections.emptyMap()
+                                : mMeterialMapper.selectBatchIds(meterialIds).stream()
+                                .collect(Collectors.toMap(MMeterial::getId, x -> x));
+
+                        // 构建一次性下发的总数组
+                        cn.hutool.json.JSONArray allOrdersArray = new cn.hutool.json.JSONArray();
+
+                        int priority = (oriBean.getPrority() == null ? 1 : oriBean.getPrority());
+                        Long zoneId   = oriBean.getZoneId();
+
+                        // —— 逐个 OrderProduct 拆箱(不与其他 OrderProduct 混装)——
+                        for (var op : productList) {
+                            MMeterialReceiveLog recv = recvMap.get(op.getMeterialReceiveId());
+                            if (recv == null) continue;
+                            MMeterial mm = meterialMap.get(recv.getMeterialId());
+                            if (mm == null) continue;
+
+                            final Long orderProductId = op.getId();
+                            final String materialCode = mm.getMeterialCode();
+                            final String materialName = mm.getEquipmentName();
+                            int qtyLeft = op.getBomNum();
+
+                            while (qtyLeft > 0) {
+                                int put = Math.min(qtyLeft, BOX_CAPACITY);
+                                qtyLeft -= put;
+
+                                // 1) 生成任务号
+                                String taskNo = codeRuleService.getBillCode(CodeRuleModule.CODE_RULE_WMS_OUT);
+
+                                // 2) WmsTransferTask(★ 绑定 order_product_id)
+                                WmsTransferTask wmsTransferTask = new WmsTransferTask();
+                                wmsTransferTask.setOrderId(oriBean.getId());          // 你的订单主ID(保持)
+                                wmsTransferTask.setOrderNo(oriBean.getOrderNo());
+                                wmsTransferTask.setOrderProductId(orderProductId);    // ★ 新增:按订单明细分组
+                                wmsTransferTask.setStatus(0);
+                                wmsTransferTaskMapper.insert(wmsTransferTask);
+
+                                // 3) WmsAgvInfo(头)
+                                WmsAgvInfo wmsAgvInfo = new WmsAgvInfo();
+                                wmsAgvInfo.setStatus(false);
+                                wmsAgvInfo.setOrderId(oriBean.getId());
+                                wmsAgvInfo.setPriority(priority);
+                                wmsAgvInfo.setTaskNo(taskNo);
+                                wmsAgvInfo.setTaskType("OUT");
+                                wmsAgvInfo.setWmsTransferTaskId(wmsTransferTask.getId());
+                                wmsAgvInfoMapper.insert(wmsAgvInfo);
+
+                                // 4) 明细(只放这一个 OrderProduct 的该批数量)
+                                List<WmsAgvInfoDetail> detailList = new ArrayList<>(1);
                                 WmsAgvInfoDetail d = new WmsAgvInfoDetail();
                                 d.setWmsAgvInfoId(wmsAgvInfo.getId());
-                                d.setMeterialId(it.getMeterialId());
-                                d.setMaterialCode(it.getMaterialCode());
-                                d.setMaterialName(it.getMaterialName());
-                                d.setQty(it.getQuantity());
+                                d.setMeterialId(mm.getId());
+                                d.setMaterialCode(materialCode);
+                                d.setMaterialName(materialName);
+                                d.setQty(put);
+                                // 如果明细表也有 order_product_id(推荐),一并写入:
+                                // d.setOrderProductId(orderProductId);
                                 detailList.add(d);
-
-                                // 下游 JSON
-                                cn.hutool.json.JSONObject obj = new cn.hutool.json.JSONObject();
-                                obj.put("materialCode", it.getMaterialCode());
-                                obj.put("materialName", it.getMaterialName());
-                                obj.put("quantity", it.getQuantity());
-                                materialArray.put(obj);
+                                wmsAgvInfoDetailMapper.insertBatchSomeColumn(detailList);
+
+                                // 5) 本任务的 JSON(materialCodeList 仅该 OrderProduct)
+                                cn.hutool.json.JSONArray materialArray = new cn.hutool.json.JSONArray();
+                                cn.hutool.json.JSONObject item = new cn.hutool.json.JSONObject();
+                                item.put("materialCode", materialCode);
+                                item.put("materialName", materialName);
+                                item.put("quantity", put);
+                                materialArray.put(item);
+
+                                cn.hutool.json.JSONObject orderObj = new cn.hutool.json.JSONObject();
+                                orderObj.put("taskNo", taskNo);
+                                orderObj.put("priority", priority);
+                                orderObj.put("zoneId", zoneId);
+                                orderObj.put("materialCodeList", materialArray);
+
+                                // 可选:把来源也带给WMS,便于对账/回滚(看WMS是否接受)
+                                // orderObj.put("orderProductId", orderProductId);
+                                // orderObj.put("orderId", oriBean.getId());
+                                // orderObj.put("orderNo", oriBean.getOrderNo());
+
+                                allOrdersArray.put(orderObj);
                             }
-                            wmsAgvInfoDetailMapper.insertBatchSomeColumn(detailList);
-
-                            // 2.5 构建“单个出库任务”的 JSON 对象,加入 order 数组
-                            cn.hutool.json.JSONObject orderObj = new cn.hutool.json.JSONObject();
-                            orderObj.put("taskNo", taskNo);
-                            orderObj.put("priority", priority);
-                            orderObj.put("zoneId", zoneId);
-                            orderObj.put("materialCodeList", materialArray);
-
-                            orderArray.put(orderObj);
                         }
 
-                        // ====== 3) 一次性发送:{"order":[ ... 多个任务 ... ]} ======
+                        // 6) 一次性发送
                         cn.hutool.json.JSONObject payload = new cn.hutool.json.JSONObject();
-                        payload.put("order", orderArray);
+                        payload.put("order", allOrdersArray);
 
-                        // —— 日志(请求前) —— //
                         apiCallLog.setInterfaceName("OUT_BATCH");
                         apiCallLog.setRequestUrl(url);
                         apiCallLog.setRequestParams(payload.toString());
@@ -624,13 +627,9 @@ public class OrderServiceImpl extends SuperServiceImpl<OrderMapper, Order> imple
                         headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
                         HttpEntity<String> formEntity = new HttpEntity<>(payload.toString(), headers);
 
-                        // 正式调用
                         // String returnData = restTemplate.postForObject(url, formEntity, String.class);
+                        String returnData = "{ \"code\":\"200\", \"msg\":\"批量操作成功\" }"; // mock
 
-                        // 模拟返回(你替换为真实调用)
-                        String returnData = "{ \"code\":\"200\", \"msg\":\"批量操作成功\" }";
-
-                        // —— 解析返回并记录 —— //
                         apiCallLog.setResponseData(returnData);
                         com.alibaba.fastjson.JSONObject retJson = com.alibaba.fastjson.JSONObject.parseObject(returnData);
                         String code = String.valueOf(retJson.get("code"));
@@ -639,7 +638,6 @@ public class OrderServiceImpl extends SuperServiceImpl<OrderMapper, Order> imple
                         if (!"200".equals(code)) {
                             throw new RuntimeException("WMS 批量返回非200,code=" + code + ", body=" + returnData);
                         }
-
                     } catch (Exception e) {
                         log.error("调用WMS批量出库接口异常:{}", e.getMessage(), e);
                         apiCallLog.setSuccess(0);
@@ -654,6 +652,7 @@ public class OrderServiceImpl extends SuperServiceImpl<OrderMapper, Order> imple
                 }
 
 
+
                 //end---imcs->wms
 
             }
@@ -668,51 +667,6 @@ public class OrderServiceImpl extends SuperServiceImpl<OrderMapper, Order> imple
     }
 
 
-    @Data
-    static class MatItem {
-        private String materialCode;
-        private String materialName;
-        private int quantity;
-        private Long meterialId;
-        private MatItem(){}
-        public MatItem(Long meterialId, String materialCode, String materialName, int quantity) {
-            this.meterialId = meterialId;
-            this.materialCode = materialCode;
-            this.materialName = materialName;
-            this.quantity = quantity;
-        }// WmsAgvInfoDetail 需要
-    }
-
-    /** 把物料清单按“单箱最多装 N 件(不限品类)”切成多箱 */
-    static List<List<MatItem>> splitByCapacity(List<MatItem> src, int capacity) {
-        if (capacity <= 0) throw new IllegalArgumentException("capacity must be > 0");
-        List<List<MatItem>> bins = new ArrayList<>();
-        List<MatItem> curr = new ArrayList<>();
-        int remain = capacity;
-
-        for (MatItem it : src) {
-            int left = it.getQuantity();
-            while (left > 0) {
-                if (remain == 0) {
-                    bins.add(curr);
-                    curr = new ArrayList<>();
-                    remain = capacity;
-                }
-                int put = Math.min(left, remain);
-                MatItem piece = new MatItem();
-                piece.setMaterialCode(it.getMaterialCode());
-                piece.setMaterialName(it.getMaterialName());
-                piece.setQuantity(put);
-                piece.setMeterialId(it.getMeterialId());
-                curr.add(piece);
-
-                left -= put;
-                remain -= put;
-            }
-        }
-        if (!curr.isEmpty()) bins.add(curr);
-        return bins;
-    }
 
 
     private List<Map>getProductMapList(List<OrderProduct>productList){

+ 9 - 1
imcs-admin-boot/imcs-business-entity/src/main/java/com/github/zuihou/business/wms/WmsTransferTask.java

@@ -48,6 +48,14 @@ public class WmsTransferTask extends Entity<Long> {
     @Excel(name = "任务编号,唯一")
     private Long orderId;
 
+
+    @ApiModelProperty(value = "任务编号,唯一")
+    @NotEmpty(message = "请填写任务编号,唯一")
+    @Size(max = 64, message = "任务编号,唯一长度不能超过64")
+    @TableField(value = "order_product_id", condition = LIKE)
+    @Excel(name = "任务编号,唯一")
+    private Long orderProductId;
+
     /**
      * 关联产线订单号
      */
@@ -68,7 +76,7 @@ public class WmsTransferTask extends Entity<Long> {
     @Size(max = 10, message = "任务类型(IN=入库,OUT=出库)长度不能超过10")
     @TableField(value = "task_type", condition = LIKE)
     @Excel(name = "任务类型(IN=入库,OUT=出库)")
-    private String taskType;*/
+    private String taskType;
 
 
     /**