支付退款定时任务
This commit is contained in:
parent
307d56054e
commit
fd94be6571
@ -59,14 +59,20 @@ public class WxPayConfig {
|
||||
private String refundNotifyUrl;
|
||||
/**
|
||||
* 支付、退款过期时间(分钟)
|
||||
* 默认24小时,超过24小时订单会自动关闭
|
||||
* 默认2小时,超过2小时订单会自动关闭
|
||||
*/
|
||||
private Integer expireMinute = 1440;
|
||||
private Integer expireMinute = 120;
|
||||
|
||||
/**
|
||||
* 定时任务单次查寻最大条数
|
||||
*/
|
||||
private Integer queryLimit = 100;
|
||||
|
||||
/**
|
||||
* 支付状态检查定时任务执行表达式
|
||||
* 默认每12小时执行1次
|
||||
* 默认每2小时执行1次
|
||||
*/
|
||||
private String paySchedule = "0 0 0/12 * * ?";
|
||||
private String paySchedule = "0 0 0/2 * * ?";
|
||||
/**
|
||||
* 退款状态检查定时任务执行表达式
|
||||
* 默认每30分钟执行1次
|
||||
|
||||
@ -47,4 +47,11 @@ public interface EbikeOrderService extends IService<EbikeOrder> {
|
||||
* @param orderId 订单ID
|
||||
*/
|
||||
void rejectRefund(Long orderId);
|
||||
|
||||
/**
|
||||
* 取消订单
|
||||
*
|
||||
* @param orderId 订单id
|
||||
*/
|
||||
void cancelOrder(Long orderId);
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ public interface EbikePaymentService extends IService<EbikePayment> {
|
||||
* @param duration 订单创建时间超过duration分钟,单位分钟
|
||||
* @return 未支付订单列表
|
||||
*/
|
||||
List<EbikePayment> getNoPayNotTimeOutOrder(int duration);
|
||||
List<EbikePayment> getNoPayNotTimeOutOrder(int duration, int queryLimit);
|
||||
|
||||
/**
|
||||
* 查询未支付订单, 超时的
|
||||
@ -31,7 +31,7 @@ public interface EbikePaymentService extends IService<EbikePayment> {
|
||||
* @param duration 订单创建时间超过duration分钟,单位分钟
|
||||
* @return 未支付订单列表
|
||||
*/
|
||||
List<EbikePayment> getNoPayOvertimeOrder(int duration);
|
||||
List<EbikePayment> getNoPayOvertimeOrder(int duration, int queryLimit);
|
||||
|
||||
/**
|
||||
* 更新支付状态
|
||||
@ -64,4 +64,11 @@ public interface EbikePaymentService extends IService<EbikePayment> {
|
||||
* @return 支付记录详情
|
||||
*/
|
||||
EbikePayment getByOrderId(Long orderId);
|
||||
|
||||
/**
|
||||
* 取消支付订单
|
||||
*
|
||||
* @param paymentId 支付id
|
||||
*/
|
||||
void cancelPayment(Long paymentId);
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ public interface EbikeRefundService extends IService<EbikeRefund> {
|
||||
* @param duration 订单创建时间超过duration分钟,单位分钟
|
||||
* @return 未成功退款订单列表
|
||||
*/
|
||||
List<EbikeRefund> getNoSuccessRefundOrderByDuration(int duration);
|
||||
List<EbikeRefund> getNoSuccessRefundOrderByDuration(int duration, int queryLimit);
|
||||
|
||||
/**
|
||||
* 更新退款状态
|
||||
|
||||
@ -74,4 +74,14 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
|
||||
userOrders.setOrderStatus(EbikeOrderStatus.REFUND_REJECTED);
|
||||
this.mapper.update(userOrders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelOrder(Long orderId) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create()
|
||||
.where(EBIKE_ORDER.ORDER_ID.eq(orderId))
|
||||
.where(EBIKE_ORDER.ORDER_STATUS.eq(EbikeOrderStatus.PENDING_PAYMENT));
|
||||
EbikeOrder userOrders = this.mapper.selectOneByQuery(queryWrapper);
|
||||
userOrders.setOrderStatus(EbikeOrderStatus.CANCELLED);
|
||||
this.mapper.update(userOrders);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package com.cdzy.payment.service.impl;
|
||||
|
||||
import com.cdzy.common.enums.GlobalConstants;
|
||||
import com.cdzy.common.utils.ConvertUtil;
|
||||
import com.cdzy.payment.enums.EbikeOrderStatus;
|
||||
import com.cdzy.payment.enums.PaymentMethod;
|
||||
import com.cdzy.payment.mapper.EbikePaymentMapper;
|
||||
import com.cdzy.payment.model.dto.EbikeOrderPaymentDto;
|
||||
@ -23,7 +24,9 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.cdzy.payment.model.entity.table.EbikeOrderDetailTableDef.EBIKE_ORDER_DETAIL;
|
||||
import static com.cdzy.payment.model.entity.table.EbikeOrderTableDef.EBIKE_ORDER;
|
||||
@ -44,40 +47,51 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
|
||||
private EbikeOrderService ebikeOrderService;
|
||||
|
||||
@Override
|
||||
public List<EbikePayment> getNoPayNotTimeOutOrder(int duration) {
|
||||
public List<EbikePayment> getNoPayNotTimeOutOrder(int duration, int queryLimit) {
|
||||
// 未支付状态(已超时),创建时间 >= 当前时间 - duration 分钟
|
||||
LocalDateTime cutoffTime = LocalDateTime.now().minusMinutes(duration);
|
||||
QueryWrapper query = QueryWrapper.create()
|
||||
.where(EBIKE_PAYMENT.TRADE_STATUS.eq(Transaction.TradeStateEnum.NOTPAY.ordinal()))
|
||||
.and(createTimeFilter(duration, ">="));
|
||||
.where(EBIKE_PAYMENT.TRADE_STATUS.eq(EbikeOrderStatus.PENDING_PAYMENT))
|
||||
.ge(EbikePayment::getCreateTime, cutoffTime)
|
||||
.limit(queryLimit);
|
||||
return list(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EbikePayment> getNoPayOvertimeOrder(int duration) {
|
||||
public List<EbikePayment> getNoPayOvertimeOrder(int duration, int queryLimit) {
|
||||
// 未支付状态(未超时),创建时间 < 当前时间 - duration 分钟
|
||||
LocalDateTime cutoffTime = LocalDateTime.now().minusMinutes(duration);
|
||||
QueryWrapper query = QueryWrapper.create()
|
||||
.where(EBIKE_PAYMENT.TRADE_STATUS.eq(Transaction.TradeStateEnum.NOTPAY.ordinal()))
|
||||
.and(createTimeFilter(duration, "<"));
|
||||
.where(EBIKE_PAYMENT.TRADE_STATUS.eq(EbikeOrderStatus.PENDING_PAYMENT))
|
||||
.lt(EbikePayment::getCreateTime, cutoffTime)
|
||||
.limit(queryLimit);
|
||||
return list(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updatePaymentStatus(Transaction transaction) {
|
||||
EbikePayment ebikePayment = getByPaymentId(transaction.getOutTradeNo());
|
||||
if (Objects.isNull(ebikePayment)) {
|
||||
log.warn("未找到本地订单,outTradeNo: {}", transaction.getOutTradeNo());
|
||||
return false;
|
||||
}
|
||||
ebikePayment.setTradeStatus(transaction.getTradeState().ordinal());
|
||||
if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
|
||||
// 支付成功, 更新订单状态
|
||||
// 支付成功, 更新支付状态
|
||||
BigDecimal totalAmount = calculateTotalAmount(transaction);
|
||||
ebikePayment.setTotal(totalAmount);
|
||||
String paymentTime = transaction.getSuccessTime();
|
||||
ebikePayment.setPaymentTime(StringUtils.toLocalDatetime(paymentTime));
|
||||
ebikePayment.setTransactionId(transaction.getTransactionId());
|
||||
// 同步支付状态
|
||||
// 同步订单状态
|
||||
EbikeOrderPaymentDto paymentParam = new EbikeOrderPaymentDto();
|
||||
paymentParam.setOrderId(ebikePayment.getOrderId());
|
||||
paymentParam.setPaymentTime(ebikePayment.getPaymentTime());
|
||||
paymentParam.setPaymentMethod(PaymentMethod.WECHAT);
|
||||
ebikeOrderService.payment(paymentParam);
|
||||
} else if (Transaction.TradeStateEnum.CLOSED.equals(transaction.getTradeState())) {
|
||||
// 微信订单已取消,同步更新订单为取消
|
||||
ebikeOrderService.cancelOrder(ebikePayment.getOrderId());
|
||||
}
|
||||
return updateById(ebikePayment);
|
||||
}
|
||||
@ -143,6 +157,18 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
|
||||
return this.getOne(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelPayment(Long paymentId) {
|
||||
QueryWrapper query = QueryWrapper.create()
|
||||
.where(EBIKE_PAYMENT.PAYMENT_ID.eq(paymentId));
|
||||
EbikePayment payment = this.getOne(query);
|
||||
payment.setTradeStatus(GlobalConstants.NUMBER_FOUR);
|
||||
payment.setUpdateTime(LocalDateTime.now());
|
||||
this.updateById(payment);
|
||||
// 同步订单状态变为取消
|
||||
ebikeOrderService.cancelOrder(payment.getOrderId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付id查询支付记录
|
||||
*
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.cdzy.payment.service.impl;
|
||||
|
||||
import com.cdzy.common.ex.EbikeException;
|
||||
import com.cdzy.payment.enums.RefundStatus;
|
||||
import com.cdzy.payment.mapper.EbikeRefundMapper;
|
||||
import com.cdzy.payment.model.entity.EbikeRefund;
|
||||
@ -17,7 +18,9 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.cdzy.payment.model.entity.table.EbikeRefundTableDef.EBIKE_REFUND;
|
||||
|
||||
@ -35,18 +38,13 @@ public class EbikeRefundServiceImpl extends ServiceImpl<EbikeRefundMapper, Ebike
|
||||
private EbikeOrderService ebikeOrderService;
|
||||
|
||||
@Override
|
||||
public List<EbikeRefund> getNoSuccessRefundOrderByDuration(int duration) {
|
||||
// trade_state 等于2(退款状态中), 并且创建时间超过duration分钟的订单
|
||||
int totalSeconds = duration * 60;
|
||||
|
||||
String timeFilter = String.format(
|
||||
"%s + INTERVAL '%d seconds' <= NOW()",
|
||||
EBIKE_REFUND.CREATE_TIME.getName(),
|
||||
totalSeconds
|
||||
);
|
||||
public List<EbikeRefund> getNoSuccessRefundOrderByDuration(int duration, int queryLimit) {
|
||||
// 查询创建时间已超过指定分钟数、且退款状态仍为“处理中”的退款单。
|
||||
LocalDateTime cutoffTime = LocalDateTime.now().minusMinutes(duration);
|
||||
QueryWrapper query = QueryWrapper.create()
|
||||
.where(EBIKE_REFUND.REFUND_STATUS.eq(RefundStatus.PROCESSING))
|
||||
.and(timeFilter);
|
||||
.lt(EbikeRefund::getCreateTime, cutoffTime)
|
||||
.limit(queryLimit);
|
||||
return list(query);
|
||||
}
|
||||
|
||||
@ -69,7 +67,11 @@ public class EbikeRefundServiceImpl extends ServiceImpl<EbikeRefundMapper, Ebike
|
||||
return false;
|
||||
}
|
||||
EbikeRefund ebikeRefund = getByRefundOrderId(refund.getOutRefundNo());
|
||||
if (Objects.isNull(ebikeRefund)) {
|
||||
throw new EbikeException("本地退款单不存在");
|
||||
}
|
||||
ebikeRefund.setRefundStatus(refund.getStatus().ordinal());
|
||||
// 退款成功
|
||||
if (Status.SUCCESS.equals(refund.getStatus())) {
|
||||
String refundTime = refund.getSuccessTime();
|
||||
ebikeRefund.setRefundTime(StringUtils.toLocalDatetime(refundTime));
|
||||
@ -81,9 +83,12 @@ public class EbikeRefundServiceImpl extends ServiceImpl<EbikeRefundMapper, Ebike
|
||||
log.info("订单Id:{}, 订单状态:{}", orderId, refund.getStatus().ordinal());
|
||||
// 更新订单退款状态
|
||||
switch (refund.getStatus()) {
|
||||
case PROCESSING, CLOSED -> ebikeOrderService.refund(orderId);
|
||||
// 退款中
|
||||
case PROCESSING -> ebikeOrderService.refund(orderId);
|
||||
// 退款成功
|
||||
case SUCCESS -> ebikeOrderService.doneRefund(orderId);
|
||||
case ABNORMAL -> ebikeOrderService.failRefund(orderId);
|
||||
// 退款失败/关闭 → 订单“退款失败”
|
||||
case ABNORMAL, CLOSED -> ebikeOrderService.failRefund(orderId);
|
||||
}
|
||||
return updateById(ebikeRefund);
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 用户订单支付任务。检测支付状态,更新订单状态。
|
||||
@ -38,54 +39,64 @@ public class WxPayTask {
|
||||
|
||||
|
||||
/**
|
||||
* 查询创建未超过24小时,并且未支付的订单
|
||||
* 查询创建未超过2小时,并且未支付的订单
|
||||
*/
|
||||
public void checkOrderStatus() {
|
||||
log.info("checkOrderStatus 执行......");
|
||||
// 1. 查询未支付的未超时的订单
|
||||
List<EbikePayment> ebikePaymentList = ebikePaymentService.getNoPayNotTimeOutOrder(wxPayConfig.getExpireMinute());
|
||||
List<EbikePayment> ebikePaymentList = ebikePaymentService.getNoPayNotTimeOutOrder(wxPayConfig.getExpireMinute(), wxPayConfig.getQueryLimit());
|
||||
if (ebikePaymentList.isEmpty()) {
|
||||
log.debug("当前无未支付订单");
|
||||
return;
|
||||
}
|
||||
log.info("共发现 {} 笔待检查订单", ebikePaymentList.size());
|
||||
// 2. 遍历订单,查询支付状态
|
||||
for (EbikePayment ebikePayment : ebikePaymentList) {
|
||||
log.warn("未支付的订单号 ===> {}", ebikePayment.getOrderId());
|
||||
log.info("未支付的订单号 ===> {}", ebikePayment.getOrderId());
|
||||
// 调用微信支付查询接口,查询支付状态
|
||||
Transaction transaction = wxPayService.queryOrderByOutTradeNo(String.valueOf(ebikePayment.getTradeId()));
|
||||
// 3. 更新订单状态
|
||||
if (transaction != null) {
|
||||
if (Objects.nonNull(transaction)) {
|
||||
// 更新订单状态
|
||||
ebikePaymentService.updatePaymentStatus(transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询创建超过24小时,并且未支付的订单
|
||||
* 查询创建超过2小时,并且未支付的订单 直接关闭订单 【未使用】
|
||||
*/
|
||||
public void closeOrder() {
|
||||
log.info("closeOrder 执行......");
|
||||
// 1. 查询未支付的超时订单
|
||||
List<EbikePayment> ebikePaymentList = ebikePaymentService.getNoPayOvertimeOrder(wxPayConfig.getExpireMinute());
|
||||
List<EbikePayment> ebikePaymentList = ebikePaymentService.getNoPayOvertimeOrder(wxPayConfig.getExpireMinute(), wxPayConfig.getQueryLimit());
|
||||
if (ebikePaymentList.isEmpty()) {
|
||||
log.debug("当前无超时未支付订单");
|
||||
return;
|
||||
}
|
||||
log.info("共发现 {} 笔超时订单,准备处理...", ebikePaymentList.size());
|
||||
// 2. 遍历订单,关闭订单
|
||||
for (EbikePayment ebikePayment : ebikePaymentList) {
|
||||
log.warn("超时未支付的订单号 ===> {}", ebikePayment.getOrderId());
|
||||
// 调用微信支付关闭接口,关闭订单
|
||||
boolean close = wxPayService.closeOrder(String.valueOf(ebikePayment.getTradeId()));
|
||||
if (close) {
|
||||
// 3. 更新订单状态
|
||||
Transaction transaction = new Transaction();
|
||||
transaction.setTradeState(Transaction.TradeStateEnum.CLOSED);
|
||||
transaction.setTradeStateDesc("订单关闭");
|
||||
ebikePaymentService.updatePaymentStatus(transaction);
|
||||
}
|
||||
// 调用微信支付关闭接口,关闭订单(*超时微信会自动关闭)
|
||||
//boolean close = wxPayService.closeOrder(String.valueOf(ebikePayment.getTradeId()));
|
||||
// 更新订单状态 订单状态变为取消、支付订单状态变为取消
|
||||
ebikePaymentService.cancelPayment(ebikePayment.getPaymentId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询创建未超过24小时,并且未成功的退款单
|
||||
* 查询创建未超过2小时,并且未成功的退款单
|
||||
*/
|
||||
public void checkRefundStatus() {
|
||||
log.info("checkRefundStatus 执行......");
|
||||
|
||||
// 1. 查询未成功的退款单
|
||||
List<EbikeRefund> ebikeRefundList = ebikeRefundService.getNoSuccessRefundOrderByDuration(wxPayConfig.getExpireMinute());
|
||||
List<EbikeRefund> ebikeRefundList = ebikeRefundService.getNoSuccessRefundOrderByDuration(wxPayConfig.getExpireMinute(), wxPayConfig.getQueryLimit());
|
||||
if (ebikeRefundList.isEmpty()) {
|
||||
log.debug("当前无退款中的退款单");
|
||||
return;
|
||||
}
|
||||
log.info("共发现 {} 笔待处理的退款单", ebikeRefundList.size());
|
||||
// 2. 遍历退款单,查询退款状态
|
||||
for (EbikeRefund ebikeRefund : ebikeRefundList) {
|
||||
log.warn("超时未退款的退款单号 ===> {}", ebikeRefund.getRefundId());
|
||||
|
||||
@ -56,8 +56,9 @@ payment:
|
||||
public-key-id: PUB_KEY_ID_0117151470052025042500331704000601
|
||||
pay-notify_url: https://www.cdzhuojing.cn/ebike/payment/wxPayment/notify/pay
|
||||
refund-notify_url: https://www.cdzhuojing.cn/ebike/payment/wxPayment/notify/refund
|
||||
expire-minutes: 1440
|
||||
pay-schedule: 0 0 0/12 * * ?
|
||||
expire-minute: 120
|
||||
query-limit: 100
|
||||
pay-schedule: 0 0 0/2 * * ?
|
||||
refund-schedule: 0 0/30 * * * ?
|
||||
task-scheduler-pool:
|
||||
poolSize: 100
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user