|
|
@@ -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));
|