rk
8 小时以前 552238172036acf08ccf36134282a06b5e21b936
server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
@@ -133,6 +133,8 @@
    @Autowired
    private MemberCouponMapper memberCouponMapper;
    @Autowired
    private CouponMapper couponMapper;
    @Autowired
    private AreasBiz areasBiz;
@@ -234,10 +236,12 @@
                .selectAll(Orders.class)
                .selectAs(Category::getDetail, Orders::getOrderLevel)
                .select("s1.name", Orders::getDepositShopName)
                .leftJoin(Category.class, Category::getId, Orders::getGoodType)
                .select("o2.code", Orders::getRelationOrderCode)
                .leftJoin(Category.class, Category::getId, Orders::getGoodLevel)
                .leftJoin(DriverInfo.class, DriverInfo::getId, Orders::getAcceptDriver)
                .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID")
                .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID") ;
                .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID")
                .leftJoin("orders o2 on o2.id = t.RELATION_ORDER_ID")
                ;
        Utils.MP.blankToNull(pageWrap.getModel());
        queryWrapper.eq(pageWrap.getModel().getDeleted() != null, Orders::getDeleted, pageWrap.getModel().getDeleted());
@@ -346,7 +350,7 @@
    }
    /**
     * 计算就地存取预估费用
     * 计算就地寄存预估费用
     *
     * 计算规则:
     * 1. 根据城市+物品类型 查询 pricing_rule(type=0),fieldA=categoryId, fieldB=单价(分/天)
@@ -355,7 +359,7 @@
     * 4. 保价费用 = 报价金额 × 保价费率(字典 INSURANCE_RATE),元转分
     * 5. 总价格 = 物品价格 + 保价费用
     *
     * @param dto 就地存取计价请求参数
     * @param dto 就地寄存计价请求参数
     * @return 价格计算结果
     */
    @Override
@@ -445,7 +449,7 @@
    }
    /**
     * 计算异地存取预估费用
     * 计算同城寄送预估费用
     *
     * 计算规则:
     * 1. 调用腾讯地图API计算寄件点与取件点的驾车距离(米→公里)
@@ -460,7 +464,7 @@
     * 7. 加急费用 = 物品价格 × 加急系数(字典 URGENT_COEFFICIENT)
     * 8. 总价格 = 物品价格 + 保价费用 + 加急费用
     *
     * @param dto 异地存取计价请求参数
     * @param dto 同城寄送计价请求参数
     * @return 价格计算结果
     */
    @Override
@@ -497,7 +501,7 @@
            ruleMap.put(r.getFieldA(), r);
        }
        // 查询就地存取计价规则 pricing_rule type=0,用于获取 locallyPrice
        // 查询就地寄存计价规则 pricing_rule type=0,用于获取 locallyPrice
        List<PricingRule> localRules = pricingRuleMapper.selectList(new QueryWrapper<PricingRule>().lambda()
                .eq(PricingRule::getDeleted, Constants.ZERO)
                .eq(PricingRule::getType, Constants.ZERO)
@@ -551,7 +555,7 @@
            long subtotal = unitPrice * item.getQuantity();
            // 就地存取单价
            // 就地寄存单价
            PricingRule localRule = localRuleMap.get(String.valueOf(item.getCategoryId()));
            Long locallyPrice = localRule != null ? Long.parseLong(localRule.getFieldB()) : null;
@@ -662,7 +666,7 @@
                .le(MemberCoupon::getLimitPrice, totalPrice)
                .ge(MemberCoupon::getEndDate, now)
                .orderByDesc(MemberCoupon::getPrice)
                .orderByAsc(MemberCoupon::getEndDate));
                .orderByAsc(MemberCoupon::getCreateDate));
        result.setAvailableCoupons(availableCoupons);
        if (couponId == null) {
@@ -810,7 +814,7 @@
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请选择取件店铺或输入自选取件地址");
            }
        } else {
            // 就地存取:取件门店同寄件门店
            // 就地寄存:取件门店同寄件门店
            takeShop = depositShop;
        }
@@ -860,6 +864,7 @@
        orders.setPayStatus(Constants.ZERO); // 未支付
        orders.setCommentStatus(Constants.ZERO); // 未评价
        orders.setSettlementStatus(Constants.ZERO); // 未结算
        orders.setExceptionStatus(Constants.ZERO); // 非异常
        orders.setDeleted(Constants.ZERO);
        orders.setCreateTime(now);
        orders.setUpdateTime(now);
@@ -1151,6 +1156,11 @@
        if (Objects.isNull(order)) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        // 实付金额 = 支付金额 - 退款金额 + 逾期费用
        long pay = order.getPayAmount() != null ? order.getPayAmount() : 0L;
        long refund = order.getRefundAmount() != null ? order.getRefundAmount() : 0L;
        long overdue = order.getOverdueAmount() != null ? order.getOverdueAmount() : 0L;
        order.setPayAmount(pay - refund + overdue);
        OrderDetailVO vo = new OrderDetailVO();
        vo.setOrder(order);
