feat 支付订单/退款订单/支付通道配置列表

This commit is contained in:
nws
2024-01-13 00:32:29 +08:00
parent 7734bf95b9
commit 5be679845b
12 changed files with 83 additions and 38 deletions

View File

@@ -50,10 +50,13 @@
- [x] (前端) 支付修复记录
- 2024-01-12:
- [x] (前端) 支付订单
- [ ] (前端) 退款订单
- [x] (前端) 退款订单
- [x] (前端) 支付通道配置列表
- 2024-01-13:
- [ ] (前端) 微信/支付宝支付通道配置
- [ ] 支付通道支持停用
- **任务池**
- [ ] 支付宝方式支持撤销方式,
- [ ] 支付宝关闭支付时支持撤销方式,
- [ ] 支持转账操作, 通过支付通道专有参数进行实现, 转账时只能单个通道进行操作
- [ ] 支付成功回调后, 如果订单已超时, 则进入待退款订单中,提示进行退款,或者自动退款
- [ ] 退款状态同步逻辑

View File

@@ -4,15 +4,22 @@ import cn.bootx.platform.common.core.rest.PageResult;
import cn.bootx.platform.common.core.rest.Res;
import cn.bootx.platform.common.core.rest.ResResult;
import cn.bootx.platform.common.core.rest.param.PageParam;
import cn.bootx.platform.common.spring.util.WebServletUtil;
import cn.bootx.platform.daxpay.param.pay.RefundParam;
import cn.bootx.platform.daxpay.service.core.order.refund.service.PayRefundOrderService;
import cn.bootx.platform.daxpay.service.core.payment.refund.service.PayRefundService;
import cn.bootx.platform.daxpay.service.dto.order.refund.PayRefundOrderDto;
import cn.bootx.platform.daxpay.service.param.order.PayOrderRefundParam;
import cn.bootx.platform.daxpay.service.param.order.PayRefundOrderQuery;
import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.servlet.ServletUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.Optional;
/**
* 支付退款控制器
@@ -25,6 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class PayRefundOrderController {
private final PayRefundOrderService payRefundOrderService;
private final PayRefundService payRefundService;
@Operation(summary = "分页查询")
@@ -38,4 +46,22 @@ public class PayRefundOrderController {
public ResResult<PayRefundOrderDto> findById(Long paymentId){
return Res.ok(payRefundOrderService.findById(paymentId));
}
@Operation(summary = "发起退款")
@PostMapping("/refund")
public ResResult<Void> refund(@RequestBody PayOrderRefundParam param){
String ip = Optional.ofNullable(WebServletUtil.getRequest())
.map(ServletUtil::getClientIP)
.orElse("未知");
RefundParam refundParam = new RefundParam();
refundParam.setRefundNo(IdUtil.getSnowflakeNextIdStr());
refundParam.setPaymentId(param.getPaymentId());
refundParam.setRefundChannels(param.getRefundChannels());
refundParam.setReqTime(LocalDateTime.now());
refundParam.setClientIp(ip);
payRefundService.refund(refundParam);
return Res.ok();
}
}

View File

@@ -13,7 +13,7 @@ import lombok.Getter;
public enum PayRefundStatusEnum {
SUCCESS("success","成功"),
FAIL("fail","失败");
FAIL("fail"," ");
/** 编码 */
private final String code;

View File

