diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductController.java index 4493c9f1..d318cb5e 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductController.java +++ b/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 categorySortMap = new HashMap<>(); + if (CharSequenceUtil.isNotBlank(shopIdStr)) { + List values = redisTemplateHelper.hValues("PRODUCT_CATEGORY_CACHE:" + shopIdStr); + if (values != null && !values.isEmpty()) { + List 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 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()); // 内存分页 diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java index 0978044f..3ccf90bb 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java +++ b/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; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGoods.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGoods.java index 3bf8b183..05ad9282 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGoods.java +++ b/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") diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGroup.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGroup.java index 2ec3d443..3009ce0a 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGroup.java +++ b/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 = "拼团商品图片") diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallOrderPageQuery.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallOrderPageQuery.java index 24cd87f7..b863e909 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallOrderPageQuery.java +++ b/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; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java index 40fe20d7..7c9f179d 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java @@ -79,7 +79,8 @@ public class MallOrderGroupServiceImpl extends ServiceImpl 激活 (超出拼团人数也可以参与) LambdaUpdateWrapper 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); // 将所有关联子订单从"待成团"改为"待商家接单" diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java index 4dd44633..a2d11ce6 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java +++ b/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 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 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 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 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 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 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 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 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 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 guw = new LambdaUpdateWrapper<>(); + guw.eq(MallOrderGroup::getId, group.getId()) + .set(MallOrderGroup::getStatus, GROUP_STATUS_FAIL); + mallOrderGroupMapper.update(null, guw); + } else { + // 配送员已接单或其他状态 → 所有子订单走商家同意流程 + List 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 pageOrder(MallOrderPageQuery q) { IPage page = new Page<>(q.getPageNum(), q.getPageSize()); - return this.baseMapper.selectPageVO(page, q); + IPage result = this.baseMapper.selectPageVO(page, q); + + // 批量查询订单商品明细,避免 N+1 问题 + List records = result.getRecords(); + if (records != null && !records.isEmpty()) { + // 1. 收集所有订单ID + List orderIds = records.stream() + .map(MallOrderVO::getId) + .collect(java.util.stream.Collectors.toList()); + + // 2. 一次 IN 查询所有商品明细 + List allGoods = mallOrderGoodsMapper.selectByOrderIds(orderIds); + + // 3. 按 orderId 分组 + java.util.Map> 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 q1 = new LambdaQueryWrapper<>(); + q1.eq(MallOrderGroup::getHeadOrderId, orderId); + MallOrderGroup group = mallOrderGroupMapper.selectOne(q1); + if (group != null) return group; + // 再通过 groupOrderIds 模糊匹配 + LambdaQueryWrapper q2 = new LambdaQueryWrapper<>(); + q2.like(MallOrderGroup::getGroupOrderIds, orderId).last("LIMIT 1"); + return mallOrderGroupMapper.selectOne(q2); + } + + /** + * 根据订单ID查找配送单 + */ + private MallDeliveryOrder findDeliveryByOrderId(String orderId) { + LambdaQueryWrapper dq = new LambdaQueryWrapper<>(); + dq.eq(MallDeliveryOrder::getOrderId, orderId).last("LIMIT 1"); + return mallDeliveryOrderMapper.selectOne(dq); + } + + /** + * 取消某订单关联的配送单(仅取消 待支付/待接单 状态的) + */ + private void cancelDeliveryOrderByOrderId(String orderId) { + LambdaUpdateWrapper 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 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 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 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()); + } + } + } } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/ProductServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/ProductServiceImpl.java index 2f1dff66..d59bd6a8 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/ProductServiceImpl.java +++ b/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 impl productPageVO.setProductGroupBuyPrices(productGroupBuyPriceMap.get(productId)); } } - // 获取商品均色均码的库存数 + /*// 获取商品均色均码的库存数 final List stockList = stockService.getDefaultStockCount(productIdList); // 处理为map, key为productId final Map stockMap = new HashMap<>(); @@ -161,7 +157,7 @@ public class ProductServiceImpl extends ServiceImpl impl productPageVO.setCheckStockAttributeVos(checkStockAttributeVoMap.get(productId)); } } - } + }*/ } page.setRecords(list); return page; diff --git a/hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderGroupMapper.xml b/hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderGroupMapper.xml index 0536780a..7bff9f8d 100644 --- a/hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderGroupMapper.xml +++ b/hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderGroupMapper.xml @@ -22,13 +22,14 @@ +