Browse Source

对接拼团数据1

master
wangfukang 1 month ago
parent
commit
97baefc6a6
  1. 16
      hiver-admin/test-output/test-report.html
  2. 5
      hiver-core/src/main/java/cc/hiver/core/entity/User.java
  3. 4
      hiver-core/src/main/java/cc/hiver/core/vo/WechatVo.java
  4. 8
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/UserController.java
  5. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallCouponController.java
  6. 54
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java
  7. 13
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ReturnCommissionController.java
  8. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerController.java
  9. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallCoupon.java
  10. 22
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderAsyncProducer.java
  11. 55
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderDelayConsumer.java
  12. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallCouponQuery.java
  13. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/WorkerMatchVO.java
  14. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java
  15. 11
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java
  16. 8
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java
  17. 15
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java
  18. 94
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/AliPayNewUtil.java
  19. 10
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/AliPayUtil.java
  20. 65
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DeliveryRejectUtil.java
  21. 37
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/RedisLuaScripts.java
  22. 7
      hiver-modules/hiver-mall/src/main/resources/mapper/MallCouponMapper.xml
  23. 9
      pom.xml

16
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">四月 27, 2026 15:09:48</span></a>
<a href="#"><span class="badge badge-primary">五月 06, 2026 18:07:29</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:09:49 下午</span> / <span>0.015 secs</span></p>
<p class="text-sm"><span>18:07:30 下午</span> / <span>0.016 secs</span></p>
</div>
<div class="test-contents d-none">
<div class="detail-head">
@ -92,9 +92,9 @@
<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.27.2026 15:09:49</span>
<span class='badge badge-danger'>04.27.2026 15:09:49</span>
<span class='badge badge-default'>0.015 secs</span>
<span class='badge badge-success'>05.06.2026 18:07:30</span>
<span class='badge badge-danger'>05.06.2026 18:07:30</span>
<span class='badge badge-default'>0.016 secs</span>
</div>
<div class="m-t-10 m-l-5"></div>
</div>
@ -104,7 +104,7 @@
<tbody>
<tr class="event-row">
<td><span class="badge log pass-bg">Pass</span></td>
<td>15:09:49</td>
<td>18:07:30</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>四月 27, 2026 15:09:48</h3>
<h3>五月 06, 2026 18:07:29</h3>
</div></div>
</div>
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Ended</p>
<h3>四月 27, 2026 15:09:49</h3>
<h3>五月 06, 2026 18:07:30</h3>
</div></div>
</div>
<div class="col-md-3">

5
hiver-core/src/main/java/cc/hiver/core/entity/User.java

