Merge remote-tracking branch 'origin/main'

This commit is contained in:
attiya 2026-01-08 17:23:38 +08:00
commit e2fc06d56c
6 changed files with 84 additions and 95 deletions

View File

@ -12,17 +12,17 @@ public interface RefundStatus {
/** /**
* 退款成功 * 退款成功
*/ */
int APPLYING = 0; int SUCCESS = 0;
/** /**
* 关闭 * 关闭
*/ */
int PROCESSING = 1; int CLOSED = 1;
/** /**
* 退款中 * 退款中
*/ */
int PROCESSED = 2; int PROCESSING = 2;
/** /**
* 异常 * 异常
*/ */
int CLOSED = 3; int ABNORMAL = 3;
} }

View File

@ -1,34 +0,0 @@
package com.cdzy.payment.model.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 退款信息
*
* @author yanglei
* @since 2025-10-21 10:26
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EbikeRefundInfoVo implements Serializable {
/**
* 退款金额单位为元
*/
private BigDecimal refund;
/**
* 原订单金额单位为元
*/
private BigDecimal total;
/**
* 退款币种 (默认CNY)
*/
private String currency = "CNY";
}

View File

@ -14,21 +14,21 @@ import com.mybatisflex.core.service.IService;
public interface EbikeOrderService extends IService<EbikeOrder> { public interface EbikeOrderService extends IService<EbikeOrder> {
/** /**
* 订单退款完成 * 订单退款完成 由退款中 -> 退款成功
* *
* @param orderId 订单ID * @param orderId 订单ID
*/ */
void doneRefund(Long orderId); void doneRefund(Long orderId);
/** /**
* 订单退款 * 订单退款 由退款申请中 -> 退款中
* *
* @param orderId 订单ID * @param orderId 订单ID
*/ */
void refund(Long orderId); void refund(Long orderId);
/** /**
* 订单退款失败 * 订单退款失败 由退款中 -> 退款失败
* *
* @param orderId 订单ID * @param orderId 订单ID
*/ */

View File

@ -36,7 +36,7 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
public void doneRefund(Long orderId) { public void doneRefund(Long orderId) {
QueryWrapper queryWrapper = QueryWrapper.create() QueryWrapper queryWrapper = QueryWrapper.create()
.where(EBIKE_ORDER.ORDER_ID.eq(orderId)) .where(EBIKE_ORDER.ORDER_ID.eq(orderId))
.where(EBIKE_ORDER.ORDER_STATUS.eq(EbikeOrderStatus.REFUND_APPLYING)); .where(EBIKE_ORDER.ORDER_STATUS.eq(EbikeOrderStatus.REFUNDING));
EbikeOrder userOrders = this.mapper.selectOneByQuery(queryWrapper); EbikeOrder userOrders = this.mapper.selectOneByQuery(queryWrapper);
if (userOrders == null) { if (userOrders == null) {
log.warn("退款完成时未找到订单订单ID: {}, 或订单状态不是退款中", orderId); log.warn("退款完成时未找到订单订单ID: {}, 或订单状态不是退款中", orderId);
@ -50,7 +50,7 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
public void failRefund(Long orderId) { public void failRefund(Long orderId) {
QueryWrapper queryWrapper = QueryWrapper.create() QueryWrapper queryWrapper = QueryWrapper.create()
.where(EBIKE_ORDER.ORDER_ID.eq(orderId)) .where(EBIKE_ORDER.ORDER_ID.eq(orderId))
.where(EBIKE_ORDER.ORDER_STATUS.eq(EbikeOrderStatus.REFUND_APPLYING)); .where(EBIKE_ORDER.ORDER_STATUS.eq(EbikeOrderStatus.REFUNDING));
EbikeOrder userOrders = this.mapper.selectOneByQuery(queryWrapper); EbikeOrder userOrders = this.mapper.selectOneByQuery(queryWrapper);
userOrders.setOrderStatus(EbikeOrderStatus.REFUND_FAILED); userOrders.setOrderStatus(EbikeOrderStatus.REFUND_FAILED);
this.mapper.update(userOrders); this.mapper.update(userOrders);

View File

@ -45,7 +45,7 @@ public class EbikeRefundServiceImpl extends ServiceImpl<EbikeRefundMapper, Ebike
totalSeconds totalSeconds
); );
QueryWrapper query = QueryWrapper.create() QueryWrapper query = QueryWrapper.create()
.where(EBIKE_REFUND.REFUND_STATUS.eq(RefundStatus.PROCESSED)) .where(EBIKE_REFUND.REFUND_STATUS.eq(RefundStatus.PROCESSING))
.and(timeFilter); .and(timeFilter);
return list(query); return list(query);
} }
@ -99,10 +99,15 @@ public class EbikeRefundServiceImpl extends ServiceImpl<EbikeRefundMapper, Ebike
log.error("未找到对应的退款记录refundOrderId: {}", refundOrderId); log.error("未找到对应的退款记录refundOrderId: {}", refundOrderId);
return false; return false;
} }
if (ebikeRefund.getRefundStatus() == RefundStatus.APPLYING) { if (ebikeRefund.getRefundStatus() == RefundStatus.SUCCESS) {
log.info("退款已处理成功。refundOrderId: {}", refundOrderId); log.info("退款已处理成功。refundOrderId: {}", refundOrderId);
return true; return true;
} }
if (ebikeRefund.getRefundStatus() == RefundStatus.CLOSED ||
ebikeRefund.getRefundStatus() == RefundStatus.ABNORMAL) {
log.info("退款单状态异常或关闭。refundOrderId: {}", refundOrderId);
return true;
}
log.info("退款回调订单Id:{}, 退款回调订单状态:{}", refundOrderId, refundNotification.getRefundStatus()); log.info("退款回调订单Id:{}, 退款回调订单状态:{}", refundOrderId, refundNotification.getRefundStatus());
ebikeRefund.setRefundStatus(refundNotification.getRefundStatus().ordinal()); ebikeRefund.setRefundStatus(refundNotification.getRefundStatus().ordinal());
if (Status.SUCCESS.equals(refundNotification.getRefundStatus())) { if (Status.SUCCESS.equals(refundNotification.getRefundStatus())) {
@ -115,9 +120,13 @@ public class EbikeRefundServiceImpl extends ServiceImpl<EbikeRefundMapper, Ebike
Long orderId = ebikeRefund.getOrderId(); Long orderId = ebikeRefund.getOrderId();
// 更新订单退款状态 // 更新订单退款状态
switch (refundNotification.getRefundStatus()) { switch (refundNotification.getRefundStatus()) {
case PROCESSING, CLOSED -> ebikeOrderService.refund(orderId); // 退款中
case PROCESSING -> ebikeOrderService.refund(orderId);
// 成功退款
case SUCCESS -> ebikeOrderService.doneRefund(orderId); case SUCCESS -> ebikeOrderService.doneRefund(orderId);
// 失败/关闭 订单退款失败
case ABNORMAL -> ebikeOrderService.failRefund(orderId); case ABNORMAL -> ebikeOrderService.failRefund(orderId);
default -> log.warn("未知的微信退款状态: {}, orderId: {}", refundNotification.getRefundStatus(), orderId);
} }
return updateById(ebikeRefund); return updateById(ebikeRefund);
} }

View File

@ -1,11 +1,18 @@
package com.cdzy.payment.service.impl; package com.cdzy.payment.service.impl;
import com.cdzy.common.enums.GlobalConstants; import com.cdzy.common.enums.GlobalConstants;
import com.cdzy.common.ex.EbikeException;
import com.cdzy.payment.config.WxPayConfig; import com.cdzy.payment.config.WxPayConfig;
import com.cdzy.payment.enums.PaymentMethod; import com.cdzy.payment.enums.PaymentMethod;
import com.cdzy.payment.enums.RefundStatus;
import com.cdzy.payment.model.entity.EbikePayment; import com.cdzy.payment.model.entity.EbikePayment;
import com.cdzy.payment.model.entity.EbikeRefund; import com.cdzy.payment.model.entity.EbikeRefund;
import com.cdzy.payment.model.vo.*; import com.cdzy.payment.model.vo.EbikePaymentAmountVo;
import com.cdzy.payment.model.vo.EbikePaymentDetailVo;
import com.cdzy.payment.model.vo.EbikePaymentVo;
import com.cdzy.payment.model.vo.EbikeWxHandleNotifyVo;
import com.cdzy.payment.model.vo.EbikeWxJsapiPromptVo;
import com.cdzy.payment.service.EbikeOrderService;
import com.cdzy.payment.service.EbikePaymentService; import com.cdzy.payment.service.EbikePaymentService;
import com.cdzy.payment.service.EbikeRefundService; import com.cdzy.payment.service.EbikeRefundService;
import com.cdzy.payment.service.EbikeWxPayService; import com.cdzy.payment.service.EbikeWxPayService;
@ -27,11 +34,22 @@ import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.core.util.NonceUtil; import com.wechat.pay.java.core.util.NonceUtil;
import com.wechat.pay.java.service.payments.jsapi.JsapiService; import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.Amount; import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.CloseOrderRequest;
import com.wechat.pay.java.service.payments.jsapi.model.Detail;
import com.wechat.pay.java.service.payments.jsapi.model.GoodsDetail; import com.wechat.pay.java.service.payments.jsapi.model.GoodsDetail;
import com.wechat.pay.java.service.payments.jsapi.model.*; import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
import com.wechat.pay.java.service.payments.jsapi.model.SettleInfo;
import com.wechat.pay.java.service.payments.model.Transaction; import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService; import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.*; import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import com.wechat.pay.java.service.refund.model.Status;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -44,8 +62,13 @@ import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import static com.wechat.pay.java.core.http.Constant.*; import static com.wechat.pay.java.core.http.Constant.REQUEST_ID;
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_NONCE;
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_SERIAL;
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_SIGNATURE;
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_TIMESTAMP;
/** /**
* 微信支付服务类JSAPI支付小程序 * 微信支付服务类JSAPI支付小程序
@ -81,6 +104,9 @@ public class EbikeWxPayServiceImpl implements EbikeWxPayService {
@Resource @Resource
private ObjectMapper objectMapper; private ObjectMapper objectMapper;
@Resource
private EbikeOrderService orderService;
@Override @Override
public boolean closeOrder(String outTradeNo) { public boolean closeOrder(String outTradeNo) {
try { try {
@ -385,31 +411,26 @@ public class EbikeWxPayServiceImpl implements EbikeWxPayService {
notifyVo.setSuccess(false); notifyVo.setSuccess(false);
// 检查退款记录是否存在 // 检查退款记录是否存在
EbikeRefund ebikeRefund = ebikeRefundService.getById(refundDto.getRefundId()); EbikeRefund ebikeRefund = ebikeRefundService.getById(refundDto.getRefundId());
if (ebikeRefund == null) { if (Objects.isNull(ebikeRefund)) {
log.error("退款refund失败{} 退款申请不存在", refundDto.getRefundId()); throw new EbikeException("退款订单不存在");
notifyVo.setMessage(String.format("{%s}退款申请不存在", refundDto.getRefundId()));
return notifyVo;
} }
// 检查退款状态 // 检查退款状态
if (Status.SUCCESS.ordinal() == ebikeRefund.getRefundStatus()) { if (RefundStatus.SUCCESS == ebikeRefund.getRefundStatus()) {
log.error("退款refund失败{} 退款已经成功,不能重复退款", refundDto.getRefundId()); throw new EbikeException("当前订单已完成退款");
notifyVo.setMessage(String.format("{%s}退款已经成功,不能重复退款", refundDto.getRefundId()));
return notifyVo;
} }
if (Status.CLOSED.ordinal() == ebikeRefund.getRefundStatus() || if (RefundStatus.CLOSED == ebikeRefund.getRefundStatus() ||
Status.ABNORMAL.ordinal() == ebikeRefund.getRefundStatus()) { RefundStatus.ABNORMAL == ebikeRefund.getRefundStatus()) {
//重新发起 //重新生成退款id并发起退款
String newOrder = StringUtils.generateSnowflakeId("refundId"); String newOrder = StringUtils.generateSnowflakeId("refundId");
ebikeRefund.setRefundOrderId(newOrder); ebikeRefund.setRefundOrderId(newOrder);
} }
// 查询支付记录 // 查询支付记录
Long orderId = ebikeRefund.getOrderId(); Long orderId = ebikeRefund.getOrderId();
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(orderId); EbikePayment ebikePayment = ebikePaymentService.getByOrderId(orderId);
if (Objects.isNull(ebikePayment)) {
throw new EbikeException("支付记录不存在");
}
String transactionId = ebikePayment.getTransactionId(); String transactionId = ebikePayment.getTransactionId();
EbikeRefundInfoVo amount = new EbikeRefundInfoVo();
amount.setTotal(ebikePayment.getCostPrice());
amount.setRefund(ebikePayment.getTotal());
amount.setCurrency(ebikeRefund.getCurrency());
// 发起退款 // 发起退款
CreateRequest request = new CreateRequest(); CreateRequest request = new CreateRequest();
request.setTransactionId(transactionId); request.setTransactionId(transactionId);
@ -418,43 +439,36 @@ public class EbikeWxPayServiceImpl implements EbikeWxPayService {
request.setReason(ebikeRefund.getProblemDescription()); request.setReason(ebikeRefund.getProblemDescription());
request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl()); request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl());
AmountReq amountReq = new AmountReq(); AmountReq amountReq = new AmountReq();
amountReq.setRefund(yuanToCent(amount.getRefund())); amountReq.setRefund(yuanToCent(ebikePayment.getTotal()));
amountReq.setTotal(yuanToCent(amount.getTotal())); amountReq.setTotal(yuanToCent(ebikePayment.getTotal()));
amountReq.setCurrency(amount.getCurrency()); amountReq.setCurrency(ebikePayment.getCurrency());
request.setAmount(amountReq); request.setAmount(amountReq);
try { try {
Refund result = wxRefundService.create(request); Refund result = wxRefundService.create(request);
// 更新退款信息 if (result == null) {
if (result != null) { log.error("调用微信退款接口返回空,订单号: {}", orderId);
ebikeRefund.setOrderId(orderId); notifyVo.setMessage("退款请求失败");
ebikeRefund.setTransactionId(transactionId);
ebikeRefund.setTotal(amount.getTotal());
ebikeRefund.setRefundStatus(result.getStatus().ordinal());
ebikeRefund.setCurrency(amount.getCurrency());
ebikeRefund.setRefund(new BigDecimal(result.getAmount().getRefund())
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
ebikeRefund.setRefundTime(LocalDateTime.now());
ebikeRefund.setRefundTransactionId(result.getRefundId());
ebikeRefundService.updateById(ebikeRefund);
notifyVo.setSuccess(true);
notifyVo.setMessage("退款成功");
return notifyVo; return notifyVo;
} }
log.error("退款refund失败订单号{}", orderId); orderService.refund(orderId);
notifyVo.setMessage("退款失败"); // 更新退款信息
ebikeRefund.setOrderId(orderId);
ebikeRefund.setTransactionId(transactionId);
ebikeRefund.setTotal(ebikePayment.getCostPrice());
ebikeRefund.setRefundStatus(result.getStatus().ordinal());
ebikeRefund.setCurrency(ebikePayment.getCurrency());
ebikeRefund.setRefund(new BigDecimal(result.getAmount().getRefund())
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
ebikeRefund.setRefundTime(LocalDateTime.now());
ebikeRefund.setRefundTransactionId(result.getRefundId());
ebikeRefundService.updateById(ebikeRefund);
notifyVo.setSuccess(true);
notifyVo.setMessage("退款已提交");
return notifyVo; return notifyVo;
} catch (Exception e) { } catch (Exception e) {
String err = logError("退款refund", e); log.error("发起退款异常refundId: {}, orderId: {}, error: {}",
try { refundDto.getRefundId(), orderId, e.getMessage(), e);
JsonNode jsonNode = objectMapper.readTree(err); notifyVo.setMessage("退款失败: " + e.getMessage());
if (jsonNode.has("message")) {
notifyVo.setMessage(jsonNode.get("message").asText());
} else {
notifyVo.setMessage(err);
}
} catch (Exception ex) {
notifyVo.setMessage(err);
}
return notifyVo; return notifyVo;
} }
} }