@@ -1219,6 +1229,25 @@
            }
        }
        // 评价信息
        List<OrderComment> comments = orderCommentMapper.selectList(new QueryWrapper<OrderComment>().lambda()
                .eq(OrderComment::getOrderId, id)
                .eq(OrderComment::getDeleted, Constants.ZERO));
        if (CollectionUtils.isNotEmpty(comments)) {
            for (OrderComment c : comments) {
                if (Constants.equalsInteger(c.getTargetType(), Constants.ONE)) {
                    vo.setDepositScore(c.getScore());
                } else if (Constants.equalsInteger(c.getTargetType(), Constants.TWO)) {
                    vo.setTakeScore(c.getScore());
                } else if (Constants.equalsInteger(c.getTargetType(), Constants.THREE)) {
                    vo.setDriverScore(c.getScore());
                }
            }
            vo.setCommentContent(comments.get(0).getContent());
            vo.setCommentTime(comments.get(0).getCreateTime());
            vo.setCommentImages(getFileUrls(id, Constants.FileType.COMMENT_ATTACH.getKey(), imgPrefix));
        }
        // 取消/退款状态时查询退款记录
        Integer status = order.getStatus();
        if (status != null && (status == Constants.OrderStatus.overdue.getStatus()
@@ -1257,7 +1286,7 @@
        vo.setCode(order.getCode());
        vo.setPayAmountYuan(order.getPayAmount() != null ? Constants.getFormatMoney(order.getPayAmount()) : 0);
        vo.setType(order.getType());
        vo.setTypeDesc(order.getType() != null && order.getType() == Constants.ONE ? "异地存取" : "就地存取");
        vo.setTypeDesc(order.getType() != null && order.getType() == Constants.ONE ? "同城寄送" : "就地寄存");
        vo.setDetailList(buildDetailList(id));
        return vo;
@@ -1276,9 +1305,9 @@
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        // 前置条件校验:异地存取 + 已寄存
        // 前置条件校验:同城寄送 + 已寄存
        if (!Constants.ONE.equals(order.getType())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅支持异地存取订单派单");
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅支持同城寄送订单派单");
        }
        if (!Integer.valueOf(Constants.OrderStatus.deposited.getStatus()).equals(order.getStatus())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅已寄存状态订单可派单");
@@ -1508,7 +1537,7 @@
     *
     * @param orders        订单实体(需要 totalAmount、cityId 已设置)
     * @param depositShop   寄件门店(需要 companyType)
     * @param takeShop      取件门店(需要 companyType,就地存取时与 depositShop 相同)
     * @param takeShop      取件门店(需要 companyType,就地寄存时与 depositShop 相同)
     */
    private void calculateAndSetFeeAllocation(Orders orders, ShopInfo depositShop, ShopInfo takeShop) {
        Long totalAmount = orders.getTotalAmount() != null ? orders.getTotalAmount() : 0L;
@@ -1655,7 +1684,8 @@
                cal.set(Calendar.MINUTE, 0);
                cal.set(Calendar.SECOND, 0);
                cal.set(Calendar.MILLISECOND, 0);
                wrapper.ge(Orders::getFinishTime, cal.getTime());
                wrapper.ge(Orders::getFinishTime, cal.getTime())
                        .eq(Orders::getStatus, Constants.OrderStatus.finished.getKey());
            }
        }
        // 关键词搜索:收件人/收件人电话模糊、订单号精准
@@ -1719,8 +1749,13 @@
                // 评价状态
                vo.setCommentStatus(o.getCommentStatus());
                String dateStr = new SimpleDateFormat("dd").format(o.getPayTime() != null ? o.getPayTime() : new Date());
                String autoNumStr = String.format("%03d", o.getAutoNum() != null ? o.getAutoNum() : 0);
                String sort = o.getDepositShopId() + "-" + dateStr + "-" + autoNumStr;
                //序号
                vo.setSortnum(Constants.formatIntegerNum(o.getDepositShopId())+"-"+o.getId());
                vo.setSortnum(sort);
                if(o.getTakeShopId()!=null){
                    vo.setSortnumTake(Constants.formatIntegerNum(o.getTakeShopId())+"-"+o.getId());
                }
@@ -1737,6 +1772,8 @@
                fillOverdueStatus(vo, o, details);
                // 优惠券抵扣金额
                vo.setDeductionAmount(o.getDeductionAmount());
                // 异常订单标识
                vo.setAbnormalOrder(o.getExceptionStatus());
                // 可开票金额(支付金额 - 退款金额)
                if (model != null && model.getInvoiceStatus() != null && Constants.equalsInteger(model.getInvoiceStatus(), Constants.ONE)) {
                    long payAmt = o.getPayAmount() != null ? o.getPayAmount() : 0L;
@@ -1815,7 +1852,7 @@
                    .or(w3-> w3.eq(Orders::getType, Constants.ONE).eq(Orders::getDepositShopId, shopId)
                            .eq(Orders::getStatus, Constants.OrderStatus.waitDeposit.getStatus()))
                    .or(w2 -> w2.eq(Orders::getType, Constants.ONE).eq(Orders::getTakeShopId, shopId)
                            .eq(Orders::getStatus, Constants.OrderStatus.arrived.getStatus())))
                            .in(Orders::getStatus, Constants.OrderStatus.arrived.getStatus(),Constants.OrderStatus.delivering.getStatus())))
            );
        } else {
            wrapper.and(w -> w.eq(Orders::getDepositShopId, shopId).or().eq(Orders::getTakeShopId, shopId));
@@ -1975,6 +2012,7 @@
        vo.setUrgentAmount(order.getUrgentAmount());
        vo.setIsUrgent(order.getIsUrgent());
        vo.setActualPayAmount(Constants.equalsInteger(order.getPayStatus(), Constants.ONE)?order.getPayAmount():order.getEstimatedAmount());
        vo.setDeductionAmount(order.getDeductionAmount());
        // 标记
        vo.setExceptionStatus(order.getExceptionStatus());
@@ -1988,13 +2026,12 @@
            vo.setPayCountdownMs(calcPayCountdownMs(order));
        }
        //序号
        vo.setSortnum(Constants.formatIntegerNum(order.getDepositShopId())+"-"+order.getId());
        if(order.getTakeShopId()!=null){
            String dateStr = new SimpleDateFormat("dd").format(order.getPayTime() != null ? order.getPayTime() : new Date());
            String autoNumStr = String.format("%03d", order.getAutoNum() != null ? order.getAutoNum() : 0);
            String sort = order.getTakeShopId() + "-" + dateStr + "-" + autoNumStr;
            vo.setSortnumTake(sort);
        }
