|
@@ -35,7 +35,9 @@ import org.dromara.system.api.RemoteUserService;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
|
|
+import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -239,7 +241,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
|
|
|
*/
|
|
*/
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
@Override
|
|
@Override
|
|
|
- public Boolean insertByBo(OrderMainBo bo) {
|
|
|
|
|
|
|
+ public Long insertByBo(OrderMainBo bo) {
|
|
|
try {
|
|
try {
|
|
|
// 1. 校验商品列表
|
|
// 1. 校验商品列表
|
|
|
List<OrderProductBo> orderProductBos = bo.getOrderProductBos();
|
|
List<OrderProductBo> orderProductBos = bo.getOrderProductBos();
|
|
@@ -254,26 +256,40 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ BigDecimal totalAmount = orderProductBos.stream().map(OrderProductBo::getSubtotal).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
|
|
|
|
|
+
|
|
|
|
|
+ // 应付总额 = 商品总价 + 运费
|
|
|
|
|
+ BigDecimal payableAmount = totalAmount.add(bo.getShippingFee());
|
|
|
|
|
+
|
|
|
// 2. 生成订单号并转换主单
|
|
// 2. 生成订单号并转换主单
|
|
|
String orderNo = SequenceUtils.generateOrderCode("RS");
|
|
String orderNo = SequenceUtils.generateOrderCode("RS");
|
|
|
bo.setOrderNo(orderNo);
|
|
bo.setOrderNo(orderNo);
|
|
|
- Date originalDate = bo.getOrderTime(); // 假设是 2025-01-06 00:00:00
|
|
|
|
|
- if (originalDate != null) {
|
|
|
|
|
- Calendar calOriginal = Calendar.getInstance();
|
|
|
|
|
- calOriginal.setTime(originalDate);
|
|
|
|
|
|
|
|
|
|
- Calendar calNow = Calendar.getInstance(); // 获取当前时分秒
|
|
|
|
|
|
|
+ bo.setTotalAmount(totalAmount);
|
|
|
|
|
+
|
|
|
|
|
+ bo.setPayableAmount(payableAmount);
|
|
|
|
|
+
|
|
|
|
|
+ // 处理下单时间:前台不传则用当前时间,后台传了则按规则调整
|
|
|
|
|
+ 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);
|
|
|
|
|
|
|
|
- // 保留原日期的年月日,替换时分秒为当前时间
|
|
|
|
|
- calOriginal.set(Calendar.HOUR_OF_DAY, calNow.get(Calendar.HOUR_OF_DAY));
|
|
|
|
|
- calOriginal.set(Calendar.MINUTE, calNow.get(Calendar.MINUTE));
|
|
|
|
|
- calOriginal.set(Calendar.SECOND, calNow.get(Calendar.SECOND));
|
|
|
|
|
- calOriginal.set(Calendar.MILLISECOND, calNow.get(Calendar.MILLISECOND));
|
|
|
|
|
|
|
|
|
|
- bo.setOrderTime(calOriginal.getTime());
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 转换主订单
|
|
|
OrderMain orderMain = MapstructUtils.convert(bo, OrderMain.class);
|
|
OrderMain orderMain = MapstructUtils.convert(bo, OrderMain.class);
|
|
|
-
|
|
|
|
|
validEntityBeforeSave(orderMain);
|
|
validEntityBeforeSave(orderMain);
|
|
|
|
|
|
|
|
// 3. 插入主订单
|
|
// 3. 插入主订单
|
|
@@ -282,8 +298,9 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
|
|
|
throw new RuntimeException("主订单保存失败");
|
|
throw new RuntimeException("主订单保存失败");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 4. 转换并填充子订单商品
|
|
|
|
|
Long orderId = orderMain.getId();
|
|
Long orderId = orderMain.getId();
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 转换并填充子订单商品
|
|
|
List<OrderProduct> orderProducts = orderProductBos.stream()
|
|
List<OrderProduct> orderProducts = orderProductBos.stream()
|
|
|
.map(productBo -> {
|
|
.map(productBo -> {
|
|
|
OrderProduct product = MapstructUtils.convert(productBo, OrderProduct.class);
|
|
OrderProduct product = MapstructUtils.convert(productBo, OrderProduct.class);
|
|
@@ -294,10 +311,10 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
|
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
|
// 5. 批量插入订单商品
|
|
// 5. 批量插入订单商品
|
|
|
- boolean productsSaved = orderProductMapper.insertBatch(orderProducts);
|
|
|
|
|
|
|
+ orderProductMapper.insertBatch(orderProducts);
|
|
|
|
|
|
|
|
log.info("成功新增订单,ID: {}", orderId);
|
|
log.info("成功新增订单,ID: {}", orderId);
|
|
|
- return productsSaved;
|
|
|
|
|
|
|
+ return orderId;
|
|
|
} catch (RuntimeException e) {
|
|
} catch (RuntimeException e) {
|
|
|
log.error("新增订单失败: {}", e.getMessage(), e);
|
|
log.error("新增订单失败: {}", e.getMessage(), e);
|
|
|
throw new RuntimeException("新增订单失败: " + e.getMessage());
|
|
throw new RuntimeException("新增订单失败: " + e.getMessage());
|
|
@@ -324,6 +341,107 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 订单确认
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param
|
|
|
|
|
+ * @return 是否确认成功
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void confirmOrder(Long orderId, List<OrderProductBo> updatedProducts) {
|
|
|
|
|
+ if (orderId == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("订单ID不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 查询现有主订单(加锁防止并发修改)
|
|
|
|
|
+ OrderMain existingOrder = baseMapper.selectOne(new LambdaQueryWrapper<OrderMain>()
|
|
|
|
|
+ .eq(OrderMain::getId, orderId)
|
|
|
|
|
+ .last("FOR UPDATE"));
|
|
|
|
|
+ if (existingOrder == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("订单不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 检查当前状态:只允许从“待确认”(比如状态0或1)变为“待发货”(2)
|
|
|
|
|
+ if (!OrderStatus.PENDING_PAYMENT.getCode().equals(existingOrder.getOrderStatus()) && !OrderStatus.PENDING_CONFIRMATION.getCode().equals(existingOrder.getOrderStatus())) {
|
|
|
|
|
+ throw new IllegalStateException("订单状态不可确认,当前状态:" + existingOrder.getOrderStatus());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 查询现有子订单商品(按 orderId)
|
|
|
|
|
+ List<OrderProduct> existingProducts = orderProductMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<OrderProduct>().eq(OrderProduct::getOrderId, orderId)
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (CollUtil.isEmpty(existingProducts)) {
|
|
|
|
|
+ throw new IllegalStateException("订单商品不存在,无法确认");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 构建商品ID -> 现有商品的映射
|
|
|
|
|
+ Map<Long, OrderProduct> existingProductMap = existingProducts.stream()
|
|
|
|
|
+ .collect(Collectors.toMap(OrderProduct::getId, Function.identity()));
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 校验传入的商品列表是否匹配(不能增删商品,只能改数量)
|
|
|
|
|
+ if (CollUtil.isEmpty(updatedProducts)) {
|
|
|
|
|
+ throw new IllegalArgumentException("确认订单时商品列表不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (updatedProducts.size() != existingProducts.size()) {
|
|
|
|
|
+ throw new IllegalArgumentException("商品数量不一致,不允许增删商品项");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 6. 遍历更新项,仅允许修改数量,并校验ID存在
|
|
|
|
|
+ List<OrderProduct> toUpdateProducts = new ArrayList<>();
|
|
|
|
|
+ BigDecimal newTotalAmount = BigDecimal.ZERO;
|
|
|
|
|
+
|
|
|
|
|
+ for (OrderProductBo bo : updatedProducts) {
|
|
|
|
|
+ if (bo.getId() == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("商品项必须包含ID(用于匹配原订单商品)");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ OrderProduct existing = existingProductMap.get(bo.getId());
|
|
|
|
|
+ if (existing == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("商品ID " + bo.getId() + " 不属于该订单");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 仅允许修改数量(可选),其他字段如 price、skuCode 等必须保持一致
|
|
|
|
|
+ Long newQty = bo.getOrderQuantity();
|
|
|
|
|
+ if (newQty == null || newQty <= 0) {
|
|
|
|
|
+ throw new IllegalArgumentException("商品数量必须大于0");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 重新计算小计:注意使用原单价 * 新数量(防止前端篡改价格)
|
|
|
|
|
+ BigDecimal unitPrice = existing.getOrderPrice(); // 使用数据库中的原始单价
|
|
|
|
|
+ BigDecimal newSubtotal = unitPrice.multiply(BigDecimal.valueOf(newQty));
|
|
|
|
|
+
|
|
|
|
|
+ // 更新对象(仅数量和小计)
|
|
|
|
|
+ existing.setOrderQuantity(newQty);
|
|
|
|
|
+ existing.setSubtotal(newSubtotal);
|
|
|
|
|
+
|
|
|
|
|
+ toUpdateProducts.add(existing);
|
|
|
|
|
+ newTotalAmount = newTotalAmount.add(newSubtotal);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 7. 重新计算应付金额(运费不变)
|
|
|
|
|
+ BigDecimal newPayableAmount = newTotalAmount.add(existingOrder.getShippingFee());
|
|
|
|
|
+
|
|
|
|
|
+ // 8. 更新主订单:仅更新 totalAmount、payableAmount 和 orderStatus
|
|
|
|
|
+ existingOrder.setTotalAmount(newTotalAmount);
|
|
|
|
|
+ existingOrder.setPayableAmount(newPayableAmount);
|
|
|
|
|
+ existingOrder.setOrderStatus(OrderStatus.PENDING_SHIPMENT.getCode()); // 待发货
|
|
|
|
|
+
|
|
|
|
|
+ // 9. 执行更新
|
|
|
|
|
+ int mainUpdated = baseMapper.updateById(existingOrder);
|
|
|
|
|
+ if (mainUpdated <= 0) {
|
|
|
|
|
+ throw new RuntimeException("主订单确认失败");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 10. 批量更新子订单商品
|
|
|
|
|
+ orderProductMapper.updateBatchById(toUpdateProducts);
|
|
|
|
|
+
|
|
|
|
|
+ log.info("订单 {} 已确认,状态更新为待发货", orderId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 修改状态
|
|
* 修改状态
|
|
|
*
|
|
*
|