Browse Source

对接拼团数据

master
wangfukang 2 weeks ago
parent
commit
f6650b6448
  1. 57
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductController.java
  2. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java
  3. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGoods.java
  4. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGroup.java
  5. 6
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallOrderPageQuery.java
  6. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java
  7. 467
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java
  8. 8
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/ProductServiceImpl.java
  9. 3
      hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderGroupMapper.xml
  10. 16
      hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderMapper.xml
  11. 3
      hiver-modules/hiver-mall/src/main/resources/mapper/ProductMapper.xml

57
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductController.java

@ -36,7 +36,9 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@ -447,6 +449,39 @@ public class ProductController {
shopIdStr = productPageQuery.getShopIdList().get(0);
}
// 获取分类排序字典
Map<String, Integer> categorySortMap = new HashMap<>();
if (CharSequenceUtil.isNotBlank(shopIdStr)) {
List<Object> values = redisTemplateHelper.hValues("PRODUCT_CATEGORY_CACHE:" + shopIdStr);
if (values != null && !values.isEmpty()) {
List<cc.hiver.mall.pojo.vo.ProductCategoryVo2> tempList = new ArrayList<>();
for (Object v : values) {
cc.hiver.mall.pojo.vo.ProductCategoryVo2 dto = cn.hutool.json.JSONUtil.toBean(v.toString(), cc.hiver.mall.pojo.vo.ProductCategoryVo2.class);
tempList.add(dto);
}
tempList.sort((o1, o2) -> {
if (o1.getSort() == null && o2.getSort() == null) return 0;
if (o1.getSort() == null) return -1;
if (o2.getSort() == null) return 1;
try {
return Integer.valueOf(o1.getSort()).compareTo(Integer.valueOf(o2.getSort()));
} catch (NumberFormatException e) {
return o1.getSort().compareTo(o2.getSort());
}
});
for (int i = 0; i < tempList.size(); i++) {
categorySortMap.put(tempList.get(i).getId(), i);
}
} else {
List<cc.hiver.mall.pojo.vo.ProductCategoryVo2> tempList = productCategoryService.getCategoryListByShopId(shopIdStr);
if (tempList != null) {
for (int i = 0; i < tempList.size(); i++) {
categorySortMap.put(tempList.get(i).getId(), i);
}
}
}
}
if (CharSequenceUtil.isNotBlank(shopIdStr) && (productPageQuery.getIdList() == null || productPageQuery.getIdList().isEmpty())) {
String productsJson = redisTemplateHelper.get("SHOP_PRODUCTS:" + shopIdStr);
if (CharSequenceUtil.isNotBlank(productsJson)) {
@ -469,6 +504,28 @@ public class ProductController {
}
}
return true;
}).sorted((p1, p2) -> {
int categoryCompare = 0;
String c1 = p1.getCategoryId();
String c2 = p2.getCategoryId();
Integer sort1 = c1 != null ? categorySortMap.getOrDefault(c1, Integer.MAX_VALUE) : Integer.MAX_VALUE;
Integer sort2 = c2 != null ? categorySortMap.getOrDefault(c2, Integer.MAX_VALUE) : Integer.MAX_VALUE;
categoryCompare = sort1.compareTo(sort2);
if (categoryCompare != 0) {
return categoryCompare;
}
Integer o1 = p1.getOrderFiled();
Integer o2 = p2.getOrderFiled();
if (o1 == null && o2 == null) {
return 0;
} else if (o1 == null) {
return 1;
} else if (o2 == null) {
return -1;
} else {
return o2.compareTo(o1);
}
}).collect(Collectors.toList());
// 内存分页

4
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java