//        vo.setSortnum(Constants.formatIntegerNum(order.getDepositShopId())+"-"+order.getId());
        String dateStr = new SimpleDateFormat("dd").format(order.getPayTime() != null ? order.getPayTime() : new Date());
        String autoNumStr = String.format("%03d", order.getAutoNum() != null ? order.getAutoNum() : 0);
        String sort = order.getDepositShopId() + "-" + dateStr + "-" + autoNumStr;
        vo.setSortnum(sort);
        vo.setDepositShopId(order.getDepositShopId());
        // 存件门店
        if (order.getDepositShopId() != null) {
            ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId());
@@ -2135,6 +2172,10 @@
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "异常订单无法取消");
        }
        Integer status = order.getStatus();
        if (status == null) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单状态异常");
@@ -2170,8 +2211,6 @@
                    "orderNo", order.getCode());
            // 短信通知会员:订单已取消
            Member cancelMember2 = memberMapper.selectById(memberId);
            sendSmsNotify(cancelMember2 != null ? cancelMember2.getTelephone() : null,
                    Constants.SmsNotify.MEMBER_CANCELLED, "orderNo", order.getCode());
            // 调用微信退款V3,全额退款
            String outRefundNo = ID.nextGUID();
@@ -2209,6 +2248,8 @@
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "退款失败,请联系客服处理");
            }
            ordersRefundMapper.insert(refund);
            sendSmsNotify(cancelMember2 != null ? cancelMember2.getTelephone() : null,
                    Constants.SmsNotify.MEMBER_CANCELLED, "orderNo", order.getCode());
            restoreCoupon(order);
            return;
        }
