From c74a6f59490cfb9a0ee37f70427739b74e7fbd58 Mon Sep 17 00:00:00 2001
From: rk <94314517@qq.com>
Date: 星期三, 20 五月 2026 08:50:29 +0800
Subject: [PATCH] 代码生成

---
 server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java |  775 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 758 insertions(+), 17 deletions(-)

diff --git a/server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
index a327585..3524470 100644
--- a/server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
+++ b/server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
@@ -36,6 +36,8 @@
 import com.doumee.dao.dto.CommentOrderDTO;
 import com.doumee.dao.dto.CreateOrderDTO;
 import com.doumee.dao.dto.DispatchDTO;
+import com.doumee.dao.dto.HandleOrderExceptionDTO;
+import com.doumee.dao.dto.ManualRefundDTO;
 import com.doumee.dao.dto.MyOrderDTO;
 import com.doumee.dao.dto.OrderItemDTO;
 import com.doumee.dao.vo.*;
@@ -112,6 +114,9 @@
     @Autowired
     private RevenueMapper revenueMapper;
 
+    @Autowired
+    private RewardRecordMapper rewardRecordMapper;
+
 
 
     @Autowired
@@ -125,6 +130,9 @@
 
     @Autowired
     private RedisTemplate<String, Object> redisTemplate;
+
+    @Autowired
+    private MemberCouponMapper memberCouponMapper;
 
     @Autowired
     private AreasBiz areasBiz;
@@ -229,7 +237,7 @@
                 .leftJoin(Category.class, Category::getId, Orders::getGoodType)
                 .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") ;
                 ;
         Utils.MP.blankToNull(pageWrap.getModel());
         queryWrapper.eq(pageWrap.getModel().getDeleted() != null, Orders::getDeleted, pageWrap.getModel().getDeleted());
@@ -259,6 +267,11 @@
             if(Constants.equalsInteger(o.getIsUrgent(),Constants.ZERO)){
                 o.setUrgentAmount(Constants.ZERO.longValue());
             }
+            // 瀹炰粯閲戦 = 鏀粯閲戦 - 閫�娆鹃噾棰� + 閫炬湡璐圭敤
+            long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L;
+            long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L;
+            long overdue = o.getOverdueAmount() != null ? o.getOverdueAmount() : 0L;
+            o.setPayAmount(pay - refund + overdue);
         }
         return pageData;
     }
@@ -427,6 +440,7 @@
         result.setTotalPrice(totalPrice);
         result.setDays(days);
         result.setUrgentFee(0L);
+        resolveCoupon(result, dto.getMemberId(), dto.getCouponId(), totalPrice);
         return result;
     }
 
@@ -630,7 +644,50 @@
             }
         }
 
+        resolveCoupon(result, dto.getMemberId(), dto.getCouponId(), totalPrice);
         return result;
+    }
+
+    private void resolveCoupon(PriceCalculateVO result, Integer memberId, Integer couponId, long totalPrice) {
+        if (memberId == null) {
+            result.setDeductionAmount(0L);
+            return;
+        }
+        // 鏌ヨ鍙敤浼樻儬鍒革細宸查鍙栥�佹湭杩囨湡銆佹弧瓒虫弧棰濋棬妲�
+        Date now = new Date();
+        List<MemberCoupon> availableCoupons = memberCouponMapper.selectList(new QueryWrapper<MemberCoupon>().lambda()
+                .eq(MemberCoupon::getMemberId, memberId)
+                .eq(MemberCoupon::getStatus, Constants.CouponStatus.claimed.getKey())
+                .eq(MemberCoupon::getIsdeleted, Constants.ZERO)
+                .le(MemberCoupon::getLimitPrice, totalPrice)
+                .ge(MemberCoupon::getEndDate, now)
+                .orderByDesc(MemberCoupon::getPrice)
+                .orderByAsc(MemberCoupon::getEndDate));
+        result.setAvailableCoupons(availableCoupons);
+
+        if (couponId == null) {
+            result.setDeductionAmount(0L);
+            return;
+        }
+
+        MemberCoupon selected;
+        if (couponId == -1) {
+            selected = availableCoupons.isEmpty() ? null : availableCoupons.get(0);
+        } else {
+            selected = availableCoupons.stream()
+                    .filter(mc -> mc.getId().equals(couponId))
+                    .findFirst().orElse(null);
+            if (selected == null) {
+                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浼樻儬鍒告棤鏁堟垨涓嶅彲鐢�");
+            }
+        }
+
+        if (selected != null) {
+            result.setDeductionAmount(selected.getPrice());
+            result.setSelectedCoupon(selected);
+        } else {
+            result.setDeductionAmount(0L);
+        }
     }
 
     @Override
@@ -767,6 +824,8 @@
             priceDTO.setDepositEndTime(takeTime);
             priceDTO.setItems(dto.getItems());
             priceDTO.setDeclaredAmount(dto.getDeclaredAmount());
+            priceDTO.setMemberId(memberId);
+            priceDTO.setCouponId(dto.getCouponId());
             priceResult = calculateLocalPrice(priceDTO);
         } else {
             // 寮傚湴瀵勫瓨
@@ -779,6 +838,8 @@
             priceDTO.setItems(dto.getItems());
             priceDTO.setDeclaredAmount(dto.getDeclaredAmount());
             priceDTO.setUrgent(Constants.ONE.equals(dto.getIsUrgent()));
+            priceDTO.setMemberId(memberId);
+            priceDTO.setCouponId(dto.getCouponId());
             priceResult = calculateRemotePrice(priceDTO);
         }
 
@@ -867,8 +928,12 @@
         // 璐圭敤淇℃伅(鍒�)
         orders.setBasicAmount(priceResult.getItemPrice());
         orders.setEstimatedAmount(priceResult.getTotalPrice());
-        orders.setTotalAmount(priceResult.getTotalPrice());
+        long deductionAmount = priceResult.getDeductionAmount() != null ? priceResult.getDeductionAmount() : 0L;
+        orders.setTotalAmount(priceResult.getTotalPrice() - deductionAmount);
         orders.setUrgentAmount(priceResult.getUrgentFee());
