Bläddra i källkod

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

肖路 1 månad sedan
förälder
incheckning
5627d00975

+ 4 - 2
ruoyi-api/ruoyi-api-customer/src/main/java/org/dromara/customer/api/RemoteCustomerService.java

@@ -24,6 +24,8 @@ public interface RemoteCustomerService {
      */
     Long selectCustomerIdByUserId(Long userId);
 
+    CustomerInfoDTO selectCustomerInfoById(Long customerId);
+
     /**
     * 根据userId查询联系人id
     * */
@@ -37,8 +39,8 @@ public interface RemoteCustomerService {
     /**
      * 新增收货人
      */
-    CustomerInfoDTO addReceiver(String name , String email);
+    CustomerInfoDTO addReceiver(String name, String email);
 
-    CustomerAddressDTO addReceiverAddress(String provinceId, String cityId, String countyId, String address , String mobile);
+    CustomerAddressDTO addReceiverAddress(String provinceId, String cityId, String countyId, String address, String mobile);
 
 }

+ 7 - 0
ruoyi-api/ruoyi-api-customer/src/main/java/org/dromara/customer/api/domain/dto/CustomerInfoDTO.java

@@ -13,4 +13,11 @@ public class CustomerInfoDTO implements Serializable {
     private Long id;
 
     private String customerName;
+
+    /**
+     * 状态(0已审核 待审核)
+     */
+    private String status;
+
+
 }

+ 9 - 3
ruoyi-auth/src/main/java/org/dromara/auth/service/impl/PasswordAuthStrategy.java

@@ -17,6 +17,7 @@ import org.dromara.common.core.constant.Constants;
 import org.dromara.common.core.constant.GlobalConstants;
 import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.enums.LoginType;
+import org.dromara.common.core.enums.SysPlatformYesNo;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.exception.user.CaptchaException;
 import org.dromara.common.core.exception.user.CaptchaExpireException;
@@ -28,6 +29,7 @@ import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.tenant.helper.TenantHelper;
 import org.dromara.customer.api.RemoteCustomerService;
+import org.dromara.customer.api.domain.dto.CustomerInfoDTO;
 import org.dromara.system.api.RemoteClientService;
 import org.dromara.system.api.RemoteUserService;
 import org.dromara.system.api.domain.vo.RemoteClientVo;
@@ -128,9 +130,13 @@ public class PasswordAuthStrategy implements IAuthStrategy {
         });
         //获取客户信息
         Long customerId = remoteCustomerService.selectCustomerIdByUserId(loginUser.getUserId());
-        if (Objects.isNull(customerId)){
+        if (Objects.isNull(customerId)) {
             throw new ServiceException("不存在该账号");
         }
+        CustomerInfoDTO customerInfoDTO = remoteCustomerService.selectCustomerInfoById(customerId);
+        if (null != customerInfoDTO && "0".equals(customerInfoDTO.getStatus())) {
+            throw new ServiceException("该企业当前未审核,请审核后再登录");
+        }
         loginUser.setClientKey(client.getClientKey());
         loginUser.setDeviceType(client.getDeviceType());
         loginUser.setCustomerId(customerId);
@@ -181,13 +187,13 @@ public class PasswordAuthStrategy implements IAuthStrategy {
             loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
             return user;
         });