@ -29,11 +29,11 @@ public class MallOrder implements Serializable {
private String userId;
@ApiModelProperty(value = "店铺ID")
private String shopId;
@ApiModelProperty(value = "订单类型 1:直接购买 2:拼团购买 3:面对面团")
@ApiModelProperty(value = "订单类型 1:直接购买 2:拼团购买 3:面对面团 4:快递 5:跑腿 6:二手")
private Integer orderType;
@ApiModelProperty(value = "配送方式 1:外卖配送 2:到店自取")
private Integer deliveryType;
@ApiModelProperty(value = "订单状态 0:待支付 1:待商家接单 01:待成团 2待配送员接单 3:待取货(配送)/待消费(自取) 4:配送中 5:已完成 6:已取消 7:待商家同意退款 8:已退款")
@ApiModelProperty(value = "订单状态 0:待支付 1:待商家接单 10:待成团 2待配送员接单 3:待取货(配送)/待消费(自取) 4:配送中 5:已完成 6:已取消 7:待商家同意退款 8:已退款")
private Integer status;
@ApiModelProperty(value = "商家-订单序号")
private String numberCode;

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGoods.java

@ -22,6 +22,8 @@ public class MallOrderGoods implements Serializable {
@Id
@TableId
private String id = SnowFlakeUtil.nextId().toString();
@ApiModelProperty(value = "")
private String childId;
@ApiModelProperty(value = "关联核心订单ID")
private String orderId;
@ApiModelProperty(value = "关联商品ID")

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGroup.java

@ -51,6 +51,8 @@ public class MallOrderGroup implements Serializable {
private Date createTime;
@ApiModelProperty(value = "过期时间")
private Date expireTime;
@ApiModelProperty(value = "成团时间")
private Date successTime;
@ApiModelProperty(value = "拼团商品名称")
private String productName;
@ApiModelProperty(value = "拼团商品图片")

6
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallOrderPageQuery.java

@ -18,6 +18,9 @@ public class MallOrderPageQuery extends HiverBasePageQuery {
@ApiModelProperty("店铺ID")
private String shopId;
@ApiModelProperty("学校ID")
private String regionId;
@ApiModelProperty("订单状态 0:待支付 1:待商家接单 2:待配送员接单 3:待取货/待消费 4:配送中 5:已完成 6:已取消 7:待退款 8:已退款")
private Integer status;
@ -27,6 +30,9 @@ public class MallOrderPageQuery extends HiverBasePageQuery {
@ApiModelProperty("配送方式 1:外卖配送 2:到店自取")
private Integer deliveryType;
@ApiModelProperty("订单类型 0:不区分 1:饭团 2:跑腿/快递 3:二手")
private Integer searchType;
@ApiModelProperty("拼团ID")
private String groupId;

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java

@ -79,7 +79,8 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
// 达到成团人数 -> 激活 (超出拼团人数也可以参与)
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, groupId)
.set(MallOrderGroup::getStatus, GROUP_STATUS_SUCCESS);
.set(MallOrderGroup::getStatus, GROUP_STATUS_SUCCESS)
.set(MallOrderGroup::getSuccessTime, new Date());
this.update(guw);
// 将所有关联子订单从"待成团"改为"待商家接单"

467
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java

@ -26,10 +26,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
* 核心订单 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.setRegionId(dto.getRegionId());
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.setRegionId(dto.getRegionId());
this.save(order);
@ -470,19 +475,298 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
MallOrder order = getById(orderId);
if (order == null) 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<>();
duw.eq(MallDeliveryOrder::getOrderId, orderId)
.in(MallDeliveryOrder::getStatus, java.util.Arrays.asList(-1, 0))
.set(MallDeliveryOrder::getStatus, 4);
mallDeliveryOrderMapper.update(null, duw);
// 若已支付(待成团状态),生成退款记录
// 拼团 / 面对面团
if (order.getOrderType() == ORDER_TYPE_GROUP || order.getOrderType() == 3) {
handleGroupCancel(order);
} else {
// 直接购买
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) {
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
public IPage<MallOrderVO> pageOrder(MallOrderPageQuery q) {
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
@ -809,4 +1116,128 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
vo.setDeliveryInfo(delivery);
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(","));
}
/**
* 团长转让更新 headOrderIdheadUserIdgroupOrderIds可选减少 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());
}
}
}
}

8
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/ProductServiceImpl.java

@ -4,11 +4,7 @@ import cc.hiver.core.common.constant.ProductConstant;
import cc.hiver.core.common.utils.SecurityUtil;
import cc.hiver.core.common.utils.StringUtils;
import cc.hiver.core.entity.User;
import cc.hiver.mall.checkstock.pojo.CheckStockPageQuery;
import cc.hiver.mall.checkstock.service.CheckStockService;
import cc.hiver.mall.checkstock.vo.CheckStockAttributeVo;
import cc.hiver.mall.checkstock.vo.CheckStockDetailVo;
import cc.hiver.mall.checkstock.vo.CheckStockPageVo;
import cc.hiver.mall.common.constant.PurchaseConstant;
import cc.hiver.mall.dao.mapper.ProductMapper;
import cc.hiver.mall.entity.Product;
@ -115,7 +111,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
productPageVO.setProductGroupBuyPrices(productGroupBuyPriceMap.get(productId));
}
}
// 获取商品均色均码的库存数
/*// 获取商品均色均码的库存数
final List<Stock> stockList = stockService.getDefaultStockCount(productIdList);
// 处理为map, key为productId
final Map<String, Stock> stockMap = new HashMap<>();
@ -161,7 +157,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
productPageVO.setCheckStockAttributeVos(checkStockAttributeVoMap.get(productId));
}
}
}
}*/
}
page.setRecords(list);
return page;