+        orders.setCouponId(dto.getCouponId());
+        orders.setDeductionAmount(deductionAmount);
+        orders.setManualRefund(Constants.ZERO);
         // 瀛樺偍鍔犳�ョ郴鏁�
         if (Constants.ONE.equals(dto.getType()) && Constants.ONE.equals(dto.getIsUrgent())) {
             String urgentRateStr = systemDictDataBiz.queryByCode(
@@ -891,6 +956,16 @@
 
         ordersMapper.insert(orders);
         Integer orderId = orders.getId();
+
+        // 鏍囪浼樻儬鍒稿凡浣跨敤
+        MemberCoupon selectedCoupon = priceResult.getSelectedCoupon();
+        if (selectedCoupon != null) {
+            memberCouponMapper.update(new UpdateWrapper<MemberCoupon>().lambda()
+                    .set(MemberCoupon::getStatus, Constants.CouponStatus.used.getKey())
+                    .set(MemberCoupon::getUseDate, new Date())
+                    .set(MemberCoupon::getOrderId, orderId)
+                    .eq(MemberCoupon::getId, selectedCoupon.getId()));
+        }
 
         // 鍒涘缓璁㈠崟鏃ュ織
         OrderLog createLog = new OrderLog();
@@ -1079,6 +1154,7 @@
 
         OrderDetailVO vo = new OrderDetailVO();
         vo.setOrder(order);
+        vo.setDeductionAmount(order.getDeductionAmount());
 
         // 璁㈠崟鐘舵�佹弿杩�
         if (order.getStatus() != null) {
@@ -1553,6 +1629,7 @@
                 .select("s1.name", Orders::getDepositShopName)
                 .select("s1.link_name", Orders::getDepositShopLinkName)
                 .select("s1.link_phone", Orders::getDepositShopLinkPhone)
+                .select("s1.address", Orders::getDepositShopAddress)
                 .select("s2.name", Orders::getTakeShopName)
                 .select("s2.address", Orders::getTakeShopAddress)
                 .select("s2.link_phone", Orders::getTakeShopLinkPhone)
@@ -1566,6 +1643,21 @@
                 .eq(status != null, Orders::getStatus, status)
                 .in(statusList != null, Orders::getStatus, statusList)
                 .orderByDesc(Orders::getCreateTime);
+        // 鍙紑绁ㄨ鍗曪細澧炲姞鏈堜唤闄愬埗
+        if (model != null && model.getInvoiceStatus() != null && Constants.equalsInteger(model.getInvoiceStatus(), Constants.ONE)) {
+            wrapper.in(Orders::getInvoiceStatus, Arrays.asList(Constants.ONE, 99));
+            String monthLimitStr = operationConfigBiz.getConfig().getInvoiceMonthLimit();
+            if (StringUtils.isNotBlank(monthLimitStr)) {
+                int monthLimit = Integer.parseInt(monthLimitStr);
+                Calendar cal = Calendar.getInstance();
+                cal.add(Calendar.MONTH, -monthLimit);
+                cal.set(Calendar.HOUR_OF_DAY, 0);
+                cal.set(Calendar.MINUTE, 0);
+                cal.set(Calendar.SECOND, 0);
+                cal.set(Calendar.MILLISECOND, 0);
+                wrapper.ge(Orders::getFinishTime, cal.getTime());
+            }
+        }
         // 鍏抽敭璇嶆悳绱細鏀朵欢浜�/鏀朵欢浜虹數璇濇ā绯娿�佽鍗曞彿绮惧噯
         if (model != null && StringUtils.isNotBlank(model.getKeyword())) {
             String kw = model.getKeyword().trim();
@@ -1601,7 +1693,7 @@
                 vo.setDepositShopName(o.getDepositShopName());
                 vo.setDepositShopLinkName(o.getDepositShopLinkName());
                 vo.setDepositShopPhone(o.getDepositShopLinkPhone());
-
+                vo.setDepositShopAddress(o.getDepositShopAddress());
                 // 鍙栦欢淇℃伅锛氭湁鍙栦欢闂ㄥ簵鍙栭棬搴楋紝鏃犲垯鍙栫敤鎴疯嚜閫夊彇浠剁偣
                 if (o.getTakeShopId() != null) {
                     vo.setTakeShopId(o.getTakeShopId());
@@ -1643,6 +1735,14 @@
                 vo.setOrderImages(getFileUrlsFromList(o.getId(),files));
                 // 閫炬湡鐘舵��
                 fillOverdueStatus(vo, o, details);
+                // 浼樻儬鍒告姷鎵i噾棰�
+                vo.setDeductionAmount(o.getDeductionAmount());
+                // 鍙紑绁ㄩ噾棰濓紙鏀粯閲戦 - 閫�娆鹃噾棰濓級
+                if (model != null && model.getInvoiceStatus() != null && Constants.equalsInteger(model.getInvoiceStatus(), Constants.ONE)) {
+                    long payAmt = o.getPayAmount() != null ? o.getPayAmount() : 0L;
+                    long refundAmt = o.getRefundAmount() != null ? o.getRefundAmount() : 0L;
+                    vo.setInvoiceAmount(payAmt - refundAmt);
+                }
                 voList.add(vo);
             }
         }
@@ -1890,7 +1990,10 @@
         //搴忓彿
         vo.setSortnum(Constants.formatIntegerNum(order.getDepositShopId())+"-"+order.getId());
         if(order.getTakeShopId()!=null){
-            vo.setSortnumTake(Constants.formatIntegerNum(order.getTakeShopId())+"-"+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.getTakeShopId() + "-" + dateStr + "-" + autoNumStr;
+            vo.setSortnumTake(sort);
         }
         // 瀛樹欢闂ㄥ簵
         if (order.getDepositShopId() != null) {
@@ -2044,6 +2147,7 @@
             order.setStatus(Constants.OrderStatus.cancelled.getStatus());
             order.setCancelTime(now);
             ordersMapper.updateById(order);
+            restoreCoupon(order);
             saveCancelLog(order, Constants.OrderLogType.memberCancel, "浼氬憳鍙栨秷璁㈠崟锛堝緟鏀粯锛�", memberId);
             // 鐭俊閫氱煡浼氬憳锛氳鍗曞凡鍙栨秷
             Member cancelMember1 = memberMapper.selectById(memberId);
@@ -2105,6 +2209,7 @@
                 throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "閫�娆惧け璐ワ紝璇疯仈绯诲鏈嶅鐞�");
             }
             ordersRefundMapper.insert(refund);
+            restoreCoupon(order);
             return;
         }
 
@@ -2176,6 +2281,19 @@
     /**
      * 淇濆瓨鍙栨秷璁㈠崟鎿嶄綔鏃ュ織
      */
+    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()));
+    }
+
     private void saveCancelLog(Orders order, Constants.OrderLogType logType, String reason, Integer memberId) {
         OrderLog log = new OrderLog();
         log.setOrderId(order.getId());
@@ -2188,6 +2306,217 @@
         log.setCreateTime(new Date());
         log.setDeleted(Constants.ZERO);
         orderLogService.create(log);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void manualRefund(ManualRefundDTO dto, Integer userId) {
+        // 1. 鏍¢獙璁㈠崟
+        Orders order = ordersMapper.selectById(dto.getOrderId());
+        if (order == null || Constants.equalsInteger(order.getDeleted(), Constants.ONE)) {
+            throw new BusinessException(ResponseStatus.DATA_EMPTY);
+        }
+        if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.finished.getStatus())) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浠呭凡瀹屾垚璁㈠崟鍙墜鍔ㄩ��娆�");
+        }
+        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(), "寮傚父璁㈠崟涓嶆敮鎸佹墜鍔ㄩ��娆�");
+        }
+
+        // 2. 鏍¢獙閫�娆鹃噾棰�
+        long payAmount = order.getPayAmount() != null ? order.getPayAmount() : 0L;
+        long existingRefund = order.getRefundAmount() != null ? order.getRefundAmount() : 0L;
+        long maxRefund = payAmount - existingRefund;
+        if (dto.getRefundAmount() <= 0) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "閫�娆鹃噾棰濆繀椤诲ぇ浜�0");
+        }
+        if (dto.getRefundAmount() > maxRefund) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "閫�娆鹃噾棰濅笉鑳借秴杩囧彲閫�閲戦(" + maxRefund + "鍒�)");
+        }
+
+        // 3. 鏍¢獙骞舵竻鐞嗘墸娆鹃噾棰濓紙鏍规嵁璁㈠崟绫诲瀷锛�
+        boolean isRemote = Constants.equalsInteger(order.getType(), Constants.ONE);
+        Long depositShopDeduct = dto.getDepositShopDeduct();
+        Long takeShopDeduct = dto.getTakeShopDeduct();
+        Long driverDeduct = dto.getDriverDeduct();
+
+        if (!isRemote) {
+            takeShopDeduct = null;
+            driverDeduct = null;
+        } else {
+            if (order.getTakeShopId() == null) {
+                takeShopDeduct = null;
+            }
+        }
+        if (depositShopDeduct != null && depositShopDeduct < 0) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "瀛樹欢闂ㄥ簵鎵f閲戦涓嶈兘涓鸿礋");
+        }
+        if (takeShopDeduct != null && takeShopDeduct < 0) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鍙栦欢闂ㄥ簵鎵f閲戦涓嶈兘涓鸿礋");
+        }
+        if (driverDeduct != null && driverDeduct < 0) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鍙告満鎵f閲戦涓嶈兘涓鸿礋");
+        }
+
+        // 4. 鏋勫缓 deductInfo JSON
+        String deductInfo = null;
+        JSONObject deductJson = new JSONObject();
+        if (depositShopDeduct != null) {
+            deductJson.put("depositShopDeduct", depositShopDeduct);
+        }
+        if (takeShopDeduct != null) {
+            deductJson.put("takeShopDeduct", takeShopDeduct);
+        }
+        if (driverDeduct != null) {
+            deductJson.put("driverDeduct", driverDeduct);
+        }
+        if (deductJson.size() > 0) {
+            deductInfo = deductJson.toJSONString();
+        }
+
+        // 5. 鍒涘缓閫�娆捐褰�
+        Date now = new Date();
+        String outRefundNo = ID.nextGUID();
+        OrdersRefund refund = new OrdersRefund();
+        refund.setOrderId(order.getId());
+        refund.setType(Constants.FOUR); // 鎵嬪姩閫�娆�
+        refund.setRefundAmount(dto.getRefundAmount());
+        refund.setDeductInfo(deductInfo);
+        refund.setRefundRemark(dto.getRemark());
+        refund.setUserId(userId);
+        refund.setBeforeStatus(order.getStatus());
+        refund.setRefundCode(outRefundNo);
+        refund.setCreateTime(now);
+        refund.setDeleted(Constants.ZERO);
+        ordersRefundMapper.insert(refund);
+
+        // 6. 璋冪敤寰俊閫�娆�
+        try {
+            Refund refundResult = wxPayV3Service.refund(
+                    outRefundNo, order.getOutTradeNo(), payAmount, dto.getRefundAmount(),
+                    "鎵嬪姩閫�娆�", wxPayProperties.getV3RefundNotifyUrl());
+
+            com.wechat.pay.java.service.refund.model.Status refundStatus = refundResult.getStatus();
+            if (com.wechat.pay.java.service.refund.model.Status.SUCCESS.equals(refundStatus)) {
+                refund.setStatus(Constants.ONE);
+                refund.setRefundTime(now);
+                ordersRefundMapper.updateById(refund);
+                // 閫�娆炬垚鍔燂紝鎵ц鎵f
+                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);
+            } else {
+                refund.setStatus(Constants.TWO);
+                refund.setRefundRemark("寰俊閫�娆惧け璐�: " + refundStatus.name());
+                ordersRefundMapper.updateById(refund);
+                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "閫�娆惧け璐ワ紝璇疯仈绯诲鏈嶅鐞�");
+            }
+        } catch (BusinessException e) {
+            throw e;
+        } catch (Exception e) {
+            log.error("鎵嬪姩閫�娆捐皟鐢ㄥ井淇¢��娆惧紓甯�, orderId={}", order.getId(), e);
+            refund.setStatus(Constants.TWO);
+            ordersRefundMapper.updateById(refund);
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "閫�娆捐皟鐢ㄥ紓甯革紝璇风◢鍚庨噸璇�");
+        }
+
+        // 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()));
+    }
+
+    /**
+     * 鎵嬪姩閫�娆炬垚鍔熷悗锛屾牴鎹墸娆句俊鎭墸闄ゅ搴旀柟浣欓骞剁敓鎴愭敹鏀褰�
+     */
+    private void processManualRefundDeduction(Orders order, Long depositShopDeduct, Long takeShopDeduct, Long driverDeduct) {
+        Date now = new Date();
+
+        // 瀛樹欢闂ㄥ簵鎵f
+        if (depositShopDeduct != null && depositShopDeduct > 0 && order.getDepositShopId() != null) {
+            ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId());
+            if (depositShop != null) {
+                shopInfoMapper.update(new UpdateWrapper<ShopInfo>().lambda()
+                        .setSql(" BALANCE = IFNULL(BALANCE, 0) - " + depositShopDeduct)
+                        .eq(ShopInfo::getId, depositShop.getId()));
+                revenueMapper.insert(buildDeductRevenue(depositShop.getId(), Constants.TWO,
+                        depositShopDeduct, order.getId(), order.getCode(), now));
+            }
+        }
+
+        // 鍙栦欢闂ㄥ簵鎵f
+        if (takeShopDeduct != null && takeShopDeduct > 0 && order.getTakeShopId() != null) {
+            ShopInfo takeShop = shopInfoMapper.selectById(order.getTakeShopId());
+            if (takeShop != null) {
+                shopInfoMapper.update(new UpdateWrapper<ShopInfo>().lambda()
+                        .setSql(" BALANCE = IFNULL(BALANCE, 0) - " + takeShopDeduct)
+                        .eq(ShopInfo::getId, takeShop.getId()));
+                revenueMapper.insert(buildDeductRevenue(takeShop.getId(), Constants.TWO,
+                        takeShopDeduct, order.getId(), order.getCode(), now));
+            }
+        }
+
+        // 鍙告満鎵f
+        if (driverDeduct != null && driverDeduct > 0 && order.getAcceptDriver() != null) {
+            DriverInfo driver = driverInfoMapper.selectById(order.getAcceptDriver());
+            if (driver != null && driver.getMemberId() != null) {
+                driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
+                        .setSql(" BALANCE = IFNULL(BALANCE, 0) - " + driverDeduct)
+                        .eq(DriverInfo::getId, driver.getId()));
+                revenueMapper.insert(buildDeductRevenue(driver.getMemberId(), Constants.ONE,
+                        driverDeduct, order.getId(), order.getCode(), now));
+            }
+        }
+    }
+
+    private Revenue buildDeductRevenue(Integer memberId, Integer memberType, Long amount, Integer orderId, String orderNo, Date now) {
+        Revenue revenue = new Revenue();
+        revenue.setMemberId(memberId);
+        revenue.setMemberType(memberType);
+        revenue.setType(Constants.FOUR); // 璐d换鎵f
+        revenue.setOptType(-Constants.ONE); // 鏀嚭
+        revenue.setAmount(amount);
+        revenue.setVaildStatus(Constants.ONE); // 宸插叆璐�
+        revenue.setObjId(orderId);
+        revenue.setObjType(Constants.ZERO); // 璁㈠崟涓氬姟
+        revenue.setOrderNo(orderNo);
+        revenue.setStatus(Constants.ZERO); // 鎴愬姛
+        revenue.setDeleted(Constants.ZERO);
+        revenue.setCreateTime(now);
+        return revenue;
+    }
+
+    @Override
+    public void processManualRefundCallback(OrdersRefund refundRecord) {
+        if (!Constants.equalsInteger(refundRecord.getType(), Constants.FOUR)) {
+            return;
+        }
+        if (StringUtils.isBlank(refundRecord.getDeductInfo())) {
+            return;
+        }
+        Orders order = ordersMapper.selectById(refundRecord.getOrderId());
+        if (order == null) {
+            return;
+        }
+        JSONObject deductJson = JSONObject.parseObject(refundRecord.getDeductInfo());
+        Long depositShopDeduct = deductJson.getLong("depositShopDeduct");
+        Long takeShopDeduct = deductJson.getLong("takeShopDeduct");
+        Long driverDeduct = deductJson.getLong("driverDeduct");
+        processManualRefundDeduction(order, depositShopDeduct, takeShopDeduct, driverDeduct);
+
+        // 鏍囪璁㈠崟宸叉墜鍔ㄩ��娆撅紝绱姞閫�娆鹃噾棰�
+        ordersMapper.update(new UpdateWrapper<Orders>().lambda()
+                .set(Orders::getManualRefund, Constants.ONE)
+                .setSql(" REFUND_AMOUNT = IFNULL(REFUND_AMOUNT, 0) + " + refundRecord.getRefundAmount())
+                .set(Orders::getUpdateTime, new Date())
+                .eq(Orders::getId, order.getId()));
     }
 
     /**
@@ -2258,6 +2587,10 @@
      * 鍙戦�佸徃鏈虹珯鍐呬俊閫氱煡
      */
     private void sendDriverNotice(Integer driverId, Constants.DriverOrderNotify notify, Integer orderId, String... params) {
+        sendDriverNotice(driverId, notify, orderId, 0, params);
+    }
+
+    private void sendDriverNotice(Integer driverId, Constants.DriverOrderNotify notify, Integer objId, Integer objType, String... params) {
         DriverInfo driver = driverInfoMapper.selectById(driverId);
         if (driver == null || driver.getMemberId() == null) {
             return;
@@ -2267,8 +2600,8 @@
         notice.setUserId(driver.getMemberId());
         notice.setTitle(notify.getTitle());
         notice.setContent(notify.format(params));
-        notice.setObjId(orderId);
-        notice.setObjType(0); // 0=璁㈠崟
+        notice.setObjId(objId);
+        notice.setObjType(objType);
         notice.setStatus(0);  // 0=鏈
         notice.setIsdeleted(Constants.ZERO);
         notice.setCreateDate(new Date());
@@ -2910,9 +3243,9 @@
             order.setMemberVerifyCode(generateVerifyCode());
             ordersMapper.updateById(order);
             // 瀵勫瓨鏃跺浘鐗囧繀濉�
-            if (images == null || images.isEmpty()) {
-                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "璇蜂笂浼犲瘎瀛樺浘鐗�");
-            }
+//            if (images == null || images.isEmpty()) {
+//                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "璇蜂笂浼犲瘎瀛樺浘鐗�");
+//            }
             // 淇濆瓨瀵勫瓨鍥剧墖锛坥bj_type=2 璁㈠崟瀵勫瓨鍥剧墖锛屾渶澶�3寮狅級
             saveVerifyImages(order.getId(), images, Constants.FileType.ORDER_DEPOSIT.getKey(), shopId);
             // 璁板綍璁㈠崟鏃ュ織
@@ -2948,7 +3281,8 @@
             }
             // 寰呭彇浠�(5) 鈫� 宸插畬鎴�(7)
             order.setStatus(Constants.OrderStatus.finished.getStatus());