@@ -2282,16 +2323,71 @@
     * 保存取消订单操作日志
     */
    private void restoreCoupon(Orders order) {
//        if (order.getCouponId() == null || order.getDeductionAmount() == null || order.getDeductionAmount() <= 0) {
//            return;
//        }
//        memberCouponMapper.update(new UpdateWrapper<MemberCoupon>().lambda()
//                .set(MemberCoupon::getStatus, Constants.CouponStatus.claimed.getKey())
//                .set(MemberCoupon::getUseDate, null)
//                .set(MemberCoupon::getOrderId, null)
//                .eq(MemberCoupon::getId, order.getCouponId())
//                .eq(MemberCoupon::getOrderId, order.getId())
//                .eq(MemberCoupon::getStatus, Constants.CouponStatus.used.getKey()));
        if (order.getCouponId() == null || order.getDeductionAmount() == null || order.getDeductionAmount() <= 0) {
            return;
        }
        memberCouponMapper.update(new UpdateWrapper<MemberCoupon>().lambda()
                .set(MemberCoupon::getStatus, Constants.CouponStatus.claimed.getKey())
                .set(MemberCoupon::getUseDate, null)
                .set(MemberCoupon::getOrderId, null)
                .eq(MemberCoupon::getId, order.getCouponId())
                .eq(MemberCoupon::getOrderId, order.getId())
                .eq(MemberCoupon::getStatus, Constants.CouponStatus.used.getKey()));
    }
    private void giftOrderCoupon(Integer memberId) {
        String orderCountStr = operationConfigBiz.getConfig().getOrderCouponOrderCount();
        String giftCountStr = operationConfigBiz.getConfig().getOrderCouponGiftCount();
        String couponIdsStr = operationConfigBiz.getConfig().getOrderCouponId();
        if (StringUtils.isAnyBlank(orderCountStr, giftCountStr, couponIdsStr)) return;
        int orderCount = Integer.parseInt(orderCountStr);
        int maxGift = Integer.parseInt(giftCountStr);
        Member member = memberMapper.selectById(memberId);
        if (member == null) return;
        int gifted = member.getOrderCouponGiftCount() != null ? member.getOrderCouponGiftCount() : 0;
        if (gifted >= maxGift) return;
        long completedCount = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda()
                .eq(Orders::getMemberId, memberId)
                .eq(Orders::getDeleted, Constants.ZERO)
                .notIn(Orders::getStatus,
                        Constants.OrderStatus.waitPay.getKey(),
                        Constants.OrderStatus.waitDeposit.getKey()));
        if (completedCount < orderCount || completedCount % orderCount != 0) return;
        String[] idArr = couponIdsStr.split(",");
        Date now = new Date();
        for (String idStr : idArr) {
            String trimmed = idStr.trim();
            if (StringUtils.isBlank(trimmed)) continue;
            Coupon coupon = couponMapper.selectById(Integer.valueOf(trimmed));
            if (coupon == null || Constants.equalsInteger(coupon.getIsdeleted(), Constants.ONE)) continue;
            MemberCoupon mc = new MemberCoupon();
            mc.setCouponId(coupon.getId());
            mc.setMemberId(memberId);
            mc.setStatus(Constants.CouponStatus.waitClaim.getKey());
            Calendar validCal = Calendar.getInstance();
            validCal.add(Calendar.DAY_OF_MONTH, coupon.getPushDays() != null ? coupon.getPushDays() : 7);
            mc.setValidDate(validCal.getTime());
            mc.setName(coupon.getName());
            mc.setInfo(coupon.getInfo());
            mc.setType(coupon.getType());
            mc.setLimitPrice(coupon.getLimitPrice());
            mc.setPrice(coupon.getPrice());
            mc.setGetMethod(coupon.getGetMethod());
            mc.setCouponType(coupon.getCouponType());
            mc.setPushDays(coupon.getPushDays());
            mc.setValidDays(coupon.getValidDays());
            mc.setIsdeleted(Constants.ZERO);
            mc.setCreateDate(now);
            mc.setEditDate(now);
            memberCouponMapper.insert(mc);
        }
        member.setOrderCouponGiftCount(gifted + 1);
        memberMapper.updateById(member);
    }
    private void saveCancelLog(Orders order, Constants.OrderLogType logType, String reason, Integer memberId) {
@@ -2322,9 +2418,10 @@
        if (Constants.equalsInteger(order.getManualRefund(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单已手动退款");
        }
        // 异常订单不允许手动退款
        if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "异常订单不支持手动退款");
        // 就地寄存异常订单不允许手动退款
        if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)
                && Constants.equalsInteger(order.getType(), Constants.ZERO)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "就地寄存异常订单不支持手动退款");
        }
        // 2. 校验退款金额
@@ -2406,7 +2503,7 @@
                refund.setRefundTime(now);
                ordersRefundMapper.updateById(refund);
                // 退款成功,执行扣款
                processManualRefundDeduction(order, depositShopDeduct, takeShopDeduct, driverDeduct);
                //processManualRefundDeduction(order, depositShopDeduct, takeShopDeduct, driverDeduct);
            } else if (com.wechat.pay.java.service.refund.model.Status.PROCESSING.equals(refundStatus)) {
                refund.setStatus(Constants.ZERO); // 退款中,等回调
                ordersRefundMapper.updateById(refund);
@@ -2428,7 +2525,6 @@
        // 7. 更新订单:标记已手动退款,累加退款金额
        ordersMapper.update(new UpdateWrapper<Orders>().lambda()
                .set(Orders::getManualRefund, Constants.ONE)
                .setSql(" REFUND_AMOUNT = IFNULL(REFUND_AMOUNT, 0) + " + dto.getRefundAmount())
                .set(Orders::getUpdateTime, now)
                .eq(Orders::getId, order.getId()));
    }
@@ -2511,10 +2607,11 @@
        Long driverDeduct = deductJson.getLong("driverDeduct");
        processManualRefundDeduction(order, depositShopDeduct, takeShopDeduct, driverDeduct);
        // 标记订单已手动退款,累加退款金额
        // 标记订单已手动退款,累加退款金额,同步更新totalAmount
        ordersMapper.update(new UpdateWrapper<Orders>().lambda()
                .set(Orders::getManualRefund, Constants.ONE)
                .setSql(" REFUND_AMOUNT = IFNULL(REFUND_AMOUNT, 0) + " + refundRecord.getRefundAmount())
                .setSql(" TOTAL_AMOUNT = IFNULL(TOTAL_AMOUNT, 0) - " + refundRecord.getRefundAmount())
                .set(Orders::getUpdateTime, new Date())
                .eq(Orders::getId, order.getId()));
    }
