diff --git a/_doc/Task.md b/_doc/Task.md index ca7efa87..8661ffa5 100644 --- a/_doc/Task.md +++ b/_doc/Task.md @@ -50,10 +50,13 @@ - [x] (前端) 支付修复记录 - 2024-01-12: - [x] (前端) 支付订单 - - [ ] (前端) 退款订单 + - [x] (前端) 退款订单 + - [x] (前端) 支付通道配置列表 +- 2024-01-13: - [ ] (前端) 微信/支付宝支付通道配置 + - [ ] 支付通道支持停用 - **任务池** - - [ ] 支付宝方式支持撤销方式, + - [ ] 支付宝关闭支付时支持撤销方式, - [ ] 支持转账操作, 通过支付通道专有参数进行实现, 转账时只能单个通道进行操作 - [ ] 支付成功回调后, 如果订单已超时, 则进入待退款订单中,提示进行退款,或者自动退款 - [ ] 退款状态同步逻辑 diff --git a/daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/order/PayRefundOrderController.java b/daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/order/PayRefundOrderController.java index d9916819..d98a5708 100644 --- a/daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/order/PayRefundOrderController.java +++ b/daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/order/PayRefundOrderController.java @@ -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 findById(Long paymentId){ return Res.ok(payRefundOrderService.findById(paymentId)); } + + @Operation(summary = "发起退款") + @PostMapping("/refund") + public ResResult 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(); + } } diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/code/PayRefundStatusEnum.java b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/code/PayRefundStatusEnum.java index 7941f302..a3ea939f 100644 --- a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/code/PayRefundStatusEnum.java +++ b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/code/PayRefundStatusEnum.java @@ -13,7 +13,7 @@ import lombok.Getter; public enum PayRefundStatusEnum { SUCCESS("success","成功"), - FAIL("fail","失败"); + FAIL("fail"," "); /** 编码 */ private final String code; diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayCommonParam.java b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayCommonParam.java index 4f929901..94341792 100644 --- a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayCommonParam.java +++ b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayCommonParam.java @@ -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 = "请求时间,传输时间戳") diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/RefundParam.java b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/RefundParam.java index d326691f..db8fb9de 100644 --- a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/RefundParam.java +++ b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/RefundParam.java @@ -24,7 +24,7 @@ public class RefundParam extends PayCommonParam { private String businessNo; /** - * 部分退款需要传输refundModes参数 + * 部分退款需要传输支付通道参数参数 */ @Schema(description = "是否全部退款") private boolean refundAll; diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/result/pay/PaySyncResult.java b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/result/pay/PaySyncResult.java index f8a51178..079334f6 100644 --- a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/result/pay/PaySyncResult.java +++ b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/result/pay/PaySyncResult.java @@ -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; diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/common/entity/RefundableInfo.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/common/entity/RefundableInfo.java index f5d41894..f8463c78 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/common/entity/RefundableInfo.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/common/entity/RefundableInfo.java @@ -13,6 +13,7 @@ import lombok.experimental.Accessors; @Accessors(chain = true) public class RefundableInfo { /** + * 通道 * @see PayChannelEnum#getCode() */ private String channel; diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WechatRefundService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WechatRefundService.java index ccad0bd3..ea4ce34d 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WechatRefundService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WechatRefundService.java @@ -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()); diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/service/PaySyncService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/service/PaySyncService.java index dea15886..60082335 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/service/PaySyncService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/service/PaySyncService.java @@ -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()); diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/record/sync/entity/PaySyncRecord.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/record/sync/entity/PaySyncRecord.java index 3859e15f..3794984c 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/record/sync/entity/PaySyncRecord.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/record/sync/entity/PaySyncRecord.java @@ -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; diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/alipay/AliPayConfigDto.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/alipay/AliPayConfigDto.java index 11cc098d..0f77c814 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/alipay/AliPayConfigDto.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/alipay/AliPayConfigDto.java @@ -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; diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/order/PayOrderRefundParam.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/order/PayOrderRefundParam.java new file mode 100644 index 00000000..9d316cdb --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/order/PayOrderRefundParam.java @@ -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 refundChannels; +}