ソースを参照

feat(order): 添加PC端订单提交功能并优化父子订单状态同步逻辑

- 新增PcSubmitOrderBo类用于PC端订单提交参数封装
- 在IOrderMainService中添加insertOrder方法处理订单创建流程
- 实现父子订单状态同步策略,支持SHIPPED、PARTIALLY_SHIPPED等状态的智能更新
- 重构批量确认收货逻辑,支持父订单和子订单的同时处理
- 集成客户审批流程服务,在订单创建后自动初始化审批流程
- 优化购物车数据清理逻辑,确保下单成功后购物车数据及时删除
- 完善订单发货服务中的父订单状态更新机制,避免无效数据库操作
hurx 1 ヶ月 前
コミット
9f4f793666

+ 1 - 14
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/pc/PcOrderController.java

@@ -413,20 +413,7 @@ public class PcOrderController extends BaseController {
             mainBo.setOrderProductBos(orderProductBos);
 
             // 5. 保存订单(关键:成功后再删除购物车)
-            Long orderId = orderMainService.insertByBo(mainBo);
-            if (orderId != null && orderId > 0) {
-                //初始化审批流程
-                Boolean initOrderFlow = orderCustomerFlowService.initOrderFlow(orderId);
-                if (initOrderFlow) {
-                    orderMainService.update(Wrappers.lambdaUpdate(OrderMain.class).eq(OrderMain::getId, orderId).set(OrderMain::getOrderStatus, 1));
-                }
-                if (bo.getPlaceOrderType() == 1) {
-                    // 成功下单后,删除对应的购物车项
-                    remoteProductShoppingCartService.deleteWithValidByIds(bo.getProductShoppingCartId());
-                }
-            } else {
-                throw new RuntimeException("订单创建失败");
-            }
+            Long orderId = orderMainService.insertOrder(bo, mainBo);
 
             return R.ok(orderId); // 正确返回 ID
         } catch (Exception e) {

+ 3 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderMainService.java

@@ -7,6 +7,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.order.domain.OrderMain;
 import org.dromara.order.domain.bo.OrderMainBo;
 import org.dromara.order.domain.bo.OrderProductBo;
+import org.dromara.order.domain.bo.PcSubmitOrderBo;
 import org.dromara.order.domain.vo.*;
 import org.dromara.order.utils.kd100.domain.TrackData;
 
@@ -72,6 +73,8 @@ public interface IOrderMainService extends IService<OrderMain> {
      */
     Boolean updateByBo(OrderMainBo bo);
 
+    Long insertOrder(PcSubmitOrderBo bo, OrderMainBo mainBo);
+
     /**
      * 订单确认
      *

+ 54 - 11
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderDeliverServiceImpl.java

@@ -234,20 +234,63 @@ public class OrderDeliverServiceImpl extends ServiceImpl<OrderDeliverMapper, Ord
 
             orderMainMapper.update(null, updateWrapper);
 
-            // 3. 【新增逻辑】如果存在父订单,同步更新父订单状态
+            // 3. 【新增逻辑】如果存在父订单,根据策略同步更新父订单状态
             if (currentOrder.getParentOrderId() != null) {
-                // “同步更新”处理,即直接设为相同状态。
-
-                LambdaUpdateWrapper<OrderMain> parentUpdateWrapper = new LambdaUpdateWrapper<OrderMain>()
-                    .eq(OrderMain::getId, currentOrder.getParentOrderId())
-                    .set(OrderMain::getOrderStatus, newStatus);
-
-                orderMainMapper.update(null, parentUpdateWrapper);
-
-                // 可选:如果需要递归更新更上层的父订单(如果存在多级嵌套),可以在此处加循环或递归调用
+                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)
+                    }
+
+                }
+                // 场景 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);
+                }
             }
 
-
             log.info("新增订单发货单成功:{}", bo.getId());
             return true;
         } catch (RuntimeException e) {

+ 64 - 10
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderMainServiceImpl.java

@@ -32,16 +32,16 @@ import org.dromara.order.domain.OrderMainCrrcExt;
 import org.dromara.order.domain.OrderProduct;
 import org.dromara.order.domain.bo.OrderMainBo;
 import org.dromara.order.domain.bo.OrderProductBo;
+import org.dromara.order.domain.bo.PcSubmitOrderBo;
 import org.dromara.order.domain.dto.AssignmentStatsDto;
 import org.dromara.order.domain.vo.*;
 import org.dromara.order.mapper.*;
-import org.dromara.order.service.IOrderDeliverService;
-import org.dromara.order.service.IOrderMainCrrcExtService;
-import org.dromara.order.service.IOrderMainService;
+import org.dromara.order.service.*;
 import org.dromara.order.utils.kd100.Kd100Util;
 import org.dromara.order.utils.kd100.domain.QueryTrackDTO;
 import org.dromara.order.utils.kd100.domain.TrackData;
 import org.dromara.order.utils.kd100.domain.TrackVO;
+import org.dromara.product.api.RemoteProductShoppingCartService;
 import org.dromara.system.api.RemoteComLogisticsCompanyService;
 import org.dromara.system.api.RemoteDeptService;
 import org.dromara.system.api.RemoteUserService;
@@ -79,6 +79,16 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
     @DubboReference
     private RemoteCustomerSalesService remoteCustomerSalesService;
 
+    //客户订单流程
+    private final IOrderCustomerFlowService orderCustomerFlowService;
+
+    @DubboReference
+    private RemoteProductShoppingCartService remoteProductShoppingCartService;
+
+    private final IOrderCustomerFlowLinkService orderCustomerFlowLinkService;
+
+    private final IOrderCustomerFlowNodeLinkService orderCustomerFlowNodeLinkService;
+
     private final OrderMainMapper baseMapper;
 
     private final OrderProductMapper orderProductMapper;
@@ -465,6 +475,35 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
         }
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long insertOrder(PcSubmitOrderBo bo, OrderMainBo mainBo) {
+        // 1. 插入主订单,获取生成的 ID
+        Long orderId = this.insertByBo(mainBo);
+
+        // 2. 校验插入是否成功
+        if (orderId != null && orderId > 0) {
+            // 3. 初始化审批流程
+            Boolean initOrderFlow = orderCustomerFlowService.initOrderFlow(orderId);
+
+            // 4. 如果流程初始化成功,更新订单状态 (注意:这里再次触发了数据库更新)
+            if (initOrderFlow) {
+                this.update(Wrappers.lambdaUpdate(OrderMain.class)
+                    .eq(OrderMain::getId, orderId)
+                    .set(OrderMain::getOrderStatus, 1)); // 假设 1 代表某种特定状态,需确认枚举值
+            }
+
+            // 5. 如果是从购物车下单,删除购物车数据
+            if (bo.getPlaceOrderType() == 1) {
+                remoteProductShoppingCartService.deleteWithValidByIds(bo.getProductShoppingCartId());
+            }
+
+            return orderId;
+        } else {
+            // 插入失败,抛出异常触发事务回滚
+            throw new RuntimeException("订单创建失败:未能生成有效的订单ID");
+        }
+    }
 
     /**
      * 订单确认
@@ -724,20 +763,35 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean batchConfirmation(Set<Long> ids) {
-        // 2. 参数校验
+        // 1. 参数校验
         if (CollectionUtils.isEmpty(ids)) {
             return true;
         }
 
+        // 将 Set 转为 List 以便 Wrapper 使用 (MyBatis-Plus in 方法通常接受 Collection)
+        List<Long> idList = new ArrayList<>(ids);
+
+        // 2. 构造更新条件
         LambdaUpdateWrapper<OrderMain> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.in(OrderMain::getId, ids)
-            .eq(OrderMain::getOrderStatus, OrderStatus.SHIPPED.getCode()) // 只有已发货的订单才能确认收货
-            .set(OrderMain::getOrderStatus, OrderStatus.COMPLETED.getCode());
 
-        // 执行更新
-        boolean updateSuccess = this.update(updateWrapper);
+        // 设置更新后的值
+        updateWrapper.set(OrderMain::getOrderStatus, OrderStatus.COMPLETED.getCode());
+
+        // 构建 WHERE 条件逻辑:
+        // (id IN (...) OR parentOrderId IN (...)) AND orderStatus = SHIPPED
+        updateWrapper.and(wrapper -> wrapper
+                .in(OrderMain::getId, idList)
+                .or()
+                .in(OrderMain::getParentOrderId, idList)
+            )
+            // 只有已发货的订单才能确认收货 (同时限制父单和子单的原状态)
+            .eq(OrderMain::getOrderStatus, OrderStatus.SHIPPED.getCode());
+
+        // 3. 执行更新
+        // 如果至少有一行被更新,则视为成功
+        int updateCount = baseMapper.update(updateWrapper);
 
-        return updateSuccess;
+        return updateCount > 0;
     }
 
     @Override