@@ -2767,13 +2864,27 @@
        if (otherOrders.getOrderId() != null) {
            Orders order = ordersMapper.selectById(otherOrders.getOrderId());
            if (order != null) {
                order.setOverdueStatus(Constants.TWO); // 2=已支付
                // 总金额 = 原金额 + 逾期费用
                Long overdueFee = otherOrders.getPayAccount() != null ? otherOrders.getPayAccount() : 0L;
                long newTotal = (order.getTotalAmount() != null ? order.getTotalAmount() : 0L) + overdueFee;
                // 异常就地寄存订单:同时更新主订单实际逾期费用
                boolean isAbnormal = Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)
                        && Constants.equalsInteger(order.getType(), Constants.ZERO);
                if(isAbnormal){
                    long shopException = isAbnormal ? (order.getShopCompensationAmount() != null ? order.getShopCompensationAmount() : 0L) : 0L;
                    long driverException = isAbnormal ? (order.getExceptionFee() != null ? order.getExceptionFee() : 0L) : 0L;
                    long actualOverdueFee = isAbnormal ? (overdueFee - shopException - driverException) : 0L;
                    if(actualOverdueFee!=order.getOverdueAmount()){
                        order.setOverdueAmount(actualOverdueFee);
                    }
                }
                order.setOverdueStatus(Constants.TWO); // 2=已支付
                order.setTotalAmount(newTotal);
                order.setUpdateTime(now);
                ordersMapper.updateById(order);
                // 重算三方收益
                calculateAndSaveOrderFees(order.getId());
            }