-        if(ObjectUtil.isEmpty(loginUser)){
+        if (ObjectUtil.isEmpty(loginUser)) {
             loginVo.setCode(5004);
             loginVo.setMsg("用户名或密码错误");
             return loginVo;
         }
         RemoteClientVo client = remoteClientService.queryByClientId("e5cd7e4891bf95d1d19206ce24a7b32e");
-        if(ObjectUtil.isEmpty(client)){
+        if (ObjectUtil.isEmpty(client)) {
             return null;
         }
         loginUser.setClientKey(client.getClientKey());

+ 8 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/dubbo/RemoteCustomerServiceImpl.java

@@ -1,6 +1,8 @@
 package org.dromara.customer.dubbo;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -112,6 +114,12 @@ public class RemoteCustomerServiceImpl implements RemoteCustomerService {
         return "";
     }
 
+    @Override
+    public CustomerInfoDTO selectCustomerInfoById(Long customerId) {
+        CustomerInfo customerInfo = customerInfoService.getById(customerId);
+        return BeanUtil.toBean(customerInfo, CustomerInfoDTO.class);
+    }
+
     @Override
     public CustomerInfoDTO addReceiver(String name, String email) {
         CustomerInfo customerInfo = new CustomerInfo();

+ 17 - 5
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/pc/PcOrderController.java

@@ -9,10 +9,13 @@ import org.apache.dubbo.config.annotation.DubboReference;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.enums.OrderSourceEnum;
 import org.dromara.common.core.enums.OrderStatus;
+import org.dromara.common.core.enums.SysPlatformYesNo;
+import org.dromara.common.core.exception.ServiceException;
 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.redis.utils.SequenceUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.web.core.BaseController;
 import org.dromara.customer.api.RemoteCustomerService;
@@ -35,10 +38,12 @@ import org.dromara.product.api.RemoteProductService;
 import org.dromara.product.api.RemoteProductShoppingCartService;
 import org.dromara.product.api.domain.ProductVo;
 import org.dromara.product.api.domain.RemoteProductShoppingCartVo;
+import org.springframework.dao.DuplicateKeyException;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.math.BigDecimal;
+import java.time.Duration;
 import java.time.LocalDate;
 import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
@@ -89,6 +94,7 @@ public class PcOrderController extends BaseController {
         Long customerId = LoginHelper.getLoginUser().getCustomerId();
         // 强制设置企业ID,防止越权访问
         bo.setCustomerId(customerId);
+        bo.setIsSplitChild(SysPlatformYesNo.NO.getCode());
 
         return orderMainService.queryPageList(bo, pageQuery);
     }
@@ -101,8 +107,8 @@ public class PcOrderController extends BaseController {
     }
 
     /**
-    * 查询当前用户能审核的订单id
-    * */
+     * 查询当前用户能审核的订单id
+     */
     @GetMapping("/getCheckOrderIds")
     public R<List<Long>> getCheckOrderIds() {
         Long contactId = remoteCustomerService.selectContactIdByUserId(LoginHelper.getUserId());
@@ -121,8 +127,8 @@ public class PcOrderController extends BaseController {
     }
 
     /**
-    * 查询当前订单的流程节点列表
-    * */
+     * 查询当前订单的流程节点列表
+     */
     @GetMapping("/getOrderFlowNodes/{orderId}")
     public R<List<OrderCustomerFlowNodeLink>> getOrderFlowNodes(@PathVariable("orderId") Long orderId) {
         return R.ok(orderCustomerFlowNodeLinkService.list(
@@ -385,8 +391,14 @@ public class PcOrderController extends BaseController {
                     orderProductBo.setProductName(productVo.getItemName());
                     orderProductBo.setProductUnitId(Long.valueOf(productVo.getUnitId()));
                     orderProductBo.setProductUnit(productVo.getUnitName());
-                    orderProductBo.setProductImage(productVo.getProductImageUrl());
+                    orderProductBo.setProductImage(productVo.getProductImage());
                     orderProductBo.setOrderPrice(productVo.getMemberPrice());
+                    orderProductBo.setMarketPrice(productVo.getMarketPrice());
+                    orderProductBo.setTaxRate(productVo.getTaxRate());
+                    orderProductBo.setCategoryName(productVo.getCategoryName());
+                    orderProductBo.setPurchasingPrice(productVo.getPurchasingPrice());
+                    orderProductBo.setMinOrderQuantity(productVo.getMinOrderQuantity());
+                    orderProductBo.setMinSellingPrice(productVo.getMinSellingPrice());
                     orderProductBo.setOrderQuantity(quantity);
                     orderProductBo.setSubtotal(productVo.getMemberPrice().multiply(BigDecimal.valueOf(quantity)));
                     return orderProductBo;

+ 2 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderProduct.java

@@ -84,6 +84,8 @@ public class OrderProduct extends TenantEntity {
      */
     private String productImage;
 
+    private String categoryName;
+
     /**
      * 平台价格(元)
      */

+ 2 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderProductBo.java

@@ -83,6 +83,8 @@ public class OrderProductBo extends BaseEntity {
      */
     private String productImage;
 
+    private String categoryName;
+
     /**
      * 平台价格(元)
      */

+ 2 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderProductVo.java

@@ -65,6 +65,8 @@ public class OrderProductVo implements Serializable {
     @ExcelProperty(value = "发货单编号")
     private String shipmentNo;
 
+    private String categoryName;
+
     /**
      * 产品ID
      */

+ 23 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderDeliverServiceImpl.java

@@ -219,12 +219,35 @@ public class OrderDeliverServiceImpl extends ServiceImpl<OrderDeliverMapper, Ord
             saveOrderDeliverProducts(deliver.getId(), bo.getOrderDeliverProducts(), false);
 
             // 9. 更新订单主表状态
+
+
+            OrderMain currentOrder = orderMainMapper.selectById(orderId);
+
+            if (currentOrder == null) {
+                throw new RuntimeException("订单不存在");
+            }
+
+            // 2. 更新当前订单状态
             LambdaUpdateWrapper<OrderMain> updateWrapper = new LambdaUpdateWrapper<OrderMain>()
                 .eq(OrderMain::getId, orderId)
                 .set(OrderMain::getOrderStatus, newStatus);
 
             orderMainMapper.update(null, updateWrapper);
 
+            // 3. 【新增逻辑】如果存在父订单,同步更新父订单状态
+            if (currentOrder.getParentOrderId() != null) {
+                // “同步更新”处理,即直接设为相同状态。
+
+                LambdaUpdateWrapper<OrderMain> parentUpdateWrapper = new LambdaUpdateWrapper<OrderMain>()
+                    .eq(OrderMain::getId, currentOrder.getParentOrderId())
+                    .set(OrderMain::getOrderStatus, newStatus);
+
+                orderMainMapper.update(null, parentUpdateWrapper);
+
+                // 可选:如果需要递归更新更上层的父订单(如果存在多级嵌套),可以在此处加循环或递归调用
+            }
+
+
             log.info("新增订单发货单成功:{}", bo.getId());
             return true;
         } catch (RuntimeException e) {

+ 91 - 31
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderMainServiceImpl.java

@@ -45,10 +45,13 @@ import org.dromara.order.utils.kd100.domain.TrackVO;
 import org.dromara.system.api.RemoteComLogisticsCompanyService;
 import org.dromara.system.api.RemoteDeptService;
 import org.dromara.system.api.RemoteUserService;
+import org.mybatis.spring.MyBatisSystemException;
+import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
+import java.sql.SQLIntegrityConstraintViolationException;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -217,7 +220,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<OrderMain> lqw = Wrappers.lambdaQuery();
         lqw.orderByDesc(OrderMain::getId);
-        lqw.eq(StringUtils.isNotBlank(bo.getOrderNo()), OrderMain::getOrderNo, bo.getOrderNo());
+        lqw.like(StringUtils.isNotBlank(bo.getOrderNo()), OrderMain::getOrderNo, bo.getOrderNo());
         lqw.eq(StringUtils.isNotBlank(bo.getCustomerCode()), OrderMain::getCustomerCode, bo.getCustomerCode());
         lqw.eq(StringUtils.isNotBlank(bo.getShipmentNo()), OrderMain::getShipmentNo, bo.getShipmentNo());
         lqw.eq(StringUtils.isNotBlank(bo.getSubOrderNo()), OrderMain::getSubOrderNo, bo.getSubOrderNo());
@@ -307,47 +310,104 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
             // 应付总额 = 商品总价 + 运费
             BigDecimal payableAmount = totalAmount.add(bo.getShippingFee());
 
-            // 2. 生成订单号并转换主单
-            String orderNo = SequenceUtils.generateOrderCode("RS");
-            bo.setOrderNo(orderNo);
+            // 2. 生成订单号并转换主单 (带防重兜底)
+            String orderNo = null;
+            OrderMain orderMain = null;
+            boolean mainSaved = false;
+
+            // 最大重试次数,防止死循环
+            int maxRetries = 5;
+            int retryCount = 0;
+
+            while (!mainSaved && retryCount < maxRetries) {
+                try {
+                    retryCount++;
+
+                    // --- 步骤 A: 生成订单号 ---
+                    orderNo = SequenceUtils.generateOrderCode("RS");
+                    bo.setOrderNo(orderNo);
+
+                    bo.setProductQuantity(productQuantity);
+                    bo.setTotalAmount(totalAmount);
+                    bo.setPayableAmount(payableAmount);
+
+                    // --- 步骤 B: 处理下单时间 ---
+                    Date orderTimeToUse;
+                    if (bo.getOrderTime() != null) {
+                        Calendar cal = Calendar.getInstance();
+                        cal.setTime(bo.getOrderTime());
+                        Calendar now = Calendar.getInstance();
+                        cal.set(Calendar.HOUR_OF_DAY, now.get(Calendar.HOUR_OF_DAY));
+                        cal.set(Calendar.MINUTE, now.get(Calendar.MINUTE));
+                        cal.set(Calendar.SECOND, now.get(Calendar.SECOND));
+                        cal.set(Calendar.MILLISECOND, now.get(Calendar.MILLISECOND));
+                        orderTimeToUse = cal.getTime();
+                    } else {
+                        orderTimeToUse = new Date();
+                    }
+                    bo.setOrderTime(orderTimeToUse);
 
-            bo.setProductQuantity(productQuantity);
+                    // --- 步骤 C: 转换对象 ---
+                    orderMain = MapstructUtils.convert(bo, OrderMain.class);
+                    validEntityBeforeSave(orderMain);
 
-            bo.setTotalAmount(totalAmount);
+                    // --- 步骤 D: 尝试插入 (关键兜底点) ---
+                    int insertResult = baseMapper.insert(orderMain);
 
-            bo.setPayableAmount(payableAmount);
+                    if (insertResult > 0) {
+                        mainSaved = true;
+                    } else {
+                        // 如果返回 0 但不是因为异常(极少见),也视为失败进行重试
+                        throw new RuntimeException("主订单保存返回影响行数为0");
+                    }
 
-            // 处理下单时间:前台不传则用当前时间,后台传了则按规则调整
-            Date orderTimeToUse;
-            if (bo.getOrderTime() != null) {
-                // 后台传了时间:保留日期,更新时分秒为当前
-                Calendar cal = Calendar.getInstance();
-                cal.setTime(bo.getOrderTime());
-                Calendar now = Calendar.getInstance();
-                cal.set(Calendar.HOUR_OF_DAY, now.get(Calendar.HOUR_OF_DAY));
-                cal.set(Calendar.MINUTE, now.get(Calendar.MINUTE));
-                cal.set(Calendar.SECOND, now.get(Calendar.SECOND));
-                cal.set(Calendar.MILLISECOND, now.get(Calendar.MILLISECOND));
-                orderTimeToUse = cal.getTime();
-            } else {
-                // 前台未传:直接使用当前时间
-                orderTimeToUse = new Date();
-            }
-            bo.setOrderTime(orderTimeToUse);
+                } catch (Exception e) {
+                    // 判断是否为唯一索引冲突异常
+                    boolean isDuplicate = false;
 
+                    // 1. Spring 的 DuplicateKeyException
+                    if (e instanceof DuplicateKeyException) {
+                        isDuplicate = true;
+                    }
+                    // 2. MyBatis 包装的异常,需要解包查看 cause
+                    else if (e instanceof MyBatisSystemException) {
+                        Throwable cause = e.getCause();
+                        if (cause instanceof SQLIntegrityConstraintViolationException) {
+                            isDuplicate = true;
+                        }
+                        // 某些驱动直接报这个
+                        else if (cause != null && cause.getMessage() != null && cause.getMessage().contains("Duplicate entry")) {
+                            isDuplicate = true;
+                        }
+                    }
+                    // 3. 直接捕获 SQL 异常 (视具体驱动而定)
+                    else if (e instanceof java.sql.SQLException) {
+                        if (e.getMessage() != null && e.getMessage().contains("Duplicate entry")) {
+                            isDuplicate = true;
+                        }
+                    }
 
-            // 转换主订单
-            OrderMain orderMain = MapstructUtils.convert(bo, OrderMain.class);
-            validEntityBeforeSave(orderMain);
+                    if (isDuplicate) {
+                        // 如果是重复,记录日志(可选),然后继续 while 循环重新生成
+                        continue;
+                    } else {
+                        // 如果是其他异常(如数据库连接断开、字段非空校验失败等),直接抛出,不重试
+                        throw new RuntimeException("创建主订单失败: " + e.getMessage(), e);
+                    }
+                }
+            }
 
-            // 3. 插入主订单
-            boolean mainSaved = baseMapper.insert(orderMain) > 0;
             if (!mainSaved) {
-                throw new RuntimeException("主订单保存失败");
+                // 超过最大重试次数仍未成功
+                throw new RuntimeException("生成订单号失败,多次尝试均发生重复,请检查序列生成器或数据库状态");
             }
 
+            // 此时 orderMain 已成功入库,且 ID 已回填 (如果使用了自增或雪花算法回填)
             Long orderId = orderMain.getId();
 
+            String orderNum = orderMain.getOrderNo();
+
+
             // 4. 转换并填充子订单商品
             List<OrderProduct> orderProducts = orderProductBos.stream()
                 .map(productBo -> {
@@ -364,7 +424,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
 
                     OrderProduct product = MapstructUtils.convert(productBo, OrderProduct.class);
                     product.setOrderId(orderId);
-                    product.setOrderNo(orderNo);
+                    product.setOrderNo(orderNum);
 
                     // 小计 = 单价 × 数量
                     BigDecimal subtotal = unitPrice.multiply(BigDecimal.valueOf(quantity));

+ 1 - 0
ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderProductMapper.xml

@@ -14,6 +14,7 @@
                op.product_name                                       AS productName,
                op.product_unit                                       AS productUnit,
                op.product_image                                      AS productImage,
+               op.category_name                                      AS categoryName,
                op.platform_price                                     AS platformPrice,
                op.min_order_quantity                                 AS minOrderQuantity,
                op.order_price                                        AS orderPrice,