Browse Source

对接拼团数据1

master
wangfukang 4 days ago
parent
commit
dddc5e79db
  1. 14
      hiver-admin/test-output/test-report.html
  2. 4
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/common/CaptchaController.java
  3. 17
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CommentController.java
  4. 29
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java
  5. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopTakeawayController.java
  6. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallDeliveryOrderMapper.java
  7. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallOrderMapper.java
  8. 7
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallRefundRecord.java
  9. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallRefundRecordPageQuery.java
  10. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java
  11. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java
  12. 100
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java
  13. 21
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java
  14. 87
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java
  15. 79
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java
  16. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallUserCouponServiceImpl.java
  17. 273
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/UserPendingOrderCacheUtil.java
  18. 21
      hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml
  19. 4
      hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderMapper.xml
  20. 4
      hiver-modules/hiver-mall/src/main/resources/mapper/MallRefundRecordMapper.xml

14
hiver-admin/test-output/test-report.html

@ -35,7 +35,7 @@
<a href="#"><span class="badge badge-primary">Hiver</span></a>
</li>
<li class="m-r-10">
<a href="#"><span class="badge badge-primary">四月 19, 2026 15:11:39</span></a>
<a href="#"><span class="badge badge-primary">四月 21, 2026 18:05:31</span></a>
</li>
</ul>
</div>
@ -84,7 +84,7 @@
<div class="test-detail">
<span class="meta text-white badge badge-sm"></span>
<p class="name">passTest</p>
<p class="text-sm"><span>15:11:39 下午</span> / <span>0.015 secs</span></p>
<p class="text-sm"><span>18:05:32 下午</span> / <span>0.015 secs</span></p>
</div>
<div class="test-contents d-none">
<div class="detail-head">
@ -92,8 +92,8 @@
<div class="info">
<div class='float-right'><span class='badge badge-default'>#test-id=1</span></div>
<h5 class="test-status text-pass">passTest</h5>
<span class='badge badge-success'>04.19.2026 15:11:39</span>
<span class='badge badge-danger'>04.19.2026 15:11:39</span>
<span class='badge badge-success'>04.21.2026 18:05:32</span>
<span class='badge badge-danger'>04.21.2026 18:05:32</span>
<span class='badge badge-default'>0.015 secs</span>
</div>
<div class="m-t-10 m-l-5"></div>
@ -104,7 +104,7 @@
<tbody>
<tr class="event-row">
<td><span class="badge log pass-bg">Pass</span></td>
<td>15:11:39</td>
<td>18:05:32</td>
<td>
Test passed
</td>
@ -128,13 +128,13 @@
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Started</p>
<h3>四月 19, 2026 15:11:39</h3>
<h3>四月 21, 2026 18:05:31</h3>
</div></div>
</div>
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Ended</p>
<h3>四月 19, 2026 15:11:39</h3>
<h3>四月 21, 2026 18:05:32</h3>
</div></div>
</div>
<div class="col-md-3">

4
hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/common/CaptchaController.java