@@ -3262,6 +3373,39 @@
                sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.WAIT_PICKUP_REMIND, order.getId(),
                        "orderNo", order.getCode(), "shopName", shopName);
            }
            // 寄存成功赠送优惠券
            giftOrderCoupon(order.getMemberId());
            // 异常订单寄存核销:标记原订单完成
            if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE) && order.getRelationOrderId() != null) {
                Orders originalOrder = ordersMapper.selectById(order.getRelationOrderId());
                if (originalOrder != null) {
                    originalOrder.setStatus(Constants.OrderStatus.finished.getStatus());
                    originalOrder.setInvoiceStatus(Constants.ONE);
                    originalOrder.setSettlementStatus(Constants.ZERO);
                    originalOrder.setFinishTime(now);
                    originalOrder.setUpdateTime(now);
                    ordersMapper.updateById(originalOrder);
                    // 触发原订单收益计算
                    calculateAndSaveOrderFees(originalOrder.getId());
                    generateRevenueRecords(originalOrder.getId());
                    // 记录原订单日志
                    saveShopVerifyLog(originalOrder, Constants.OrderLogType.shopTake, "异常订单核销,原订单完成", remark, shopId);
                    // 通知会员:订单已完成
                    sendOrderNotice(originalOrder.getMemberId(), Constants.MemberOrderNotify.FINISHED, originalOrder.getId(),
                            "orderNo", originalOrder.getCode());
                    // 通知存件门店和取件门店
                    String settleDays = operationConfigBiz.getConfig().getSettlementDate();
                    notifyBothShops(originalOrder, Constants.ShopOrderNotify.FINISHED,
                            "orderNo", originalOrder.getCode(),
                            "settleDays", settleDays != null ? settleDays : "7");
                    // 通知司机:订单已完成
                    if (originalOrder.getAcceptDriver() != null) {
                        sendDriverNotice(originalOrder.getAcceptDriver(), Constants.DriverOrderNotify.FINISHED, originalOrder.getId(),
                                "orderNo", originalOrder.getCode(),
                                "settleDays", settleDays != null ? settleDays : "7");
                    }
                }
            }
        } else if (Constants.equalsInteger(status, Constants.OrderStatus.arrived.getStatus())) {
            // 异地寄存 + 无取件门店 → 无法核销(客户自取,无门店操作)
            if (Constants.equalsInteger(order.getType(), Constants.ONE) && order.getTakeShopId() == null) {
@@ -3430,30 +3574,7 @@
                sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.WAIT_PICKUP_REMIND, order.getId(),
                        "orderNo", order.getCode(), "shopName", shopName);
            }
            // 异常订单寄存核销:标记原订单完成
            if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE) && order.getRelationOrderId() != null) {
                Orders originalOrder = ordersMapper.selectById(order.getRelationOrderId());
                if (originalOrder != null) {
                    originalOrder.setStatus(Constants.OrderStatus.finished.getStatus());
                    originalOrder.setInvoiceStatus(Constants.ONE);
                    originalOrder.setFinishTime(now);
                    originalOrder.setUpdateTime(now);
                    ordersMapper.updateById(originalOrder);
                    // 触发原订单收益计算
                    calculateAndSaveOrderFees(originalOrder.getId());
                    generateRevenueRecords(originalOrder.getId());
                    // 通知会员:订单已完成
                    sendOrderNotice(originalOrder.getMemberId(), Constants.MemberOrderNotify.FINISHED, originalOrder.getId(),
                            "orderNo", originalOrder.getCode());
                    // 通知司机:订单已完成
                    if (originalOrder.getAcceptDriver() != null) {
                        String settleDays = operationConfigBiz.getConfig().getSettlementDate();
                        sendDriverNotice(originalOrder.getAcceptDriver(), Constants.DriverOrderNotify.FINISHED, originalOrder.getId(),
                                "orderNo", originalOrder.getCode(),
                                "settleDays", settleDays != null ? settleDays : "7");
                    }
                }
            }
        } else if (Constants.equalsInteger(status, Constants.OrderStatus.arrived.getStatus())) {
            // 异地寄存 + 无取件门店 → 无法核销(客户自取,无门店操作)
            if (Constants.equalsInteger(order.getType(), Constants.ONE) && order.getTakeShopId() == null) {
@@ -3681,13 +3802,17 @@
        }
        Long totalAmount = order.getTotalAmount() != null ? order.getTotalAmount() : 0L;
        Long shopCompensationAmount = order.getShopCompensationAmount() != null ? order.getShopCompensationAmount() : 0L;
        Long exceptionFee = order.getExceptionFee() != null ? order.getExceptionFee() : 0L;
        // 分成基数 = 总金额 - 门店异常金额 - 司机异常金额
        Long feeBase = totalAmount - shopCompensationAmount - exceptionFee;
        // 费率(为空时默认0)
        BigDecimal depositRate = order.getDepositShopFeeRata() != null ? order.getDepositShopFeeRata() : BigDecimal.ZERO;
        BigDecimal takeRate = order.getTakeShopFeeRata() != null ? order.getTakeShopFeeRata() : BigDecimal.ZERO;
        BigDecimal driverRate = order.getDriverFeeRata() != null ? order.getDriverFeeRata() : BigDecimal.ZERO;
        //存件门店收益
        Long depositShopFee = new BigDecimal(totalAmount)
        Long depositShopFee = new BigDecimal(feeBase)
                .multiply(depositRate)
                .setScale(0, RoundingMode.HALF_UP)
                .longValue();
@@ -3697,14 +3822,14 @@
        if (Constants.equalsInteger(order.getType(), Constants.ONE)) {
            // 异地寄存:存件门店 + 司机
            driverFee = new BigDecimal(totalAmount)
            driverFee = new BigDecimal(feeBase)
                    .multiply(driverRate)
                    .setScale(0, RoundingMode.HALF_UP)
                    .longValue();
            // 异地寄存且有取件门店:加上取件门店收益
            if (order.getTakeShopId() != null) {
                takeShopFee = new BigDecimal(totalAmount)
                takeShopFee = new BigDecimal(feeBase)
                        .multiply(takeRate)
                        .setScale(0, RoundingMode.HALF_UP)
                        .longValue();
@@ -3742,6 +3867,29 @@
            }
        }
        // 异常订单:存件门店异常补偿收益(单独一条记录,type=5)
        if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)
                && order.getShopCompensationAmount() != null && order.getShopCompensationAmount() > 0
                && order.getDepositShopId() != null) {
            ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId());
            if (depositShop != null && depositShop.getId() != null) {
                Revenue shopExRevenue = new Revenue();
                shopExRevenue.setMemberId(depositShop.getId());
                shopExRevenue.setMemberType(Constants.TWO); // 2=门店
                shopExRevenue.setType(5); // 5=异常金额
                shopExRevenue.setOptType(Constants.ONE); // 1=收入
                shopExRevenue.setAmount(order.getShopCompensationAmount());
                shopExRevenue.setVaildStatus(Constants.ZERO);
                shopExRevenue.setObjId(orderId);
                shopExRevenue.setObjType(Constants.ZERO);
                shopExRevenue.setStatus(Constants.ZERO);
                shopExRevenue.setOrderNo(order.getCode());
                shopExRevenue.setDeleted(Constants.ZERO);
                shopExRevenue.setCreateTime(now);
                revenueMapper.insert(shopExRevenue);
            }
        }
        // 取件门店收益(异地寄存且有取件门店)
        if (takeShopFee > 0 && order.getTakeShopId() != null) {
            ShopInfo takeShop = shopInfoMapper.selectById(order.getTakeShopId());
@@ -3760,27 +3908,33 @@
            }
        }
        // 异常订单:司机异常补偿(异地 + 异常标记 + 有异常补偿金额)
        // 异常订单:司机异常补偿(异地 + 异常标记,从关联异常子订单获取exceptionFee)
        if (Constants.equalsInteger(order.getType(), Constants.ONE)
                && Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)
                && order.getExceptionFee() != null && order.getExceptionFee() > 0
                && order.getAcceptDriver() != null) {
            DriverInfo driver = driverInfoMapper.selectById(order.getAcceptDriver());
            if (driver != null && driver.getMemberId() != null) {
                Revenue exRevenue = new Revenue();
                exRevenue.setMemberId(driver.getMemberId());
                exRevenue.setMemberType(Constants.ONE); // 1=司机
                exRevenue.setType(5); // 5=异常金额
                exRevenue.setOptType(Constants.ONE); // 1=收入
                exRevenue.setAmount(order.getExceptionFee());
                exRevenue.setVaildStatus(Constants.ZERO);
                exRevenue.setObjId(orderId);
                exRevenue.setObjType(Constants.ZERO);
                exRevenue.setStatus(Constants.ZERO);
                exRevenue.setOrderNo(order.getCode());
                exRevenue.setDeleted(Constants.ZERO);
                exRevenue.setCreateTime(now);
                revenueMapper.insert(exRevenue);
            Orders childOrder = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda()
                    .eq(Orders::getRelationOrderId, orderId)
                    .eq(Orders::getExceptionStatus, Constants.ONE)
                    .eq(Orders::getDeleted, Constants.ZERO)
                    .last("limit 1"));
            if (childOrder != null && childOrder.getExceptionFee() != null && childOrder.getExceptionFee() > 0) {
                DriverInfo driver = driverInfoMapper.selectById(order.getAcceptDriver());
                if (driver != null && driver.getMemberId() != null) {
                    Revenue exRevenue = new Revenue();
                    exRevenue.setMemberId(driver.getMemberId());
                    exRevenue.setMemberType(Constants.ONE); // 1=司机
                    exRevenue.setType(5); // 5=异常金额
                    exRevenue.setOptType(Constants.ONE); // 1=收入
                    exRevenue.setAmount(childOrder.getExceptionFee());
                    exRevenue.setVaildStatus(Constants.ZERO);
                    exRevenue.setObjId(orderId);
                    exRevenue.setObjType(Constants.ZERO);
                    exRevenue.setStatus(Constants.ZERO);
                    exRevenue.setOrderNo(order.getCode());
                    exRevenue.setDeleted(Constants.ZERO);
                    exRevenue.setCreateTime(now);
                    revenueMapper.insert(exRevenue);
                }
            }
        }