-            order.setConfirmArriveTime(now);
+            order.setFinishTime(now);
+            order.setInvoiceStatus(Constants.ONE);
             ordersMapper.updateById(order);
             // 灏卞湴瀵勫瓨(type=0)鍙栦欢鏃跺浘鐗囦笉蹇呭~锛屽叾浠栫被鍨嬪彇浠跺繀濉�
             if (!Constants.equalsInteger(order.getType(), Constants.ZERO)) {
@@ -3096,6 +3430,30 @@
                 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) {
@@ -3115,6 +3473,7 @@
             }
             // 寰呭彇浠�(5) 鈫� 宸插畬鎴�(7)
             order.setStatus(Constants.OrderStatus.finished.getStatus());
+            order.setInvoiceStatus(Constants.ONE);
             order.setConfirmArriveTime(now);
             ordersMapper.updateById(order);
             // 璁㈠崟瀹屾垚锛岄噴鏀炬牳閿�鐮�
@@ -3191,6 +3550,7 @@
         // 7. 鏇存柊璁㈠崟鐘舵�佷负宸插畬鎴�
         Date now = new Date();
         order.setStatus(Constants.OrderStatus.finished.getStatus());
+        order.setInvoiceStatus(Constants.ONE);
         order.setFinishTime(now);
         order.setUpdateTime(now);
         ordersMapper.updateById(order);
