自动化立体仓库 - WMS系统
lty
16 小时以前 f08dd93e49e8461f362c8f45f17fe10e0fbdebec
#新增和得码入库流程,渝程进仓后续下发货主转换
1个文件已添加
14个文件已修改
543 ■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/OrderPakinController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/Order.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/OrderDetl.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/mapper/OrderPakinMapper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/OrderPakinService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/OrderPakinServiceImpl.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/kingdee/AutoTransferScheduler.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/kingdee/InboundOrderScheduler.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/kingdee/handler/AutoTransferHandler.java 194 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/kingdee/handler/AutoTransferOutHandler.java 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/kingdee/handler/InboundOrderHandler.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/OrderPakinMapper.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/orderPakin/order.js 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/orderPakin/order.html 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/OrderPakinController.java
@@ -44,6 +44,8 @@
    private WrkMastLogService wrkMastLogService;
    @Autowired
    private LocOwnerService locOwnerService;
    @Autowired
    private OrderDetlPakinService orderDetlPakinService;
    @RequestMapping(value = "/order/nav/list/auth")
    @ManagerAuth
@@ -389,7 +391,21 @@
                throw new CoolException("存在作业中数据,不能完结。请检查入库通知档和工作档");
            }
        }
        if(order.getSettle() == 66){
            List<OrderDetlPakin> lists = orderDetlPakinService.selectList(new EntityWrapper<OrderDetlPakin>().eq("order_no",order.getOrderNo()));
            for (OrderDetlPakin orderDetlPakin : lists) {
                String boxType3 = orderDetlPakin.getBoxType3();
                if (boxType3 == null || !boxType3.contains("HDU")) {
                    throw new CoolException(
                            String.format("订单 %s 的明细中不存在包含HDU的物料明细: %s (物料: %s)",
                                    order.getOrderNo(),
                                    boxType3,
                                    orderDetlPakin.getMatnr() != null ? orderDetlPakin.getMatnr() : "未知物料"
                            )
                    );
                }
            }
        }
        order.setUpdateBy(getUserId());
        order.setUpdateTime(new Date());
        if (!orderService.updateById(order)) {
src/main/java/com/zy/asrs/entity/Order.java
@@ -393,6 +393,46 @@
        this.pakinPakoutStatus = order.getPakinPakoutStatus();
    }
    public Order(OrderPakin order) {
        this.uuid = order.getUuid();
        this.orderNo = order.getOrderNo();
        this.orderTime = order.getOrderTime();
        this.docType = order.getDocType();
        this.itemId = order.getItemId();
        this.itemName = order.getItemName();
        this.allotItemId = order.getAllotItemId();
        this.defNumber = order.getDefNumber();
        this.number = order.getNumber();
        this.cstmr = order.getCstmr();
        this.cstmrName = order.getCstmrName();
        this.tel = order.getTel();
        this.operMemb = order.getOperMemb();
        this.totalFee = order.getTotalFee();
        this.discount = order.getDiscount();
        this.discountFee = order.getDiscountFee();
        this.otherFee = order.getOtherFee();
        this.actFee = order.getActFee();
        this.payType = order.getPayType();
        this.salesman = order.getSalesman();
        this.accountDay = order.getAccountDay();
        this.postFeeType = order.getPostFeeType();
        this.postFee = order.getPostFee();
        this.payTime = order.getPayTime();
        this.sendTime = order.getSendTime();
        this.shipName = order.getShipName();
        this.shipCode = order.getShipCode();
        this.settle = order.getSettle();
        this.status = order.getStatus();
        this.createBy = order.getCreateBy();
        this.createTime = order.getCreateTime();
        this.updateBy = order.getUpdateBy();
        this.updateTime = order.getUpdateTime();
        this.memo = order.getMemo();
        this.moveStatus = order.getMoveStatus();
        this.pakinPakoutStatus = order.getPakinPakoutStatus();
    }