@@ -3881,14 +4035,16 @@
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "核销码无效");
        }
        // 仅异地寄存 + 有取件门店 + 派送中(4) 可核销
        if (!Constants.equalsInteger(order.getType(), Constants.ONE)) {
        // 仅异地寄存 + 有取件门店 + 派送中(4) 可核销(异常订单允许)
        if (!Constants.equalsInteger(order.getType(), Constants.ONE)
                && !Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅异地寄存订单支持司机核销");
        }
        if (order.getTakeShopId() == null) {
        if (order.getTakeShopId() == null && !Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单无取件门店,无需司机核销");
        }
        if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.delivering.getStatus())) {
        if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.delivering.getStatus())
                && !Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.deposited.getStatus())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许核销");
        }
@@ -4012,8 +4168,7 @@
        if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)
                && order.getRelationOrderId() != null) {
            Orders originalOrder = ordersMapper.selectById(order.getRelationOrderId());
            long driverExceptionFee = (originalOrder != null && originalOrder.getExceptionFee() != null)
                    ? originalOrder.getExceptionFee() : 0L;
            long driverExceptionFee = order.getExceptionFee() != null ? order.getExceptionFee() : 0L;
            long shopExceptionFee = order.getShopCompensationAmount() != null ? order.getShopCompensationAmount() : 0L;
            long totalExceptionFee = driverExceptionFee + shopExceptionFee;
@@ -4027,13 +4182,14 @@
                overdueFee = totalExceptionFee;
                overdueDays = totalExceptionFee > 0 ? 1 : 0;
            } else {
                // 非当天取件:正常逾期计算 + 司机异常费用(不含门店异常费用)
                // 非当天取件:正常逾期计算 + 司机异常费用(不含门店异常费用),门店异常金额清零
                OverdueFeeVO normalOverdue = calculateOverdueFeeInternal(order, details);
                long normalFee = (normalOverdue != null && normalOverdue.getOverdueFee() != null)
                        ? normalOverdue.getOverdueFee() : 0L;
                overdueFee = normalFee + driverExceptionFee;
                overdueDays = (normalOverdue != null && normalOverdue.getOverdueDays() != null)
                        ? normalOverdue.getOverdueDays() : 0;
                order.setShopCompensationAmount(0L);
            }
            order.setConfirmArriveTime(now);