@@ -49,7 +49,7 @@ public abstract class PayCommonParam {
/** API版本号 */
@Schema(description = "API版本号")
@NotBlank(message = "API版本号必填")
private String version;
private String version = "1.0.0";
/** 请求时间,时间戳转时间 */
@Schema(description = "请求时间,传输时间戳")

View File

@@ -24,7 +24,7 @@ public class RefundParam extends PayCommonParam {
private String businessNo;
/**
* 部分退款需要传输refundModes参数
* 部分退款需要传输支付通道参数参数
*/
@Schema(description = "是否全部退款")
private boolean refundAll;

View File

@@ -33,10 +33,10 @@ public class PaySyncResult extends PayCommonResult{
private boolean repair;
@Schema(description = "支付单修复前状态")
private String oldStatus;
private String beforeStatus;
@Schema(description = "支付单修复后状态")
private String repairStatus;
private String afterStatus;
@Schema(description = "失败原因")
private String errorMsg;

View File

@@ -13,6 +13,7 @@ import lombok.experimental.Accessors;
@Accessors(chain = true)
public class RefundableInfo {
/**
* 通道
* @see PayChannelEnum#getCode()
*/
private String channel;

View File

@@ -63,7 +63,7 @@ public class WechatRefundService {
if (StrUtil.isBlank(weChatPayConfig.getP12())){
String errorMsg = "微信p.12证书未配置,无法进行退款";
refundInfo.setErrorMsg(errorMsg);
refundInfo.setErrorCode(PayRefundStatusEnum.SUCCESS.getCode());
refundInfo.setErrorCode(PayRefundStatusEnum.FAIL.getCode());
throw new PayFailureException(errorMsg);
}
byte[] fileBytes = Base64.decode(weChatPayConfig.getP12());

View File

@@ -92,15 +92,15 @@ public class PaySyncService {
AbsPaySyncStrategy syncPayStrategy = PaySyncStrategyFactory.create(payOrder.getAsyncChannel());
syncPayStrategy.initPayParam(payOrder);
// 记录支付单同步前后的状态
String oldStatus = payOrder.getStatus();
String repairStatus = null;
String beforeStatus = payOrder.getStatus();
String afterStatus = null;
// 执行同步操作, 获取支付网关同步的结果
GatewaySyncResult syncResult = syncPayStrategy.doSyncStatus();
// 判断是否同步成功
if (Objects.equals(syncResult.getSyncStatus(), PaySyncStatusEnum.FAIL)){
// 同步失败, 返回失败响应, 同时记录失败的日志
this.saveRecord(payOrder, syncResult, true, oldStatus, null, syncResult.getErrorMsg());
this.saveRecord(payOrder, syncResult, true, beforeStatus, null, syncResult.getErrorMsg());
return new PaySyncResult().setErrorMsg(syncResult.getErrorMsg());
}
@@ -110,23 +110,23 @@ public class PaySyncService {
// 状态不一致,执行支付单修复逻辑
if (!statusSync){
this.resultHandler(syncResult, payOrder);
repairStatus = payOrder.getStatus();
afterStatus = payOrder.getStatus();
}
} catch (PayFailureException e) {
// 同步失败, 返回失败响应, 同时记录失败的日志
syncResult.setSyncStatus(PaySyncStatusEnum.FAIL);
this.saveRecord(payOrder, syncResult, false, oldStatus, null, e.getMessage());
this.saveRecord(payOrder, syncResult, false, beforeStatus, null, e.getMessage());
return new PaySyncResult().setErrorMsg(e.getMessage());
}
// 同步成功记录日志
this.saveRecord( payOrder, syncResult, !statusSync, oldStatus, repairStatus, null);
this.saveRecord( payOrder, syncResult, !statusSync, beforeStatus, afterStatus, null);
return new PaySyncResult()
.setGatewayStatus(syncResult.getSyncStatus().getCode())
.setSuccess(true)
.setRepair(!statusSync)
.setOldStatus(oldStatus)
.setRepairStatus(repairStatus);
.setBeforeStatus(beforeStatus)
.setAfterStatus(afterStatus);
} finally {
lockTemplate.releaseLock(lock);
}
@@ -233,11 +233,11 @@ public class PaySyncService {
* @param payOrder 支付单
* @param syncResult 同步结果
* @param repair 是否修复
* @param oldStatus 修复前的状态
* @param beforeStatus 修复前的状态
* @param repairStatus 修复后的状态
* @param errorMsg 错误信息
*/
private void saveRecord(PayOrder payOrder,GatewaySyncResult syncResult, boolean repair, String oldStatus, String repairStatus, String errorMsg){
private void saveRecord(PayOrder payOrder,GatewaySyncResult syncResult, boolean repair, String beforeStatus, String repairStatus, String errorMsg){
PaySyncRecord paySyncRecord = new PaySyncRecord()
.setPaymentId(payOrder.getId())
.setBusinessNo(payOrder.getBusinessNo())
@@ -245,8 +245,8 @@ public class PaySyncService {
.setSyncInfo(syncResult.getSyncInfo())
.setGatewayStatus(syncResult.getSyncStatus().getCode())
.setRepairOrder(repair)
.setOldStatus(oldStatus)
.setRepairStatus(repairStatus)
.setBeforeStatus(beforeStatus)
.setAfterStatus(repairStatus)
.setErrorMsg(errorMsg)
.setClientIp(PaymentContextLocal.get().getRequest().getClientIp())
.setReqId(PaymentContextLocal.get().getRequest().getReqId());

View File

@@ -62,11 +62,10 @@ public class PaySyncRecord extends MpCreateEntity implements EntityBaseFunction<
/** 支付单修复前状态 */
@DbColumn(comment = "支付单修复前状态")
private String oldStatus;
private String beforeStatus;
/** 支付单修复后状态 */
@DbColumn(comment = "支付单修复后状态")
private String repairStatus;
private String afterStatus;
@DbColumn(comment = "错误消息")
private String errorMsg;

View File

@@ -22,15 +22,6 @@ public class AliPayConfigDto extends BaseDto implements Serializable {
private static final long serialVersionUID = 6641158663606363171L;
@Schema(description = "名称")
private String name;
@Schema(description = "商户编码")
private String mchCode;
@Schema(description = "商户应用编码")
private String mchAppCode;
@Schema(description = "支付宝商户appId")
@SensitiveInfo
private String appId;
@@ -38,9 +29,6 @@ public class AliPayConfigDto extends BaseDto implements Serializable {
@Schema(description = "服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数必须外网可以正常访问")
private String notifyUrl;
@Schema(description = "页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数必须外网可以正常访问 商户可以自定义同步跳转地址")
private String returnUrl;
@Schema(description = "请求网关地址")
private String serverUrl;

View File

@@ -0,0 +1,28 @@
package cn.bootx.platform.daxpay.service.param.order;
import cn.bootx.platform.daxpay.param.pay.RefundChannelParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 支付订单退款发起参数
* @author xxm
* @since 2024/1/12
*/
@Data
@Accessors(chain = true)
@Schema(title = "支付订单退款发起参数")
public class PayOrderRefundParam {
/** 支付id */
private Long paymentId;
/** 原因 */
private String reason;
/** 退款明细 */
private List<RefundChannelParam> refundChannels;
}