@ -54,8 +54,8 @@ public class CaptchaController {
@RequestMapping(value = "/init", method = RequestMethod.GET)
@ApiOperation(value = "初始化验证码")
@RateLimiter(rate = 1, ipLimit = true)
public Result initCaptcha(@ApiParam("仅生成数字") @RequestParam(required = false, defaultValue = "false") Boolean isDigit,
@ApiParam("验证码长度") @RequestParam(required = false, defaultValue = "4") Integer length) {
public Result initCaptcha(@ApiParam("仅生成数字") @RequestParam(value = "isDigit",required = false, defaultValue = "false") Boolean isDigit,
@ApiParam("验证码长度") @RequestParam(value = "length",required = false, defaultValue = "4") Integer length) {
String captchaId = IdUtil.simpleUUID();
String code;
if (isDigit) {

17
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CommentController.java

@ -38,6 +38,7 @@ import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -78,7 +79,7 @@ public class CommentController {
if(e.getShopId().toUpperCase().startsWith("W")){
//更新配送员评分
Worker worker = workerServiceImpl.findByWorkerId(e.getShopId());
Integer oldCount = worker.getOrderCount();
Integer oldCount = worker.getOrderCount() == null ? 0 : worker.getOrderCount();
BigDecimal oldScore = worker.getScore();
BigDecimal score = e.getScore();
@ -89,8 +90,10 @@ public class CommentController {
BigDecimal newScore = oldScore.multiply(new BigDecimal(oldCount))
.add(score)
.divide(new BigDecimal(newCount), 2, RoundingMode.HALF_UP); // 保留2位小数
DecimalFormat df = new DecimalFormat("00.00");
worker.setScore(newScore);
String formattedResult = df.format(newScore);
worker.setScore(new BigDecimal(formattedResult));
// 3. 保存更新
workerServiceImpl.update(worker);
@ -98,7 +101,7 @@ public class CommentController {
}else{
//更新店铺评分
Shop shop = shopService.findById(e.getShopId());
Integer oldSaleCount = shop.getSaleCount() + 1;
Integer oldSaleCount = shop.getSaleCount() == null ? 0 : shop.getSaleCount();
BigDecimal oldScore = shop.getShopScore();
BigDecimal score = e.getScore();
@ -108,8 +111,10 @@ public class CommentController {
BigDecimal newScore = oldScore.multiply(new BigDecimal(oldSaleCount))
.add(score)
.divide(new BigDecimal(newCount), 2, RoundingMode.HALF_UP); // 保留2位小数
DecimalFormat df = new DecimalFormat("00.00");
shop.setShopScore(newScore);
String formattedResult = df.format(newScore);
shop.setShopScore(new BigDecimal(formattedResult));
shopService.update(shop);
String shopCacheKey = "SHOP_CACHE:" + shop.getRegionId();
@ -117,13 +122,13 @@ public class CommentController {
if (org.apache.commons.lang3.StringUtils.isNotBlank(shopJson)) {
ShopCacheDTO cacheDTO = JSONUtil.toBean(shopJson, ShopCacheDTO.class);
if (cacheDTO.getShop() != null) {
cacheDTO.getShop().setShopScore(newScore);
cacheDTO.getShop().setShopScore(new BigDecimal(formattedResult));
redisTemplateHelper.hPut(shopCacheKey, shop.getId(), JSONUtil.toJsonStr(cacheDTO));
}
}
}
});
if(comment != null && comment.get(0).getParentId()!=null){
if(comment != null && StringUtils.isNotBlank(comment.get(0).getParentId())){
Comment commentPar = commentService.getById(comment.get(0).getParentId());
commentPar.setHasAnswer(1);
commentService.updateById(commentPar);

29
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java

@ -9,6 +9,7 @@ import cc.hiver.mall.pojo.query.MallOrderPageQuery;
import cc.hiver.mall.pojo.vo.MallOrderVO;
import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.utils.UserPendingOrderCacheUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -32,6 +33,9 @@ public class MallOrderController {
@Autowired
private MallOrderService mallOrderService;
@Autowired
private UserPendingOrderCacheUtil userPendingOrderCacheUtil;
@Autowired
private MallOrderGroupService mallOrderGroupService;
@ -43,6 +47,7 @@ public class MallOrderController {
public Result<MallOrderVO> createOrder(@RequestBody CreateOrderDTO dto) {
try {
MallOrderVO vo = mallOrderService.createOrder(dto);
userPendingOrderCacheUtil.put(dto.getUserId(), vo);
return new ResultUtil<MallOrderVO>().setData(vo);
} catch (Exception e) {
log.error("下单失败: {}", e.getMessage(), e);
@ -68,6 +73,30 @@ public class MallOrderController {
return new ResultUtil<List<MallOrderGroup>>().setData(mallOrderGroupService.selectMallGroup(group));
}
/**
* 查询用户当前待完成订单
*/
@GetMapping("/getOrdersByUserId/{userId}")
@ApiOperation(value = "查询用户当前待完成订单")
public Result<List<MallOrderVO>> getOrdersByUserId(@ApiParam("用户ID") @PathVariable String userId) {
// 1. 先从缓存获取
List<MallOrderVO> orders = userPendingOrderCacheUtil.getAll(userId);
// 2. 缓存未命中,查数据库
if (orders == null) {
// 建议:加个判空,防止数据库也没数据时做无用功
orders = mallOrderService.getPeiSongOrders(userId);
// 3. 【关键步骤】如果查到了数据,必须回写到缓存!
if (orders != null && !orders.isEmpty()) {
// 设置过期时间,比如 30 分钟(根据订单平均配送时长决定)
userPendingOrderCacheUtil.putAll(userId, orders);
}
}
// 4. 返回结果
return new ResultUtil<List<MallOrderVO>>().setData(orders);
}
/**
* 根据拼团id查询团长订单配送费信息

4
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopTakeawayController.java

@ -48,7 +48,7 @@ public class ShopTakeawayController {
@RequestMapping(value = "/getByShopId", method = RequestMethod.GET)
@ApiOperation("根据店铺id获取外卖业务配置")
public Result<ShopTakeaway> getByShopId(
@ApiParam("店铺id") @RequestParam String shopId) {
@ApiParam("店铺id") @RequestParam(value = "shopId") String shopId) {
final ShopTakeaway shopTakeaway = shopTakeawayService.selectByPrimaryKey(shopId);
return new ResultUtil<ShopTakeaway>().setData(shopTakeaway);
}
@ -81,7 +81,7 @@ public class ShopTakeawayController {
@RequestMapping(value = "/deleteByShopId", method = RequestMethod.POST)
@ApiOperation("删除外卖业务配置")
public Result<Object> deleteByShopId(
@ApiParam("店铺id") @RequestParam String shopId) {
@ApiParam("店铺id") @RequestParam(value = "shopId") String shopId) {
shopTakeawayService.deleteByPrimaryKey(shopId);
return ResultUtil.success("删除成功");
}

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallDeliveryOrderMapper.java

@ -37,4 +37,6 @@ public interface MallDeliveryOrderMapper extends BaseMapper<MallDeliveryOrder> {
MallDeliveryOrder selectByGroupId(@Param("orderId") String orderId);
List<MallDeliveryOrder> selectByOrderIds(@Param("ids") List<String> ids);
}

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallOrderMapper.java

@ -34,4 +34,6 @@ public interface MallOrderMapper extends BaseMapper<MallOrder> {
Integer selectRefundCount(@Param("shopId") String shopId);
List<String> getWeChatId();
List<MallOrderVO> getPeiSongOrders(@Param("userId") String userId);
}

7
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallRefundRecord.java

@ -36,6 +36,8 @@ public class MallRefundRecord implements Serializable {
private BigDecimal refundAmount;
@ApiModelProperty(value = "退款原因")
private String reason;
@ApiModelProperty(value = "区域id")
private String regionId;
@ApiModelProperty(value = "退款图片")
private String pictures;
@ApiModelProperty(value = "退款状态 0:退款处理中 1:同意退款 2:(商家或者配送员)拒绝退款 退款失败 3售后中 4同意售后 5 (商家或者配送员)拒绝售后")
@ -61,6 +63,11 @@ public class MallRefundRecord implements Serializable {
@TableField(exist = false)
private MallOrder mallOrder;
@ApiModelProperty("售后订单配送详情")
@Transient
@TableField(exist = false)
private MallDeliveryOrder mallDeliveryOrder;
@ApiModelProperty("订单是否配送")
@Transient
@TableField(exist = false)

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallRefundRecordPageQuery.java

@ -20,6 +20,9 @@ public class MallRefundRecordPageQuery extends HiverBasePageQuery {
@ApiModelProperty(value = "关联的商家或者配送员ID 如果 refundType = 3 && refundTypeStatus == 3 MallRefundRecord存两条记录")
private String linkId;
@ApiModelProperty(value = "区域id")
private String regionId;
@ApiModelProperty("多种状态查")
private List<Integer> statusList;
}

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java

@ -83,4 +83,6 @@ public interface MallDeliveryOrderService extends IService<MallDeliveryOrder> {
MallDeliveryOrder selectByGroupId(String orderId);
MallOrder insertDeliveryOrder(MallDeliveryOrder deliveryOrder);
List<MallDeliveryOrder> selectByOrderIds(List<String> ids);
}

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java

@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
@ -86,4 +87,6 @@ public interface MallOrderService extends IService<MallOrder> {
MallOrder selectMallOrderByGroupId(@Param("groupId") String groupId);
Map<String, Object> countByShop(String shopId);
List<MallOrderVO> getPeiSongOrders(String userId);
}

100
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java

@ -13,12 +13,14 @@ import cc.hiver.mall.entity.*;
import cc.hiver.mall.mq.OrderAsyncProducer;
import cc.hiver.mall.pojo.query.MallDeliveryOrderPageQuery;
import cc.hiver.mall.pojo.query.MallRefundRecordPageQuery;
import cc.hiver.mall.pojo.vo.MallOrderVO;
import cc.hiver.mall.service.ShopService;
import cc.hiver.mall.service.mybatis.MallDeliveryOrderService;
import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.service.mybatis.MallRefundRecordService;
import cc.hiver.mall.service.mybatis.MallUserCouponService;
import cc.hiver.mall.utils.MerchantOrderSeqUtil;
import cc.hiver.mall.utils.UserPendingOrderCacheUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -34,6 +36,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
@ -83,6 +86,9 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
@Autowired
private MallOrderGroupMapper mallOrderGroupMapper;
@Autowired
private UserPendingOrderCacheUtil userPendingOrderCacheUtil;
@Autowired
private MallOrderGoodsMapper mallOrderGoodsMapper;
@ -178,6 +184,17 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
oUw.eq(MallOrder::getId, orderId)
.set(MallOrder::getNumberCode, latestSeq).set(MallOrder::getStatus, 3);
mallOrderService.update(oUw);
//更新缓存
delivery.setWorkerPhone(workerPhone);
delivery.setStatus(STATUS_WAIT_PICKUP);
delivery.setWorkerId(workerId);
delivery.setWorkerName(workerName);
delivery.setAcceptTime(new Date());
delivery.setMustFinishTime(mustFinishTime);
MallOrderVO orderVO = buildVO(orderInner, null, null, delivery);
orderVO.setStatus(3);
userPendingOrderCacheUtil.update(orderInner.getUserId(), orderVO);
//极光推送
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的订单",orderId);
numberCode+=latestSeq+"+";
}
@ -193,6 +210,17 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
.set(MallOrder::getNumberCode, latestSeq).set(MallOrder::getStatus, 3); // 待取货
//缺少根据groupId更新面对面团所有订单状态
mallOrderService.update(oUw);
//更新缓存
delivery.setWorkerPhone(workerPhone);
delivery.setStatus(STATUS_WAIT_PICKUP);
delivery.setWorkerId(workerId);
delivery.setWorkerName(workerName);
delivery.setAcceptTime(new Date());
delivery.setMustFinishTime(mustFinishTime);
MallOrderVO orderVO = buildVO(order, null, null, delivery);
orderVO.setStatus(3);
userPendingOrderCacheUtil.update(order.getUserId(), orderVO);
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的订单",delivery.getOrderId());
numberCode = latestSeq;
}
@ -209,6 +237,16 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
.set(MallOrder::getNumberCode, latestSeq).set(MallOrder::getStatus, 3); // 待取货
//缺少根据groupId更新面对面团所有订单状态
mallOrderService.update(oUw);
//更新缓存
delivery.setWorkerPhone(workerPhone);
delivery.setStatus(STATUS_WAIT_PICKUP);
delivery.setWorkerId(workerId);
delivery.setWorkerName(workerName);
delivery.setAcceptTime(new Date());
delivery.setMustFinishTime(mustFinishTime);
MallOrderVO orderVO = buildVO(order, null, null, delivery);
orderVO.setStatus(3);
userPendingOrderCacheUtil.update(order.getUserId(), orderVO);
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的订单",delivery.getOrderId());
numberCode = latestSeq;
}
@ -222,6 +260,19 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
return 3;
}
/**
* 构建返回 VO
*/
private MallOrderVO buildVO(MallOrder order, List<MallOrderGoods> goods,
MallOrderGroup group, MallDeliveryOrder delivery) {
MallOrderVO vo = new MallOrderVO();
org.springframework.beans.BeanUtils.copyProperties(order, vo);
vo.setGoodsList(goods);
vo.setGroupInfo(group);
vo.setDeliveryInfo(delivery);
return vo;
}
//设置商家出餐超时提醒
private void triggerShopCookTimeoutEvent(List<String> orderId) {
orderId.forEach(id -> {
@ -267,6 +318,15 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
LambdaUpdateWrapper<MallOrder> oUw = new LambdaUpdateWrapper<>();
oUw.in(MallOrder::getId, orderIds).set(MallOrder::getStatus, ORDER_STATUS_DELIVERING);
mallOrderService.update(oUw);
//更新缓存
for (String orderId : orderIds) {
MallOrder orderInner = mallOrderService.getById(orderId);
delivery.setGetTime(new Date());
delivery.setStatus(STATUS_DELIVERING);
MallOrderVO orderVO = buildVO(orderInner, null, null, delivery);
orderVO.setStatus(ORDER_STATUS_DELIVERING);
userPendingOrderCacheUtil.update(orderInner.getUserId(), orderVO);
}
}
}else{
// 同步订单状态 -> 配送中
@ -275,6 +335,12 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
oUw.eq(MallOrder::getId, delivery.getOrderId())
.set(MallOrder::getStatus, ORDER_STATUS_DELIVERING);
mallOrderService.update(oUw);
MallOrder orderInner = mallOrderService.getById(delivery.getOrderId());
delivery.setGetTime(new Date());
delivery.setStatus(STATUS_DELIVERING);
MallOrderVO orderVO = buildVO(orderInner, null, null, delivery);
orderVO.setStatus(ORDER_STATUS_DELIVERING);
userPendingOrderCacheUtil.update(orderInner.getUserId(), orderVO);
}
}
}
@ -304,7 +370,11 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
if(StringUtils.isNotBlank(delivery.getGroupId())){
MallOrderGroup group = mallOrderGroupMapper.selectById(delivery.getGroupId());
List<String> orderIdList = Arrays.asList(group.getGroupOrderIds().split(","));
//更新缓存
for (String orderId : orderIdList) {
MallOrder orderInner = mallOrderService.getById(orderId);
userPendingOrderCacheUtil.remove(orderInner.getUserId(),orderInner.getId());
}
LambdaUpdateWrapper<MallOrder> oqw = new LambdaUpdateWrapper<>();
oqw.in(MallOrder::getId, orderIdList).set(MallOrder::getStatus,ORDER_STATUS_DONE);
mallOrderService.update(oqw);
@ -321,6 +391,10 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
oUw.eq(MallOrder::getId, delivery.getOrderId())
.set(MallOrder::getStatus, ORDER_STATUS_DONE);
mallOrderService.update(oUw);
//更新缓存
MallOrder orderInner = mallOrderService.getById(delivery.getOrderId());
userPendingOrderCacheUtil.remove(orderInner.getUserId(),orderInner.getId());
//优惠券变成已使用
mallUserCouponService.useCoupon(delivery.getOrderId());
}
@ -329,19 +403,28 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
Worker worker = workerServiceImpl.findByWorkerId(delivery.getWorkerId());
//更新余额
worker.setDepoBal(worker.getDepoBal().add(delivery.getDeliveryFee()));
Integer oldCount = worker.getOrderCount();
Integer oldCount = worker.getOrderCount() == null ? 0 : worker.getOrderCount();
//更新单量
worker.setOrderCount(worker.getOrderGetCount() + 1);
worker.setOrderCount(oldCount + 1);
//更新配送时间
// 3.1 计算本次配送耗时 (毫秒)
long currentDuration = delivery.getFinishTime().getTime() - delivery.getAcceptTime().getTime();
long currentDuration = new Date().getTime() - delivery.getAcceptTime().getTime();
double minutesDouble = currentDuration / 60000.0;
// 2. 转换为 BigDecimal 并保留两位小数 (四舍五入)
BigDecimal minutesDecimal = new BigDecimal(minutesDouble)
.setScale(2, RoundingMode.HALF_UP);
BigDecimal oldAvgTime = worker.getAvgTime();
Integer newCount = oldCount + 1;
// 新的平均时间 = (旧平均时间 * 旧单量 + 本次配送时间) / 新单量
BigDecimal newAvgTime = oldAvgTime.multiply(new BigDecimal(oldCount))
.add(new BigDecimal(currentDuration))
.add(minutesDecimal)
.divide(new BigDecimal(newCount), 2, RoundingMode.HALF_UP);
worker.setAvgTime(newAvgTime);
DecimalFormat df = new DecimalFormat("00.00");
String formattedResult = df.format(newAvgTime);
worker.setAvgTime(new BigDecimal(formattedResult));
workerServiceImpl.update(worker);
}
@ -611,4 +694,9 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
this.baseMapper.insert(deliveryOrder);
return order;
}
@Override
public List<MallDeliveryOrder> selectByOrderIds(List<String> ids) {
return this.baseMapper.selectByOrderIds(ids);
}
}

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

@ -6,10 +6,12 @@ import cc.hiver.core.entity.Worker;
import cc.hiver.core.service.WorkerService;
import cc.hiver.mall.dao.mapper.*;
import cc.hiver.mall.entity.*;
import cc.hiver.mall.pojo.vo.MallOrderVO;
import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.service.mybatis.MallUserCouponService;
import cc.hiver.mall.utils.MerchantOrderSeqUtil;
import cc.hiver.mall.utils.UserPendingOrderCacheUtil;
import cc.hiver.mall.utils.WechatPayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@ -71,6 +73,9 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
@Autowired
private MallDeliveryOrderMapper mallDeliveryOrderMapper;
@Autowired
private UserPendingOrderCacheUtil userPendingOrderCacheUtil;
@Autowired
private WorkerService workerService;
@ -140,6 +145,9 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
.set(MallOrder::getStatus, targetStatus);
}
mallOrderService.update(ouw);
MallOrderVO orderVO = buildVO(order, null, null, null);
orderVO.setStatus(targetStatus);
userPendingOrderCacheUtil.update(order.getUserId(), orderVO);
if (order.getDeliveryType() != null && order.getDeliveryType() == 1) {
if (isFace2Face && !order.getId().equals(group.getHeadOrderId())) {
@ -198,6 +206,19 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
log.info("拼团 {} 成团成功,激活 {} 条子订单", groupId, waitingOrders.size());
}
/**
* 构建返回 VO
*/
private MallOrderVO buildVO(MallOrder order, List<MallOrderGoods> goods,
MallOrderGroup group, MallDeliveryOrder delivery) {
MallOrderVO vo = new MallOrderVO();
org.springframework.beans.BeanUtils.copyProperties(order, vo);
vo.setGoodsList(goods);
vo.setGroupInfo(group);
vo.setDeliveryInfo(delivery);
return vo;
}
/**
* 触发配送订单异步事件微信推给骑手加入超时检查死信队列等
*/

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

@ -21,6 +21,7 @@ import cc.hiver.mall.service.mybatis.MallDeliveryOrderService;
import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.utils.MerchantOrderSeqUtil;
import cc.hiver.mall.utils.UserPendingOrderCacheUtil;
import cc.hiver.mall.utils.WechatPayUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
@ -91,6 +92,9 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
@Autowired
private MallDeliveryOrderService mallDeliveryOrderService;
@Autowired
private UserPendingOrderCacheUtil userPendingOrderCacheUtil;
@Autowired
JPushServiceImpl jPushService;
@ -187,9 +191,6 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
for (CreateOrderDTO.OrderItemDTO item : dto.getItems()) {
Product product = productMap.get(item.getProductId());
shopSaleCount += item.getQuantity();
// 扣减库存(更新 attributeListPrice 中的 specNum)以及销量
deductStock(product, item.getQuantity());
// 累计商品金额
goodsAmount = goodsAmount.add(item.getPrice().multiply(new BigDecimal(item.getQuantity())));
@ -204,11 +205,6 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
snapshot.setQuantity(item.getQuantity());
goodsSnapshots.add(snapshot);
}
//更新店铺销量
if(shopSaleCount != 0){
shopMapper.update(null,new UpdateWrapper<Shop>().eq("id",dto.getShopId()).set("sale_count",shopSaleCount));
}
// 增量更新Redis缓存(店铺销量 + 商品销量),改为交给MQ异步处理
try {
java.util.Map<String, Object> asyncParams = new java.util.HashMap<>();
@ -496,6 +492,9 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
// 直购支付成功 -> 跳过待商家接单,直接进入待配送或待消费
if (DELIVERY_TYPE_EXPRESS == order.getDeliveryType()) {
updateOrderStatus(orderId, STATUS_WAIT_DELIVERY);
MallOrderVO orderVO = buildVO(order, null, null, null);
orderVO.setStatus(STATUS_WAIT_DELIVERY);
userPendingOrderCacheUtil.update(order.getUserId(), orderVO);
// 激活配送单,状态改为待接单(0)
Date createTime = new Timestamp(System.currentTimeMillis());
// 1. 获取当前时间 (LocalDateTime)
@ -516,10 +515,16 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
LambdaUpdateWrapper<MallOrder> uw = new LambdaUpdateWrapper<>();
uw.eq(MallOrder::getId, orderId).set(MallOrder::getStatus, STATUS_WAIT_PICKUP).set(MallOrder::getNumberCode, latestSeq);
this.update(uw);
MallOrderVO orderVO = buildVO(order, null, null, null);
orderVO.setStatus(STATUS_WAIT_PICKUP);
userPendingOrderCacheUtil.update(order.getUserId(), orderVO);
}
} else if (order.getOrderType() == ORDER_TYPE_GROUP || order.getOrderType() == ORDER_TYPE_FACETOFACE) {
// 拼团订单支付成功 -> 改为待成团
updateOrderStatus(orderId, STATUS_WAIT_GROUP);
MallOrderVO orderVO = buildVO(order, null, null, null);
orderVO.setStatus(STATUS_WAIT_GROUP);
userPendingOrderCacheUtil.update(order.getUserId(), orderVO);
// 查找属于该订单的拼团并检查成团条件
LambdaQueryWrapper<MallOrderGroup> gq = new LambdaQueryWrapper<>();
@ -686,6 +691,10 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
// ---- 1. 未支付 ----
if (order.getStatus() == STATUS_WAIT_PAY) {
updateOrderStatus(order.getId(), STATUS_CANCELLED);
//回退优惠券
mallUserCouponService.refundCoupon(order.getId());
//更新缓存
userPendingOrderCacheUtil.remove(order.getUserId(), order.getId());
//cancelDeliveryOrderByOrderId(order.getId());
//String remainingIds = removeOrderIdStr(group.getGroupOrderIds(), order.getId());
@ -775,6 +784,10 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
// ---- 1. 未支付 ----
if (order.getStatus() == STATUS_WAIT_PAY) {
updateOrderStatus(order.getId(), STATUS_CANCELLED);
//回退优惠券
mallUserCouponService.refundCoupon(order.getId());
//更新缓存
userPendingOrderCacheUtil.remove(order.getUserId(), order.getId());
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){
cancelDeliveryOrderByOrderId(order.getId());
}
@ -905,6 +918,10 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
// ---- 1. 未支付 ----
if (order.getStatus() == STATUS_WAIT_PAY) {
updateOrderStatus(order.getId(), STATUS_CANCELLED);
//回退优惠券
mallUserCouponService.refundCoupon(order.getId());
//更新缓存
userPendingOrderCacheUtil.remove(order.getUserId(), order.getId());
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){
cancelDeliveryOrderByOrderId(order.getId());
}
@ -961,6 +978,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
}
@Override
@Transactional(rollbackFor = Exception.class)
public void shopMakeTime(String orderId) {
LambdaUpdateWrapper<MallOrder> uw = new LambdaUpdateWrapper<>();
uw.eq(MallOrder::getId, orderId).set(MallOrder::getShopMakeTime,new Date());
@ -969,6 +987,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
//自取订单用户点击立即出餐
@Override
@Transactional(rollbackFor = Exception.class)
public void userRequireMake(String orderId) {
MallOrder order = this.getById(orderId);
LambdaUpdateWrapper<MallOrder> uw = new LambdaUpdateWrapper<>();
@ -1013,6 +1032,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
//优惠券变成已使用
mallUserCouponService.useCoupon(orderId);
updateOrderStatus(orderId, STATUS_DONE);
//更新缓存
userPendingOrderCacheUtil.remove(order.getUserId(),order.getId());
}
@Override
@ -1043,6 +1064,24 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
return result;
}
@Override
public List<MallOrderVO> getPeiSongOrders(String userId) {
List<MallOrderVO> orders = this.baseMapper.getPeiSongOrders(userId);
if(orders != null && !orders.isEmpty()){
orders.forEach(order -> {
// 配送信息
if(order.getOrderType() == ORDER_TYPE_FACETOFACE){
order.setDeliveryInfo(mallDeliveryOrderMapper.selectByGroupId(order.getId()));
}else{
LambdaQueryWrapper<MallDeliveryOrder> dq = new LambdaQueryWrapper<>();
dq.eq(MallDeliveryOrder::getOrderId, order.getId()).last("LIMIT 1");
order.setDeliveryInfo(mallDeliveryOrderMapper.selectOne(dq));
}
});
}
return orders;
}
// ================================================================
// 查询
// ================================================================
@ -1202,8 +1241,15 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
ShopCacheDTO cacheDTO = JSONUtil.toBean(shopJson, ShopCacheDTO.class);
if (cacheDTO.getShop() != null) {
Integer oldSaleCount = cacheDTO.getShop().getSaleCount();
cacheDTO.getShop().setSaleCount((oldSaleCount != null ? oldSaleCount : 0) + shopSaleCount);
cacheDTO.getShop().setSaleCount((oldSaleCount != null ? oldSaleCount : 0) + 1);
//更新店铺销量
if(shopSaleCount != 0){
Shop shop = shopService.findById(shopId);
Integer oldSaleCount1 = shop.getSaleCount() == null ? 0 : shop.getSaleCount();
shopMapper.update(null,new UpdateWrapper<Shop>().eq("id",shopId).set("sale_count",(oldSaleCount1 != null ? oldSaleCount1 : 0) + 1));
}
redisTemplateHelper.hPut(shopCacheKey, shopId, JSONUtil.toJsonStr(cacheDTO));
}
}
}
@ -1225,8 +1271,19 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
String pid = productObj.getStr("id");
if (pid != null && quantityMap.containsKey(pid)) {
int oldTailWarn = productObj.getInt("tailWarn", 0);
productObj.set("tailWarn", oldTailWarn + quantityMap.get(pid));
int qty = quantityMap.get(pid);
productObj.set("tailWarn", oldTailWarn + qty);
changed = true;
// 扣减库存(更新 attributeListPrice 中的 specNum)以及销量
Product product = productMap.get(pid);
if (product != null) {
deductStock(product, qty);
// 同步更新缓存中的 attributeListPrice
String updatedAttrJson = productMapper.selectById(pid).getAttributeListPrice();
if (StringUtils.isNotBlank(updatedAttrJson)) {
productObj.set("attributeListPrice", updatedAttrJson);
}
}
}
}
if (changed) {
@ -1449,6 +1506,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
record.setOrderId(order.getId());
record.setUserId(order.getUserId());
record.setRefundAmount(amount);
record.setRegionId(order.getRegionId());
record.setReason(reason);
if(order.getGroupOrderIds() != null){
record.setGroupOrderIds(order.getGroupOrderIds());
@ -1636,8 +1694,11 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
*/
private void autoRefund(MallOrder order, String reason) {
updateOrderStatus(order.getId(), STATUS_REFUNDED);
//更新缓存
userPendingOrderCacheUtil.remove(order.getUserId(), order.getId());
MallRefundRecord record = new MallRefundRecord();
record.setOrderId(order.getId());
record.setRegionId(order.getRegionId());
record.setUserId(order.getUserId());
record.setRefundAmount(order.getTotalAmount());
record.setReason(reason);
@ -1647,6 +1708,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
record.setRefundType(3);
record.setRefundTypeStatus(4);
mallRefundRecordMapper.insert(record);
//回退优惠券
mallUserCouponService.refundCoupon(order.getId());
wechatPayUtil.refund(order.getId(), order.getTotalAmount().multiply(new BigDecimal(100)).longValue(), order.getTotalAmount().multiply(new BigDecimal(100)).longValue());
List<MallOrderGoods> goodsList = mallOrderGoodsMapper.selectByOrderId(order.getId());
if (goodsList == null || goodsList.isEmpty()) return;
@ -1672,6 +1735,10 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
*/
private void applyMerchantRefund(String workerId, MallOrder order, String reason,Integer refundType,Integer refundTypeStatus) {
updateOrderStatus(order.getId(), STATUS_WAIT_REFUND);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_WAIT_REFUND);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
//如果是外卖,更新配送单状态
if(order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){
LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>();

79
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java

@ -6,9 +6,11 @@ import cc.hiver.core.serviceimpl.WorkerServiceImpl;
import cc.hiver.mall.dao.mapper.*;
import cc.hiver.mall.entity.*;
import cc.hiver.mall.pojo.query.MallRefundRecordPageQuery;
import cc.hiver.mall.pojo.vo.MallOrderVO;
import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.service.mybatis.MallRefundRecordService;
import cc.hiver.mall.service.mybatis.MallUserCouponService;
import cc.hiver.mall.utils.UserPendingOrderCacheUtil;
import cc.hiver.mall.utils.WechatPayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@ -17,6 +19,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
@ -39,6 +42,8 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
private static final int STATUS_REFUNDED = 8;
private static final int STATUS_LAST_REFUNDED = 12;
private static final int ORDER_TYPE_FACETOFACE = 3;
// 配送方式常量// 外卖
private static final int DELIVERY_TYPE_SELF = 2;// 外
private static final int DELIVERY_TYPE_PEISONG = 1;
@ -64,6 +69,9 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
@Autowired
private MallUserCouponService mallUserCouponService;
@Autowired
private UserPendingOrderCacheUtil userPendingOrderCacheUtil;
@Autowired
private MallOrderGoodsMapper mallOrderGoodsMapper;
@ -82,12 +90,14 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
private WorkerServiceImpl workerServiceImpl;
@Override
@Transactional(rollbackFor = Exception.class)
public void create(MallRefundRecord mallRefundRecord) {
//更新订单为 待售后
LambdaUpdateWrapper<MallOrder> oUw = new LambdaUpdateWrapper<>();
oUw.eq(MallOrder::getId, mallRefundRecord.getOrderId())
.set(MallOrder::getStatus, 11);
mallOrderService.update(oUw);
MallOrder order = mallOrderService.getById(mallRefundRecord.getOrderId());
BigDecimal ratio = null;
LambdaQueryWrapper<MallUserCoupon> uq = new LambdaQueryWrapper<>();
uq.eq(MallUserCoupon::getOrderId, mallRefundRecord.getOrderId());
@ -108,6 +118,7 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
//如果是全额退款商家问题给商家加一条如果是配送问题给配送员加一条 如果两者都有给两者都加一条(处理以后需要查一下还有没有没处理的再更新订单状态)
mallRefundRecord.setStatus(3); // 申请售后
mallRefundRecord.setCreateTime(new Date());
mallRefundRecord.setRegionId(order.getRegionId());
if(mallRefundRecord.getRefundType() == 1){
// 退商品
mallRefundRecord.setLinkId(mallRefundRecord.getShopId());
@ -172,6 +183,7 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateStatus(MallRefundRecord mallRefundRecord) {
LambdaUpdateWrapper<MallRefundRecord> uw = new LambdaUpdateWrapper<>();
uw.eq(MallRefundRecord::getId, mallRefundRecord.getId())
@ -200,7 +212,9 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
//都同意退款
if(!hasReject){
//同意退款
//MallOrder order = mallOrderService.getById(mallRefundRecord.getOrderId());
MallOrder order = mallOrderService.getById(mallRefundRecord.getOrderId());
//更新缓存
userPendingOrderCacheUtil.remove(order.getUserId(), order.getId());
updateOrderStatus(mallRefundRecord.getOrderId(), STATUS_REFUNDED);
//回退优惠券
mallUserCouponService.refundCoupon(mallRefundRecord.getOrderId());
@ -223,18 +237,30 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
}
}else{
//拒绝退款
//MallOrder order = mallOrderService.getById(mallRefundRecord.getOrderId());
MallOrder order = mallOrderService.getById(mallRefundRecord.getOrderId());
//如果是自取订单,则恢复待消费状态
if(mallRefundRecord.getDeliveryType() == DELIVERY_TYPE_SELF){
updateOrderStatusAndReturn(mallRefundRecord.getOrderId(), STATUS_WAIT_PICKUP);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_WAIT_PICKUP);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
}else{
//面对面拼团
if(mallRefundRecord.getOrderType() == STATUS_WAIT_PICKUP){
MallDeliveryOrder delivery = mallDeliveryOrderMapper.selectByGroupId(mallRefundRecord.getOrderId());
if(delivery.getStatus() == STATUS_WAIT_SHOP){
updateOrderStatusAndReturn(mallRefundRecord.getOrderId(), STATUS_WAIT_PICKUP);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_WAIT_PICKUP);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
}else if(delivery.getStatus() == DELIVERY_TYPE_SELF){
updateOrderStatusAndReturn(mallRefundRecord.getOrderId(), STATUS_DELIVERING);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_DELIVERING);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
}
//更新配送单isReturn
LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>();
@ -245,8 +271,16 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
MallDeliveryOrder delivery = findDeliveryByOrderId(mallRefundRecord.getOrderId());
if(delivery.getStatus() == STATUS_WAIT_SHOP){
updateOrderStatusAndReturn(mallRefundRecord.getOrderId(), STATUS_WAIT_PICKUP);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_WAIT_PICKUP);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
}else if(delivery.getStatus() == DELIVERY_TYPE_SELF){
updateOrderStatusAndReturn(mallRefundRecord.getOrderId(), STATUS_DELIVERING);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_DELIVERING);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
}
//更新配送单isReturn
LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>();
@ -292,18 +326,30 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
if(isTuiKuan){
//拒绝退款
if(mallRefundRecord.getStatus() == 2){
//MallOrder order = mallOrderService.getById(mallRefundRecord.getOrderId());
MallOrder order = mallOrderService.getById(mallRefundRecord.getOrderId());
//如果是自取订单,则恢复待消费状态
if(mallRefundRecord.getDeliveryType() == DELIVERY_TYPE_SELF){
updateOrderStatusAndReturn(mallRefundRecord.getOrderId(), STATUS_WAIT_PICKUP);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_WAIT_PICKUP);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
}else{
//面对面拼团
if(mallRefundRecord.getOrderType() == STATUS_WAIT_PICKUP){
MallDeliveryOrder delivery = mallDeliveryOrderMapper.selectByGroupId(mallRefundRecord.getOrderId());
if(delivery.getStatus() == STATUS_WAIT_SHOP){
updateOrderStatusAndReturn(mallRefundRecord.getOrderId(), STATUS_WAIT_PICKUP);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_WAIT_PICKUP);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
}else if(delivery.getStatus() == DELIVERY_TYPE_SELF){
updateOrderStatusAndReturn(mallRefundRecord.getOrderId(), STATUS_DELIVERING);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_DELIVERING);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
}
//更新配送单isReturn
LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>();
@ -314,8 +360,16 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
MallDeliveryOrder delivery = findDeliveryByOrderId(mallRefundRecord.getOrderId());
if(delivery.getStatus() == STATUS_WAIT_SHOP){
updateOrderStatusAndReturn(mallRefundRecord.getOrderId(), STATUS_WAIT_PICKUP);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_WAIT_PICKUP);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
}else if(delivery.getStatus() == DELIVERY_TYPE_SELF){
updateOrderStatusAndReturn(mallRefundRecord.getOrderId(), STATUS_DELIVERING);
//更新缓存
MallOrderVO vo = userPendingOrderCacheUtil.get(order.getUserId(), order.getId());
vo.setStatus(STATUS_DELIVERING);
userPendingOrderCacheUtil.update(order.getUserId(),vo);
}
//更新配送单isReturn
LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>();
@ -326,8 +380,10 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
}
}else{
//同意退款
//MallOrder order = mallOrderService.getById(mallRefundRecord.getOrderId());
MallOrder order = mallOrderService.getById(mallRefundRecord.getOrderId());
updateOrderStatus(mallRefundRecord.getOrderId(), STATUS_REFUNDED);
//更新缓存
userPendingOrderCacheUtil.remove(order.getUserId(), order.getId());
//回退优惠券
mallUserCouponService.refundCoupon(mallRefundRecord.getOrderId());
if(mallRefundRecord.getDeliveryType() == DELIVERY_TYPE_PEISONG){
@ -429,7 +485,20 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
// 4. 组装到每个 VO
for (MallRefundRecord vo : records) {
vo.setItems(goodsMap.getOrDefault(vo.getOrderId(), java.util.Collections.emptyList()));
vo.setMallOrder(orderMap.getOrDefault(vo.getOrderId(), new java.util.ArrayList<>()).get(0));
MallOrder order = orderMap.getOrDefault(vo.getOrderId(), new java.util.ArrayList<>()).get(0);
if(order != null){
vo.setMallOrder(order);
if(order.getDeliveryType() == DELIVERY_TYPE_PEISONG){
// 配送信息
if(order.getOrderType() == ORDER_TYPE_FACETOFACE){
vo.setMallDeliveryOrder(mallDeliveryOrderMapper.selectByGroupId(order.getId()));
}else{
LambdaQueryWrapper<MallDeliveryOrder> dq = new LambdaQueryWrapper<>();
dq.eq(MallDeliveryOrder::getOrderId, order.getId()).last("LIMIT 1");
vo.setMallDeliveryOrder(mallDeliveryOrderMapper.selectOne(dq));
}
}
}
}
}
return result;

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallUserCouponServiceImpl.java

@ -122,7 +122,7 @@ public class MallUserCouponServiceImpl extends ServiceImpl<MallUserCouponMapper,
@Override
public boolean refundCoupon(String orderId) {
UpdateWrapper<MallUserCoupon> uw = new UpdateWrapper<>();
uw.eq("order_id", orderId).in("status", 1, 2)
uw.eq("order_id", orderId)
.set("status", 0)
.set("order_id", null)
.set("use_time", null);

273
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/UserPendingOrderCacheUtil.java

@ -0,0 +1,273 @@
package cc.hiver.mall.utils;
import cc.hiver.core.common.redis.RedisTemplateHelper;
import cc.hiver.mall.pojo.vo.MallOrderVO;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 用户待完成订单缓存工具类
* <p>
* 底层使用 Redis Hash 结构保证按 userId + orderId 维度的 O(1) 读写效率
* <pre>
* Key = USER_PENDING_ORDERS:{userId}
* Field = orderId
* Value = MallOrderVO JSON 序列化
* </pre>
* <p>
* 使用场景订单状态发生变化时创建更新取消完成等
* 由业务方主动调用本工具类的方法维护缓存以减少 getOrdersByUserId 接口对数据库的查询压力
*
* @author system
*/
@Slf4j
@Component
public class UserPendingOrderCacheUtil {
/** Redis Key 前缀 */
private static final String KEY_PREFIX = "USER_PENDING_ORDERS:";
/** 订单完成/取消/退款等不再属于"待完成"的状态集合 */
private static final int STATUS_DONE = 5;
private static final int STATUS_CANCELLED = 6;
private static final int STATUS_REFUNDED = 8;
private static final int STATUS_RETURNED = 12;
@Autowired
private RedisTemplateHelper redisTemplateHelper;
// ================================================================
// Key 构建
// ================================================================
private String buildKey(String userId) {
return KEY_PREFIX + userId;
}
// ================================================================
// 存放(put)
// ================================================================
/**
* 存放单个订单到缓存
*
* @param userId 用户ID
* @param orderVO 订单VO必须包含有效的 id
*/
public void put(String userId, MallOrderVO orderVO) {
if (StringUtils.isBlank(userId) || orderVO == null || StringUtils.isBlank(orderVO.getId())) {
log.warn("UserPendingOrderCacheUtil.put 参数无效, userId={}, orderVO={}", userId, orderVO);
return;
}
try {
String key = buildKey(userId);
String json = JSONUtil.toJsonStr(orderVO);
redisTemplateHelper.hPut(key, orderVO.getId(), json);
log.debug("缓存用户待完成订单: userId={}, orderId={}", userId, orderVO.getId());
} catch (Exception e) {
log.error("缓存用户待完成订单失败: userId={}, orderId={}", userId, orderVO.getId(), e);
}
}
/**
* 批量存放订单到缓存通常用于缓存预热 / 首次加载
*
* @param userId 用户ID
* @param orders 订单列表
*/
public void putAll(String userId, List<MallOrderVO> orders) {
if (StringUtils.isBlank(userId) || orders == null || orders.isEmpty()) {
return;
}
try {
String key = buildKey(userId);
java.util.Map<String, String> map = new java.util.LinkedHashMap<>(orders.size());
for (MallOrderVO order : orders) {
if (order != null && StringUtils.isNotBlank(order.getId())) {
map.put(order.getId(), JSONUtil.toJsonStr(order));
}
}
if (!map.isEmpty()) {
redisTemplateHelper.hPutAll(key, map);
log.debug("批量缓存用户待完成订单: userId={}, count={}", userId, map.size());
}
} catch (Exception e) {
log.error("批量缓存用户待完成订单失败: userId={}", userId, e);
}
}
// ================================================================
// 删除(remove)
// ================================================================
/**
* 根据 userId orderId 从缓存中删除指定订单
* <p>
* 典型场景订单完成取消退款成功后调用
*
* @param userId 用户ID
* @param orderId 订单ID
*/
public void remove(String userId, String orderId) {
if (StringUtils.isBlank(userId) || StringUtils.isBlank(orderId)) {
log.warn("UserPendingOrderCacheUtil.remove 参数无效, userId={}, orderId={}", userId, orderId);
return;
}
try {
String key = buildKey(userId);
redisTemplateHelper.hDelete(key, orderId);
log.debug("删除用户待完成订单缓存: userId={}, orderId={}", userId, orderId);
} catch (Exception e) {
log.error("删除用户待完成订单缓存失败: userId={}, orderId={}", userId, orderId, e);
}
}
/**
* 清除指定用户的所有待完成订单缓存
* <p>
* 典型场景需要强制刷新该用户缓存时调用
*
* @param userId 用户ID
*/
public void removeAll(String userId) {
if (StringUtils.isBlank(userId)) {
return;
}
try {
redisTemplateHelper.delete(buildKey(userId));
log.debug("清除用户全部待完成订单缓存: userId={}", userId);
} catch (Exception e) {
log.error("清除用户全部待完成订单缓存失败: userId={}", userId, e);
}
}
// ================================================================
// 更新(update)
// ================================================================
/**
* 根据 userId orderId 更新缓存中的订单信息
* <p>
* 如果更新后的订单状态已经不属于"待完成"status {5,6,8,12}
* 则自动从缓存中移除该订单无需调用方额外判断
*
* @param userId 用户ID
* @param orderVO 更新后的订单VO
*/
public void update(String userId, MallOrderVO orderVO) {
if (StringUtils.isBlank(userId) || orderVO == null || StringUtils.isBlank(orderVO.getId())) {
log.warn("UserPendingOrderCacheUtil.update 参数无效, userId={}, orderVO={}", userId, orderVO);
return;
}
try {
// 如果订单状态已不属于待完成,直接删除
if (isTerminalStatus(orderVO.getStatus())) {
remove(userId, orderVO.getId());
log.debug("订单已终态,从缓存移除: userId={}, orderId={}, status={}",
userId, orderVO.getId(), orderVO.getStatus());
return;
}
// 否则覆盖更新
put(userId, orderVO);
log.debug("更新用户待完成订单缓存: userId={}, orderId={}, status={}",
userId, orderVO.getId(), orderVO.getStatus());
} catch (Exception e) {
log.error("更新用户待完成订单缓存失败: userId={}, orderId={}", userId, orderVO.getId(), e);
}
}
// ================================================================
// 查询(get)
// ================================================================
/**
* 获取用户全部待完成订单缓存
*
* @param userId 用户ID
* @return 缓存的订单列表缓存不存在时返回 null调用方可据此判断是否需要回源查库
*/
public List<MallOrderVO> getAll(String userId) {
if (StringUtils.isBlank(userId)) {
return null;
}
try {
String key = buildKey(userId);
Map<Object, Object> entries = redisTemplateHelper.hGetAll(key);
if (entries == null || entries.isEmpty()) {
return null;
}
List<MallOrderVO> result = new ArrayList<>(entries.size());
for (Object value : entries.values()) {
if (value != null) {
result.add(JSONUtil.toBean(value.toString(), MallOrderVO.class));
}
}
return result;
} catch (Exception e) {
log.error("获取用户待完成订单缓存失败: userId={}", userId, e);
return null;
}
}
/**
* 获取用户缓存中的单个订单
*
* @param userId 用户ID
* @param orderId 订单ID
* @return 缓存的订单VO不存在时返回 null
*/
public MallOrderVO get(String userId, String orderId) {
if (StringUtils.isBlank(userId) || StringUtils.isBlank(orderId)) {
return null;
}
try {
String key = buildKey(userId);
Object value = redisTemplateHelper.hGet(key, orderId);
if (value == null) {
return null;
}
return JSONUtil.toBean(value.toString(), MallOrderVO.class);
} catch (Exception e) {
log.error("获取用户单个待完成订单缓存失败: userId={}, orderId={}", userId, orderId, e);
return null;
}
}
/**
* 判断该用户的缓存是否已存在
*
* @param userId 用户ID
* @return true 表示缓存存在
*/
public boolean exists(String userId) {
if (StringUtils.isBlank(userId)) {
return false;
}
Boolean hasKey = redisTemplateHelper.hasKey(buildKey(userId));
return hasKey != null && hasKey;
}
// ================================================================
// 内部工具
// ================================================================
/**
* 判断订单状态是否为终态不再属于"待完成"
*/
private boolean isTerminalStatus(Integer status) {
if (status == null) {
return false;
}
return status == STATUS_DONE
|| status == STATUS_CANCELLED
|| status == STATUS_REFUNDED
|| status == STATUS_RETURNED;
}
}

21
hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml

@ -202,6 +202,27 @@
</select>
<select id="selectByOrderIds" resultMap="deliveryMap">
-- 第一部分:直接查 order_id
SELECT * FROM mall_delivery_order WHERE order_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
UNION -- 使用 UNION 自动去重(如果想去重)
-- 第二部分:通过 group_id 关联查
SELECT * FROM mall_delivery_order
WHERE group_id IN (
SELECT id FROM mall_order_group
WHERE
<foreach collection="ids" item="id" open="(" separator=" OR " close=")">
FIND_IN_SET(#{id}, group_order_ids)
</foreach>
)
</select>
<select id="countOrdersByStatus" resultType="map">
SELECT status ,count(*) as orderCount FROM `mall_delivery_order` where `status` in (0,1,2)
and worker_id = #{workerId} GROUP BY status

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

@ -204,4 +204,8 @@
select u.official_account_openid from t_worker w LEFT JOIN t_user u on w.user_id = u.id where u.official_account_openid is not null
</select>
<select id="getPeiSongOrders" resultMap="mallOrderVOMap">
select * from mall_order where status not in (5,6,8,12) and user_id = #{userId}
</select>
</mapper>

4
hiver-modules/hiver-mall/src/main/resources/mapper/MallRefundRecordMapper.xml

@ -17,6 +17,7 @@
<result column="refund_type_status" property="refundTypeStatus"/>
<result column="link_id" property="linkId"/>
<result column="group_order_ids" property="groupOrderIds"/>
<result column="region_id" property="regionId"/>
</resultMap>
<select id="selectPageVO" resultMap="refundMap">
@ -25,6 +26,9 @@
<if test="q.linkId != null and q.linkId != ''">
AND link_id = #{q.linkId}
</if>
<if test="q.regionId != null and q.regionId != ''">
AND region_id = #{q.regionId}
</if>
<if test="q.status != null">
AND status = #{q.status}
</if>

Loading…
Cancel
Save