Bläddra i källkod

Merge remote-tracking branch 'origin/master' into master

# Conflicts:
#	ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderMainServiceImpl.java
肖路 3 veckor sedan
förälder
incheckning
cfdce2862f

+ 4 - 1
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlatformDataScopeInterceptor.java

@@ -102,7 +102,10 @@ public class PlatformDataScopeInterceptor implements Interceptor {
         "customer_business_info",
         "mall_page_link",
         "mall_page_category",
-        "sys_user"
+        "sys_user",
+        "statement_invoice",
+        "statement_invoice_detail",
+        "statement_invoice_product"
 
 
         // 注意:前缀匹配需特殊处理(如 qrtz_),见 isIgnoreTable 方法

+ 1 - 1
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/pc/CustomerRegisterController.java

@@ -32,7 +32,7 @@ public class CustomerRegisterController {
      */
     @PostMapping("/validate")
     public R<Void> verifyCodeAndPassword(@RequestBody CustomerRegisterBo bo) {
-        customerInfoService.verifyCodeAndPssword(bo);
+        customerInfoService.verifyCodeAndPassword(bo);
         return R.ok();
     }
 

+ 1 - 1
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/ICustomerInfoService.java

@@ -142,7 +142,7 @@ public interface ICustomerInfoService extends IService<CustomerInfo> {
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
 
     /*验证密码与验证码*/
-    Boolean verifyCodeAndPssword(CustomerRegisterBo bo);
+    Boolean verifyCodeAndPassword(CustomerRegisterBo bo);
 
     /**
      * 客户注册

+ 9 - 1
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerInfoServiceImpl.java

@@ -898,9 +898,13 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
     }
 
     @Override
-    public Boolean verifyCodeAndPssword(CustomerRegisterBo bo) {
+    public Boolean verifyCodeAndPassword(CustomerRegisterBo bo) {
         //先校验验证码是否正确
         String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + bo.getPurchasePhone());
+        if (code == null) {
+            throw new ServiceException("验证码已过期");
+        }
+
         if (!code.equals(bo.getCode())) {
             throw new ServiceException("验证码错误");
 
@@ -1089,6 +1093,10 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
         }
 
         log.info("客户注册成功,客户ID:{},客户名称:{}", customerId, bo.getCustomerName());
+
+        if (null != code) {
+            RedisUtils.deleteObject(GlobalConstants.CAPTCHA_CODE_KEY + bo.getPurchasePhone());
+        }
         return true;
     }
 

+ 22 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerShippingAddressServiceImpl.java

@@ -147,6 +147,7 @@ public class CustomerShippingAddressServiceImpl extends ServiceImpl<CustomerShip
         // 4. 设置生成的业务字段
         add.setShippingAddressNo(shippingAddressNo);
 
+
         // 5. 业务校验
         validEntityBeforeSave(add);
 
@@ -156,6 +157,27 @@ public class CustomerShippingAddressServiceImpl extends ServiceImpl<CustomerShip
         // 7. 回填 ID
         if (flag) {
             bo.setId(add.getId());
+            if (null != bo.getDefaultAddress() && StringUtils.isNotBlank(bo.getDefaultAddress())) {
+                if (IsDefault.Yes.getCode().equals(bo.getDefaultAddress())) {
+                    // 1. 清除该客户下所有默认地址
+                    CustomerShippingAddress updateObj = new CustomerShippingAddress();
+                    updateObj.setDefaultAddress(IsDefault.No.getCode()); //
+
+                    baseMapper.update(
+                        updateObj,
+                        new LambdaUpdateWrapper<CustomerShippingAddress>()
+                            .eq(CustomerShippingAddress::getCustomerId, bo.getCustomerId()) //
+                            .eq(CustomerShippingAddress::getDefaultAddress, IsDefault.Yes.getCode())
+                    );
+
+                    // 2. 设置当前地址为默认
+                    CustomerShippingAddress current = new CustomerShippingAddress();
+                    current.setId(bo.getId());
+                    current.setDefaultAddress(IsDefault.Yes.getCode());
+                    baseMapper.updateById(current);
+
+                }
+            }
         }
 
         return flag;

+ 3 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SupplierInfoServiceImpl.java

@@ -2270,6 +2270,9 @@ public class SupplierInfoServiceImpl extends ServiceImpl<SupplierInfoMapper, Sup
             throw new ServiceException("供应商供应区域信息批量新增失败");
         }
 
+        if (null != code) {
+            RedisUtils.deleteObject(GlobalConstants.CAPTCHA_CODE_KEY + bo.getPurchasePhone());
+        }
 
         return true;
     }

+ 10 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderMainController.java

@@ -1,6 +1,7 @@
 package org.dromara.order.controller;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.NotEmpty;
@@ -15,6 +16,7 @@ import org.dromara.common.log.annotation.Log;
 import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.tenant.helper.PlatformHelper;
 import org.dromara.common.web.core.BaseController;
 import org.dromara.order.domain.OrderProduct;
@@ -51,6 +53,14 @@ public class OrderMainController extends BaseController {
      */
     @GetMapping("/list")
     public TableDataInfo<OrderMainVo> list(OrderMainBo bo, PageQuery pageQuery) {
+        Long partnerId = LoginHelper.getLoginUser().getPartnerId();
+        if (ObjectUtil.isNotEmpty(partnerId)) {
+            bo.setAssigneeId(partnerId);
+        }
+        Long supplierId = LoginHelper.getLoginUser().getSupplierId();
+        if (ObjectUtil.isNotEmpty(supplierId)) {
+            bo.setAssigneeId(supplierId);
+        }
         return orderMainService.queryPageList(bo, pageQuery);
     }
 

+ 6 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderMain.java

@@ -180,6 +180,12 @@ public class OrderMain extends TenantEntity {
      */
     private Date shippingTime;
 
+
+    /**
+     * 已发货数量
+     */
+    private Integer quantityShipped;
+
     /**
      * 收货时间
      */

+ 5 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderMainBo.java

@@ -196,6 +196,11 @@ public class OrderMainBo extends BaseEntity {
      */
     private String isSplitChild;
 
+    /**
+     * 已发货数量
+     */
+    private Integer quantityShipped;
+
     /**
      * 包裹数量
      */

+ 5 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderMainVo.java

@@ -253,6 +253,11 @@ public class OrderMainVo implements Serializable {
     @ExcelProperty(value = "包裹数量")
     private Long packageCount;
 
+    /**
+     * 已发货数量
+     */
+    private Integer quantityShipped;
+
     /**
      * 签收数量
      */

+ 2 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderAssignmentServiceImpl.java

@@ -473,6 +473,8 @@ public class OrderAssignmentServiceImpl extends ServiceImpl<OrderAssignmentMappe
         child.setPayableAmount(parent.getPayableAmount());
         child.setShippingFee(parent.getShippingFee());
         child.setOrderSource(parent.getOrderSource());
+        child.setProductQuantity(parent.getProductQuantity());
+        child.setQuantityShipped(parent.getQuantityShipped());
         child.setOrderStatus(parent.getOrderStatus()); // 继承状态,后续由子订单独立流转
         child.setOrderTime(parent.getOrderTime());
         child.setConfirmTime(parent.getConfirmTime());

+ 99 - 90
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderDeliverServiceImpl.java

@@ -171,134 +171,143 @@ public class OrderDeliverServiceImpl extends ServiceImpl<OrderDeliverMapper, Ord
     @Transactional(rollbackFor = Exception.class)
     @Override
     public Boolean insertByBo(OrderDeliverBo bo) {
+        // 建议使用 @Transactional 注解在方法上,确保整个流程原子性
         try {
+            Long orderId = bo.getOrderId();
+
             // 1. 生成发货单号
             bo.setDeliverCode(SequenceUtils.nextIdDateTimePadded(""));
 
-            Long orderId = bo.getOrderId();
+            // 2. 计算本次发货总数
+            long currentDeliverQty = bo.getOrderDeliverProducts().stream()
+                .mapToLong(OrderDeliverProductBo::getDeliverNum)
+                .sum();
+
+            if (currentDeliverQty <= 0) {
+                throw new RuntimeException("发货数量必须大于0");
+            }
+
+            // 3. 使用 SQL 原子更新来计算新状态和累加数量
 
-            // 2. 查询订单主信息(用于后续状态更新)
             OrderMain orderMain = orderMainMapper.selectById(orderId);
             if (orderMain == null) {
                 throw new RuntimeException("订单不存在: " + orderId);
             }
 
-            // 3. 获取 订单总数量 和 已发货总数量
-            OrderQuantitySummary summary = orderProductMapper.selectOrderAndDeliveredQuantity(orderId);
-            long orderTotalQty = Optional.ofNullable(summary.getOrderTotalQty()).orElse(0L);
-            long deliveredTotalQty = Optional.ofNullable(summary.getDeliveredTotalQty()).orElse(0L);
+            // 获取当前的已发货数量 (假设订单主表有 delivered_qty 字段)
+            // 如果你的架构是查 OrderProduct 汇总表,请确保那个汇总表也是实时准确的
+            // 强烈建议:订单主表 OrderMain 应该有一个 delivered_total_qty 字段
+            Long currentDeliveredQty = orderMain.getQuantityShipped().longValue();
+            if (currentDeliveredQty == null) currentDeliveredQty = 0L;
+
+            Long orderTotalQty = orderMain.getProductQuantity(); // 假设主表也有总数量字段,否则查明细
+            if (orderTotalQty == null) {
+                // 如果主表没存总数量,才去查明细,但要注意明细也可能并发变
+                OrderQuantitySummary summary = orderProductMapper.selectOrderAndDeliveredQuantity(orderId);
+                orderTotalQty = Optional.ofNullable(summary.getOrderTotalQty()).orElse(0L);
+                // 注意:这里如果依赖明细表统计总数,在高并发下依然有风险,最好主表冗余总数量
+            }
 
-            // 4. 新增本次发货数量(从 BO 中累加)
-            long currentDeliverQty = bo.getOrderDeliverProducts().stream()
-                .mapToLong(OrderDeliverProductBo::getDeliverNum)
-                .sum();
+            long newDeliveredTotalQty = currentDeliveredQty + currentDeliverQty;
 
-            // 5. 计算发货后总量
-            long newDeliveredTotalQty = deliveredTotalQty + currentDeliverQty;
+            // 4. 校验是否超发
+            if (newDeliveredTotalQty > orderTotalQty) {
+                throw new RuntimeException("发货数量超过订单总数!订单总数:" + orderTotalQty + ", 当前尝试发货后累计:" + newDeliveredTotalQty);
+            }
 
-            // 6. 判断新状态
+            // 5. 确定新状态
             String newStatus;
             if (newDeliveredTotalQty >= orderTotalQty) {
-                newStatus = OrderStatus.SHIPPED.getCode(); // 已全部发货
-            } else if (newDeliveredTotalQty > 0) {
-                newStatus = OrderStatus.PARTIALLY_SHIPPED.getCode(); // 部分发货
+                newStatus = OrderStatus.SHIPPED.getCode();
             } else {
-                newStatus = orderMain.getOrderStatus(); // 无发货,保持原状态
+                newStatus = OrderStatus.PARTIALLY_SHIPPED.getCode();
             }
 
-            // 7. 插入发货单主表
+            // 6. 插入发货单主表和明细 (略,保持你原有的逻辑)
             OrderDeliver deliver = MapstructUtils.convert(bo, OrderDeliver.class);
             validEntityBeforeSave(deliver);
             boolean inserted = baseMapper.insert(deliver) > 0;
-            if (!inserted) {
-                return false;
-            }
+            if (!inserted) return false;
             bo.setId(deliver.getId());
-
-            // 8. 插入发货商品明细
             saveOrderDeliverProducts(deliver.getId(), bo.getOrderDeliverProducts(), false);
 
-            // 9. 更新订单主表状态
-
-
-            OrderMain currentOrder = orderMainMapper.selectById(orderId);
-
-            if (currentOrder == null) {
-                throw new RuntimeException("订单不存在");
-            }
-
-            // 2. 更新当前订单状态
+            // 7. 【核心修复】更新订单主表
+            // 必须同时更新:1. 已发货数量 2. 订单状态
+            // 并且要带上版本号或条件判断,防止并发覆盖
             LambdaUpdateWrapper<OrderMain> updateWrapper = new LambdaUpdateWrapper<OrderMain>()
                 .eq(OrderMain::getId, orderId)
+                // 乐观锁检查:确保更新时的基础数量和我们计算时的一致,防止中间被别人改了
+                // 如果你的表有 version 字段,优先用 version
+                // .eq(OrderMain::getVersion, orderMain.getVersion())
+                // 如果没有 version,至少校验当前已发货数量是否变动(防止重复提交或并发)
+                .eq(OrderMain::getQuantityShipped, currentDeliveredQty)
+                .set(OrderMain::getQuantityShipped, newDeliveredTotalQty)
                 .set(OrderMain::getOrderStatus, newStatus);
 
-            orderMainMapper.update(null, updateWrapper);
-
-            // 3. 【新增逻辑】如果存在父订单,根据策略同步更新父订单状态
-            if (currentOrder.getParentOrderId() != null) {
-                Long parentId = currentOrder.getParentOrderId();
-                boolean shouldUpdateParent = false;
-                String targetParentStatus = null;
-
-                // 场景 1: 当前子单变为 "已发货" (SHIPPED)
-                if (OrderStatus.SHIPPED.getCode().equals(newStatus)) {
-                    // 逻辑:查询该父订单下所有的子订单
-                    List<OrderMain> siblingOrders = orderMainMapper.selectList(
-                        new LambdaQueryWrapper<OrderMain>()
-                            .eq(OrderMain::getParentOrderId, parentId)
-                            .select(OrderMain::getOrderStatus) // 只查状态字段,优化性能
-                    );
-
-                    // 校验:是否所有子订单都已经是 "已发货"
-                    if (!siblingOrders.isEmpty()) {
-                        boolean allShipped = siblingOrders.stream()
-                            .allMatch(order -> OrderStatus.SHIPPED.getCode().equals(order.getOrderStatus()));
-
-                        if (allShipped) {
-                            shouldUpdateParent = true;
-                            targetParentStatus = OrderStatus.SHIPPED.getCode();
-                        }
-                        // 如果并非全部发货,则父订单不应更新为 SHIPPED (保持原状或维持 PARTIALLY_SHIPPED)
-                    }
+            // 如果使用了 version,这里也要 +1
+            // .set(OrderMain::getVersion, orderMain.getVersion() + 1)
 
-                }
-                // 场景 2: 当前子单变为 "部分发货" (PARTIALLY_SHIPPED)
-                else if (OrderStatus.PARTIALLY_SHIPPED.getCode().equals(newStatus)) {
-                    // 逻辑:子单部分发货,父单必然也是部分发货,直接标记需要更新
-                    shouldUpdateParent = true;
-                    targetParentStatus = OrderStatus.PARTIALLY_SHIPPED.getCode();
-                }
-                // 场景 3: 状态无变化 (保持原状态)
-                else if (currentOrder.getOrderStatus().equals(newStatus)) {
-                    // 逻辑:状态没变,不需要处理父订单
-                    shouldUpdateParent = false;
-                }
-                // [可选扩展] 场景 4: 其他状态 (如取消 CANCELLED, 关闭 CLOSED 等)
-                // 如果你的业务要求子单取消父单也必须取消,可以在这里添加 else if 分支
-                // else if (OrderStatus.CANCELLED.getCode().equals(newStatus)) { ... }
-
-                // 执行父订单更新
-                if (shouldUpdateParent && targetParentStatus != null) {
-                    LambdaUpdateWrapper<OrderMain> parentUpdateWrapper = new LambdaUpdateWrapper<OrderMain>()
-                        .eq(OrderMain::getId, parentId)
-                        // 优化:只有当父订单当前状态不等于目标状态时才更新,避免无效写操作
-                        .ne(OrderMain::getOrderStatus, targetParentStatus)
-                        .set(OrderMain::getOrderStatus, targetParentStatus);
-
-                    // 再次确认父订单存在且状态不同再执行,ne 条件已经涵盖了大部分,但为了严谨可以执行 update
-                    // 如果 ne 条件不满足,update 返回 0,不会报错
-                    orderMainMapper.update(null, parentUpdateWrapper);
+            int updateCount = orderMainMapper.update(null, updateWrapper);
+            if (updateCount == 0) {
+                // 更新失败,说明数据被其他人修改了(并发冲突),抛出异常让事务回滚,前端重试
+                throw new RuntimeException("订单状态更新失败,可能存在并发操作,请刷新后重试");
+            }
+
+            // 8. 处理父订单状态同步
+            // 只有当当前子单成功更新为 SHIPPED 时,才需要检查父订单
+            if (OrderStatus.SHIPPED.getCode().equals(newStatus)) {
+                syncParentOrderStatus(orderId, orderMain.getParentOrderId());
+            } else if (OrderStatus.PARTIALLY_SHIPPED.getCode().equals(newStatus)) {
+                // 部分发货时,父订单理论上至少是部分发货
+                if (orderMain.getParentOrderId() != null) {
+                    LambdaUpdateWrapper<OrderMain> parentPartialWrapper = new LambdaUpdateWrapper<OrderMain>()
+                        .eq(OrderMain::getId, orderMain.getParentOrderId())
+                        .ne(OrderMain::getOrderStatus, OrderStatus.PARTIALLY_SHIPPED.getCode())
+                        // 只有当父订单状态是“未发货”或其他非部分/全发状态时才升级
+                        .set(OrderMain::getOrderStatus, OrderStatus.PARTIALLY_SHIPPED.getCode());
+                    orderMainMapper.update(null, parentPartialWrapper);
                 }
             }
 
-            log.info("新增订单发货单成功:{}", bo.getId());
+            log.info("新增订单发货单成功:{}, 订单新状态:{}", bo.getId(), newStatus);
             return true;
-        } catch (RuntimeException e) {
+
+        } catch (Exception e) {
             log.error("新增订单发货主失败:{}", e.getMessage(), e);
             throw new RuntimeException(e);
         }
     }
 
+    /**
+     * 单独提取父订单同步逻辑,增加健壮性
+     */
+    private void syncParentOrderStatus(Long currentOrderId, Long parentId) {
+        if (parentId == null) return;
+
+        // 使用数据库锁或者再次查询确认
+        // 这里的逻辑:查询该父订单下所有子单的状态
+        List<OrderMain> siblingOrders = orderMainMapper.selectList(
+            new LambdaQueryWrapper<OrderMain>()
+                .eq(OrderMain::getParentOrderId, parentId)
+                .select(OrderMain::getId, OrderMain::getOrderStatus)
+        );
+
+        if (siblingOrders.isEmpty()) return;
+
+        boolean allShipped = siblingOrders.stream()
+            .allMatch(o -> OrderStatus.SHIPPED.getCode().equals(o.getOrderStatus()));
+
+        if (allShipped) {
+            // 所有子单都发货了,更新父单
+            LambdaUpdateWrapper<OrderMain> parentUpdateWrapper = new LambdaUpdateWrapper<OrderMain>()
+                .eq(OrderMain::getId, parentId)
+                .ne(OrderMain::getOrderStatus, OrderStatus.SHIPPED.getCode()) // 避免无效更新
+                .set(OrderMain::getOrderStatus, OrderStatus.SHIPPED.getCode());
+
+            orderMainMapper.update(null, parentUpdateWrapper);
+        }
+    }
+
     @Override
     public TableDataInfo<OrderDeliverProductVo> getCustomerOrderProductList(Set<Long> orderIdList) {
         // 1. 空值与空集合校验

+ 15 - 13
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderMainServiceImpl.java

@@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.dromara.common.core.enums.OrderPayType;
 import org.dromara.common.core.enums.OrderStatus;
+import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.exception.api.ZhongcheException;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -271,6 +272,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
         lqw.eq(bo.getReceivingTime() != null, OrderMain::getReceivingTime, bo.getReceivingTime());
         lqw.eq(bo.getPackageCount() != null, OrderMain::getPackageCount, bo.getPackageCount());
         lqw.eq(bo.getSignedQuantity() != null, OrderMain::getSignedQuantity, bo.getSignedQuantity());
+        lqw.eq(bo.getAssigneeId() != null, OrderMain::getAssigneeId, bo.getAssigneeId());
         lqw.eq(bo.getAfterSaleCompleted() != null, OrderMain::getAfterSaleCompleted, bo.getAfterSaleCompleted());
         lqw.eq(bo.getAfterSalePending() != null, OrderMain::getAfterSalePending, bo.getAfterSalePending());
         lqw.eq(StringUtils.isNotBlank(bo.getPushStatus()), OrderMain::getPushStatus, bo.getPushStatus());
@@ -561,7 +563,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
             .eq(OrderMain::getId, orderId)
             .last("FOR UPDATE"));
         if (existingOrder == null) {
-            throw new IllegalArgumentException("订单不存在");
+            throw new ServiceException("订单不存在");
         }
 
         // 2. 检查当前状态:只允许从“待确认”(比如状态0或1)变为“待发货”(2)
@@ -575,7 +577,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
         );
 
         if (CollUtil.isEmpty(existingProducts)) {
-            throw new IllegalStateException("订单商品不存在,无法确认");
+            throw new ServiceException("订单商品不存在,无法确认");
         }
 
         // 4. 构建商品ID -> 现有商品的映射
@@ -584,7 +586,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
 
         // 5. 校验传入的商品列表是否匹配(不能增删商品,只能改数量)
         if (CollUtil.isEmpty(updatedProducts)) {
-            throw new IllegalArgumentException("确认订单时商品列表不能为空");
+            throw new ServiceException("确认订单时商品列表不能为空");
         }
 
         if (updatedProducts.size() != existingProducts.size()) {
@@ -608,7 +610,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
             // 仅允许修改数量(可选),其他字段如 price、skuCode 等必须保持一致
             Long newQty = bo.getOrderQuantity();
             if (newQty == null || newQty <= 0) {
-                throw new IllegalArgumentException("商品数量必须大于0");
+                throw new ServiceException("商品数量必须大于0");
             }
 
             // 重新计算小计:注意使用原单价 * 新数量(防止前端篡改价格)
@@ -649,33 +651,33 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
     public Boolean orderPay(Long customerId, Long orderId, String payType) {
         // 参数校验
         if (orderId == null) {
-            throw new IllegalArgumentException("订单ID不能为空");
+            throw new ServiceException("订单ID不能为空");
         }
         if (customerId == null) {
-            throw new IllegalArgumentException("客户ID不能为空");
+            throw new ServiceException("客户ID不能为空");
         }
         if (payType == null || !OrderPayType.CREDIT_PAY.getCode().equals(payType)) {
-            throw new IllegalArgumentException("仅支持信用支付方式");
+            throw new ServiceException("仅支持信用支付方式");
         }
 
         // 查询订单
         OrderMainVo orderMainVo = baseMapper.selectVoById(orderId);
         if (orderMainVo == null) {
-            throw new IllegalArgumentException("订单不存在");
+            throw new ServiceException("订单不存在");
         }
         if (!Objects.equals(customerId, orderMainVo.getCustomerId())) {
-            throw new IllegalArgumentException("订单不属于当前客户");
+            throw new ServiceException("订单不属于当前客户");
         }
 
         BigDecimal totalAmount = orderMainVo.getTotalAmount();
         if (totalAmount == null || totalAmount.compareTo(BigDecimal.ZERO) <= 0) {
-            throw new IllegalArgumentException("订单金额无效");
+            throw new ServiceException("订单金额无效");
         }
 
         // 查询客户信用销售信息
         RemoteCustomerSalesVo salesInfo = remoteCustomerSalesService.selectCustomerSalesInfoByCustomerId(customerId);
         if (salesInfo == null) {
-            throw new IllegalStateException("客户信用信息未配置,无法使用信用支付");
+            throw new ServiceException("客户信用信息未配置,无法使用信用支付");
         }
 
         // 获取可用额度:剩余额度 + 临时额度
@@ -688,7 +690,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
 
         // 判断额度是否足够
         if (availableCredit.compareTo(totalAmount) < 0) {
-            throw new IllegalStateException("信用额度不足,无法完成支付");
+            throw new ServiceException("信用额度不足,无法完成支付");
         }
 
         // 扣减逻辑:优先扣减临时额度,再扣剩余额度
@@ -706,7 +708,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
 
             // 理论上不会为负(前面已校验总额度足够),但防御性检查
             if (newRemainingQuota.compareTo(BigDecimal.ZERO) < 0) {
-                throw new IllegalStateException("信用额度计算异常,请联系管理员");
+                throw new ServiceException("信用额度计算异常,请联系管理员");
             }
         }