|
|
@ -26,10 +26,8 @@ import org.springframework.transaction.annotation.Transactional; |
|
|
|
|
|
|
|
|
import java.math.BigDecimal; |
|
|
import java.math.BigDecimal; |
|
|
import java.math.RoundingMode; |
|
|
import java.math.RoundingMode; |
|
|
import java.util.ArrayList; |
|
|
import java.util.*; |
|
|
import java.util.Calendar; |
|
|
import java.util.stream.Collectors; |
|
|
import java.util.Date; |
|
|
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 核心订单 Service 实现 |
|
|
* 核心订单 Service 实现 |
|
|
@ -235,7 +233,12 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// 创建团长订单(初始状态:待支付)
|
|
|
// 创建团长订单(初始状态:待支付)
|
|
|
MallOrder order = buildBaseOrder(dto, ORDER_TYPE_GROUP, goodsAmount, deliveryFee, packageFee); |
|
|
Integer orderType = ORDER_TYPE_GROUP; |
|
|
|
|
|
if(isFace2Face){ |
|
|
|
|
|
//面对面拼团
|
|
|
|
|
|
orderType = 3; |
|
|
|
|
|
} |
|
|
|
|
|
MallOrder order = buildBaseOrder(dto, orderType, goodsAmount, deliveryFee, packageFee); |
|
|
order.setStatus(STATUS_WAIT_PAY); |
|
|
order.setStatus(STATUS_WAIT_PAY); |
|
|
order.setRegionId(dto.getRegionId()); |
|
|
order.setRegionId(dto.getRegionId()); |
|
|
this.save(order); |
|
|
this.save(order); |
|
|
@ -341,7 +344,9 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// 创建参团人订单(初始状态:待支付)
|
|
|
// 创建参团人订单(初始状态:待支付)
|
|
|
MallOrder order = buildBaseOrder(dto, ORDER_TYPE_GROUP, goodsAmount, deliveryFee, packageFee); |
|
|
//区分普通拼团和面对面拼团
|
|
|
|
|
|
Integer orderType = isFace2Face ? 3 : ORDER_TYPE_GROUP; |
|
|
|
|
|
MallOrder order = buildBaseOrder(dto, orderType, goodsAmount, deliveryFee, packageFee); |
|
|
order.setStatus(STATUS_WAIT_PAY); |
|
|
order.setStatus(STATUS_WAIT_PAY); |
|
|
order.setRegionId(dto.getRegionId()); |
|
|
order.setRegionId(dto.getRegionId()); |
|
|
this.save(order); |
|
|
this.save(order); |
|
|
@ -470,19 +475,298 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder |
|
|
MallOrder order = getById(orderId); |
|
|
MallOrder order = getById(orderId); |
|
|
if (order == null) throw new RuntimeException("订单不存在"); |
|
|
if (order == null) throw new RuntimeException("订单不存在"); |
|
|
if (!userId.equals(order.getUserId())) throw new RuntimeException("无权操作该订单"); |
|
|
if (!userId.equals(order.getUserId())) throw new RuntimeException("无权操作该订单"); |
|
|
if (order.getStatus() != STATUS_WAIT_PAY && order.getStatus() != STATUS_WAIT_GROUP) { |
|
|
|
|
|
throw new RuntimeException("当前订单状态不允许取消"); |
|
|
// 已取消/已退款/待商家同意退款 不可重复操作
|
|
|
|
|
|
if (order.getStatus() == STATUS_CANCELLED || order.getStatus() == STATUS_REFUNDED |
|
|
|
|
|
|| order.getStatus() == STATUS_WAIT_REFUND) { |
|
|
|
|
|
throw new RuntimeException("订单当前状态不可取消"); |
|
|
} |
|
|
} |
|
|
updateOrderStatus(orderId, STATUS_CANCELLED); |
|
|
|
|
|
// 先取消相关的配送单
|
|
|
// 拼团 / 面对面团
|
|
|
LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>(); |
|
|
if (order.getOrderType() == ORDER_TYPE_GROUP || order.getOrderType() == 3) { |
|
|
duw.eq(MallDeliveryOrder::getOrderId, orderId) |
|
|
handleGroupCancel(order); |
|
|
.in(MallDeliveryOrder::getStatus, java.util.Arrays.asList(-1, 0)) |
|
|
} else { |
|
|
.set(MallDeliveryOrder::getStatus, 4); |
|
|
// 直接购买
|
|
|
mallDeliveryOrderMapper.update(null, duw); |
|
|
handleDirectCancel(order); |
|
|
// 若已支付(待成团状态),生成退款记录
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ================================================================
|
|
|
|
|
|
// 拼团取消逻辑
|
|
|
|
|
|
// ================================================================
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 拼团取消总调度:判断团长/团员后分流 |
|
|
|
|
|
*/ |
|
|
|
|
|
private void handleGroupCancel(MallOrder order) { |
|
|
|
|
|
MallOrderGroup group = findGroupByOrderId(order.getId()); |
|
|
|
|
|
if (group == null) throw new RuntimeException("拼团信息不存在"); |
|
|
|
|
|
|
|
|
|
|
|
boolean isHead = order.getId().equals(group.getHeadOrderId()); |
|
|
|
|
|
if (isHead) { |
|
|
|
|
|
handleGroupHeadCancel(order, group); |
|
|
|
|
|
} else { |
|
|
|
|
|
handleGroupMemberCancel(order, group); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 团长取消订单 |
|
|
|
|
|
*/ |
|
|
|
|
|
private void handleGroupHeadCancel(MallOrder order, MallOrderGroup group) { |
|
|
|
|
|
boolean isFace2Face = (order.getOrderType() == 3); |
|
|
|
|
|
|
|
|
|
|
|
// ---- 1. 未支付 ----
|
|
|
|
|
|
if (order.getStatus() == STATUS_WAIT_PAY) { |
|
|
|
|
|
updateOrderStatus(order.getId(), STATUS_CANCELLED); |
|
|
|
|
|
//cancelDeliveryOrderByOrderId(order.getId());
|
|
|
|
|
|
//String remainingIds = removeOrderIdStr(group.getGroupOrderIds(), order.getId());
|
|
|
|
|
|
|
|
|
|
|
|
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>(); |
|
|
|
|
|
guw.eq(MallOrderGroup::getId, group.getId()) |
|
|
|
|
|
.set(MallOrderGroup::getStatus, GROUP_STATUS_FAIL) |
|
|
|
|
|
.set(MallOrderGroup::getGroupOrderIds, ""); |
|
|
|
|
|
mallOrderGroupMapper.update(null, guw); |
|
|
|
|
|
|
|
|
|
|
|
/*if (StringUtils.isBlank(remainingIds)) { |
|
|
|
|
|
// 没有其他人,取消整个团
|
|
|
|
|
|
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>(); |
|
|
|
|
|
guw.eq(MallOrderGroup::getId, group.getId()) |
|
|
|
|
|
.set(MallOrderGroup::getStatus, GROUP_STATUS_FAIL) |
|
|
|
|
|
.set(MallOrderGroup::getGroupOrderIds, ""); |
|
|
|
|
|
mallOrderGroupMapper.update(null, guw); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 有其他人(虽未支付),转让团长
|
|
|
|
|
|
transferGroupHead(group, order.getId(), remainingIds, false); |
|
|
|
|
|
}*/ |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ---- 2. 已支付 待成团 ----
|
|
|
|
|
|
if (order.getStatus() == STATUS_WAIT_GROUP) { |
|
|
|
|
|
if (group.getCurrentMembers() <= 1) { |
|
|
|
|
|
// 2.1 仅自己
|
|
|
|
|
|
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>(); |
|
|
|
|
|
guw.eq(MallOrderGroup::getId, group.getId()) |
|
|
|
|
|
.set(MallOrderGroup::getStatus, GROUP_STATUS_FAIL) |
|
|
|
|
|
.set(MallOrderGroup::getCurrentMembers, 0); |
|
|
|
|
|
mallOrderGroupMapper.update(null, guw); |
|
|
|
|
|
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){ |
|
|
|
|
|
cancelDeliveryOrderByOrderId(order.getId()); |
|
|
|
|
|
} |
|
|
|
|
|
autoRefund(order, "团长取消拼团,系统退款"); |
|
|
|
|
|
restoreStock(order.getId()); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 2.2 有其他已支付的团员
|
|
|
|
|
|
autoRefund(order, "团长取消拼团,系统退款"); |
|
|
|
|
|
restoreStock(order.getId()); |
|
|
|
|
|
String remainingIds = removeOrderIdStr(group.getGroupOrderIds(), order.getId()); |
|
|
|
|
|
// 面对面团 + 配送:直接取消所有参团人员的订单,并且根据团长orderId取消配送单,设置拼团订单失效
|
|
|
|
|
|
if (isFace2Face && order.getDeliveryType() != null |
|
|
|
|
|
&& order.getDeliveryType() == DELIVERY_TYPE_EXPRESS) { |
|
|
|
|
|
// 取消所有参团人员的订单并退款
|
|
|
|
|
|
if (StringUtils.isNotBlank(remainingIds)) { |
|
|
|
|
|
List<String> memberOrderIds = Arrays.stream(remainingIds.split(",")) |
|
|
|
|
|
.map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList()); |
|
|
|
|
|
for (String memberOrderId : memberOrderIds) { |
|
|
|
|
|
MallOrder memberOrder = getById(memberOrderId); |
|
|
|
|
|
if (memberOrder != null && memberOrder.getStatus() != STATUS_CANCELLED |
|
|
|
|
|
&& memberOrder.getStatus() != STATUS_REFUNDED) { |
|
|
|
|
|
autoRefund(memberOrder, "面对面团团长取消拼团,系统退款"); |
|
|
|
|
|
restoreStock(memberOrderId); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// 取消配送单
|
|
|
|
|
|
cancelDeliveryOrderByOrderId(order.getId()); |
|
|
|
|
|
|
|
|
|
|
|
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>(); |
|
|
|
|
|
guw.eq(MallOrderGroup::getId, group.getId()) |
|
|
|
|
|
.set(MallOrderGroup::getStatus, GROUP_STATUS_FAIL) |
|
|
|
|
|
.set(MallOrderGroup::getGroupOrderIds, ""); |
|
|
|
|
|
mallOrderGroupMapper.update(null, guw); |
|
|
|
|
|
return; |
|
|
|
|
|
}else{ |
|
|
|
|
|
// 普通拼团:取消团长自己的配送单
|
|
|
|
|
|
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){ |
|
|
|
|
|
cancelDeliveryOrderByOrderId(order.getId()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
transferGroupHead(group, order.getId(), remainingIds, true); |
|
|
|
|
|
} |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ---- 3. 已成团后 ----
|
|
|
|
|
|
handlePostGroupCancel(order, group); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 团员取消订单 |
|
|
|
|
|
*/ |
|
|
|
|
|
private void handleGroupMemberCancel(MallOrder order, MallOrderGroup group) { |
|
|
|
|
|
// ---- 1. 未支付 ----
|
|
|
|
|
|
if (order.getStatus() == STATUS_WAIT_PAY) { |
|
|
|
|
|
updateOrderStatus(order.getId(), STATUS_CANCELLED); |
|
|
|
|
|
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){ |
|
|
|
|
|
cancelDeliveryOrderByOrderId(order.getId()); |
|
|
|
|
|
} |
|
|
|
|
|
// 从团中移除(未支付不影响 currentMembers)
|
|
|
|
|
|
String remainingIds = removeOrderIdStr(group.getGroupOrderIds(), order.getId()); |
|
|
|
|
|
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>(); |
|
|
|
|
|
guw.eq(MallOrderGroup::getId, group.getId()) |
|
|
|
|
|
.set(MallOrderGroup::getGroupOrderIds, remainingIds); |
|
|
|
|
|
mallOrderGroupMapper.update(null, guw); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ---- 2. 已支付 待成团 ----
|
|
|
if (order.getStatus() == STATUS_WAIT_GROUP) { |
|
|
if (order.getStatus() == STATUS_WAIT_GROUP) { |
|
|
createRefundRecord(order, order.getTotalAmount(), "用户取消拼团"); |
|
|
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){ |
|
|
|
|
|
cancelDeliveryOrderByOrderId(order.getId()); |
|
|
|
|
|
} |
|
|
|
|
|
autoRefund(order, "用户取消拼团,系统退款"); |
|
|
|
|
|
restoreStock(order.getId()); |
|
|
|
|
|
String remainingIds = removeOrderIdStr(group.getGroupOrderIds(), order.getId()); |
|
|
|
|
|
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>(); |
|
|
|
|
|
guw.eq(MallOrderGroup::getId, group.getId()) |
|
|
|
|
|
.set(MallOrderGroup::getCurrentMembers, Math.max(group.getCurrentMembers() - 1, 0)) |
|
|
|
|
|
.set(MallOrderGroup::getGroupOrderIds, remainingIds); |
|
|
|
|
|
mallOrderGroupMapper.update(null, guw); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ---- 3. 已成团后 ----
|
|
|
|
|
|
handlePostGroupCancel(order, group); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 成团后取消逻辑(团长和团员共用) |
|
|
|
|
|
*/ |
|
|
|
|
|
private void handlePostGroupCancel(MallOrder order, MallOrderGroup group) { |
|
|
|
|
|
boolean isFace2Face = (order.getOrderType() == 3); |
|
|
|
|
|
boolean isHead = order.getId().equals(group.getHeadOrderId()); |
|
|
|
|
|
|
|
|
|
|
|
// 已完成订单 → 申请售后(待商家同意)
|
|
|
|
|
|
if (order.getStatus() == STATUS_DONE) { |
|
|
|
|
|
applyMerchantRefund(order, "用户申请售后退款"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ---- 面对面团 + 配送 特殊处理 ----
|
|
|
|
|
|
if (isFace2Face && order.getDeliveryType() != null |
|
|
|
|
|
&& order.getDeliveryType() == DELIVERY_TYPE_EXPRESS) { |
|
|
|
|
|
if (!isHead) { |
|
|
|
|
|
throw new RuntimeException("面对面配送团只有团长可以取消订单"); |
|
|
|
|
|
} |
|
|
|
|
|
handleFace2FaceDeliveryCancel(order, group); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ---- 普通拼团 / 面对面团自取 ----
|
|
|
|
|
|
if (order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS) { |
|
|
|
|
|
// 配送方式
|
|
|
|
|
|
MallDeliveryOrder delivery = findDeliveryByOrderId(order.getId()); |
|
|
|
|
|
if (delivery != null && delivery.getStatus() != null && delivery.getStatus() >= 1) { |
|
|
|
|
|
applyMerchantRefund(order, "用户申请取消订单退款"); |
|
|
|
|
|
} |
|
|
|
|
|
// 10分钟冷却期
|
|
|
|
|
|
if (group.getSuccessTime() != null) { |
|
|
|
|
|
long diffMs = System.currentTimeMillis() - group.getSuccessTime().getTime(); |
|
|
|
|
|
if (diffMs < 10 * 60 * 1000L) { |
|
|
|
|
|
throw new RuntimeException("拼团订单10分钟内无法退款"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// 允许取消
|
|
|
|
|
|
cancelDeliveryOrderByOrderId(order.getId()); |
|
|
|
|
|
autoRefund(order, "成团后用户取消订单,系统退款"); |
|
|
|
|
|
restoreStock(order.getId()); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 自取(待消费)→ 待商家同意退款
|
|
|
|
|
|
applyMerchantRefund(order, "用户申请取消订单退款"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 面对面团 + 配送 成团后团长取消(批量操作所有子订单) |
|
|
|
|
|
*/ |
|
|
|
|
|
private void handleFace2FaceDeliveryCancel(MallOrder order, MallOrderGroup group) { |
|
|
|
|
|
MallDeliveryOrder delivery = findDeliveryByOrderId(order.getId()); |
|
|
|
|
|
|
|
|
|
|
|
if (delivery != null && delivery.getStatus() != null && delivery.getStatus() == 0) { |
|
|
|
|
|
// 待配送员接单 → 可以直接取消所有人
|
|
|
|
|
|
List<String> allOrderIds = Arrays.stream(group.getGroupOrderIds().split(",")) |
|
|
|
|
|
.map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList()); |
|
|
|
|
|
for (String oid : allOrderIds) { |
|
|
|
|
|
MallOrder subOrder = getById(oid); |
|
|
|
|
|
if (subOrder != null && subOrder.getStatus() != STATUS_CANCELLED |
|
|
|
|
|
&& subOrder.getStatus() != STATUS_REFUNDED) { |
|
|
|
|
|
autoRefund(subOrder, "面对面团团长取消订单,系统退款"); |
|
|
|
|
|
restoreStock(oid); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// 取消配送单
|
|
|
|
|
|
cancelDeliveryOrderByOrderId(order.getId()); |
|
|
|
|
|
// 取消团
|
|
|
|
|
|
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>(); |
|
|
|
|
|
guw.eq(MallOrderGroup::getId, group.getId()) |
|
|
|
|
|
.set(MallOrderGroup::getStatus, GROUP_STATUS_FAIL); |
|
|
|
|
|
mallOrderGroupMapper.update(null, guw); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 配送员已接单或其他状态 → 所有子订单走商家同意流程
|
|
|
|
|
|
List<String> allOrderIds = Arrays.stream(group.getGroupOrderIds().split(",")) |
|
|
|
|
|
.map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList()); |
|
|
|
|
|
for (String oid : allOrderIds) { |
|
|
|
|
|
MallOrder subOrder = getById(oid); |
|
|
|
|
|
if (subOrder != null && subOrder.getStatus() != STATUS_CANCELLED |
|
|
|
|
|
&& subOrder.getStatus() != STATUS_REFUNDED |
|
|
|
|
|
&& subOrder.getStatus() != STATUS_WAIT_REFUND) { |
|
|
|
|
|
applyMerchantRefund(subOrder, "面对面团团长申请取消,待商家同意"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ================================================================
|
|
|
|
|
|
// 直购订单取消逻辑
|
|
|
|
|
|
// ================================================================
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 直接购买订单取消 |
|
|
|
|
|
*/ |
|
|
|
|
|
private void handleDirectCancel(MallOrder order) { |
|
|
|
|
|
// ---- 1. 未支付 ----
|
|
|
|
|
|
if (order.getStatus() == STATUS_WAIT_PAY) { |
|
|
|
|
|
updateOrderStatus(order.getId(), STATUS_CANCELLED); |
|
|
|
|
|
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){ |
|
|
|
|
|
cancelDeliveryOrderByOrderId(order.getId()); |
|
|
|
|
|
} |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ---- 2. 已完成 → 申请售后 ----
|
|
|
|
|
|
if (order.getStatus() == STATUS_DONE) { |
|
|
|
|
|
applyMerchantRefund(order, "用户申请售后退款"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ---- 3. 已支付 ----
|
|
|
|
|
|
if (order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS) { |
|
|
|
|
|
// 外卖配送
|
|
|
|
|
|
MallDeliveryOrder delivery = findDeliveryByOrderId(order.getId()); |
|
|
|
|
|
if (delivery != null && delivery.getStatus() != null && delivery.getStatus() >= 1) { |
|
|
|
|
|
// 配送员已接单 → 走商家同意流程
|
|
|
|
|
|
applyMerchantRefund(order, "用户申请取消订单,待商家同意"); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 未接单 → 直接取消并退款
|
|
|
|
|
|
cancelDeliveryOrderByOrderId(order.getId()); |
|
|
|
|
|
autoRefund(order, "用户取消订单,系统退款"); |
|
|
|
|
|
restoreStock(order.getId()); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
// 自取(待消费)→ 直接退款
|
|
|
|
|
|
autoRefund(order, "用户取消订单,系统退款"); |
|
|
|
|
|
restoreStock(order.getId()); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -545,7 +829,30 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder |
|
|
@Override |
|
|
@Override |
|
|
public IPage<MallOrderVO> pageOrder(MallOrderPageQuery q) { |
|
|
public IPage<MallOrderVO> pageOrder(MallOrderPageQuery q) { |
|
|
IPage<MallOrderVO> page = new Page<>(q.getPageNum(), q.getPageSize()); |
|
|
IPage<MallOrderVO> page = new Page<>(q.getPageNum(), q.getPageSize()); |
|
|
return this.baseMapper.selectPageVO(page, q); |
|
|
IPage<MallOrderVO> result = this.baseMapper.selectPageVO(page, q); |
|
|
|
|
|
|
|
|
|
|
|
// 批量查询订单商品明细,避免 N+1 问题
|
|
|
|
|
|
List<MallOrderVO> records = result.getRecords(); |
|
|
|
|
|
if (records != null && !records.isEmpty()) { |
|
|
|
|
|
// 1. 收集所有订单ID
|
|
|
|
|
|
List<String> orderIds = records.stream() |
|
|
|
|
|
.map(MallOrderVO::getId) |
|
|
|
|
|
.collect(java.util.stream.Collectors.toList()); |
|
|
|
|
|
|
|
|
|
|
|
// 2. 一次 IN 查询所有商品明细
|
|
|
|
|
|
List<MallOrderGoods> allGoods = mallOrderGoodsMapper.selectByOrderIds(orderIds); |
|
|
|
|
|
|
|
|
|
|
|
// 3. 按 orderId 分组
|
|
|
|
|
|
java.util.Map<String, List<MallOrderGoods>> goodsMap = allGoods.stream() |
|
|
|
|
|
.collect(java.util.stream.Collectors.groupingBy(MallOrderGoods::getOrderId)); |
|
|
|
|
|
|
|
|
|
|
|
// 4. 组装到每个 VO
|
|
|
|
|
|
for (MallOrderVO vo : records) { |
|
|
|
|
|
vo.setGoodsList(goodsMap.getOrDefault(vo.getId(), java.util.Collections.emptyList())); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
@ -809,4 +1116,128 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder |
|
|
vo.setDeliveryInfo(delivery); |
|
|
vo.setDeliveryInfo(delivery); |
|
|
return vo; |
|
|
return vo; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ================================================================
|
|
|
|
|
|
// 取消订单辅助方法
|
|
|
|
|
|
// ================================================================
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 根据订单ID查找所属拼团 |
|
|
|
|
|
*/ |
|
|
|
|
|
private MallOrderGroup findGroupByOrderId(String orderId) { |
|
|
|
|
|
// 先尝试团长精确匹配
|
|
|
|
|
|
LambdaQueryWrapper<MallOrderGroup> q1 = new LambdaQueryWrapper<>(); |
|
|
|
|
|
q1.eq(MallOrderGroup::getHeadOrderId, orderId); |
|
|
|
|
|
MallOrderGroup group = mallOrderGroupMapper.selectOne(q1); |
|
|
|
|
|
if (group != null) return group; |
|
|
|
|
|
// 再通过 groupOrderIds 模糊匹配
|
|
|
|
|
|
LambdaQueryWrapper<MallOrderGroup> q2 = new LambdaQueryWrapper<>(); |
|
|
|
|
|
q2.like(MallOrderGroup::getGroupOrderIds, orderId).last("LIMIT 1"); |
|
|
|
|
|
return mallOrderGroupMapper.selectOne(q2); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 根据订单ID查找配送单 |
|
|
|
|
|
*/ |
|
|
|
|
|
private MallDeliveryOrder findDeliveryByOrderId(String orderId) { |
|
|
|
|
|
LambdaQueryWrapper<MallDeliveryOrder> dq = new LambdaQueryWrapper<>(); |
|
|
|
|
|
dq.eq(MallDeliveryOrder::getOrderId, orderId).last("LIMIT 1"); |
|
|
|
|
|
return mallDeliveryOrderMapper.selectOne(dq); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 取消某订单关联的配送单(仅取消 待支付/待接单 状态的) |
|
|
|
|
|
*/ |
|
|
|
|
|
private void cancelDeliveryOrderByOrderId(String orderId) { |
|
|
|
|
|
LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>(); |
|
|
|
|
|
duw.eq(MallDeliveryOrder::getOrderId, orderId) |
|
|
|
|
|
.in(MallDeliveryOrder::getStatus, Arrays.asList(-1, 0)) |
|
|
|
|
|
.set(MallDeliveryOrder::getStatus, 4); |
|
|
|
|
|
mallDeliveryOrderMapper.update(null, duw); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 从逗号分隔的 groupOrderIds 中移除指定 orderId |
|
|
|
|
|
*/ |
|
|
|
|
|
private String removeOrderIdStr(String groupOrderIds, String orderIdToRemove) { |
|
|
|
|
|
if (StringUtils.isBlank(groupOrderIds)) return ""; |
|
|
|
|
|
return Arrays.stream(groupOrderIds.split(",")) |
|
|
|
|
|
.map(String::trim) |
|
|
|
|
|
.filter(s -> !s.isEmpty() && !s.equals(orderIdToRemove)) |
|
|
|
|
|
.collect(Collectors.joining(",")); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 团长转让:更新 headOrderId、headUserId、groupOrderIds,可选减少 currentMembers |
|
|
|
|
|
*/ |
|
|
|
|
|
private void transferGroupHead(MallOrderGroup group, String removedOrderId, |
|
|
|
|
|
String remainingIds, boolean decrementMembers) { |
|
|
|
|
|
String newHeadOrderId = remainingIds.split(",")[0].trim(); |
|
|
|
|
|
MallOrder newHeadOrder = getById(newHeadOrderId); |
|
|
|
|
|
if (newHeadOrder == null) { |
|
|
|
|
|
throw new RuntimeException("转让团长失败:下一位团员订单不存在"); |
|
|
|
|
|
} |
|
|
|
|
|
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>(); |
|
|
|
|
|
guw.eq(MallOrderGroup::getId, group.getId()) |
|
|
|
|
|
.set(MallOrderGroup::getHeadOrderId, newHeadOrderId) |
|
|
|
|
|
.set(MallOrderGroup::getHeadUserId, newHeadOrder.getUserId()) |
|
|
|
|
|
.set(MallOrderGroup::getGroupOrderIds, remainingIds); |
|
|
|
|
|
if (decrementMembers) { |
|
|
|
|
|
guw.set(MallOrderGroup::getCurrentMembers, Math.max(group.getCurrentMembers() - 1, 0)); |
|
|
|
|
|
} |
|
|
|
|
|
mallOrderGroupMapper.update(null, guw); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 系统直接退款:订单状态 → 已退款(8),退款记录状态 → 退款成功(1) |
|
|
|
|
|
*/ |
|
|
|
|
|
private void autoRefund(MallOrder order, String reason) { |
|
|
|
|
|
updateOrderStatus(order.getId(), STATUS_REFUNDED); |
|
|
|
|
|
MallRefundRecord record = new MallRefundRecord(); |
|
|
|
|
|
record.setOrderId(order.getId()); |
|
|
|
|
|
record.setUserId(order.getUserId()); |
|
|
|
|
|
record.setRefundAmount(order.getTotalAmount()); |
|
|
|
|
|
record.setReason(reason); |
|
|
|
|
|
record.setStatus(1); // 退款成功
|
|
|
|
|
|
record.setCreateTime(new Date()); |
|
|
|
|
|
record.setSuccessTime(new Date()); |
|
|
|
|
|
mallRefundRecordMapper.insert(record); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 申请商家同意退款:订单状态 → 待商家同意退款(7),退款记录状态 → 待商家同意(0) |
|
|
|
|
|
*/ |
|
|
|
|
|
private void applyMerchantRefund(MallOrder order, String reason) { |
|
|
|
|
|
updateOrderStatus(order.getId(), STATUS_WAIT_REFUND); |
|
|
|
|
|
createRefundRecord(order, order.getTotalAmount(), reason); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 取消订单时回退商品库存 |
|
|
|
|
|
*/ |
|
|
|
|
|
private void restoreStock(String orderId) { |
|
|
|
|
|
List<MallOrderGoods> goodsList = mallOrderGoodsMapper.selectByOrderId(orderId); |
|
|
|
|
|
if (goodsList == null || goodsList.isEmpty()) return; |
|
|
|
|
|
|
|
|
|
|
|
for (MallOrderGoods goods : goodsList) { |
|
|
|
|
|
Product product = productMapper.selectById(goods.getProductId()); |
|
|
|
|
|
if (product == null) continue; |
|
|
|
|
|
String attrJson = product.getAttributeListPrice(); |
|
|
|
|
|
if (StringUtils.isBlank(attrJson)) continue; |
|
|
|
|
|
try { |
|
|
|
|
|
JSONArray arr = JSONUtil.parseArray(attrJson); |
|
|
|
|
|
if (arr.isEmpty()) continue; |
|
|
|
|
|
JSONObject spec = arr.getJSONObject(0); |
|
|
|
|
|
int current = spec.getInt("specNum"); |
|
|
|
|
|
spec.set("specNum", current + goods.getQuantity()); |
|
|
|
|
|
LambdaUpdateWrapper<Product> uw = new LambdaUpdateWrapper<>(); |
|
|
|
|
|
uw.eq(Product::getId, product.getId()) |
|
|
|
|
|
.set(Product::getAttributeListPrice, arr.toString()); |
|
|
|
|
|
productMapper.update(null, uw); |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
log.warn("库存回退失败: orderId={}, productId={}, error={}", |
|
|
|
|
|
orderId, goods.getProductId(), e.getMessage()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|