@@ -4601,7 +4757,7 @@
                    sendSmsNotify(member != null ? member.getTelephone() : null,
                            Constants.SmsNotify.MEMBER_CANCELLED, "orderNo", order.getCode());
                }
                restoreCoupon(order);
                count++;
            } catch (Exception e) {
                log.error("取消超时订单异常, orderId={}, error={}", order.getId(), e.getMessage());
@@ -5019,29 +5175,26 @@
                }
                targetLat = order.getDepositLat();
                targetLgt = order.getDepositLgt();
            } else if (Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.arrived.getStatus())) {
                // status=5 门店完成核销
                if (Constants.equalsInteger(order.getType(), Constants.ZERO)) {
                    // 就地存取 → 对比存件门店
                    if (!Constants.equalsInteger(order.getDepositShopId(), userId)) {
                        throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "无权操作该订单");
                    }
                    targetLat = order.getDepositLat();
                    targetLgt = order.getDepositLgt();
                } else {
                    // 异地存取 → 对比取件门店
                    if (!Constants.equalsInteger(order.getTakeShopId(), userId)) {
                        throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "无权操作该订单");
                    }
                    targetLat = order.getTakeLat();
                    targetLgt = order.getTakeLgt();
            } else if (Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.arrived.getStatus())&&Constants.equalsInteger(order.getType(), Constants.ZERO)) {
                // 就地寄存 → 对比存件门店
                if (!Constants.equalsInteger(order.getDepositShopId(), userId)) {
                    throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "无权操作该订单");
                }
                targetLat = order.getDepositLat();
                targetLgt = order.getDepositLgt();
            } else if ((Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.delivering.getStatus())||Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.arrived.getStatus()))&&Constants.equalsInteger(order.getType(), Constants.ONE)) {
                // 同城寄送 → 对比取件门店
                if (!Constants.equalsInteger(order.getTakeShopId(), userId)) {
                    throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "无权操作该订单");
                }
                targetLat = order.getTakeLat();
                targetLgt = order.getTakeLgt();
            } else {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单状态不允许此操作");
            }
        } else if (Constants.equalsInteger(userType, Constants.ONE)) {
            // 司机操作
            if (Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.deposited.getStatus())) {
            if (Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.accepted.getStatus())) {
                // status=2 司机取件
                if (!Constants.equalsInteger(order.getAcceptDriver(), userId)) {
                    throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "无权操作该订单");
@@ -5082,8 +5235,8 @@
        if (original.getTakeShopId() != null) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单已关联取件门店,不支持异常处理");
        }
        if (!Constants.equalsInteger(original.getStatus(), Constants.FIVE)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅支持已送达状态的订单");
        if (!Constants.equalsInteger(original.getStatus(), Constants.OrderStatus.delivering.getKey())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅支持配送中的订单进行异常处理");
        }
        if (Constants.equalsInteger(original.getExceptionStatus(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单已处理过异常,请勿重复操作");
@@ -5096,7 +5249,7 @@
        Date now = new Date();
        // ========== B. 创建新订单(就地存取) ==========
        // ========== B. 创建新订单(就地寄存) ==========
        String orderCode = "JC" + new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(now)
                + String.format("%04d", new java.util.Random().nextInt(10000));
        String orderTradeNo = generateOrderTradeNo();
@@ -5137,7 +5290,7 @@
            }
        }
        // 存件门店分成占比(就地存取)
        // 存件门店分成占比(就地寄存)
        Integer cityId = Integer.valueOf(original.getCityId());
        boolean isCompany = Constants.equalsInteger(newShop.getCompanyType(), Constants.ONE);
        int fallbackFieldA = isCompany ? Constants.FIVE : Constants.SIX;
@@ -5147,7 +5300,7 @@
        newOrder.setCode(orderCode);
        newOrder.setOutTradeNo(orderTradeNo);
        newOrder.setMemberId(original.getMemberId());
        newOrder.setType(Constants.ZERO); // 就地存取
        newOrder.setType(Constants.ZERO); // 就地寄存
        newOrder.setCityId(original.getCityId());
        newOrder.setStatus(Constants.ONE); // 待寄存
        newOrder.setPayStatus(Constants.ONE); // 已支付
@@ -5198,8 +5351,8 @@
        newOrder.setDeclaredAmount(0L);
        newOrder.setDeclaredFee(0L);
        newOrder.setPrice(price);
        newOrder.setBasicAmount(basicAmount);
        newOrder.setEstimatedAmount(basicAmount);
        newOrder.setBasicAmount(0L);//);
        newOrder.setEstimatedAmount(0L);//basicAmount);
        newOrder.setTotalAmount(0L);
        newOrder.setPayAmount(0L);
        newOrder.setManualRefund(Constants.ZERO);
@@ -5214,6 +5367,8 @@
        // 门店补偿金额
        newOrder.setShopCompensationAmount(dto.getShopCompensation());
        // 司机异常补偿金额
        newOrder.setExceptionFee(dto.getDriverCompensation());
        newOrder.setRemark(dto.getRemark());
        newOrder.setPlatformSmsNotified(Constants.ZERO);
@@ -5270,7 +5425,6 @@
        // ========== E. 更新原订单 ==========
        ordersMapper.update(new UpdateWrapper<Orders>().lambda()
                .set(Orders::getExceptionStatus, Constants.ONE)
                .set(Orders::getExceptionFee, dto.getDriverCompensation())
                .set(Orders::getUpdateTime, now)
                .eq(Orders::getId, original.getId()));
@@ -5299,4 +5453,27 @@
        }
    }
    @Override
    public ManualRefundDetailVO getManualRefundDetail(Integer orderId) {
        OrdersRefund refundRecord = ordersRefundMapper.selectOne(new QueryWrapper<OrdersRefund>().lambda()
                .eq(OrdersRefund::getOrderId, orderId)
                .eq(OrdersRefund::getType, Constants.FOUR)
                .eq(OrdersRefund::getDeleted, Constants.ZERO)
                .orderByDesc(OrdersRefund::getCreateTime)
                .last("limit 1"));
        if (refundRecord == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        ManualRefundDetailVO vo = new ManualRefundDetailVO();
        vo.setRefundAmount(refundRecord.getRefundAmount());
        if (StringUtils.isNotBlank(refundRecord.getDeductInfo())) {
            JSONObject json = JSONObject.parseObject(refundRecord.getDeductInfo());
            vo.setDepositShopDeduct(json.getLong("depositShopDeduct"));
            vo.setTakeShopDeduct(json.getLong("takeShopDeduct"));
            vo.setDriverDeduct(json.getLong("driverDeduct"));
        }
        vo.setRefundRemark(refundRecord.getRefundRemark());
        return vo;
    }
}