3
hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderGroupMapper.xml

@ -22,13 +22,14 @@
<result column="product_name" property="productName"/>
<result column="product_picture" property="productPicture"/>
<result column="product_id" property="productId"/>
<result column="success_time" property="successTime"/>
</resultMap>
<select id="selectMallGroup" resultMap="groupMap">
SELECT id,shop_id,head_user_id,head_order_id,group_order_ids,target_members,
current_members,status,group_price,worker_id,worker_commission,total_delivery_fee,
create_time,expire_time,is_face,product_name,product_picture,product_id
create_time,expire_time,is_face,product_name,product_picture,product_id,success_time
FROM mall_order_group
<where>
<if test="group.shopId != null and group.shopId != ''">

16
hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderMapper.xml

@ -4,7 +4,7 @@
<mapper namespace="cc.hiver.mall.dao.mapper.MallOrderMapper">
<!-- 通用结果映射 -->
<resultMap id="mallOrderVOMap" type="cc.hiver.mall.entity.MallOrder">
<resultMap id="mallOrderVOMap" type="cc.hiver.mall.pojo.vo.MallOrderVO">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="shop_id" property="shopId"/>
@ -36,7 +36,7 @@
o.status, o.total_amount, o.goods_amount, o.delivery_fee,
o.package_fee, o.address_id, o.remark, o.create_time, o.pay_time,
o.receiver_name, o.receiver_phone, o.receiver_address,
o.shop_name, o.shop_phone, o.shop_address,o.number_code,region_id
o.shop_name, o.shop_phone, o.shop_address,o.number_code,o.region_id
FROM mall_order o
<where>
<if test="q.userId != null and q.userId != ''">
@ -45,12 +45,24 @@
<if test="q.shopId != null and q.shopId != ''">
AND o.shop_id = #{q.shopId}
</if>
<if test="q.regionId != null and q.regionId != ''">
AND o.region_id = #{q.regionId}
</if>
<if test="q.status != null">
AND o.status = #{q.status}
</if>
<if test="q.orderType != null">
AND o.order_type = #{q.orderType}
</if>
<if test="q.searchType != null and q.searchType == 1">
AND o.order_type in (1,2,3)
</if>
<if test="q.searchType != null and q.searchType == 2">
AND o.order_type in (4,5)
</if>
<if test="q.searchType != null and q.searchType == 3">
AND o.order_type = 6
</if>
<if test="q.deliveryType != null">
AND o.delivery_type = #{q.deliveryType}
</if>

3
hiver-modules/hiver-mall/src/main/resources/mapper/ProductMapper.xml

@ -742,6 +742,7 @@
t.lunch_box,
t.is_more_buy
FROM t_product t
LEFT JOIN t_product_category pc ON t.category_id = pc.id
<where>
t.del_flag != 2
<!--店铺id-->
@ -789,7 +790,7 @@
)
</if>
</where>
ORDER BY t.order_filed desc,
ORDER BY CAST(pc.sort AS SIGNED) ASC, t.order_filed desc,
<!--销量排序
<if test='queryParams.startDate !=null and queryParams.startDate.trim() neq "" and queryParams.endDate !=null and queryParams.endDate.trim() neq ""'>
<if test='queryParams.sortField!=null and queryParams.sortField.trim() neq "" and queryParams.sortField eq "totalSold"'>

Loading…
Cancel
Save