|
@@ -7,6 +7,7 @@ import com.haha.common.enums.RefundStatus;
|
|
|
import com.haha.entity.Order;
|
|
import com.haha.entity.Order;
|
|
|
import com.haha.service.AccountService;
|
|
import com.haha.service.AccountService;
|
|
|
import com.haha.service.OrderService;
|
|
import com.haha.service.OrderService;
|
|
|
|
|
+import com.haha.service.RefundService;
|
|
|
import com.haha.service.payment.*;
|
|
import com.haha.service.payment.*;
|
|
|
import com.haha.service.payment.payscore.PayScoreResult;
|
|
import com.haha.service.payment.payscore.PayScoreResult;
|
|
|
import com.haha.service.payment.payscore.PayScoreService;
|
|
import com.haha.service.payment.payscore.PayScoreService;
|
|
@@ -41,6 +42,9 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
|
|
|
|
|
@Autowired(required = false)
|
|
@Autowired(required = false)
|
|
|
private PayScoreService payScoreService;
|
|
private PayScoreService payScoreService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private RefundService refundService;
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public PaymentResult createPayment(Long orderId, PaymentChannel channel, Map<String, String> extra) {
|
|
public PaymentResult createPayment(Long orderId, PaymentChannel channel, Map<String, String> extra) {
|
|
@@ -133,8 +137,14 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
@Override
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public RefundResult refund(Long orderId, String reason) {
|
|
public RefundResult refund(Long orderId, String reason) {
|
|
|
- log.info("发起退款请求: orderId={}, reason={}", orderId, reason);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ return refund(orderId, reason, null);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public RefundResult refund(Long orderId, String reason, BigDecimal refundAmount) {
|
|
|
|
|
+ log.info("发起退款请求: orderId={}, reason={}, refundAmount={}", orderId, reason, refundAmount);
|
|
|
|
|
+
|
|
|
// 1. 参数校验
|
|
// 1. 参数校验
|
|
|
if (orderId == null) {
|
|
if (orderId == null) {
|
|
|
log.error("退款失败: 订单ID不能为空");
|
|
log.error("退款失败: 订单ID不能为空");
|
|
@@ -144,7 +154,7 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
.errorMsg("订单ID不能为空")
|
|
.errorMsg("订单ID不能为空")
|
|
|
.build();
|
|
.build();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 2. 查询订单
|
|
// 2. 查询订单
|
|
|
Order order = orderService.getById(orderId);
|
|
Order order = orderService.getById(orderId);
|
|
|
if (order == null) {
|
|
if (order == null) {
|
|
@@ -155,7 +165,7 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
.errorMsg("订单不存在")
|
|
.errorMsg("订单不存在")
|
|
|
.build();
|
|
.build();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 3. 校验订单状态(必须是已支付)
|
|
// 3. 校验订单状态(必须是已支付)
|
|
|
if (!OrderConstants.PAY_STATUS_PAID.equals(order.getPayStatus())) {
|
|
if (!OrderConstants.PAY_STATUS_PAID.equals(order.getPayStatus())) {
|
|
|
log.error("退款失败: 订单状态不正确, orderId={}, payStatus={}", orderId, order.getPayStatus());
|
|
log.error("退款失败: 订单状态不正确, orderId={}, payStatus={}", orderId, order.getPayStatus());
|
|
@@ -165,12 +175,12 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
.errorMsg("订单状态不正确,只有已支付订单可以退款")
|
|
.errorMsg("订单状态不正确,只有已支付订单可以退款")
|
|
|
.build();
|
|
.build();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 4. 校验订单完成时间是否超过7天
|
|
// 4. 校验订单完成时间是否超过7天
|
|
|
if (order.getPayTime() != null) {
|
|
if (order.getPayTime() != null) {
|
|
|
LocalDateTime now = LocalDateTime.now();
|
|
LocalDateTime now = LocalDateTime.now();
|
|
|
long daysDiff = java.time.temporal.ChronoUnit.DAYS.between(order.getPayTime(), now);
|
|
long daysDiff = java.time.temporal.ChronoUnit.DAYS.between(order.getPayTime(), now);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (daysDiff > PaymentConstants.REFUND_MAX_DAYS) {
|
|
if (daysDiff > PaymentConstants.REFUND_MAX_DAYS) {
|
|
|
log.error("退款失败: 订单已完成超过7天,不允许退款, orderId={}, payTime={}", orderId, order.getPayTime());
|
|
log.error("退款失败: 订单已完成超过7天,不允许退款, orderId={}, payTime={}", orderId, order.getPayTime());
|
|
|
return RefundResult.builder()
|
|
return RefundResult.builder()
|
|
@@ -180,10 +190,14 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
.build();
|
|
.build();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 确定实际退款金额
|
|
|
|
|
+ BigDecimal actualRefundAmount = refundAmount != null ? refundAmount
|
|
|
|
|
+ : (order.getPaidAmount() != null ? order.getPaidAmount() : order.getTotalAmount());
|
|
|
|
|
+
|
|
|
// 5. 根据订单的 payChannel 获取支付渠道
|
|
// 5. 根据订单的 payChannel 获取支付渠道
|
|
|
PaymentChannel channel = PaymentChannel.fromCode(order.getPayChannel());
|
|
PaymentChannel channel = PaymentChannel.fromCode(order.getPayChannel());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 6. 如果 channel 为 WECHAT_PAYSCORE,走支付分退款流程
|
|
// 6. 如果 channel 为 WECHAT_PAYSCORE,走支付分退款流程
|
|
|
if (channel == PaymentChannel.WECHAT_PAYSCORE) {
|
|
if (channel == PaymentChannel.WECHAT_PAYSCORE) {
|
|
|
if (payScoreService == null) {
|
|
if (payScoreService == null) {
|
|
@@ -195,12 +209,12 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
.build();
|
|
.build();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- BigDecimal actualRefundAmount = order.getPaidAmount() != null ? order.getPaidAmount() : order.getTotalAmount();
|
|
|
|
|
PayScoreResult payScoreResult = payScoreService.refundPayScoreOrder(
|
|
PayScoreResult payScoreResult = payScoreService.refundPayScoreOrder(
|
|
|
orderId, actualRefundAmount, reason != null ? reason : "用户申请退款");
|
|
orderId, actualRefundAmount, reason != null ? reason : "用户申请退款");
|
|
|
|
|
|
|
|
if (payScoreResult.isSuccess()) {
|
|
if (payScoreResult.isSuccess()) {
|
|
|
log.info("支付分退款成功: orderId={}, refundId={}", orderId, payScoreResult.getPackageStr());
|
|
log.info("支付分退款成功: orderId={}, refundId={}", orderId, payScoreResult.getPackageStr());
|
|
|
|
|
+ updateOrderRefundStatus(order, reason, payScoreResult.getPackageStr(), actualRefundAmount);
|
|
|
return RefundResult.builder()
|
|
return RefundResult.builder()
|
|
|
.success(true)
|
|
.success(true)
|
|
|
.refundId(payScoreResult.getPackageStr())
|
|
.refundId(payScoreResult.getPackageStr())
|
|
@@ -219,14 +233,14 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
// 7. 如果 channel 为 null 或 BALANCE,直接更新退款状态(余额退款不经过第三方)
|
|
// 7. 如果 channel 为 null 或 BALANCE,直接更新退款状态(余额退款不经过第三方)
|
|
|
if (channel == null || channel == PaymentChannel.BALANCE) {
|
|
if (channel == null || channel == PaymentChannel.BALANCE) {
|
|
|
log.info("余额退款,直接更新订单状态: orderId={}", orderId);
|
|
log.info("余额退款,直接更新订单状态: orderId={}", orderId);
|
|
|
- updateOrderRefundStatus(order, reason, null);
|
|
|
|
|
|
|
+ updateOrderRefundStatus(order, reason, null, actualRefundAmount);
|
|
|
return RefundResult.builder()
|
|
return RefundResult.builder()
|
|
|
.success(true)
|
|
.success(true)
|
|
|
.refundId("BALANCE_REFUND_" + orderId)
|
|
.refundId("BALANCE_REFUND_" + orderId)
|
|
|
.build();
|
|
.build();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 7. 获取支付策略
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 8. 获取支付策略
|
|
|
PaymentStrategy strategy;
|
|
PaymentStrategy strategy;
|
|
|
try {
|
|
try {
|
|
|
strategy = channelFactory.getStrategy(channel);
|
|
strategy = channelFactory.getStrategy(channel);
|
|
@@ -238,9 +252,8 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
.errorMsg("不支持的支付渠道: " + channel.getCode())
|
|
.errorMsg("不支持的支付渠道: " + channel.getCode())
|
|
|
.build();
|
|
.build();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 8. 构建退款请求(使用实付金额 paidAmount,避免多退优惠券部分)
|
|
|
|
|
- BigDecimal actualRefundAmount = order.getPaidAmount() != null ? order.getPaidAmount() : order.getTotalAmount();
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 9. 构建退款请求
|
|
|
String refundNo = generateRefundNo(order.getOrderNo());
|
|
String refundNo = generateRefundNo(order.getOrderNo());
|
|
|
RefundRequest refundRequest = RefundRequest.builder()
|
|
RefundRequest refundRequest = RefundRequest.builder()
|
|
|
.orderId(orderId)
|
|
.orderId(orderId)
|
|
@@ -251,22 +264,22 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
.reason(reason)
|
|
.reason(reason)
|
|
|
.refundNo(refundNo)
|
|
.refundNo(refundNo)
|
|
|
.build();
|
|
.build();
|
|
|
-
|
|
|
|
|
- log.info("调用支付策略执行退款: orderNo={}, refundNo={}, amount={}",
|
|
|
|
|
- order.getOrderNo(), refundNo, order.getTotalAmount());
|
|
|
|
|
-
|
|
|
|
|
- // 9. 调用策略退款
|
|
|
|
|
|
|
+
|
|
|
|
|
+ log.info("调用支付策略执行退款: orderNo={}, refundNo={}, amount={}",
|
|
|
|
|
+ order.getOrderNo(), refundNo, actualRefundAmount);
|
|
|
|
|
+
|
|
|
|
|
+ // 10. 调用策略退款
|
|
|
RefundResult result = strategy.refund(refundRequest);
|
|
RefundResult result = strategy.refund(refundRequest);
|
|
|
-
|
|
|
|
|
- // 10. 更新订单退款状态
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 11. 更新订单退款状态
|
|
|
if (result.isSuccess()) {
|
|
if (result.isSuccess()) {
|
|
|
- updateOrderRefundStatus(order, reason, result.getRefundId());
|
|
|
|
|
|
|
+ updateOrderRefundStatus(order, reason, result.getRefundId(), actualRefundAmount);
|
|
|
log.info("退款成功: orderId={}, refundId={}", orderId, result.getRefundId());
|
|
log.info("退款成功: orderId={}, refundId={}", orderId, result.getRefundId());
|
|
|
} else {
|
|
} else {
|
|
|
- log.warn("退款失败: orderId={}, errorCode={}, errorMsg={}",
|
|
|
|
|
|
|
+ log.warn("退款失败: orderId={}, errorCode={}, errorMsg={}",
|
|
|
orderId, result.getErrorCode(), result.getErrorMsg());
|
|
orderId, result.getErrorCode(), result.getErrorMsg());
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -504,7 +517,50 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
Long orderId = Long.valueOf(params.get("orderId").toString());
|
|
Long orderId = Long.valueOf(params.get("orderId").toString());
|
|
|
String reason = params.containsKey("reason") ? params.get("reason").toString() : "用户申请退款";
|
|
String reason = params.containsKey("reason") ? params.get("reason").toString() : "用户申请退款";
|
|
|
|
|
|
|
|
- log.info("退款请求 - 订单ID: {}, 原因: {}", orderId, reason);
|
|
|
|
|
|
|
+ // 提取商品列表和自定义金额
|
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
|
+ List<Map<String, Object>> products = (List<Map<String, Object>>) params.get("products");
|
|
|
|
|
+ BigDecimal customRefundAmount = null;
|
|
|
|
|
+ if (params.containsKey("refundAmount") && params.get("refundAmount") != null) {
|
|
|
|
|
+ customRefundAmount = new BigDecimal(params.get("refundAmount").toString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果指定了商品或自定义金额,走部分退款流程
|
|
|
|
|
+ boolean hasProducts = products != null && !products.isEmpty();
|
|
|
|
|
+ boolean hasCustomAmount = customRefundAmount != null;
|
|
|
|
|
+ if (hasProducts || hasCustomAmount) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 创建退款记录(PENDING),内部完成金额计算和校验
|
|
|
|
|
+ com.haha.entity.Refund refundRecord = refundService.createRefundRecord(orderId, reason, products, customRefundAmount);
|
|
|
|
|
+ BigDecimal refundAmount = refundRecord.getRefundAmount();
|
|
|
|
|
+
|
|
|
|
|
+ // 执行第三方退款
|
|
|
|
|
+ RefundResult result = refund(orderId, reason, refundAmount);
|
|
|
|
|
+
|
|
|
|
|
+ if (result.isSuccess()) {
|
|
|
|
|
+ refundService.markRefunded(refundRecord.getId(), result.getRefundId());
|
|
|
|
|
+ // 更新订单关联的退款记录ID
|
|
|
|
|
+ Order order = orderService.getById(orderId);
|
|
|
|
|
+ if (order != null) {
|
|
|
|
|
+ order.setCurrentRefundId(refundRecord.getId());
|
|
|
|
|
+ orderService.updateById(order);
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("退款成功(含商品明细) - orderId: {}, refundId: {}, amount: {}, items: {}",
|
|
|
|
|
+ orderId, refundRecord.getId(), refundAmount, products != null ? products.size() : 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("退款失败 - orderId: {}, error: {}", orderId, e.getMessage());
|
|
|
|
|
+ return RefundResult.builder()
|
|
|
|
|
+ .success(false)
|
|
|
|
|
+ .errorCode("REFUND_ERROR")
|
|
|
|
|
+ .errorMsg(e.getMessage())
|
|
|
|
|
+ .build();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 无商品选择、无自定义金额 → 全额退款(兼容旧行为)
|
|
|
|
|
+ log.info("退款请求(全额) - 订单ID: {}, 原因: {}", orderId, reason);
|
|
|
return refund(orderId, reason);
|
|
return refund(orderId, reason);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -524,34 +580,35 @@ public class PaymentServiceImpl implements PaymentService {
|
|
|
/**
|
|
/**
|
|
|
* 更新订单退款状态
|
|
* 更新订单退款状态
|
|
|
*
|
|
*
|
|
|
- * 处理逻辑:
|
|
|
|
|
- * 1. 如果是余额支付,同步将退款金额退还到用户账户余额
|
|
|
|
|
- * 2. 退款金额使用实付金额 (paidAmount),而非订单总金额 (totalAmount)
|
|
|
|
|
- * 3. 更新订单退款相关字段
|
|
|
|
|
|
|
+ * @param order 订单
|
|
|
|
|
+ * @param reason 退款原因
|
|
|
|
|
+ * @param refundId 第三方退款ID
|
|
|
|
|
+ * @param refundAmount 退款金额(null则使用实付金额)
|
|
|
*/
|
|
*/
|
|
|
- private void updateOrderRefundStatus(Order order, String reason, String refundId) {
|
|
|
|
|
- BigDecimal refundAmount = order.getPaidAmount() != null ? order.getPaidAmount() : order.getTotalAmount();
|
|
|
|
|
|
|
+ private void updateOrderRefundStatus(Order order, String reason, String refundId, BigDecimal refundAmount) {
|
|
|
|
|
+ BigDecimal amount = refundAmount != null ? refundAmount
|
|
|
|
|
+ : (order.getPaidAmount() != null ? order.getPaidAmount() : order.getTotalAmount());
|
|
|
|
|
|
|
|
// 如果是余额支付,将退款金额退还到用户账户
|
|
// 如果是余额支付,将退款金额退还到用户账户
|
|
|
if (PaymentChannel.BALANCE.getCode().equals(order.getPayChannel())) {
|
|
if (PaymentChannel.BALANCE.getCode().equals(order.getPayChannel())) {
|
|
|
- boolean balanceUpdated = accountService.updateBalance(order.getUserId(), refundAmount);
|
|
|
|
|
|
|
+ boolean balanceUpdated = accountService.updateBalance(order.getUserId(), amount);
|
|
|
if (balanceUpdated) {
|
|
if (balanceUpdated) {
|
|
|
log.info("余额退款 - 用户 {} 余额已增加: {}元, orderId={}",
|
|
log.info("余额退款 - 用户 {} 余额已增加: {}元, orderId={}",
|
|
|
- order.getUserId(), refundAmount, order.getId());
|
|
|
|
|
|
|
+ order.getUserId(), amount, order.getId());
|
|
|
} else {
|
|
} else {
|
|
|
log.error("余额退款失败 - 用户 {} 余额退还失败: {}元, orderId={}",
|
|
log.error("余额退款失败 - 用户 {} 余额退还失败: {}元, orderId={}",
|
|
|
- order.getUserId(), refundAmount, order.getId());
|
|
|
|
|
|
|
+ order.getUserId(), amount, order.getId());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
order.setRefundStatus(RefundStatus.REFUNDED.getCode());
|
|
order.setRefundStatus(RefundStatus.REFUNDED.getCode());
|
|
|
- order.setRefundAmount(refundAmount);
|
|
|
|
|
|
|
+ order.setRefundAmount(amount);
|
|
|
order.setRefundTime(LocalDateTime.now());
|
|
order.setRefundTime(LocalDateTime.now());
|
|
|
order.setRefundReason(reason);
|
|
order.setRefundReason(reason);
|
|
|
order.setPayStatus(OrderConstants.PAY_STATUS_REFUND);
|
|
order.setPayStatus(OrderConstants.PAY_STATUS_REFUND);
|
|
|
orderService.updateById(order);
|
|
orderService.updateById(order);
|
|
|
log.info("订单退款状态已更新 - orderId={}, refundAmount={}, payStatus={}",
|
|
log.info("订单退款状态已更新 - orderId={}, refundAmount={}, payStatus={}",
|
|
|
- order.getId(), refundAmount, OrderConstants.PAY_STATUS_REFUND);
|
|
|
|
|
|
|
+ order.getId(), amount, OrderConstants.PAY_STATUS_REFUND);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|