@ -112,7 +112,7 @@ public class User extends HiverBaseEntity {
@ApiModelProperty(value = "导入数据时使用")
private Integer defaultRole;
@ApiModelProperty(value = "邀请人ID")
@ApiModelProperty(value = "是否为新用户 no 不是")
private String inviteCode;
@ApiModelProperty(value = "设备编号 推送用")
@ -137,4 +137,7 @@ public class User extends HiverBaseEntity {
@ApiModelProperty(value = "微信昵称")
private String wechatName;
@ApiModelProperty(value = "邀请人Id")
private String inviterId;
}

4
hiver-core/src/main/java/cc/hiver/core/vo/WechatVo.java

@ -14,8 +14,8 @@ public class WechatVo {
@ApiModelProperty(value = "grantType")
private String grantType = "authorization_code";
@ApiModelProperty(value = "customId")
private String customId;
@ApiModelProperty(value = "inviterId")
private String inviterId;
@ApiModelProperty(value = "wechatName")
private String wechatName;

8
hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/UserController.java

@ -642,6 +642,10 @@ public class UserController {
final String encryptPass = new BCryptPasswordEncoder().encode("123456");
wechatUser.setPassword(encryptPass);
wechatUser.setType(UserConstant.USER_TYPE_NORMAL);
//设置邀请人
if(wechatVo.getInviterId() != null){
wechatUser.setInviterId(wechatVo.getInviterId());
}
wechatUser = userService.save(wechatUser);
// 设置用户角色
// 默认角色
@ -653,10 +657,10 @@ public class UserController {
}
}
// 更新客户信息,绑定登录用户
customerService.updateUserId(wechatVo.getCustomId(), wechatUser.getId());
//customerService.updateUserId(wechatVo.getCustomId(), wechatUser.getId());
// 返回当前登录人的信息
resultMap.put("msg", "新增用户信息,并绑定成功!");
resultMap.put("customId", wechatVo.getCustomId());
//resultMap.put("customId", wechatVo.getCustomId());
} catch (Exception e) {
return ResultUtil.error(e.getMessage());
}

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallCouponController.java

@ -47,6 +47,7 @@ public class MallCouponController {
@PostMapping("/add")
@ApiOperation(value = "添加/发行优惠券")
public Result<Object> addCoupon(@RequestBody MallCoupon coupon) {
coupon.setRemainCount(coupon.getTotalCount());
mallCouponService.save(coupon);
return ResultUtil.success("发行成功");
}

54
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java

@ -171,9 +171,17 @@ public class MallDeliveryOrderController {
*/
@PostMapping("/accept")
@ApiOperation(value = "配送员接单", notes = "抢单大厅单或指派单均通过此接口接单")
public Result<Worker> accept(@RequestParam String deliveryId,
public Result<Worker> accept(@RequestParam String deliveryId,@RequestParam String geolocation,
@RequestParam String workerId,@RequestParam String workerPhone,@RequestParam String workerName,@RequestParam String regionId,@RequestParam String groupId) {
try {
Worker worker1 = workerService.findByWorkerId(workerId);
worker1.setGeolocation(geolocation);
workerService.update(worker1);
WorkerRedisVo workerRedisVo = workerRedisCacheUtil.get(regionId, workerId);
if(workerRedisVo != null){
workerRedisVo.setWorker(worker1);
}
workerRedisCacheUtil.update(regionId, workerRedisVo);
if(StrUtil.isBlank(workerId)){
//当前人没有注册兼职,先赋予兼职身份
final User user = securityUtil.getCurrUser();
@ -226,9 +234,17 @@ public class MallDeliveryOrderController {
*/
@PostMapping("/arriveShop")
@ApiOperation("配送员到店)")
public Result arriveShop(@RequestParam String deliveryId,
@RequestParam String workerId) {
public Result arriveShop(@RequestParam String deliveryId,@RequestParam String geolocation,
@RequestParam String regionId,@RequestParam String workerId) {
try {
Worker worker1 = workerService.findByWorkerId(workerId);
worker1.setGeolocation(geolocation);
workerService.update(worker1);
WorkerRedisVo workerRedisVo = workerRedisCacheUtil.get(regionId, workerId);
if(workerRedisVo != null){
workerRedisVo.setWorker(worker1);
}
workerRedisCacheUtil.update(regionId, workerRedisVo);
mallDeliveryOrderService.arriveShop(deliveryId, workerId);
return ResultUtil.success("到店成功");
} catch (Exception e) {
@ -257,9 +273,17 @@ public class MallDeliveryOrderController {
*/
@PostMapping("/pickup")
@ApiOperation("配送员取货(待取货 -> 配送中)")
public Result pickup(@RequestParam String deliveryId,
@RequestParam String workerId) {
public Result pickup(@RequestParam String deliveryId,@RequestParam String geolocation,
@RequestParam String regionId,@RequestParam String workerId) {
try {
Worker worker1 = workerService.findByWorkerId(workerId);
worker1.setGeolocation(geolocation);
workerService.update(worker1);
WorkerRedisVo workerRedisVo = workerRedisCacheUtil.get(regionId, workerId);
if(workerRedisVo != null){
workerRedisVo.setWorker(worker1);
}
workerRedisCacheUtil.update(regionId, workerRedisVo);
mallDeliveryOrderService.workerPickup(deliveryId, workerId);
return ResultUtil.success("取货成功");
} catch (Exception e) {
@ -273,9 +297,17 @@ public class MallDeliveryOrderController {
*/
@PostMapping("/complete")
@ApiOperation("配送员确认送达(配送中 -> 已送达)")
public Result complete(@RequestParam String deliveryId,
@RequestParam String workerId) {
public Result complete(@RequestParam String deliveryId,@RequestParam String geolocation,
@RequestParam String regionId,@RequestParam String workerId) {
try {
Worker worker1 = workerService.findByWorkerId(workerId);
worker1.setGeolocation(geolocation);
workerService.update(worker1);
WorkerRedisVo workerRedisVo = workerRedisCacheUtil.get(regionId, workerId);
if(workerRedisVo != null){
workerRedisVo.setWorker(worker1);
}
workerRedisCacheUtil.update(regionId, workerRedisVo);
mallDeliveryOrderService.workerComplete(deliveryId, workerId);
return ResultUtil.success("送达成功");
} catch (Exception e) {
@ -291,8 +323,12 @@ public class MallDeliveryOrderController {
@ApiOperation("配送员拒绝接指派单")
public Result reject(@RequestParam String deliveryId) {
try {
mallDeliveryOrderService.rejectDelivery(deliveryId);
return ResultUtil.success("已拒绝");
Integer result = mallDeliveryOrderService.rejectDelivery(deliveryId);
if(result == -1){
return ResultUtil.error("今日拒单次数已达上限,无法继续拒单!");
}else{
return ResultUtil.success("拒单成功!今日剩余拒单次数:" + result);
}
} catch (Exception e) {
log.error("取消配送失败: {}", e.getMessage(), e);
return ResultUtil.error(e.getMessage());

13
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ReturnCommissionController.java

@ -8,7 +8,7 @@ import cc.hiver.mall.entity.ReturnCommission;
import cc.hiver.mall.entity.Shop;
import cc.hiver.mall.service.ShopService;
import cc.hiver.mall.service.mybatis.ReturnCommissionService;
import cc.hiver.mall.utils.AliPayUtil;
import cc.hiver.mall.utils.AliPayNewUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -98,7 +98,7 @@ public class ReturnCommissionController {
@RequestMapping(value = "/handleReturn", method = RequestMethod.POST)
@ApiOperation("提现处理")
public Result handleReturn(@RequestBody ReturnCommission returnCommission) {
final String shopId = securityUtil.getShopId();
//final String shopId = securityUtil.getShopId();
if(returnCommission.getCommission() == null ){
return ResultUtil.error("提现金额不能为空!");
@ -115,9 +115,10 @@ public class ReturnCommissionController {
boolean result = false;
String aliResult = "";
final Shop shop = shopService.findById(shopId);
if(shop.getYearFee() == null || shop.getYearFee().compareTo(BigDecimal.ZERO) == 0){
return ResultUtil.error("店铺处于试用期,不能提现!");
final Shop shop = shopService.findById(returnCommission.getShopId());
if (shop.getBalance().compareTo(returnCommission.getCommission()) < 0) {
// 如果提现金额大于返佣余额,则不允许提现
return ResultUtil.error("提现金额不可大于佣金余额!");
}
//支付宝户名(姓名)
final String name = returnCommission.getAliName(); //shop.getAliName();
@ -134,7 +135,7 @@ public class ReturnCommissionController {
return ResultUtil.error("提现金额不可大于佣金余额!");
}*/
try {
final AlipayFundTransUniTransferResponse payResult = AliPayUtil.pay(phoneNumber, name, String.valueOf(commission), returnCommission.getId());
final AlipayFundTransUniTransferResponse payResult = AliPayNewUtil.pay(phoneNumber, name, String.valueOf(commission), returnCommission.getId());
if ("SUCCESS".equals(payResult.getStatus())) {
returnCommission.setStatus("1");
aliResult = "支付宝转账成功";

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerController.java

@ -397,6 +397,7 @@ public class WorkerController {
matchVO.setRebateAmount(w.getRebateAmount());
matchVO.setHighFloorFee(w.getHighFloorFee());
matchVO.setOrderBkge(matchedRule.getOrderBkge());
matchVO.setRemark(matchedRule.getRemark());
matchVO.setOrderWaitCount(orderWaitCount);
matchVO.setOrderGetCount(orderGetCount);
matchVO.setOrderPutCount(orderPutCount);

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallCoupon.java

@ -32,6 +32,9 @@ public class MallCoupon extends HiverBaseEntity {
@ApiModelProperty(value = "优惠券类型:1-满减券,2-无门槛直减券")
private Integer type;
@ApiModelProperty(value = "规则类型 0 新用户 1 其他")
private Integer ruleType;
@ApiModelProperty(value = "使用门槛金额")
private BigDecimal minAmount;

22
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderAsyncProducer.java

@ -39,6 +39,28 @@ public class OrderAsyncProducer {
rabbitTemplate.convertAndSend(OrderQueueConfig.ORDER_DIRECT_EXCHANGE, OrderQueueConfig.ASYNC_CACHE_ROUTING, JSON.toJSONString(params));
}
/**
* 发送退款/售后申请超时延时消息默认1小时后自动同意
* @param refundId 退款记录IDMallRefundRecord.id
* @param orderId 订单ID用于日志追踪
*/
public void sendRefundDelayMessage(String refundId, String orderId) {
Map<String, Object> msgBody = new HashMap<>();
msgBody.put("refundId", refundId);
msgBody.put("orderId", orderId);
msgBody.put("delayType", "Refund_Auto_Agree_1h");
msgBody.put("timestamp", System.currentTimeMillis());
final long delayMillis = 60 * 60 * 1000L; // 1小时
rabbitTemplate.convertAndSend(OrderQueueConfig.DELAY_EXCHANGE, OrderQueueConfig.DELAY_ROUTING,
JSON.toJSONString(msgBody),
message -> {
message.getMessageProperties().setExpiration(String.valueOf(delayMillis));
return message;
});
log.info("【退款MQ】已发送退款超时延时消息,1小时后自动处理,refundId={}, orderId={}", refundId, orderId);
}
/**
* 发送延迟(死信)超时消息
* @param orderId 订单ID

55
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderDelayConsumer.java

@ -8,7 +8,9 @@ import cc.hiver.mall.dao.mapper.MallOrderMapper;
import cc.hiver.mall.dao.mapper.ShopMapper;
import cc.hiver.mall.entity.MallDeliveryOrder;
import cc.hiver.mall.entity.MallOrder;
import cc.hiver.mall.entity.MallRefundRecord;
import cc.hiver.mall.entity.Shop;
import cc.hiver.mall.service.mybatis.MallRefundRecordService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -32,6 +34,9 @@ public class OrderDelayConsumer {
@Autowired
private MallOrderMapper mallOrderMapper;
@Autowired
private MallRefundRecordService mallRefundRecordService;
@Autowired
private ShopMapper shopMapper;
@ -41,6 +46,12 @@ public class OrderDelayConsumer {
@Autowired
private JPushServiceImpl jPushService;
@Autowired
private cc.hiver.mall.dao.mapper.MallRefundRecordMapper mallRefundRecordMapper;
@Autowired
private cc.hiver.mall.utils.RefundOrderCacheUtil refundOrderCacheUtil;
@RabbitListener(queues = OrderQueueConfig.DEAD_QUEUE)
public void processDelayMessage(String messageBody) {
log.info("【订单延时处理】接收到死信超时消息: {}", messageBody);
@ -62,6 +73,10 @@ public class OrderDelayConsumer {
case "Shop_Cook_Timeout":
handleShopCookTimeout(orderId);
break;
case "Refund_Auto_Agree_1h":
String refundId = msg.getString("refundId");
handleRefundAutoAgree(refundId);
break;
default:
log.warn("【订单延时处理】未知的延迟类型: {}", delayType);
}
@ -133,4 +148,44 @@ public class OrderDelayConsumer {
qw.eq(MallDeliveryOrder::getOrderId, orderId);
return mallDeliveryOrderMapper.selectOne(qw);
}
/**
* 退款/售后申请1小时未处理自动默认同意
*
* 幂等判断status == 0退款待同意 status == 3售后申请中才触发自动处理
* 如果已主动处理商家/配送员操作过 status 已变直接跳过
*/
private void handleRefundAutoAgree(String refundId) {
if (org.apache.commons.lang3.StringUtils.isBlank(refundId)) {
log.warn("【退款超时自动处理】refundId 为空,跳过");
return;
}
MallRefundRecord record = mallRefundRecordMapper.selectById(refundId);
if (record == null) {
log.warn("【退款超时自动处理】退款记录不存在, refundId={}", refundId);
return;
}
// 幂等判断:0=退款待商家/配送员同意,3=售后申请中
if (record.getStatus() != 0 && record.getStatus() != 3) {
log.info("【退款超时自动处理】已被主动处理,跳过。 refundId={}, status={}", refundId, record.getStatus());
return;
}
MallRefundRecord mallRefundRecord1 = new MallRefundRecord();
MallOrder order = mallOrderMapper.selectById(record.getOrderId());
mallRefundRecord1.setId(record.getId());
mallRefundRecord1.setLinkId(record.getLinkId());
mallRefundRecord1.setOrderId(record.getOrderId());
if(record.getStatus() < 3){
mallRefundRecord1.setStatus(1);
}else if(record.getStatus() >= 3){
mallRefundRecord1.setStatus(4);
}
mallRefundRecord1.setDeliveryType(order.getDeliveryType());
mallRefundRecord1.setOrderType(order.getOrderType());
mallRefundRecord1.setRefundAmount(record.getRefundAmount());
mallRefundRecord1.setRefundType(record.getRefundType());
mallRefundRecord1.setRefundTypeStatus(record.getRefundTypeStatus());
mallRefundRecordService.updateStatus(mallRefundRecord1);
log.info("【退款超时自动处理】超时1小时未处理,自动同意退款/售后。 refundId={}, orderId={}", refundId, record.getOrderId());
}
}

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

@ -30,6 +30,9 @@ public class MallCouponQuery extends HiverBasePageQuery {
@ApiModelProperty(value = "优惠券类型:1-满减券,2-无门槛直减券")
private Integer type;
@ApiModelProperty(value = "规则类型 0 新用户 1 其他")
private Integer ruleType;
@ApiModelProperty(value = "使用门槛金额")
private BigDecimal minAmount;

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/WorkerMatchVO.java

@ -25,6 +25,9 @@ public class WorkerMatchVO {
@ApiModelProperty("头像")
private String icon;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("定位")
private String geolocation;

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

@ -53,7 +53,7 @@ public interface MallDeliveryOrderService extends IService<MallDeliveryOrder> {
/**
* 拒绝配送单
*/
void rejectDelivery(String deliveryId);
Integer rejectDelivery(String deliveryId);
/**
* 统计抢单大厅未被接单的数量

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

@ -78,6 +78,9 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
@Autowired
private ShopTakeawayMapper shopTakeawayMapper;
@Autowired
private DeliveryRejectUtil deliveryRejectUtil;
@Autowired
WorkerRedisCacheUtil workerRedisCacheUtil;
@ -519,8 +522,12 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
}
@Override
public void rejectDelivery(String deliveryId) {
public Integer rejectDelivery(String deliveryId) {
MallDeliveryOrder delivery = this.getById(deliveryId);
Integer result = deliveryRejectUtil.handleRejectOrder(delivery.getWorkerId(), delivery.getOrderId());
if(result == -1){
return -1;
}else{
if (delivery == null) throw new RuntimeException("配送单不存在");
LambdaUpdateWrapper<MallDeliveryOrder> uw = new LambdaUpdateWrapper<>();
uw.eq(MallDeliveryOrder::getId, deliveryId)
@ -537,6 +544,8 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
}
//给用户发送短信通知被拒绝
smsUtil.sendCode(delivery.getReceiverPhone(), null, SettingConstant.SMS_TYPE.SMS_REJECT_ORDER.name());
return result;
}
}
// ================================================================

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

@ -1612,6 +1612,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
mallRefundRecordMapper.insert(record);
//退款放到缓存
refundOrderCacheUtil.put(record.getLinkId(),record);
//发送1小时延时MQ:超时未处理则自动同意
orderAsyncProducer.sendRefundDelayMessage(record.getId(), order.getId());
//发送商家通知
jPushService.sendPushNotification(shopService.findById(order.getShopId()).getClientId(), "您有一笔订单申请退款",order.getId());
}else if(refundTypeStatus == 2){
@ -1623,6 +1625,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
mallRefundRecordMapper.insert(record);
//退款放到缓存
refundOrderCacheUtil.put(record.getLinkId(),record);
//发送1小时延时MQ:超时未处理则自动同意
orderAsyncProducer.sendRefundDelayMessage(record.getId(), order.getId());
//发送商家通知
jPushService.sendPushNotification(shopService.findById(order.getShopId()).getClientId(), "您有一笔订单申请退款,配送员原因",order.getId());
}else if(refundTypeStatus == 3){
@ -1636,6 +1640,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
mallRefundRecordMapper.insert(record);
//退款放到缓存
refundOrderCacheUtil.put(record.getLinkId(),record);
//发送1小时延时MQ:超时未处理则自动同意(商家侧)
orderAsyncProducer.sendRefundDelayMessage(record.getId(), order.getId());
//发送商家通知
jPushService.sendPushNotification(shopService.findById(order.getShopId()).getClientId(), "您有一笔订单申请退款",order.getId());
MallRefundRecord mallRefundRecord1 = record;
@ -1649,6 +1655,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
mallRefundRecordMapper.insert(mallRefundRecord1);
//退款放到缓存
refundOrderCacheUtil.put(mallRefundRecord1.getLinkId(),mallRefundRecord1);
//发送1小时延时MQ:超时未处理则自动同意(配送员侧)
orderAsyncProducer.sendRefundDelayMessage(mallRefundRecord1.getId(), order.getId());
}
}

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

@ -53,6 +53,9 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
@Autowired
private MallRefundRecordMapper mallRefundRecordMapper;
@Autowired
private cc.hiver.mall.mq.OrderAsyncProducer orderAsyncProducer;
@Autowired
private MallReturnOrderGoodsMapper mallReturnOrderGoodsMapper;
@ -137,6 +140,8 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
mallRefundRecordMapper.insert(mallRefundRecord);
//售后放到缓存
refundOrderCacheUtil.put(mallRefundRecord.getLinkId(),mallRefundRecord);
//发送1小时延时MQ:超时未处理则自动同意
orderAsyncProducer.sendRefundDelayMessage(mallRefundRecord.getId(), mallRefundRecord.getOrderId());
}else if(mallRefundRecord.getRefundType() == 2){
// 退配送费
mallRefundRecord.setLinkId(mallRefundRecord.getWorkerId());
@ -145,6 +150,8 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
mallRefundRecordMapper.insert(mallRefundRecord);
//售后放到缓存
refundOrderCacheUtil.put(mallRefundRecord.getLinkId(),mallRefundRecord);
//发送1小时延时MQ:超时未处理则自动同意
orderAsyncProducer.sendRefundDelayMessage(mallRefundRecord.getId(), mallRefundRecord.getOrderId());
}else if(mallRefundRecord.getRefundType() == 3){
// 全额退款
if(mallRefundRecord.getRefundTypeStatus() == 1){
@ -152,11 +159,15 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
mallRefundRecordMapper.insert(mallRefundRecord);
//售后放到缓存
refundOrderCacheUtil.put(mallRefundRecord.getLinkId(),mallRefundRecord);
//发送1小时延时MQ:超时未处理则自动同意
orderAsyncProducer.sendRefundDelayMessage(mallRefundRecord.getId(), mallRefundRecord.getOrderId());
}else if(mallRefundRecord.getRefundTypeStatus() == 2){
mallRefundRecord.setLinkId(mallRefundRecord.getWorkerId());
mallRefundRecordMapper.insert(mallRefundRecord);
//售后放到缓存
refundOrderCacheUtil.put(mallRefundRecord.getLinkId(),mallRefundRecord);
//发送1小时延时MQ:超时未处理则自动同意
orderAsyncProducer.sendRefundDelayMessage(mallRefundRecord.getId(), mallRefundRecord.getOrderId());
}else if(mallRefundRecord.getRefundTypeStatus() == 3){
//商家、配送员都加一条
mallRefundRecord.setLinkId(mallRefundRecord.getShopId());
@ -166,6 +177,8 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
mallRefundRecordMapper.insert(mallRefundRecord);
//售后放到缓存
refundOrderCacheUtil.put(mallRefundRecord.getLinkId(),mallRefundRecord);
//发送1小时延时MQ:超时未处理则自动同意(商家侧)
orderAsyncProducer.sendRefundDelayMessage(mallRefundRecord.getId(), mallRefundRecord.getOrderId());
MallRefundRecord mallRefundRecord1 = mallRefundRecord;
mallRefundRecord1.setId(SnowFlakeUtil.nextId().toString());
mallRefundRecord1.setLinkId(mallRefundRecord.getWorkerId());
@ -175,6 +188,8 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
mallRefundRecordMapper.insert(mallRefundRecord1);
//售后放到缓存
refundOrderCacheUtil.put(mallRefundRecord1.getLinkId(),mallRefundRecord1);
//发送1小时延时MQ:超时未处理则自动同意(配送员侧)
orderAsyncProducer.sendRefundDelayMessage(mallRefundRecord1.getId(), mallRefundRecord1.getOrderId());
}
}
if(!mallRefundRecord.getItems().isEmpty()){

94
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/AliPayNewUtil.java

@ -0,0 +1,94 @@
package cc.hiver.mall.utils;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.domain.TransferSceneReportInfo;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import java.util.ArrayList;
import java.util.List;
public class AliPayNewUtil {
public static AlipayFundTransUniTransferResponse pay(String phoneNumber, String name, String transAmount, String orderNo) throws AlipayApiException {
// 初始化SDK
AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
// 构造请求参数以调用接口
AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
// 设置商家侧唯一订单号
model.setOutBizNo(orderNo);
// 设置订单总金额
model.setTransAmount(transAmount);
// 设置描述特定的业务场景
model.setBizScene("DIRECT_TRANSFER");
// 设置业务产品码
model.setProductCode("TRANS_ACCOUNT_NO_PWD");
// 设置转账业务的标题
model.setOrderTitle("业务结算");
// 设置收款方信息
Participant payeeInfo = new Participant();
payeeInfo.setIdentity(phoneNumber); // 这里传入对方的手机号,例如 "13800138000"
payeeInfo.setName(name); // 对方真实姓名(用于校验,防止转错人)
payeeInfo.setIdentityType("ALIPAY_LOGON_ID"); // 将身份类型改为 ALIPAY_LOGON_ID,代表支付宝登录号(即手机号或邮箱)
model.setPayeeInfo(payeeInfo);
// 设置业务备注
model.setRemark("业务结算");
// 设置转账场景名称
model.setTransferSceneName("业务结算");
// 设置转账场景上报信息
List<TransferSceneReportInfo> transferSceneReportInfos = new ArrayList<TransferSceneReportInfo>();
TransferSceneReportInfo transferSceneReportInfos0 = new TransferSceneReportInfo();
transferSceneReportInfos0.setInfoType("结算款项名称");
transferSceneReportInfos0.setInfoContent("业务结算");
transferSceneReportInfos.add(transferSceneReportInfos0);
model.setTransferSceneReportInfos(transferSceneReportInfos);
// 设置转账业务请求的扩展参数
model.setBusinessParams("{\"payer_show_name_use_alias\":\"true\"}");
request.setBizModel(model);
AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
return response;
}
private static AlipayConfig getAlipayConfig() {
String privateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCE5qCd8aPXAVtlvYupJkZSin4KkDzDdxsOwXtXACJW1Oyx8Q0M2i0PAfALCe8PPinM4mZzUzp57yw/Lipyu7usLTXiPMtyutGvqHshYE/rC4rBT991hq/1fiIOjRrB9RuZEIjS7BtwDYsZh+vfggiR5FXn4VeSSpXYuVROIAt9irpMYxuAfU6QXc1p6afrBWUCPp/LSES4XfP6of0nmjbxfqorfXXkjPultGJtjyH6C9GPshCHkRYgmbOsp89A565qJ9CnQOYv/1hpHf1wj76oaAj9vPZis/w2J+YwPODa29VMsHEsKPUKIc32xwPW68caS/WF1YHKnXBLSr/KytLLAgMBAAECggEADcTvQy3z8aS8WXAn9iB3DLo4kNOc2AuRDBhTtRHYfPKWi2EUHw7DuFhVDG+9CvE/13BlePFYj6WOCgW4dCarLQ2KFaSC16Ivc2mbSDv4S7voZlrmJgEMXfzxflx0N0Az2cnywxefSB6/GKgSchfA14y2sc2RCyEbIVciOu3rAtikeAQClQgr1XB/UIzMFEAESQaNgYkoRKjcfoSPhgixTxuCCVjEVv+me7kT35knzCvNKhzi/MH4X0XjPLHNf5Gz6bPvFdAEPbCrgbMgjflwVefiuCR4kbFehcVea0qnmQVfocdbRK00IiduWTvgJeKrMaCDYJzSCNUwjyAcWD1+gQKBgQC4htY/wx1BZDmvKo+3xc59z6YvcJBO2ov0SSltKtKxOiTcbWBlcJq6y5PFsVo5oLed6A8fcHNNPVA94TxCCYTW1gRlDjSIcgQWM864ceScvPuFay/kRu+CC5AmoEg3Oo4hzKYK/jb0b6TzJ1EYh2mLaGi/ZL4guHdvfsINeGfqqwKBgQC4YLc2o47rtRBotUfRMJjVg3kzf8r4SU4luITtZE1kF9ahmTXPFeqoLjh0mB/RJkt61yPEdsTqPtGfUiEx7LCarH/86bCr8rsLOVuNCltEVDp/MqqaSKLDV3Z8zdKfFOsfSS8U949+LVFTvCYDX7CkWIstCcihyA34y01fcEC4YQKBgDKn2VMBthtIb0l17qQtaiVBhsaJKSRsfHUgTH4KfnJmms3kPM08H03eKv/fUvx08VMo7FXeIdj3VvrVxRv/zvbHI8e2IZe/bP3HVR1vLqoUexvCNBB/pKpXkEf6QjjfGzuOGZr09JMfvvF9Ppb0PXYmwHKiLkt/OFJkQtM91ZEnAoGARd9BD0/EZcbkRQoOAVStVpzQXZfcT2NYXisjFOOiAICYMf1hyuy/VKTPeD/+LsCYciD9yQJJdYwA3KO/OLA97R/aEPpunXsLLyG5dCWsmKRi1rlYtcc5B1Yp7PoDC45d3Clb0lJO6r45x8XRkg29X0q+036VrdmmkdZZqAVeQYECgYA8LixZQDsgC7gwud60xmP8EIy9LHOJezA305zDcvXkIn3gyoPxedA+ZpjjxWYbZcbo7LTn0Wb36cEbUP/9eB5wSODs186wRmShb9F3uc8SgbFYcDmIdKx0LBQ5qOkKUwrI3yitrGHDP02zTsbpYWQ8i0yfi0Di6a+h9iqyP8slog==";
AlipayConfig alipayConfig = new AlipayConfig();
alipayConfig.setPrivateKey(privateKey);
alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
alipayConfig.setAppId("2021005179691569");
alipayConfig.setCharset("UTF-8");
alipayConfig.setSignType("RSA2");
alipayConfig.setFormat("json");
alipayConfig.setAppCertPath("/home/mingzhu/alipay/appCertPublicKey_2021005179691569.crt");
alipayConfig.setAlipayPublicCertPath("/home/mingzhu/alipay/alipayCertPublicKey_RSA2.crt");
alipayConfig.setRootCertPath("/home/mingzhu/alipay/alipayRootCert.crt");
return alipayConfig;
}
}

10
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/AliPayUtil.java

@ -19,23 +19,23 @@ public class AliPayUtil {
public static AlipayFundTransUniTransferResponse pay(String phoneNumber, String name, String transAmount, String orderNo) throws AlipayApiException {
//应用私钥
String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCPjWS3hfusQ3/w0chhZpxHM/DZtMvC+cfXs3xysaJWhVt+6uvyKhtBoYCDDCcKD5vvTx4SB0uC0U98lcusrcV9SCtzvum1gbfYBBYiuNruCb9HRRFIVVe4nn54QDcgVZseHiGdJSr49m23o+S9pTacoplaWNvdwC0B5MSP5ufjabtXYo1DeXMGGS1qgqOJxfuUG+ihs3Fpz+QAkApDd1wSytLhh9svwvC/oJMrX/uA/ZhbUqq812iPJ5bW67jY2dzDCPNO97Gk8f5zPHirsqowQjwAXICn91fwEMb7BO+K8iJm6jv8iIIuB4D+4UUG8VhaK0PF88qX5lq8TwN/q7SfAgMBAAECggEAfVdg9JmJST1azePuSZV1qPoiN4UUUTcVljKC3AZcD527aRMoVzcKu4CPnF0VDUTZy9dSEz3JYfzuoYKN50WHZb+JKTQuDiyoYHYY+dJcXnGmUU1uLLFPucSx+r9fIt18Zoy6nuKgJefNnwX8qNZD2/phWjCyMWomIjwkoN1l5frNuTP0h5FAcr/bEnoHLFXXiAXtioI4ffHnQ5c8AM/z9bqw/49kJ9QOOBVSwuHgZggsbvLVKASSBKWbDoCwB+AIgYuJKzC0iXY7rfsVnxqI2+0fruca36KwCOlwWrYaWglQvGv9706r6SA5Ux2zyEMOm0TQHJNiwliblzVqb2mLAQKBgQDht/B4DYQzUItJnGpKi8dCiQPYEw+n0DMzBKV9a6L0/Aig1n6Ev42zrWq7UYEFMnLSfT/fDOaIeu/kkiTeTRwuERXm/1kjXX4yhkaF7bA//woQlHGuhyTSbhNywNNE1UCeqJ3OVy/FHa+Ro5RYXOceJR/3J4XZC4rhXeXgYlOuHwKBgQCiz4tJ/Uybc66H7ToxY52ZTYf/zjwgdg6/f8N8xxkhC5JD5GQEUU+8eShC+lxa3PcNil1GFagh4vIVANgqJPPMopq2EDNMpz2EKDvzS87VOoLsP3np9yNc+2nOhTmsrXRNOSX1B0c7W6dRuTDA/esmJB4/kBNV73ZNpdxMA6IpgQKBgQDPt0vNzvJ3nolvpkeSbmtiaWBmObRQhCJ5sq7wals+A6mVCY7IbtbiIJZ15x1KQRC1b5mVk/OaaTfWKj9Pa7qhEgwL1bSb/O+jYzoHCaMGYZdLhq/PIoLaO34ePiCt2WlsGFOQjV9ikFz/M3/SiTwO26887NwZzqtxlc1z3kiPlQKBgCtSrM7Yby0iYDvdPVHtHv+vKNRB7a/5mj0M41jtpdssOBSGzrJzbJNLbhI8ipzHFZptyhofIyk5OY+rNNoqERHP5vkxYGUyT2U+S42XC4ej1TjGP0uprqhMYkBJJSq00TDHVzlXYXYDEofljnqcVplEnSPu06ZXXRSWYQN9KAaBAoGATLuDMRsipdLujfo+CF9iyxXP2kAzRLRx6QFZ9SRu/9BLPnaiCntDENZaXYZmHSYZ13Ab8XpfK8ms75fUDg4LKEy6UyCsHv4288wtz4mjHnAFKLhQkrsimDx6byTTjVo5eF22WKVGw9tLyAzii160wmubjsU4XG5vtSwUoGYL73w=";
String privateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCE5qCd8aPXAVtlvYupJkZSin4KkDzDdxsOwXtXACJW1Oyx8Q0M2i0PAfALCe8PPinM4mZzUzp57yw/Lipyu7usLTXiPMtyutGvqHshYE/rC4rBT991hq/1fiIOjRrB9RuZEIjS7BtwDYsZh+vfggiR5FXn4VeSSpXYuVROIAt9irpMYxuAfU6QXc1p6afrBWUCPp/LSES4XfP6of0nmjbxfqorfXXkjPultGJtjyH6C9GPshCHkRYgmbOsp89A565qJ9CnQOYv/1hpHf1wj76oaAj9vPZis/w2J+YwPODa29VMsHEsKPUKIc32xwPW68caS/WF1YHKnXBLSr/KytLLAgMBAAECggEADcTvQy3z8aS8WXAn9iB3DLo4kNOc2AuRDBhTtRHYfPKWi2EUHw7DuFhVDG+9CvE/13BlePFYj6WOCgW4dCarLQ2KFaSC16Ivc2mbSDv4S7voZlrmJgEMXfzxflx0N0Az2cnywxefSB6/GKgSchfA14y2sc2RCyEbIVciOu3rAtikeAQClQgr1XB/UIzMFEAESQaNgYkoRKjcfoSPhgixTxuCCVjEVv+me7kT35knzCvNKhzi/MH4X0XjPLHNf5Gz6bPvFdAEPbCrgbMgjflwVefiuCR4kbFehcVea0qnmQVfocdbRK00IiduWTvgJeKrMaCDYJzSCNUwjyAcWD1+gQKBgQC4htY/wx1BZDmvKo+3xc59z6YvcJBO2ov0SSltKtKxOiTcbWBlcJq6y5PFsVo5oLed6A8fcHNNPVA94TxCCYTW1gRlDjSIcgQWM864ceScvPuFay/kRu+CC5AmoEg3Oo4hzKYK/jb0b6TzJ1EYh2mLaGi/ZL4guHdvfsINeGfqqwKBgQC4YLc2o47rtRBotUfRMJjVg3kzf8r4SU4luITtZE1kF9ahmTXPFeqoLjh0mB/RJkt61yPEdsTqPtGfUiEx7LCarH/86bCr8rsLOVuNCltEVDp/MqqaSKLDV3Z8zdKfFOsfSS8U949+LVFTvCYDX7CkWIstCcihyA34y01fcEC4YQKBgDKn2VMBthtIb0l17qQtaiVBhsaJKSRsfHUgTH4KfnJmms3kPM08H03eKv/fUvx08VMo7FXeIdj3VvrVxRv/zvbHI8e2IZe/bP3HVR1vLqoUexvCNBB/pKpXkEf6QjjfGzuOGZr09JMfvvF9Ppb0PXYmwHKiLkt/OFJkQtM91ZEnAoGARd9BD0/EZcbkRQoOAVStVpzQXZfcT2NYXisjFOOiAICYMf1hyuy/VKTPeD/+LsCYciD9yQJJdYwA3KO/OLA97R/aEPpunXsLLyG5dCWsmKRi1rlYtcc5B1Yp7PoDC45d3Clb0lJO6r45x8XRkg29X0q+036VrdmmkdZZqAVeQYECgYA8LixZQDsgC7gwud60xmP8EIy9LHOJezA305zDcvXkIn3gyoPxedA+ZpjjxWYbZcbo7LTn0Wb36cEbUP/9eB5wSODs186wRmShb9F3uc8SgbFYcDmIdKx0LBQ5qOkKUwrI3yitrGHDP02zTsbpYWQ8i0yfi0Di6a+h9iqyP8slog==";
CertAlipayRequest alipayConfig = new CertAlipayRequest();//支付宝配置
alipayConfig.setPrivateKey(privateKey);
alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
alipayConfig.setAppId("2021004134683124");//支付宝分配给开发者的应用ID 明珠快小店
alipayConfig.setAppId("2021005179691569");//支付宝分配给开发者的应用ID 明珠快小店
alipayConfig.setCharset("UTF8");
alipayConfig.setSignType("RSA2");
alipayConfig.setEncryptor("");
alipayConfig.setFormat("json");
alipayConfig.setCertPath("/home/mingzhu/alipay/appCertPublicKey_2021004134683124.crt");//应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt
alipayConfig.setCertPath("/home/mingzhu/alipay/appCertPublicKey_2021005179691569.crt");//应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt
alipayConfig.setAlipayPublicCertPath("/home/mingzhu/alipay/alipayCertPublicKey_RSA2.crt");//支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt
alipayConfig.setRootCertPath("/home/mingzhu/alipay/alipayRootCert.crt");//支付宝根证书文件路径,例如:/foo/alipayRootCert.crt
AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();//转账类型请求
AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();//转账请求参数
model.setOutBizNo(orderNo);//商家侧唯一订单号
model.setRemark("返佣");//
model.setRemark("余额提现");//
model.setBusinessParams("{\"payer_show_name_use_alias\":\"true\"}");
model.setBizScene("DIRECT_TRANSFER");//单笔无密转账固定为 DIRECT_TRANSFER
Participant payeeInfo = new Participant();//收款方信息
@ -45,7 +45,7 @@ public class AliPayUtil {
model.setPayeeInfo(payeeInfo);
model.setTransAmount(transAmount);
model.setProductCode("TRANS_ACCOUNT_NO_PWD");
model.setOrderTitle("软件返佣");
model.setOrderTitle("余额提现");
request.setBizModel(model);
AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request);
// Result result = new Result();

65
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DeliveryRejectUtil.java

@ -0,0 +1,65 @@
package cc.hiver.mall.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
@Service
public class DeliveryRejectUtil {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisLuaScripts redisLuaScripts;
// 每日最大拒单次数限制
private static final int MAX_DAILY_REJECT_COUNT = 5;
// Redis Key 的前缀
private static final String REJECT_KEY_PREFIX = "reject_limit:";
/**
* 处理配送员拒绝接单
* @param riderId 配送员ID
* @param orderId 订单ID
* @return 处理结果提示语
*/
public Integer handleRejectOrder(String riderId, String orderId) {
// 1. 构建 Redis Key:reject_limit:{riderId}:{yyyy-MM-dd}
String today = LocalDate.now().toString();
String redisKey = REJECT_KEY_PREFIX + riderId + ":" + today;
// 2. 计算到当天 23:59:59 的剩余秒数(比固定24小时更严谨)
long secondsUntilMidnight = ChronoUnit.SECONDS.between(
java.time.LocalDateTime.now(),
LocalDate.now().plusDays(1).atStartOfDay()
);
// 3. 执行 Lua 脚本进行原子判断与计数
Long result = stringRedisTemplate.execute(
redisLuaScripts.getRejectLimitScript(),
Collections.singletonList(redisKey),
String.valueOf(MAX_DAILY_REJECT_COUNT),
String.valueOf(secondsUntilMidnight)
);
// 4. 根据脚本返回值处理业务
if (result == -1) {
// 达到拒单上限,直接拦截
return -1;
} else {
// 未达上限,允许拒单。
// 这里可以继续执行后续的订单状态更新、MQ消息发送等逻辑
System.out.println("配送员 " + riderId + " 拒单成功,今日已拒单 " + result + " 次。");
// 可以在这里异步记录拒单流水到 MySQL,用于后续的数据统计
// asyncSaveRejectRecord(riderId, orderId);
return Math.toIntExact(MAX_DAILY_REJECT_COUNT - result);
}
}
}

37
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/RedisLuaScripts.java

@ -0,0 +1,37 @@
package cc.hiver.mall.utils;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
@Component
public class RedisLuaScripts {
// 封装拒单次数限制的 Lua 脚本
// 逻辑:获取当前值 -> 判断是否超限 -> 未超限则自增并设置过期时间 -> 返回当前次数或错误码
private static final String REJECT_LIMIT_SCRIPT =
"local key = KEYS[1] " +
"local limit = tonumber(ARGV[1]) " +
"local expireSeconds = tonumber(ARGV[2]) " +
"local current = tonumber(redis.call('GET', key) or '0') " +
"if current >= limit then " +
" return -1 " + // 返回 -1 代表今日拒单次数已达上限
"else " +
" local newCount = redis.call('INCR', key) " +
" if newCount == 1 then " +
" redis.call('EXPIRE', key, expireSeconds) " +
" end " +
" return newCount " + // 返回当前的拒单次数
"end";
private final DefaultRedisScript<Long> rejectLimitScript;
public RedisLuaScripts() {
this.rejectLimitScript = new DefaultRedisScript<>();
this.rejectLimitScript.setScriptText(REJECT_LIMIT_SCRIPT);
this.rejectLimitScript.setResultType(Long.class);
}
public DefaultRedisScript<Long> getRejectLimitScript() {
return rejectLimitScript;
}
}

7
hiver-modules/hiver-mall/src/main/resources/mapper/MallCouponMapper.xml

@ -20,6 +20,7 @@
<result column="valid_days" property="validDays"/>
<result column="status" property="status"/>
<result column="region_id" property="regionId"/>
<result column="rule_type" property="ruleType"/>
</resultMap>
<sql id="selectCouponColumns">
@ -39,7 +40,8 @@
valid_end_time,
valid_days,
status,
region_id
region_id,
rule_type
</sql>
<update id="deductStock">
UPDATE t_mall_coupon
@ -64,6 +66,9 @@
<if test="q.type != null">
AND type = #{q.type}
</if>
<if test="q.ruleType != null">
AND rule_type = #{q.ruleType}
</if>
<if test="q.issuerType != null">
AND issuer_type = #{q.issuerType}
</if>

9
pom.xml

@ -45,7 +45,7 @@
<activiti.version>5.22.0</activiti.version>
<mapstruct.version>1.5.2.Final</mapstruct.version>
<easypoi.version>4.2.0</easypoi.version>
<alipay.version>4.31.7.ALL</alipay.version>
<alipay.version>4.40.626.ALL</alipay.version>
<aio.core.version>1.6.1</aio.core.version>
<smart.flow.version>1.0.6</smart.flow.version>
<smart.license.version>2.0</smart.license.version>
@ -221,7 +221,7 @@
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>${alipay.version}</version>
<version>4.40.626.ALL</version> <!-- 推荐使用较新的稳定版本 -->
</dependency>
<!-- 支付接口 -->
<dependency>
@ -379,6 +379,11 @@
<version>3.8.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<compilerArgs>
<!-- 强制忽略 sun.* 内部类的符号文件检查 -->
<arg>-XDignore.symbol.file</arg>
</compilerArgs>
<fork>true</fork> <!-- 注意:这个参数必须加上,否则不生效 -->
<target>${maven.compiler.target}</target>
<annotationProcessorPaths>
<path>

Loading…
Cancel
Save