@@ -3280,10 +3640,15 @@
         if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.arrived.getStatus())) {
             throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "褰撳墠璁㈠崟鐘舵�佷笉鍏佽纭鏀惰揣");
         }
+        // 5.1 鏍¢獙寮傚父鐘舵��
+        if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "璁㈠崟寮傚父锛屽凡琚浆瀛橈紝璇疯仈绯荤鐞嗗憳鎴栨煡鐪嬬煭淇�");
+        }
 
         // 6. 鏇存柊璁㈠崟鐘舵�佷负宸插畬鎴�
         Date now = new Date();
         order.setStatus(Constants.OrderStatus.finished.getStatus());
+        order.setInvoiceStatus(Constants.ONE);
         order.setFinishTime(now);
         order.setUpdateTime(now);
         ordersMapper.updateById(order);
@@ -3320,7 +3685,6 @@
         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 exceptionFeeVal = order.getExceptionFee() != null ? order.getExceptionFee() : 0L;
 
         //瀛樹欢闂ㄥ簵鏀剁泭
         Long depositShopFee = new BigDecimal(totalAmount)
@@ -3336,8 +3700,7 @@
             driverFee = new BigDecimal(totalAmount)
                     .multiply(driverRate)
                     .setScale(0, RoundingMode.HALF_UP)