//    Order order = new Order(
//            null,    // 编号[非空]
//            null,    // 订单编号
src/main/java/com/zy/asrs/entity/OrderDetl.java
@@ -477,6 +477,59 @@
        this.height = orderDetl.getHeight();
    }
    public OrderDetl(OrderDetlPakin orderDetl) {
        this.orderId = orderDetl.getOrderId();
        this.orderNo = orderDetl.getOrderNo();
        this.anfme = orderDetl.getAnfme();
        this.qty = orderDetl.getQty();
        this.matnr = orderDetl.getMatnr();
        this.maktx = orderDetl.getMaktx();
        this.batch = orderDetl.getBatch();
        this.specs = orderDetl.getSpecs();
        this.model = orderDetl.getModel();
        this.color = orderDetl.getColor();
        this.brand = orderDetl.getBrand();
        this.unit = orderDetl.getUnit();
        this.price = orderDetl.getPrice();
        this.sku = orderDetl.getSku();
        this.units = orderDetl.getUnits();
        this.barcode = orderDetl.getBarcode();
        this.origin = orderDetl.getOrigin();
        this.manu = orderDetl.getManu();
        this.manuDate = orderDetl.getManuDate();
        this.itemNum = orderDetl.getItemNum();
        this.safeQty = orderDetl.getSafeQty();
        this.weight = orderDetl.getWeight();
        this.manLength = orderDetl.getManLength();
        this.volume = orderDetl.getVolume();
        this.threeCode = orderDetl.getThreeCode();
        this.supp = orderDetl.getSupp();
        this.suppCode = orderDetl.getSuppCode();
        this.beBatch = orderDetl.getBeBatch();
        this.deadTime = orderDetl.getDeadTime();
        this.deadWarn = orderDetl.getDeadWarn();
        this.source = orderDetl.getSource();
        this.inspect = orderDetl.getInspect();
        this.danger = orderDetl.getDanger();
        this.status = orderDetl.getStatus();
        this.createBy = orderDetl.getCreateBy();
        this.createTime = orderDetl.getCreateTime();
        this.updateBy = orderDetl.getUpdateBy();
        this.updateTime = orderDetl.getUpdateTime();
        this.memo = orderDetl.getMemo();
        this.pakinPakoutStatus = orderDetl.getPakinPakoutStatus();
        this.lineNumber = orderDetl.getLineNumber();
        this.standby1 = orderDetl.getStandby1();
        this.standby2 = orderDetl.getStandby2();
        this.standby3 = orderDetl.getStandby3();
        this.boxType1 = orderDetl.getBoxType1();
        this.boxType2 = orderDetl.getBoxType2();
        this.boxType3 = orderDetl.getBoxType3();
        this.erpAnfme = orderDetl.getErpAnfme();
        this.width = orderDetl.getWidth();
        this.height = orderDetl.getHeight();
    }
    public String getOrderId$(){
        OrderService service = SpringUtils.getBean(OrderService.class);
src/main/java/com/zy/asrs/mapper/OrderPakinMapper.java
@@ -20,6 +20,7 @@
    List<OrderPakin> selectComplete9();
    List<OrderPakin> selectComplete10();
    List<OrderPakin> selectComplete66();
    List<OrderPakin> selectComplete67();
    int addToLogTable(OrderPakin order);
src/main/java/com/zy/asrs/service/OrderPakinService.java
@@ -30,6 +30,7 @@
    List<OrderPakin> selectComplete9();
    List<OrderPakin> selectComplete10();
    List<OrderPakin> selectComplete66();
    List<OrderPakin> selectComplete67();
    boolean addToLogTable(OrderPakin order);
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java
@@ -937,7 +937,7 @@
            List<OrderDetlPakin> orderDetlPakins = orderDetlPakinService.selectList(new EntityWrapper<OrderDetlPakin>()
                    .eq("matnr", combMat.getMatnr()).eq("box_type3", combMat.getOrderNo())
                    .eq("standby1", combMat.getStandby1()).eq("standby2", combMat.getStandby2())
                    .eq("standby3", combMat.getStandby3()).eq("box_type2","shyucheng.test"));
                    .eq("standby3", combMat.getStandby3()));
            if (orderDetlPakins.size() > 0) {
                orderNo = orderDetlPakins.get(0).getOrderNo();
                combMat.setBoxType1(orderDetlPakins.get(0).getBoxType1());
src/main/java/com/zy/asrs/service/impl/OrderPakinServiceImpl.java
@@ -191,7 +191,10 @@
    public List<OrderPakin> selectComplete66() {
        return this.baseMapper.selectComplete66();
    }
    @Override
    public List<OrderPakin> selectComplete67() {
        return this.baseMapper.selectComplete67();
    }
    @Override
    public List<OrderPakin> selectComplete8() {
src/main/java/com/zy/asrs/task/kingdee/AutoTransferScheduler.java
@@ -8,6 +8,7 @@
import com.zy.asrs.service.OrderService;
import com.zy.asrs.task.core.ReturnT;
import com.zy.asrs.task.kingdee.handler.AutoTransferHandler;
import com.zy.asrs.task.kingdee.handler.AutoTransferOutHandler;
import com.zy.asrs.task.kingdee.handler.SaveOrderSyncHandler;
import com.zy.common.entity.Parameter;
import lombok.extern.slf4j.Slf4j;
@@ -35,10 +36,11 @@
    private boolean ReviewOrderSwitch;
    @Autowired
    private AutoTransferHandler autoTransferHandler;
    @Autowired
    private AutoTransferOutHandler autoTransferOutHandler;
    @Scheduled(cron = "0/30 * * * * ? ")
    @Async("orderThreadPool")
    public void completeAndReport(){
    public void completeAndReport(){   //库内库存转换,出库对应物料及数量,更新库存明细
        List<OrderPakin> orders = orderPakinService.selectComplete66();
        if(orders.size() > 0){
            for (OrderPakin order : orders) {
@@ -50,4 +52,18 @@
        }
    }
    @Scheduled(cron = "0/30 * * * * ? ")
    @Async("orderThreadPool")
    public void completeAndReportHD(){   ///和得出库渝程上报
        List<OrderPakin> orders = orderPakinService.selectComplete67();
        if(orders.size() > 0){
            for (OrderPakin order : orders) {
                ReturnT<String> result = autoTransferOutHandler.start(order);//
                if (!result.isSuccess()) {
                    log.error("单据[orderNo={}]转换出库上报失败", order.getOrderNo());
                }
            }
        }
    }
}
src/main/java/com/zy/asrs/task/kingdee/InboundOrderScheduler.java
@@ -27,8 +27,8 @@
        inboundOrderHandler.syncMaterialData(); // 同步物料档案
    }
    @Scheduled(cron = "0 */6 * * * ?")
//    @Scheduled(cron = "0/5 * * * * ?")
    //    @Scheduled(cron = "0 */6 * * * ?")
    @Scheduled(cron = "0/5 * * * * ?")
    void login(){
        if(!InboundOrderSwitch){
            return;
src/main/java/com/zy/asrs/task/kingdee/handler/AutoTransferHandler.java
@@ -1,5 +1,6 @@
package com.zy.asrs.task.kingdee.handler;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zy.asrs.entity.*;
import com.zy.asrs.service.*;
@@ -44,105 +45,134 @@
    @Transactional(rollbackFor = Exception.class)
    public ReturnT<String> start(OrderPakin order) {
        // 获取该订单下的所有明细
        List<OrderDetlPakin> orderDetlPakins = orderDetlPakinService.selectList(
                new EntityWrapper<OrderDetlPakin>().eq("order_no", order.getOrderNo()));
        JSONObject logData = new JSONObject();
        String responseMsg = "";
        boolean success = false;
        // 遍历每个订单明细进行库存转换
        for (OrderDetlPakin orderDetlPakin : orderDetlPakins) {
            double orderQuantity = orderDetlPakin.getAnfme(); // 本明细需要转换的数量
            double remainingQuantity = orderQuantity;        // 剩余未满足的数量
            double convertedQuantity = 0.0;                  // 已成功转换的数量
        try {
            logData.put("orderNo", order.getOrderNo());
            logData.put("docType", order.getDocType());
            logData.put("settle", order.getSettle());
            logData.put("startTime", System.currentTimeMillis());
            log.info("开始处理订单明细: 订单号 = {}, 物料号 = {}, 需要转换数量 = {}",
                    order.getOrderNo(), orderDetlPakin.getMatnr(), orderQuantity);
            // 获取该订单下的所有明细
            List<OrderDetlPakin> orderDetlPakins = orderDetlPakinService.selectList(
                    new EntityWrapper<OrderDetlPakin>().eq("order_no", order.getOrderNo()));
            // 查询符合条件的可用库存:同一物料 + box_type3 以 HDU25 开头
            List<LocDetl> locDetls = locDetlService.selectList(
                    new EntityWrapper<LocDetl>()
                            .eq("matnr", orderDetlPakin.getMatnr())
                            .like("box_type3", "HDU25%")
                            .orderBy("anfme") // 可根据业务调整排序(如先进先出)
            );
            if (locDetls.isEmpty()) {
                log.error("无符合条件的库存: 订单 {} 物料 {}", order.getOrderNo(), orderDetlPakin.getMatnr());
                throw new IllegalArgumentException("无符合条件的库存满足订单 " + order.getOrderNo() +
                        " 的物料 " + orderDetlPakin.getMatnr());
            if (orderDetlPakins.isEmpty()) {
                throw new IllegalArgumentException("订单 " + order.getOrderNo() + " 无任何明细,无法转换");
            }
            // 逐条消耗库存
            for (LocDetl locDetl : locDetls) {
                if (remainingQuantity <= 0) {
                    break; // 已完全满足需求
            // 遍历每个订单明细进行库存转换(原逻辑保持不变)
            for (OrderDetlPakin orderDetlPakin : orderDetlPakins) {
                double orderQuantity = orderDetlPakin.getAnfme();
                double remainingQuantity = orderQuantity;
                double convertedQuantity = 0.0;
                log.info("开始处理订单明细: 订单号={}, 物料号={}, 需要转换数量={}",
                        order.getOrderNo(), orderDetlPakin.getMatnr(), orderQuantity);
                List<LocDetl> locDetls = locDetlService.selectList(
                        new EntityWrapper<LocDetl>()
                                .eq("matnr", orderDetlPakin.getMatnr())
                                .like("box_type3", "HDU%")
                                .orderBy("anfme")
                );
                if (locDetls.isEmpty()) {
                    throw new IllegalArgumentException("无符合条件的库存: 订单 " + order.getOrderNo() +
                            " 物料 " + orderDetlPakin.getMatnr());
                }
                double stockQty = locDetl.getAnfme();
                if (stockQty <= 0) {
                    continue; // 跳过空库存
                for (LocDetl locDetl : locDetls) {
                    if (remainingQuantity <= 0) break;
                    double stockQty = locDetl.getAnfme();
                    if (stockQty <= 0) continue;
                    double consumeQty = Math.min(stockQty, remainingQuantity);
                    // 创建分配记录...
                    LocDetl allocated = new LocDetl();
                    BeanUtils.copyProperties(locDetl, allocated);
                    allocated.setAnfme(consumeQty);
                    allocated.setStandby1(orderDetlPakin.getStandby1());
                    allocated.setStandby2(orderDetlPakin.getStandby2());
                    allocated.setStandby3(orderDetlPakin.getStandby3());
                    allocated.setBoxType1(orderDetlPakin.getBoxType1());
                    allocated.setBoxType2(orderDetlPakin.getBoxType2());
                    allocated.setBoxType3(orderDetlPakin.getBoxType3());
                    allocated.setOrderNo(orderDetlPakin.getOrderNo());
                    locDetlService.insert(allocated);
                    // 扣减原库存...
                    double remainingStock = stockQty - consumeQty;
                    if (remainingStock <= 0) {
                        locDetlService.delete(new EntityWrapper<LocDetl>()
                                .eq("loc_no", locDetl.getLocNo())
                                .eq("matnr", locDetl.getMatnr())
                                .eq("box_type3", locDetl.getBoxType3()));
                    } else {
                        locDetl.setAnfme(remainingStock);
                        locDetlService.update(locDetl, new EntityWrapper<LocDetl>()
                                .eq("loc_no", locDetl.getLocNo())
                                .eq("matnr", locDetl.getMatnr())
                                .eq("box_type3", locDetl.getBoxType3()));
                    }
                    convertedQuantity += consumeQty;
                    remainingQuantity -= consumeQty;
                }
                // 本次实际消耗的数量
                double consumeQty = Math.min(stockQty, remainingQuantity);
                // 创建一条新的“已分配给订单”的库存记录(完整复制原记录)
                LocDetl allocated = new LocDetl();
                BeanUtils.copyProperties(locDetl, allocated);
                // 设置分配数量 + 覆盖指定字段
                allocated.setAnfme(consumeQty);
                allocated.setStandby1(orderDetlPakin.getStandby1());
                allocated.setStandby2(orderDetlPakin.getStandby2());
                allocated.setStandby3(orderDetlPakin.getStandby3());
                allocated.setBoxType1(orderDetlPakin.getBoxType1());
                allocated.setBoxType2(orderDetlPakin.getBoxType2());
                allocated.setBoxType3(orderDetlPakin.getBoxType3());
                allocated.setOrderNo(orderDetlPakin.getOrderNo());
                // 插入已分配记录
                locDetlService.insert(allocated);
                log.info("已分配库存记录: 位置={}, 数量={}, 剩余需求={}",
                        locDetl.getLocNo(), consumeQty, remainingQuantity - consumeQty);
                // 处理原库存记录:扣减后数量为0则删除,否则更新剩余数量
                double remainingStock = stockQty - consumeQty;
                if (remainingStock <= 0) {
                    // 数量正好耗尽或已为0,直接删除原记录
                    locDetlService.delete(new EntityWrapper<LocDetl>().eq("loc_no",locDetl.getLocNo()).eq("matnr",locDetl.getMatnr()).eq("box_type3",locDetl.getBoxType3()));
                    log.info("原库存已耗尽,删除记录: 位置={}, 原数量={}", locDetl.getLocNo(), stockQty);
                } else {
                    // 仍有剩余,更新数量
                    locDetl.setAnfme(remainingStock);
                    locDetlService.update(locDetl,new EntityWrapper<LocDetl>().eq("loc_no",locDetl.getLocNo()).eq("matnr",locDetl.getMatnr()).eq("box_type3",locDetl.getBoxType3()));
                    log.info("原库存部分消耗,更新剩余数量: 位置={}, 剩余={}", locDetl.getLocNo(), remainingStock);
                if (remainingQuantity > 0) {
                    throw new IllegalArgumentException("库存不足: 订单 " + order.getOrderNo() +
                            " 物料 " + orderDetlPakin.getMatnr() + " 缺少 " + remainingQuantity);
                }
                // 更新统计量
                convertedQuantity += consumeQty;
                remainingQuantity -= consumeQty;
                orderDetlPakin.setQty(convertedQuantity);
                orderDetlPakinService.updateById(orderDetlPakin);
            }
            // 检查是否完全满足该明细的需求
            if (remainingQuantity > 0) {
                log.error("库存不足: 订单 {} 物料 {} 需求 {},仅转换 {},缺少 {}",
                        order.getOrderNo(), orderDetlPakin.getMatnr(), orderQuantity, convertedQuantity, remainingQuantity);
                throw new IllegalArgumentException("库存不足以满足订单 " + order.getOrderNo() +
                        " 的物料 " + orderDetlPakin.getMatnr() + " 需求,缺少 " + remainingQuantity);
            }
            // 全部成功
            order.setSettle(67L);
            orderPakinServiceImpl.updateById(order);
            // 更新订单明细已转换数量
            orderDetlPakin.setQty(convertedQuantity);
            orderDetlPakinService.updateById(orderDetlPakin);
            success = true;
            responseMsg = "库存转换成功,订单号: " + order.getOrderNo() + ",已设置 settle=67";
            log.info(responseMsg);
            log.info("订单明细转换完成: 订单号 = {}, 物料号 = {}, 转换数量 = {}",
                    order.getOrderNo(), orderDetlPakin.getMatnr(), convertedQuantity);
        } catch (Exception e) {
            success = false;
            responseMsg = "库存转换失败: " + e.getMessage();
            log.error("自动转换失败,订单号: {}, 原因: {}", order.getOrderNo(), e.getMessage(), e);
            throw e;  // 让 @Transactional 回滚
        } finally {
            // 无论成功失败,都记录日志
            logData.put("endTime", System.currentTimeMillis());
            logData.put("durationMs", logData.getLongValue("endTime") - logData.getLongValue("startTime"));
            logData.put("success", success);
            logData.put("message", responseMsg);
            saveApiLog(logData, responseMsg, success);
        }
        // 所有明细均处理完成,设置订单 settle = 67
        order.setSettle(67L);
        orderPakinServiceImpl.updateById(order);
        log.info("订单全部明细转换完成,设置 settle = 67,订单号 = {}", order.getOrderNo());
        return success ? SUCCESS : FAIL;
    }
        return SUCCESS;
    private void saveApiLog(JSONObject add, String response, boolean success) {
        try {
            apiLogService.save(
                    "货主转换",
                    "AutoTransferHandler",
                    null,
                    "127.0.0.1",
                    add.toJSONString(),
                    response,
                    success
            );
        } catch (Exception e) {
            log.error("接口日志保存失败", e);
        }
    }
}
src/main/java/com/zy/asrs/task/kingdee/handler/AutoTransferOutHandler.java
New file
@@ -0,0 +1,146 @@
package com.zy.asrs.task.kingdee.handler;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.toolkit.CollectionUtils;
import com.zy.asrs.entity.Order;
import com.zy.asrs.entity.OrderDetl;
import com.zy.asrs.entity.OrderDetlPakin;
import com.zy.asrs.entity.OrderPakin;
import com.zy.asrs.service.*;
import com.zy.asrs.service.impl.ErpSecretServiceImpl;
import com.zy.asrs.service.impl.OrderDetlPakinServiceImpl;
import com.zy.asrs.service.impl.OrderDetlServiceImpl;
import com.zy.asrs.service.impl.OrderPakinServiceImpl;
import com.zy.asrs.task.AbstractHandler;
import com.zy.asrs.task.core.ReturnT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
public class AutoTransferOutHandler extends AbstractHandler<String> {
    @Autowired
    private OrderService orderService;
    @Autowired
    private ApiLogService apiLogService;
    @Autowired
    private DocTypeService docTypeService;
    @Autowired
    private LoginAuthenticationHandler loginAuthenticationHandler;
    @Autowired
    private ErpSecretServiceImpl erpSecretService;
    @Autowired
    private LocDetlService locDetlService;
    @Autowired
    private MatService matService;
    @Autowired
    private OrderDetlPakinServiceImpl orderDetlPakinService;
    @Autowired
    private OrderDetlServiceImpl orderDetlService;
    @Autowired
    private OrderPakinServiceImpl orderPakinServiceImpl;
    @Autowired
    private OrderPakinServiceImpl orderPakinService;
    @Transactional(rollbackFor = Exception.class)
    public ReturnT<String> start(OrderPakin orderPakin) {
        JSONObject logData = new JSONObject();
        String responseMsg = "";
        boolean apiSuccess = false;
        Order orderNew = null;
        try {
            logData.put("orderNo", orderPakin.getOrderNo());
            logData.put("operation", "生成出库单");
            logData.put("source", "入库单转出库单");
            logData.put("startTime", System.currentTimeMillis());
            orderNew = new Order(orderPakin);
            orderNew.setDocType(23L);
            orderNew.setOrderNo(orderPakin.getOrderNo() + "ZHCK");
            orderNew.setSettle(65L);
            // 插入出库主单
            orderService.insert(orderNew);
            List<OrderDetlPakin> pakinDetails = orderDetlPakinService.selectList(
                    new EntityWrapper<OrderDetlPakin>().eq("order_no", orderPakin.getOrderNo())
            );
            boolean hasInsertFailed = false;
            if (CollectionUtils.isNotEmpty(pakinDetails)) {
                for (OrderDetlPakin pd : pakinDetails) {
                    OrderDetl od = new OrderDetl(pd);
                    od.setOrderId(orderNew.getId());
                    boolean insertSuccess = orderDetlService.insert(od);
                    if (!insertSuccess) {
                        hasInsertFailed = true;
                        log.warn("出库明细插入失败:出库单号={}, 物料={}",
                                orderNew.getOrderNo(), pd.getMatnr());
                    }
                }
            }
            // 根据明细插入结果更新状态
            if (!hasInsertFailed) {
                orderNew.setSettle(4L);           // 出库单成功状态
                orderPakin.setSettle(4L);         // 原入库单更新状态(视业务是否需要)
                orderService.updateById(orderNew);
                orderPakinService.updateById(orderPakin);  // 注意:这里用了 orderPakinService
                apiSuccess = true;
                responseMsg = String.format("成功生成出库单:%s,共 %d 条明细",
                        orderNew.getOrderNo(), pakinDetails.size());
                log.info(responseMsg);
            } else {
                responseMsg = "部分出库明细插入失败,订单号:" + orderNew.getOrderNo();
                log.error(responseMsg);
                throw new RuntimeException("部分明细插入失败,触发事务回滚");
            }
        } catch (Exception e) {
            apiSuccess = false;
            responseMsg = "生成出库单失败:" + e.getMessage();
            log.error("生成出库单失败,入库单号:{},原因:{}", orderPakin.getOrderNo(), e.getMessage(), e);
            // 如果你希望失败时不回滚,可以注释掉下面这行
            throw e;  // ← 保持事务回滚(推荐)
        } finally {
            // 无论成功失败,都记录日志
            logData.put("endTime", System.currentTimeMillis());
            logData.put("durationMs", logData.getLongValue("endTime") - logData.getLongValue("startTime"));
            logData.put("success", apiSuccess);
            logData.put("message", responseMsg);
            logData.put("outOrderNo", orderNew != null ? orderNew.getOrderNo() : "未生成");
            saveApiLog(logData, responseMsg, apiSuccess);
        }
        return apiSuccess ? SUCCESS : FAIL;
    }
    private void saveApiLog(JSONObject add, String response, boolean success) {
        try {
            apiLogService.save(
                    "货主转换出库上报",
                    "AutoTransferHandler",
                    null,
                    "127.0.0.1",
                    add.toJSONString(),
                    response,
                    success
            );
        } catch (Exception e) {
            log.error("接口日志保存失败", e);
        }
    }
}
src/main/java/com/zy/asrs/task/kingdee/handler/InboundOrderHandler.java
@@ -157,7 +157,7 @@
                case "PUR_RECEIVEBIll": //已审核收料单查询
                    jsonObject.put("start_biztime",  latestUpdateTime);//业务起始日期
                    jsonObject.put("end_biztime", sdf1.format(now));//业务结束日期
                    jsonObject.put("billno", null);
                    jsonObject.put("billno", "CGSL-260106-000001");
                    jsonObject.put("billstatus", Arrays.asList("C"));//数据状态 [A:暂存, B:已提交, C:已审核]
                    jsonObject.put("start_auditdate", latestUpdateTime);
                    jsonObject.put("end_auditdate", sdf1.format(now));
src/main/resources/mapper/OrderPakinMapper.xml
@@ -87,6 +87,14 @@
          and status = 1
        order by create_time asc
    </select>
    <select id="selectComplete67" resultMap="BaseResultMap">
        select top 5 *
        from man_order_pakin
        where 1=1
          and settle = 67
          and status = 1
        order by create_time asc
    </select>
    <select id="selectComplete8" resultMap="BaseResultMap">
        select top 5 *
        from man_order_pakin
src/main/webapp/static/js/orderPakin/order.js
@@ -96,6 +96,8 @@
            showWrkTrace(data.id);
        } else if (layEvent === 'del') {
            doDel(data.id);
        }else if(layEvent === 'transfer'){
            doModifyTransfer(data.id, data.orderNo, 66);
        } else if (layEvent === 'complete') {
            doModify(data.id, data.orderNo, 4);
        } else if (layEvent === 'look') {
@@ -484,6 +486,44 @@
        });
    }
    // 修改订单状态
    function doModifyTransfer(orderId, orderNo, settle) {
        layer.confirm('确定要货主转换吗?', {
            shade: .1,
            skin: 'layui-layer-admin'
        }, function (i) {
            layer.close(i);
            layer.load(2);
            console.log(orderId);
            console.log(settle);
            $.ajax({
                url: baseUrl+"/order/pakin/order/update/auth",
                headers: {'token': localStorage.getItem('token')},
                data: {
                    id: orderId,
                    orderNo: orderNo,
                    settle: settle
                },
                method: 'POST',
                success: function (res) {
                    layer.closeAll('loading');
                    if (res.code === 200){
                        if (insTbCount === 0) {
                            insTb.reload({page: {curr: 1}});
                        } else {
                            $(".layui-laypage-btn")[0].click();
                        }
                        layer.msg(res.msg, {icon: 1});
                    } else if (res.code === 403){
                        top.location.href = baseUrl+"/";
                    }else {
                        layer.msg(res.msg, {icon: 2});
                    }
                }
            })
        });
    }
    // 任务追溯
    function showWrkTrace(orderId) {
        let loadIndex = layer.msg('请求中...', {icon: 16, shade: 0.01, time: false});
src/main/webapp/views/orderPakin/order.html
@@ -103,6 +103,9 @@
    {{# if (d.settle == 0 || d.settle == 1 || d.settle == 2) { }}
    <a class="layui-btn layui-btn-primary layui-border-blue layui-btn-xs btn-complete" lay-event="complete">完结</a>
    {{# } }}
    {{# if (d.settle == 0 || d.settle == 1 || d.settle == 2) { }}
    <a class="layui-btn layui-btn-primary layui-border-blue layui-btn-xs btn-complete" lay-event="transfer">转换</a>
    {{# } }}
</script>
<!-- 表格操作列 -->
<script type="text/html" id="tbLook">
@@ -135,6 +138,12 @@
          class="layui-badge layui-badge-blue"
          {{# }else if(d.settle === 5){ }}
          class="layui-badge layui-badge-gray"
          {{# }else if(d.settle === 66){ }}
          class="layui-badge layui-badge-gray"
          {{# }else if(d.settle === 67){ }}
          class="layui-badge layui-badge-gray"
          {{# }else if(d.settle === 65){ }}
          class="layui-badge layui-badge-gray"
          {{# }else if(d.settle === 6){ }}
          class="layui-badge layui-badge-gray"
          {{# } }}