-                    .longValue()
-                    + exceptionFeeVal;
+                    .longValue();
 
             // 寮傚湴瀵勫瓨涓旀湁鍙栦欢闂ㄥ簵锛氬姞涓婂彇浠堕棬搴楁敹鐩�
             if (order.getTakeShopId() != null) {
@@ -3396,6 +3759,91 @@
                         driverFee, orderId, order.getCode()));
             }
         }
+
+        // 寮傚父璁㈠崟锛氬徃鏈哄紓甯歌ˉ鍋匡紙寮傚湴 + 寮傚父鏍囪 + 鏈夊紓甯歌ˉ鍋块噾棰濓級
+        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);
+            }
+        }
+
+        // 鍙告満濂栧姳閲戯紙浠呯敓鎴愬鍔辫褰曪紝涓嶇洿鎺ュ叆璐︼級
+        generateDriverReward(order);
+    }
+
+    /**
+     * 鐢熸垚鍙告満濂栧姳璁板綍
+     * 瑙勫垯锛�
+     *   宸插鍔辨鏁� < registerRewardOrderCount 鈫� 娉ㄥ唽濂栧姳锛坱ype=0, amount=registerRewardAmount锛�
+     *   registerRewardOrderCount <= 宸插鍔辨鏁� < (registerRewardOrderCount + platformRewardOrderCount) 鈫� 骞冲彴濂栧姳锛坱ype=1, amount=platformRewardAmount锛�
+     *   瓒呭嚭鎬诲悕棰濅笉濂栧姳
+     */
+    private void generateDriverReward(Orders order) {
+        if (order.getAcceptDriver() == null) return;
+        DriverInfo driver = driverInfoMapper.selectById(order.getAcceptDriver());
+        if (driver == null || driver.getId() == null) return;
+
+        // 璇诲彇濂栧姳閰嶇疆
+        String registerCountStr = operationConfigBiz.getConfig().getRegisterRewardOrderCount();
+        String registerAmountStr = operationConfigBiz.getConfig().getRegisterRewardAmount();
+        String platformCountStr = operationConfigBiz.getConfig().getPlatformRewardOrderCount();
+        String platformAmountStr = operationConfigBiz.getConfig().getPlatformRewardAmount();
+        if (StringUtils.isAnyBlank(registerCountStr, registerAmountStr, platformCountStr, platformAmountStr)) return;
+
+        int registerCount = Integer.parseInt(registerCountStr);
+        long registerAmount = new BigDecimal(registerAmountStr).multiply(BigDecimal.valueOf(100)).longValue();
+        int platformCount = Integer.parseInt(platformCountStr);
+        long platformAmount = new BigDecimal(platformAmountStr).multiply(BigDecimal.valueOf(100)).longValue();
+        int totalRewardSlots = registerCount + platformCount; // 鎬诲鍔卞悕棰�
+
+        // 鏌ヨ鍙告満宸插鍔辨鏁�
+        Long rewarded = rewardRecordMapper.selectCount(new QueryWrapper<RewardRecord>().lambda()
+                .eq(RewardRecord::getDriverId, driver.getId())
+                .eq(RewardRecord::getDeleted, Constants.ZERO));
+        int count = rewarded.intValue();
+        if (count >= totalRewardSlots) return; // 宸茶秴鍑哄鍔卞悕棰�
+
+        // 鍒ゆ柇鏈濂栧姳绫诲瀷鍜岄噾棰�
+        int rewardType;
+        long rewardAmount;
+        if (count < registerCount) {
+            // 娉ㄥ唽濂栧姳闃舵
+            rewardType = Constants.ZERO;
+            rewardAmount = registerAmount;
+        } else {
+            // 骞冲彴濂栧姳闃舵
+            rewardType = Constants.ONE;
+            rewardAmount = platformAmount;
+        }
+        if (rewardAmount <= 0) return;
+
+        // 鍒涘缓濂栧姳璁板綍锛堢姸鎬�=0寰呴鍙栵紝鍚庣画鐢卞徃鏈洪鍙栨椂鍏ヨ处锛�
+        RewardRecord record = new RewardRecord();
+        record.setOrderId(order.getId());
+        record.setDriverId(driver.getId());
+        record.setStatus(Constants.ZERO); // 0=寰呴鍙�
+        record.setType(rewardType);       // 0=娉ㄥ唽濂栧姳, 1=骞冲彴濂栧姳
+        record.setAmount(rewardAmount);
+        record.setDeleted(Constants.ZERO);
+        record.setCreateTime(new Date());
+        rewardRecordMapper.insert(record);
     }
 
     /**
@@ -3558,9 +4006,57 @@
                         .eq(OrdersDetail::getOrderId, orderId)
                         .eq(OrdersDetail::getDeleted, Constants.ZERO));
 
-        OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(order, details);
-
         Date now = new Date();
+
+        // 寮傚父璁㈠崟閫炬湡閫昏緫
+        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 shopExceptionFee = order.getShopCompensationAmount() != null ? order.getShopCompensationAmount() : 0L;
+            long totalExceptionFee = driverExceptionFee + shopExceptionFee;
+
+            // 鍒ゆ柇鏄惁褰撳ぉ鍙栦欢锛堟寜 expectedTakeTime 鏃ユ湡锛�
+            boolean sameDay = isSameDay(now, order.getExpectedTakeTime());
+
+            long overdueFee;
+            int overdueDays;
+            if (sameDay) {
+                // 褰撳ぉ鍙栦欢锛氶�炬湡璐圭敤 = 寮傚父璐圭敤鎬诲拰
+                overdueFee = totalExceptionFee;
+                overdueDays = totalExceptionFee > 0 ? 1 : 0;
+            } else {
+                // 闈炲綋澶╁彇浠讹細姝e父閫炬湡璁$畻 + 鍙告満寮傚父璐圭敤锛堜笉鍚棬搴楀紓甯歌垂鐢級
+                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.setConfirmArriveTime(now);
+            order.setUpdateTime(now);
+            if (overdueFee > 0) {
+                order.setOverdueStatus(Constants.ONE);
+                order.setOverdueDays(overdueDays);
+                order.setOverdueAmount(overdueFee);
+                ordersMapper.updateById(order);
+                String overdueLogInfo = "闂ㄥ簵銆�" + shopName + "銆戠‘璁ら【瀹㈠埌搴楋紝閫炬湡" + overdueDays
+                        + "澶╋紝閫炬湡璐圭敤" + Constants.getFormatMoney(overdueFee) + "鍏�";
+                saveShopVerifyLog(order, Constants.OrderLogType.shopConfirmArriveOverdue, overdueLogInfo, null, shopId);
+            } else {
+                order.setOverdueStatus(Constants.ZERO);
+                ordersMapper.updateById(order);
+                saveShopVerifyLog(order, Constants.OrderLogType.shopConfirmArrive,
+                        "闂ㄥ簵銆�" + shopName + "銆戠‘璁ら【瀹㈠埌搴楋紝鏈�炬湡", null, shopId);
+            }
+            return;
+        }
+
+        // 鏅�氳鍗曢�炬湡璁$畻
+        OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(order, details);
 
         if (overdueInfo.getOverdue() && overdueInfo.getOverdueDays() > 0) {
             // 瀛樺湪閫炬湡锛氭爣璁伴�炬湡鐘舵�侊紝璁㈠崟淇濇寔褰撳墠鐘舵��
@@ -3890,6 +4386,16 @@
         long diffMs = nowCal.getTimeInMillis() - depositCal.getTimeInMillis();
         int days = (int) (diffMs / (1000 * 60 * 60 * 24));
         return Math.max(days, 1);
+    }
+
+    private boolean isSameDay(Date d1, Date d2) {
+        if (d1 == null || d2 == null) return false;
+        Calendar c1 = Calendar.getInstance();
+        c1.setTime(d1);
+        Calendar c2 = Calendar.getInstance();
+        c2.setTime(d2);
+        return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR)
+                && c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR);
     }
 
     /**
@@ -4229,6 +4735,7 @@
 
                 // 鏇存柊璁㈠崟鐘舵�佷负宸插畬鎴�
                 order.setStatus(Constants.OrderStatus.finished.getStatus());
+                order.setInvoiceStatus(Constants.ONE);
                 order.setFinishTime(now);
                 order.setUpdateTime(now);
                 ordersMapper.updateById(order);
@@ -4450,6 +4957,9 @@
         Date now = new Date();
         Date threshold = new Date(now.getTime() + (long) minutes * 60 * 1000);
         // 鏌ヨ锛歴tatus=5銆佹湭閫氱煡銆佸氨鍦板瘎瀛� or 寮傚湴(鏈夊彇浠堕棬搴�)銆侀璁″彇浠舵椂闂村湪 now~threshold 涔嬮棿
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String nowStr = sdf.format(now);
+        String thresholdStr = sdf.format(threshold);
         List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda()
                 .eq(Orders::getStatus, Constants.OrderStatus.arrived.getStatus())
                 .eq(Orders::getPayStatus, Constants.ONE)
@@ -4460,8 +4970,8 @@
                 )
                 .ne(Orders::getPickUpNotifyStatus, Constants.ONE)
                 .isNotNull(Orders::getExpectedTakeTime)
-                .ge(Orders::getExpectedTakeTime, now)
-                .le(Orders::getExpectedTakeTime, threshold));
+                .apply("DATE_FORMAT(EXPECTED_TAKE_TIME, '%Y-%m-%d %H:%i:%s') >= {0}", nowStr)
+                .apply("DATE_FORMAT(EXPECTED_TAKE_TIME, '%Y-%m-%d %H:%i:%s') <= {0}", thresholdStr));
         if (orders == null || orders.isEmpty()) {
             return 0;
         }
@@ -4558,4 +5068,235 @@
         return distanceKm * 1000 <= radiusM;
     }
 
+    @Override
+    @Transactional(rollbackFor = {Exception.class, BusinessException.class})
+    public void handleOrderException(HandleOrderExceptionDTO dto) {
+        // ========== A. 鏍¢獙 ==========
+        Orders original = ordersMapper.selectById(dto.getOrderId());
+        if (original == null || Constants.equalsInteger(original.getDeleted(), Constants.ONE)) {
+            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "璁㈠崟涓嶅瓨鍦�");
+        }
+        if (!Constants.equalsInteger(original.getType(), Constants.ONE)) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "浠呮敮鎸佸紓鍦拌鍗曞紓甯稿鐞�");
+        }
+        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.getExceptionStatus(), Constants.ONE)) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "璇ヨ鍗曞凡澶勭悊杩囧紓甯革紝璇峰嬁閲嶅鎿嶄綔");
+        }
+
+        ShopInfo newShop = shopInfoMapper.selectById(dto.getDepositShopId());
+        if (newShop == null || Constants.equalsInteger(newShop.getStatus(), Constants.ONE)) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "瀛樻斁闂ㄥ簵涓嶅瓨鍦ㄦ垨宸茬鐢�");
+        }
+
+        Date now = new Date();
+
+        // ========== B. 鍒涘缓鏂拌鍗曪紙灏卞湴瀛樺彇锛� ==========
+        String orderCode = "JC" + new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(now)
+                + String.format("%04d", new java.util.Random().nextInt(10000));
+        String orderTradeNo = generateOrderTradeNo();
+
+        // 褰撳ぉ23:30
+        Calendar cal = Calendar.getInstance();
+        cal.set(Calendar.HOUR_OF_DAY, 23);
+        cal.set(Calendar.MINUTE, 30);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        Date expectedTakeTime = cal.getTime();
+
+        // 璁$畻鍩虹鍗曚环
+        Long price = 0L;
+        Long basicAmount = 0L;
+        // 鏌ヨ鍘熻鍗曟槑缁嗚幏鍙栫墿鍝佸垪琛�
+        List<OrdersDetail> originalDetails = ordersDetailMapper.selectList(
+                new QueryWrapper<OrdersDetail>().lambda()
+                        .eq(OrdersDetail::getOrderId, original.getId())
+                        .eq(OrdersDetail::getDeleted, Constants.ZERO));
+        if (!CollectionUtils.isEmpty(originalDetails)) {
+            CalculateLocalPriceDTO priceDTO = new CalculateLocalPriceDTO();
+            priceDTO.setCityId(Integer.valueOf(original.getCityId()));
+            priceDTO.setDepositStartTime(now);
+            priceDTO.setDepositEndTime(expectedTakeTime);
+            List<OrderItemDTO> items = new ArrayList<>();
+            for (OrdersDetail d : originalDetails) {
+                OrderItemDTO item = new OrderItemDTO();
+                item.setCategoryId(d.getLuggageId());
+                item.setQuantity(d.getNum());
+                items.add(item);
+            }
+            priceDTO.setItems(items);
+            PriceCalculateVO priceResult = calculateLocalPrice(priceDTO);
+            if (priceResult != null) {
+                price = priceResult.getItemPrice();
+                basicAmount = priceResult.getItemPrice();
+            }
+        }
+
+        // 瀛樹欢闂ㄥ簵鍒嗘垚鍗犳瘮锛堝氨鍦板瓨鍙栵級
+        Integer cityId = Integer.valueOf(original.getCityId());
+        boolean isCompany = Constants.equalsInteger(newShop.getCompanyType(), Constants.ONE);
+        int fallbackFieldA = isCompany ? Constants.FIVE : Constants.SIX;
+        BigDecimal depositShopFeeRate = getShopRevenueShare(newShop, "localDeposit", cityId, fallbackFieldA);
+
+        Orders newOrder = new Orders();
+        newOrder.setCode(orderCode);
+        newOrder.setOutTradeNo(orderTradeNo);
+        newOrder.setMemberId(original.getMemberId());
+        newOrder.setType(Constants.ZERO); // 灏卞湴瀛樺彇
+        newOrder.setCityId(original.getCityId());
+        newOrder.setStatus(Constants.ONE); // 寰呭瘎瀛�
+        newOrder.setPayStatus(Constants.ONE); // 宸叉敮浠�
+        newOrder.setPayTime(now);
+        newOrder.setCommentStatus(Constants.ZERO);
+        newOrder.setSettlementStatus(Constants.ZERO);
+        newOrder.setDeleted(Constants.ZERO);
+        newOrder.setCreateTime(now);
+        newOrder.setUpdateTime(now);
+        newOrder.setIsConverted(Constants.ZERO);
+
+        // 瀛樹欢淇℃伅锛堝叆鍙傞棬搴楋級
+        newOrder.setDepositShopId(dto.getDepositShopId());
+        newOrder.setDepositLocation(newShop.getAddress());
+        newOrder.setDepositLocationRemark(newShop.getAddress());
+        newOrder.setDepositLat(BigDecimal.valueOf(newShop.getLatitude()));
+        newOrder.setDepositLgt(BigDecimal.valueOf(newShop.getLongitude()));
+        // 鍙栦欢淇℃伅锛堝氨鍦�=瀛樹欢闂ㄥ簵锛�
+        newOrder.setTakeShopId(dto.getDepositShopId());
+        newOrder.setTakeLocation(newShop.getAddress());
+        newOrder.setTakeLocationRemark(newShop.getAddress());
+        newOrder.setTakeLat(BigDecimal.valueOf(newShop.getLatitude()));
+        newOrder.setTakeLgt(BigDecimal.valueOf(newShop.getLongitude()));
+
+        // 鏃堕棿
+        newOrder.setExpectedDepositTime(now);
+        newOrder.setExpectedTakeTime(expectedTakeTime);
+        newOrder.setEstimatedDepositDays(1);
+
+        // 鐗╁搧淇℃伅
+        newOrder.setGoodType(original.getGoodType());
+        newOrder.setGoodLevel(original.getGoodLevel());
+        newOrder.setGoodsInfo(original.getGoodsInfo());
+        newOrder.setSupplement(original.getSupplement());
+        newOrder.setSelfTake(original.getSelfTake());
+        newOrder.setTakeUser(original.getTakeUser());
+        newOrder.setTakePhone(original.getTakePhone());
+
+        // 寮傚父鏍囪
+        newOrder.setExceptionStatus(Constants.ONE);
+        newOrder.setRelationOrderId(original.getId());
+        newOrder.setExceptionInfo(dto.getRemark());
+
+        // 璐圭敤
+        newOrder.setIsUrgent(Constants.ZERO);
+        newOrder.setUrgentRata(BigDecimal.ONE);
+        newOrder.setUrgentAmount(0L);
+        newOrder.setDeclaredAmount(0L);
+        newOrder.setDeclaredFee(0L);
+        newOrder.setPrice(price);
+        newOrder.setBasicAmount(basicAmount);
+        newOrder.setEstimatedAmount(basicAmount);
+        newOrder.setTotalAmount(0L);
+        newOrder.setPayAmount(0L);
+        newOrder.setManualRefund(Constants.ZERO);
+
+        // 璐圭敤鍒嗛厤
+        newOrder.setDriverFee(0L);
+        newOrder.setDriverFeeRata(BigDecimal.ZERO);
+        newOrder.setDepositShopFee(0L);
+        newOrder.setDepositShopFeeRata(depositShopFeeRate);
+        newOrder.setTakeShopFee(0L);
+        newOrder.setTakeShopFeeRata(BigDecimal.ZERO);
+
+        // 闂ㄥ簵琛ュ伩閲戦
+        newOrder.setShopCompensationAmount(dto.getShopCompensation());
+
+        newOrder.setRemark(dto.getRemark());
+        newOrder.setPlatformSmsNotified(Constants.ZERO);
+        newOrder.setMemberVerifyCode(generateVerifyCode());
+        newOrder.setDriverVerifyCode(generateVerifyCode());
+        // 璁$畻搴楅摵璁㈠崟搴忓彿
+        Date todayStart = DateUtil.getStartOfDay(now);
+        Long currentCount = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda()
+                .eq(Orders::getDepositShopId, dto.getDepositShopId())
+                .eq(Orders::getPayStatus, Constants.ONE)
+                .ge(Orders::getPayTime, todayStart)
+                .eq(Orders::getDeleted, Constants.ZERO));
+        newOrder.setAutoNum(currentCount + 1);
+        ordersMapper.insert(newOrder);
+
+        // ========== C. 鍒涘缓鏂拌鍗曟槑缁� ==========
+        if (!CollectionUtils.isEmpty(originalDetails)) {
+            for (OrdersDetail od : originalDetails) {
+                OrdersDetail detail = new OrdersDetail();
+                detail.setOrderId(newOrder.getId());
+                detail.setLuggageId(od.getLuggageId());
+                detail.setLuggageName(od.getLuggageName());
+                detail.setLuggageDetail(od.getLuggageDetail());
+                detail.setNum(od.getNum());
+                detail.setUnitPrice(od.getLocallyPrice());
+                detail.setLocallyPrice(od.getLocallyPrice());
+                detail.setDeleted(Constants.ZERO);
+                detail.setCreateTime(now);
+                ordersDetailMapper.insert(detail);
+            }
+        }
+
+        // ========== D. 鎷疯礉闄勪欢 ==========
+        List<Multifile> originalFiles = multifileMapper.selectList(
+                new QueryWrapper<Multifile>().lambda()
+                        .eq(Multifile::getObjId, original.getId())
+                        .eq(Multifile::getObjType, Constants.FileType.ORDER_FILE.getKey())
+                        .eq(Multifile::getIsdeleted, Constants.ZERO));
+        if (!CollectionUtils.isEmpty(originalFiles)) {
+            int sortNum = 1;
+            for (Multifile mf : originalFiles) {
+                Multifile newFile = new Multifile();
+                newFile.setObjId(newOrder.getId());
+                newFile.setObjType(Constants.FileType.ORDER_FILE.getKey());
+                newFile.setType(mf.getType());
+                newFile.setFileurl(mf.getFileurl());
+                newFile.setIsdeleted(Constants.ZERO);
+                newFile.setCreateDate(now);
+                newFile.setSortnum(sortNum++);
+                multifileMapper.insert(newFile);
+            }
+        }
+
+        // ========== 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()));
+
+        // ========== F. 鍙戦�佺煭淇¢�氱煡 ==========
+        // 鍙告満绔�-寮傚父娲惧崟
+        if (original.getAcceptDriver() != null) {
+            DriverInfo driver = driverInfoMapper.selectById(original.getAcceptDriver());
+            if (driver != null && StringUtils.isNotBlank(driver.getTelephone())) {
+                sendSmsNotify(driver.getTelephone(), Constants.SmsNotify.EXCEPTION_DISPATCH,
+                        "orderNo", original.getCode(),
+                        "address", newShop.getAddress(),
+                        "code", newOrder.getMemberVerifyCode());
+            }
+        }
+        // 浼氬憳绔�-寮傚父娲惧崟
+        String memberPhone = StringUtils.isNotBlank(original.getTakePhone()) ? original.getTakePhone() : null;
+        if (memberPhone == null) {
+            Member member = memberMapper.selectById(original.getMemberId());
+            if (member != null) {
+                memberPhone = member.getTelephone();
+            }
+        }
+        if (StringUtils.isNotBlank(memberPhone)) {
+            sendSmsNotify(memberPhone, Constants.SmsNotify.MEMBER_EXCEPTION_DISPATCH,
+                    "address", newShop.getAddress());
+        }
+    }
+
 }

--
Gitblit v1.9.3