ref 修改云闪付退款, 调整一些记录的结构

This commit is contained in:
DaxPay
2024-04-28 20:51:34 +08:00
parent 54081fd0df
commit d36f10c14d
48 changed files with 497 additions and 339 deletions

303
README.md
View File

@@ -219,85 +219,230 @@ public class SimplePayOrderTest {
Apache License Version 2.0
## 📚 Dromara 成员项目
<p align="center">
<a href="https://gitee.com/dromara/TLog" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/tlog2.png" title="一个轻量级的分布式日志标记追踪神器10分钟即可接入自动对日志打标签完成微服务的链路追踪" width="15%">
</a>
<a href="https://gitee.com/dromara/liteFlow" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/liteflow.png" title="轻量,快速,稳定,可编排的组件式流程引擎" width="15%">
</a>
<a href="https://hutool.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/hutool.jpg" title="小而全的Java工具类库使Java拥有函数式语言般的优雅让Java语言也可以“甜甜的”。" width="15%">
</a>
<a href="https://sa-token.dev33.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/sa-token.png" title="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!" width="15%">
</a>
<a href="https://gitee.com/dromara/hmily" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/hmily.png" title="高性能一站式分布式事务解决方案。" width="15%">
</a>
<a href="https://gitee.com/dromara/Raincat" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/raincat.png" title="强一致性分布式事务解决方案。" width="15%">
</a>
</p>
<p align="center">
<a href="https://gitee.com/dromara/myth" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/myth.png" title="可靠消息分布式事务解决方案。" width="15%">
</a>
<a href="https://cubic.jiagoujishu.com/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/cubic.png" title="一站式问题定位平台以agent的方式无侵入接入应用完整集成arthas功能模块致力于应用级监控帮助开发人员快速定位问题" width="15%">
</a>
<a href="https://maxkey.top/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/maxkey.png" title="业界领先的身份管理和认证产品" width="15%">
</a>
<a href="http://forest.dtflyx.com/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/forest-logo.png" title="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端" width="15%">
</a>
<a href="https://jpom.io/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/jpom.png" title="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件" width="15%">
</a>
<a href="https://su.usthe.com/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/sureness.png" title="面向 REST API 的高性能认证鉴权框架" width="15%">
</a>
</p>
<p align="center">
<a href="https://easy-es.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/easy-es2.png" title="傻瓜级ElasticSearch搜索引擎ORM框架" width="15%">
</a>
<a href="https://gitee.com/dromara/northstar" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/northstar_logo.png" title="Northstar盈富量化交易平台" width="15%">
</a>
<a href="https://hertzbeat.com/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/hertzbeat_brand.jpg" title="易用友好的云监控系统" width="15%">
</a>
<a href="https://plugins.sheng90.wang/fast-request/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/fast-request.gif" title="Idea 版 Postman为简化调试API而生" width="15%">
</a>
<a href="https://www.jeesuite.com/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/mendmix.png" title="开源分布式云原生架构一站式解决方案" width="15%">
</a>
<a href="https://gitee.com/dromara/koalas-rpc" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/koalas-rpc2.png" title="企业生产级百亿日PV高可用可拓展的RPC框架。" width="15%">
</a>
</p>
<p align="center">
<a href="https://async.sizegang.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/gobrs-async.png" title="配置极简功能强大的异步任务动态编排框架" width="15%">
</a>
<a href="https://dynamictp.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/dynamic-tp.png" title="基于配置中心的轻量级动态可监控线程池" width="15%">
</a>
<a href="https://www.x-easypdf.cn" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/x-easypdf.png" title="一个用搭积木的方式构建pdf的框架基于pdfbox" width="15%">
</a>
<a href="http://dromara.gitee.io/image-combiner" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/image-combiner.png" title="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大" width="15%">
</a>
<a href="https://www.herodotus.cn/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/dante-cloud2.png" title="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。" width="15%">
</a>
<a href="https://dromara.org/zh/projects/" target="_blank">
<img src="https://oss.dev33.cn/sa-token/link/dromara.png" title="让每一位开源爱好者,体会到开源的快乐。" width="15%">
</a>
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/tlog.png"
msg="一个轻量级的分布式日志标记追踪神器10分钟即可接入自动对日志打标签完成微服务的链路追踪">
</a>
<a href="https://gitee.com/dromara/liteFlow" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/liteflow.png"
msg="轻量,快速,稳定,可编排的组件式流程引擎">
</a>
<a href="https://hutool.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hutool.jpg"
msg="小而全的Java工具类库使Java拥有函数式语言般的优雅让Java语言也可以“甜甜的”。">
</a>
<a href="https://sa-token.cc/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/sa-token.png"
msg="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!">
</a>
<a href="https://gitee.com/dromara/hmily" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hmily.png"
msg="高性能一站式分布式事务解决方案。">
</a>
<a href="https://gitee.com/dromara/Raincat" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/raincat.png"
msg="强一致性分布式事务解决方案。">
</a>
<a href="https://gitee.com/dromara/myth" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/myth.png"
msg="可靠消息分布式事务解决方案。">
</a>
<a href="https://cubic.jiagoujishu.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/cubic.png"
msg="一站式问题定位平台以agent的方式无侵入接入应用完整集成arthas功能模块致力于应用级监控帮助开发人员快速定位问题">
</a>
<a href="https://maxkey.top/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/maxkey.png"
msg="业界领先的身份管理和认证产品">
</a>
<a href="http://forest.dtflyx.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/forest-logo.png"
msg="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端" nf>
</a>
<a href="https://jpom.top/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/jpom.png"
msg="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件">
</a>
<a href="https://su.usthe.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/sureness.png"
msg="面向 REST API 的高性能认证鉴权框架">
</a>
<a href="https://easy-es.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/easy-es2.png"
msg="傻瓜级ElasticSearch搜索引擎ORM框架">
</a>
<a href="https://gitee.com/dromara/northstar" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/northstar_logo.png"
msg="Northstar盈富量化交易平台">
</a>
<a href="https://dromara.gitee.io/fast-request/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/fast-request.gif"
msg="Idea 版 Postman为简化调试API而生">
</a>
<a href="https://www.jeesuite.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/mendmix.png"
msg="开源分布式云原生架构一站式解决方案">
</a>
<a href="https://gitee.com/dromara/koalas-rpc" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/koalas-rpc2.png"
msg="企业生产级百亿日PV高可用可拓展的RPC框架。">
</a>
<a href="https://async.sizegang.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/gobrs-async.png"
msg="配置极简功能强大的异步任务动态编排框架">
</a>
<a href="https://dynamictp.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dynamic-tp.png"
msg="基于配置中心的轻量级动态可监控线程池">
</a>
<a href="https://www.x-easypdf.cn" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/x-easypdf.png"
msg="一个用搭积木的方式构建pdf的框架基于pdfbox">
</a>
<a href="http://dromara.gitee.io/image-combiner" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/image-combiner.png"
msg="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大">
</a>
<a href="https://www.herodotus.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dante-cloud2.png"
msg="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。">
</a>
<a href="http://www.mtruning.club" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/go-view.png"
msg="低代码数据可视化开发平台">
</a>
<a href="https://tangyh.top/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/lamp-cloud.png"
msg="微服务中后台快速开发平台,支持租户(SaaS)模式、非租户模式">
</a>
<a href="https://www.redisfront.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/redis-front.png"
msg="RedisFront 是一款开源免费的跨平台 Redis 桌面客户端工具, 支持单机模式, 集群模式, 哨兵模式以及 SSH 隧道连接, 可轻松管理Redis缓存数据.">
</a>
<a href="https://www.yuque.com/u34495/mivcfg" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/electron-egg.png"
msg="一个入门简单、跨平台、企业级桌面软件开发框架">
</a>
<a href="https://gitee.com/dromara/open-capacity-platform" target="_blank">
<img class="lazy"
data-original="https://oss.dev33.cn/sa-token/link/open-capacity-platform.jpg"
msg="简称ocp是基于Spring Cloud的企业级微服务框架(用户权限管理,配置中心管理,应用管理,....)">
</a>
<a href="http://easy-trans.fhs-opensource.top/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/easy_trans.png"
msg="Easy-Trans 一个注解搞定数据翻译,减少30%SQL代码量">
</a>
<a href="https://gitee.com/dromara/neutrino-proxy" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/neutrino-proxy.svg"
msg="一款基于 Netty 的、开源的内网穿透神器。">
</a>
<a href="https://chatgpt.cn.obiscr.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/chatgpt.png"
msg="一个支持在 JetBrains 系列 IDE 上运行的 ChatGPT 的插件。">
</a>
<a href="https://gitee.com/dromara/zyplayer-doc" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/zyplayer-doc.png"
msg="zyplayer-doc是一款适合团队和个人使用的WIKI文档管理工具同时还包含数据库文档、Api接口文档。">
</a>
<a href="https://gitee.com/dromara/payment-spring-boot" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/payment-spring-boot.png"
msg="最全最好用的微信支付V3 Spring Boot 组件。">
</a>
<a href="https://www.j2eefast.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/j2eefast.png"
msg="J2eeFAST 是一个致力于中小企业 Java EE 企业级快速开发平台,我们永久开源!">
</a>
<a href="https://gitee.com/dromara/data-compare" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dataCompare.png"
msg="数据库比对工具hive 表数据比对mysql、Doris 数据比对实现自动化配置进行数据比对避免频繁写sql 进行处理,低代码(Low-Code) 平台">
</a>
<a href="https://gitee.com/dromara/open-giteye-api" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/open-giteye-api.svg"
msg="giteye.net 是专为开源作者设计的数据图表服务工具类站点,提供了包括 Star 趋势图、贡献者列表、Gitee指数等数据图表服务。">
</a>
<a href="https://gitee.com/dromara/RuoYi-Vue-Plus" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/RuoYi-Vue-Plus.png"
msg="后台管理系统 重写 RuoYi-Vue 所有功能 集成 Sa-Token + Mybatis-Plus + Jackson + Xxl-Job + SpringDoc + Hutool + OSS 定期同步">
</a>
<a href="https://gitee.com/dromara/RuoYi-Cloud-Plus" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/RuoYi-Cloud-Plus.png"
msg="微服务管理系统 重写RuoYi-Cloud所有功能 整合 SpringCloudAlibaba Dubbo3.0 Sa-Token Mybatis-Plus MQ OSS ES Xxl-Job Docker 全方位升级 定期同步">
</a>
<a href="https://gitee.com/dromara/stream-query" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/stream-query.png"
msg="允许完全摆脱 Mapper 的 mybatis-plus 体验!封装 stream 和 lambda 操作进行数据返回处理。">
</a>
<a href="https://wind.kim/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/sms4j.png"
msg="短信聚合工具,让发送短信变的更简单。">
</a>
<a href="https://cloudeon.top/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/cloudeon.png"
msg="简化kubernetes上大数据集群的运维管理">
</a>
<a href="https://github.com/dromara/hodor" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/hodor.png"
msg="Hodor是一个专注于任务编排和高可用性的分布式任务调度系统。">
</a>
<a href="http://nsrule.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/test-hub.png"
msg="流程编排,插件驱动,测试无限可能">
</a>
<a href="https://gitee.com/dromara/disjob" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/disjob-2.png"
msg="Disjob是一个分布式的任务调度框架">
</a>
<a href="https://gitee.com/dromara/binlog4j" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/Binlog4j.png"
msg="轻量级 Mysql Binlog 客户端, 提供宕机续读, 高可用集群等特性">
</a>
<a href="https://gitee.com/dromara/yft-design" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/yft-design.png"
msg="基于 Canvas 的开源版 创客贴 支持导出jsonsvg, image文件。">
</a>
<a href="https://gitee.com/dromara/spring-file-storage" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/file4j.png"
msg="在 SpringBoot 中通过简单的方式将文件存储到 本地、阿里云 OSS、腾讯云 COS、七牛云 Kodo等">
</a>
<a href="https://wemq.nicholasld.cn/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/wemq.png"
msg="开源、高性能、安全、功能强大的物联网调试和管理解决方案。">
</a>
<a href="https://gitee.com/dromara/mayfly-go" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/mayfly-go.png"
msg="web 版 linux(终端[终端回放] 文件 脚本 进程 计划任务)、数据库mysql postgres、redis(单机 哨兵 集群)、mongo 统一管理操作平台">
</a>
<a href="https://akali.yomahub.com/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/akali.png"
msg="Akali(阿卡丽),轻量级本地化热点检测/降级框架10秒钟即可接入使用大流量下的神器">
</a>
<a href="https://gitee.com/dromara/dbswitch" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dbswitch.png"
msg="异构数据库迁移同步(搬家)工具。">
</a>
<a href="https://gitee.com/dromara/easyAi" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/easyAI.png"
msg="Java 傻瓜式 AI 框架。">
</a>
<a href="https://gitee.com/dromara/mybatis-plus-ext" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/mybatis-plus-ext.png"
msg="mybatis-plus 框架的增强拓展包。">
</a>
<a href="https://gitee.com/dromara/dax-pay" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dax-pay.png"
msg="免费开源的支付网关。">
</a>
<a href="https://gitee.com/dromara/sayOrder" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/sayorder.png"
msg="基于easyAi引擎的JAVA高性能低成本轻量级智能客服。">
</a>
<a href="https://gitee.com/dromara/mybatis-jpa-extra" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/mybatis-jpa-extra.png"
msg="扩展MyBatis JPA支持简化CUID操作增强SELECT分页查询">
</a>
<a href="https://dromara.org/zh/projects/" target="_blank">
<img class="lazy" data-original="https://oss.dev33.cn/sa-token/link/dromara.png"
msg="让每一位开源爱好者,体会到开源的快乐。">
</a>
</p>

View File

@@ -14,21 +14,11 @@ import lombok.Setter;
@Setter
public class PayOrderResult {
/** 支付ID */
private Long paymentId;
/** 商户订单号 */
private String bizOrderNo;
/** 是否是异步支付 */
private boolean asyncPay;
/**
* 异步支付通道
* @see PayChannelEnum
*/
private String asyncChannel;
/** 支付参数体(通常用于发起异步支付的参数) */
private String payBody;
/** 订单号 */
private String orderNo;
/**
* 支付状态
@@ -36,4 +26,7 @@ public class PayOrderResult {
*/
private String status;
/** 支付参数体(通常用于发起支付的参数) */
private String payBody;
}

View File

@@ -6,6 +6,8 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.time.LocalDateTime;
/**
* 支付异步通知类
* @author xxm
@@ -16,20 +18,23 @@ import lombok.ToString;
@ToString
public class PayNoticeModel {
/** 支付ID */
private Long paymentId;
/** 订单号 */
private String orderNo;
/** 业务号 */
private String businessNo;
/** 商户订单号 */
private String bizOrderNo;
/** 是否是异步支付 */
private boolean asyncPay;
/** 标题 */
private String title;
/**
* 异步支付通道
* 支付通道
* @see PayChannelEnum
*/
private String asyncChannel;
private String channel;
/** 支付方式 */
private String method;
/** 支付金额 */
private Integer amount;
@@ -40,15 +45,15 @@ public class PayNoticeModel {
*/
private String status;
/** 支付创建时间 */
private Long createTime;
/** 支付成功时间 */
private Long payTime;
/** 支付关闭时间 */
private Long closeTime;
/** 支付创建时间 */
private Long createTime;
/** 商户扩展参数,回调时会原样返回 */
private String attach;

View File

@@ -6,6 +6,8 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.time.LocalDateTime;
/**
* 退款通知消息
* @author xxm
@@ -16,20 +18,17 @@ import lombok.ToString;
@ToString
public class RefundNoticeModel {
/** 退款ID */
private Long refundId;
/** 退款号 */
private String refundNo;
/** 是否含有异步通道 */
private boolean asyncPay;
/** 商户退款号 */
private String bizRefundNo;
/**
* 异步通道
* 支付通道
* @see PayChannelEnum
*/
private String asyncChannel;
private String channel;
/** 退款金额 */
private Integer amount;
@@ -41,7 +40,7 @@ public class RefundNoticeModel {
private String status;
/** 退款成功时间 */
private Long refundTime;
private Long finishTime;
/** 退款创建时间 */
private Long createTime;

View File

@@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 账接收方控制器
* 账接收方控制器
* @author xxm
* @since 2024/3/28
*/

View File

@@ -59,6 +59,7 @@ public class PayOrderController {
.orElseThrow(() -> new DataNotExistException("支付订单不存在"));
return Res.ok(order);
}
@Operation(summary = "查询订单详情")
@GetMapping("/findByOrderNo")
public ResResult<PayOrderDetailDto> findByOrderNo(String orderNo){
@@ -67,14 +68,14 @@ public class PayOrderController {
.orElseThrow(() -> new DataNotExistException("支付订单不存在"));
PayOrderDetailDto detailDto=new PayOrderDetailDto();
detailDto.setPayOrder(order);
detailDto.setPayOrderExtra(payOrderExtraService.findById(order.getId()).toDto());
detailDto.setPayOrderExtra(payOrderExtraService.findById(order.getId()));
return Res.ok(detailDto);
}
@Operation(summary = "查询支付订单扩展信息")
@GetMapping("/getExtraById")
public ResResult<PayOrderExtraDto> getExtraById(Long id){
return Res.ok(payOrderExtraService.findById(id).toDto());
return Res.ok(payOrderExtraService.findById(id));
}
@Operation(summary = "同步支付状态")

View File

@@ -9,6 +9,7 @@ import cn.bootx.platform.daxpay.result.pay.SyncResult;
import cn.bootx.platform.daxpay.service.core.order.refund.service.RefundOrderQueryService;
import cn.bootx.platform.daxpay.service.core.order.refund.service.RefundOrderService;
import cn.bootx.platform.daxpay.service.core.payment.sync.service.RefundSyncService;
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundOrderDetailDto;
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundOrderDto;
import cn.bootx.platform.daxpay.service.dto.order.refund.RefundOrderExtraDto;
import cn.bootx.platform.daxpay.service.param.order.PayOrderRefundParam;
@@ -38,12 +39,23 @@ public class RefundOrderController {
return Res.ok(refundOrderQueryService.page(pageParam, query));
}
@Operation(summary = "查询退款订单详情")
@GetMapping("/findByOrderNo")
public ResResult<RefundOrderDetailDto> findByRefundNo(String refundNo){
RefundOrderDto order = refundOrderQueryService.findByRefundNo(refundNo);
RefundOrderDetailDto detailDto = new RefundOrderDetailDto();
detailDto.setRefundOrder(order);
detailDto.setRefundOrderExtra(refundOrderQueryService.findExtraById(order.getId()));
return Res.ok(detailDto);
}
@Operation(summary = "查询单条")
@GetMapping("/findById")
public ResResult<RefundOrderDto> findById(Long id){
return Res.ok(refundOrderQueryService.findById(id));
}
@Operation(summary = "查询扩展信息")
@GetMapping("/findExtraById")
public ResResult<RefundOrderExtraDto> findExtraById(Long id){
@@ -57,6 +69,13 @@ public class RefundOrderController {
return Res.ok();
}
@Operation(summary = "重新发起退款")
@PostMapping("/resetRefund")
public ResResult<Void> resetRefund(Long id){
refundOrderService.resetRefund(id);
return Res.ok();
}
@Operation(summary = "退款同步")
@PostMapping("/syncByRefundNo")
public ResResult<SyncResult> syncByRefundNo(String refundNo){

View File

@@ -32,11 +32,6 @@ public class RefundOrderResult {
@Schema(description = "退款金额")
private BigDecimal amount;
/** 退款发起时间 */
@Schema(description = "退款发起时间")
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime refundTime;
@Schema(description = "退款完成时间")
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime finishTime;

View File

@@ -46,7 +46,7 @@ public class AliPayAllocationService {
public void allocation(AllocationOrder allocationOrder, List<AllocationOrderDetail> orderDetails){
// 分账主体参数
AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel();
model.setOutRequestNo(String.valueOf(allocationOrder.getOrderNo()));
model.setOutRequestNo(allocationOrder.getOrderNo());
model.setTradeNo(allocationOrder.getOutOrderNo());
model.setRoyaltyMode(AliPayCode.ALLOC_ASYNC);

View File

@@ -32,8 +32,8 @@ public class AliPayRefundService {
public void refund(RefundOrder refundOrder) {
RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();
AlipayTradeRefundModel refundModel = new AlipayTradeRefundModel();
refundModel.setOutTradeNo(String.valueOf(refundOrder.getOrderNo()));
refundModel.setOutRequestNo(String.valueOf(refundOrder.getRefundNo()));
refundModel.setOutTradeNo(refundOrder.getOrderNo());
refundModel.setOutRequestNo(refundOrder.getRefundNo());
// 金额转换
String refundAmount = String.valueOf(refundOrder.getAmount()*0.01);
refundModel.setRefundAmount(refundAmount);

View File

@@ -119,7 +119,7 @@ public class AliPaySyncService {
// 成功
if (Objects.equals(tradeStatus, AliPayCode.REFUND_SUCCESS)){
LocalDateTime localDateTime = LocalDateTimeUtil.of(response.getGmtRefundPay());
return syncResult.setRefundTime(localDateTime).setSyncStatus(RefundSyncStatusEnum.SUCCESS);
return syncResult.setFinishTime(localDateTime).setSyncStatus(RefundSyncStatusEnum.SUCCESS);
} else {
return syncResult.setSyncStatus(RefundSyncStatusEnum.FAIL).setErrorMsg("支付宝网关退款未成功");
}

View File

@@ -62,7 +62,7 @@ public class UnionPayCallbackService {
// 判断并保存回调类型
PaymentTypeEnum callbackType = this.getCallbackType();
callbackInfo.setCallbackType(callbackType)
.setChannel(PayChannelEnum.ALI.getCode());
.setChannel(PayChannelEnum.UNION_PAY.getCode());
// 验证消息
if (!this.verifyNotify()) {

View File

@@ -28,22 +28,22 @@ public class UnionPayRefundService {
/**
* 退款方法
*/
public void refund(RefundOrder refundOrder, PayOrder payOrder,UnionPayKit unionPayKit) {
public void refund(RefundOrder refundOrder, UnionPayKit unionPayKit) {
// 金额转换
BigDecimal refundAmount = BigDecimal.valueOf(refundOrder.getAmount() * 0.01);
BigDecimal orderAmount = BigDecimal.valueOf(payOrder.getAmount() * 0.01);
BigDecimal orderAmount = BigDecimal.valueOf(refundOrder.getOrderAmount() * 0.01);
UnionRefundOrder unionRefundOrder = new UnionRefundOrder();
unionRefundOrder.setRefundNo(refundOrder.getRefundNo());
unionRefundOrder.setTradeNo(String.valueOf(payOrder.getOrderNo()));
unionRefundOrder.setTradeNo(refundOrder.getOutOrderNo());
unionRefundOrder.setRefundAmount(refundAmount);
unionRefundOrder.setTotalAmount(orderAmount);
UnionRefundResult refund = unionPayKit.refund(unionRefundOrder);
String gatewayNo = (String) refund.getAttr(UnionPayCode.QUERY_ID);
String outRefundNo = (String) refund.getAttr(UnionPayCode.QUERY_ID);
// 云闪付退款是否成功需要查询状态, 所以设置为退款中状态
RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo();
refundInfo.setStatus(RefundStatusEnum.PROGRESS).setOutRefundNo(gatewayNo);
refundInfo.setStatus(RefundStatusEnum.PROGRESS).setOutRefundNo(outRefundNo);
}
}

View File

@@ -43,7 +43,7 @@ public class UnionPaySyncService {
PaySyncResult syncResult = new PaySyncResult().setSyncStatus(PaySyncStatusEnum.FAIL);
AssistOrder query = new AssistOrder();
query.setOutTradeNo(String.valueOf(order.getId()));
query.setOutTradeNo(order.getOrderNo());
Map<String, Object> result = unionPayKit.query(query);
syncResult.setSyncInfo(JSONUtil.toJsonStr(result));
@@ -132,7 +132,7 @@ public class UnionPaySyncService {
String queryId = MapUtil.getStr(result, QUERY_ID);
String timeEnd = MapUtil.getStr(result, TXN_TIME);
LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN);
return syncResult.setOutRefundNo(queryId).setRefundTime(time).setSyncStatus(RefundSyncStatusEnum.SUCCESS);
return syncResult.setOutRefundNo(queryId).setFinishTime(time).setSyncStatus(RefundSyncStatusEnum.SUCCESS);
}
// 退款中

View File

@@ -47,7 +47,7 @@ public class WeChatPaySyncService {
.appid(weChatPayConfig.getWxAppId())
.mch_id(weChatPayConfig.getWxMchId())
.nonce_str(WxPayKit.generateStr())
.out_trade_no(String.valueOf(order.getOrderNo()))
.out_trade_no(order.getOrderNo())
.build()
.createSign(weChatPayConfig.getApiKeyV2(), SignType.HMACSHA256);
try {
@@ -110,7 +110,7 @@ public class WeChatPaySyncService {
.mch_id(weChatPayConfig.getWxMchId())
.nonce_str(WxPayKit.generateStr())
// 使用退款单号查询, 只返回当前这条, 如果使用支付订单号查询,返回所有相关的
.out_refund_no(String.valueOf(refundOrder.getRefundNo()))
.out_refund_no(refundOrder.getRefundNo())
.build()
.createSign(weChatPayConfig.getApiKeyV2(), SignType.HMACSHA256);
@@ -127,7 +127,7 @@ public class WeChatPaySyncService {
if (Objects.equals(tradeStatus, WeChatPayCode.REFUND_SUCCESS)) {
String timeEnd = result.get(WeChatPayCode.REFUND_SUCCESS_TIME);
LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.NORM_DATETIME_PATTERN);
return syncResult.setRefundTime(time).setSyncStatus(RefundSyncStatusEnum.SUCCESS);
return syncResult.setFinishTime(time).setSyncStatus(RefundSyncStatusEnum.SUCCESS);
}
// 退款中
if (Objects.equals(tradeStatus, WeChatPayCode.REFUND_PROCESSING)) {

View File

@@ -3,6 +3,7 @@ package cn.bootx.platform.daxpay.service.core.order.pay.service;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderExtraManager;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderExtraDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -23,8 +24,9 @@ public class PayOrderExtraService {
/**
* 查询详情
*/
public PayOrderExtra findById(Long id){
return payOrderExtraManager.findById(id).orElseThrow(()->new DataNotExistException("支付订单扩展信息不存在"));
public PayOrderExtraDto findById(Long id){
return payOrderExtraManager.findById(id).map(PayOrderExtra::toDto)
.orElseThrow(()->new DataNotExistException("支付订单扩展信息不存在"));
}
/**

View File

@@ -39,6 +39,10 @@ public class RefundOrder extends MpBaseEntity implements EntityBaseFunction<Refu
@DbColumn(comment = "商户支付订单号")
private String bizOrderNo;
/** 外部支付订单号 */
@DbColumn(comment = "商户支付订单号")
private String outOrderNo;
/** 支付标题 */
@DbColumn(comment = "支付标题")
private String title;

View File

@@ -60,6 +60,15 @@ public class RefundOrderQueryService {
.orElseThrow(() -> new DataNotExistException("退款订单扩展信息不存在"));
}
/**
* 根据退款号查询
*/
public RefundOrderDto findByRefundNo(String refundNo){
return refundOrderManager.findByRefundNo(refundNo).map(RefundOrder::toDto)
.orElseThrow(() -> new DataNotExistException("退款订单扩展信息不存在"));
}
/**
* 根据退款号和商户退款号查询
*/

View File

@@ -4,12 +4,17 @@ import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.common.spring.util.WebServletUtil;
import cn.bootx.platform.daxpay.code.PaymentApiCode;
import cn.bootx.platform.daxpay.param.payment.refund.RefundParam;
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderExtraManager;
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrderExtra;
import cn.bootx.platform.daxpay.service.core.payment.common.service.PaymentAssistService;
import cn.bootx.platform.daxpay.service.core.payment.refund.service.RefundService;
import cn.bootx.platform.daxpay.service.core.system.config.dao.PayApiConfigManager;
import cn.bootx.platform.daxpay.service.core.system.config.entity.PayApiConfig;
import cn.bootx.platform.daxpay.service.core.system.config.service.PayApiConfigService;
import cn.bootx.platform.daxpay.service.param.order.PayOrderRefundParam;
import cn.bootx.platform.daxpay.util.OrderNoGenerateUtil;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -33,6 +38,10 @@ public class RefundOrderService {
private final PayApiConfigService apiConfigService;
private final PaymentAssistService paymentAssistService;
private final RefundOrderExtraManager refundOrderExtraManager;
private final RefundOrderManager refundOrderManager;
private final PayApiConfigManager apiConfigManager;
/**
@@ -47,7 +56,7 @@ public class RefundOrderService {
RefundParam refundParam = new RefundParam();
refundParam.setOrderNo(param.getOrderNo());
refundParam.setBizRefundNo(param.getOrderNo()+"R");
refundParam.setBizRefundNo(OrderNoGenerateUtil.refund());
refundParam.setAmount(param.getAmount());
refundParam.setReason(param.getReason());
refundParam.setReqTime(LocalDateTime.now());
@@ -61,4 +70,39 @@ public class RefundOrderService {
// 调用统一退款接口
refundService.refund(refundParam);
}
/**
* 重新退款
*/
public void resetRefund(Long id){
// 查询扩展信息
RefundOrderExtra refundOrderExtra = refundOrderExtraManager.findById(id)
.orElseThrow(() -> new DataNotExistException("未找到退款订单"));
// 查询扩展信息
RefundOrder refundOrder = refundOrderManager.findById(id)
.orElseThrow(() -> new DataNotExistException("未找到退款订单"));
String ip = Optional.ofNullable(WebServletUtil.getRequest())
.map(ServletUtil::getClientIP)
.orElse("未知");
RefundParam refundParam = new RefundParam();
refundParam.setBizRefundNo(refundOrder.getBizRefundNo());
// 回调通知
refundParam.setNotifyUrl(refundOrderExtra.getNotifyUrl());
refundParam.setAttach(refundOrderExtra.getAttach());
refundParam.setReqTime(LocalDateTime.now());
refundParam.setClientIp(ip);
// 手动初始化上下文
paymentAssistService.initContext(refundParam);
// 初始化接口信息为统一退款
PayApiConfig api = apiConfigManager.findByCode(PaymentApiCode.REFUND).orElseThrow(() -> new DataNotExistException("未找到统一退款接口信息"));
// 设置接口信息
apiConfigService.initApiInfo(api);
// 调用统一退款接口
refundService.refund(refundParam);
}
}

View File

@@ -43,7 +43,7 @@ public class AllocationGroupManager extends BaseManager<AllocationGroupMapper,Al
/**
* 获取默认分账组
*/
public Optional<AllocationGroup> findDefaultGroup(String asyncChannel) {
return findByField(AllocationGroup::getChannel,asyncChannel);
public Optional<AllocationGroup> findDefaultGroup(String channel) {
return findByField(AllocationGroup::getChannel,channel);
}
}

View File

@@ -93,6 +93,7 @@ public class AllocationService {
order.setStatus(AllocationOrderStatusEnum.ALLOCATION_PROCESSING.getCode())
.setErrorMsg(null);
} catch (Exception e) {
log.error("分账出现错误:", e);
// 失败
order.setStatus(AllocationOrderStatusEnum.ALLOCATION_FAILED.getCode())
.setErrorMsg(e.getMessage());
@@ -144,6 +145,7 @@ public class AllocationService {
.setErrorMsg(null);
} catch (Exception e) {
log.error("重新分账出现错误:", e);
// 失败
allocationOrder.setStatus(AllocationOrderStatusEnum.ALLOCATION_FAILED.getCode())
.setErrorMsg(e.getMessage());
@@ -182,6 +184,7 @@ public class AllocationService {
allocationOrder.setStatus(AllocationOrderStatusEnum.FINISH.getCode())
.setErrorMsg(null);
} catch (Exception e) {
log.error("分账完结错误:", e);
// 失败
allocationOrder.setStatus(AllocationOrderStatusEnum.FINISH_FAILED.getCode())
.setErrorMsg(e.getMessage());

View File

@@ -80,6 +80,8 @@ public class PayCloseService {
// 返回结果
return result;
} catch (Exception e) {
log.error("关闭订单失败, id: {}:", payOrder.getId());
log.error("关闭订单失败:", e);
// 记录关闭失败的记录
this.saveRecord(payOrder, false, e.getMessage());
result.setCode("1").setMsg(e.getMessage());

View File

@@ -20,51 +20,60 @@ import java.time.LocalDateTime;
@Schema(title = "支付异步通知类")
public class PayNoticeResult {
/** 订单号 */
@Schema(description = "订单号")
private String orderNo;
/** 商户订单号 */
@Schema(description = "商户订单号")
private String bizOrderNo;
/** 标题 */
@Schema(description = "标题")
private String title;
/**
* 支付通道
* @see PayChannelEnum
*/
@Schema(description = "支付通道")
private String channel;
/**
* 支付方式
*/
/** 支付方式 */
@Schema(description = "支付方式")
private String method;
/** 支付金额 */
@Schema(description = "支付金额")
private Integer amount;
/**
* 支付状态
* @see PayStatusEnum
*/
@Schema(description = "支付状态")
private String status;
/** 支付成功时间 */
@Schema(description = "支付成功时间")
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime payTime;
/** 支付关闭时间 */
@Schema(description = "支付关闭时间")
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime closeTime;
/** 支付创建时间 */
@Schema(description = "支付创建时间")
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime createTime;
/** 商户扩展参数,回调时会原样返回 */
@Schema(description = "商户扩展参数,回调时会原样返回")
private String attach;
/** 签名 */
@Schema(description = "签名")
private String sign;

View File

@@ -20,38 +20,47 @@ import java.time.LocalDateTime;
@Schema(title = "退款通知消息")
public class RefundNoticeResult {
/** 退款号 */
@Schema(description = "退款号")
private String refundNo;
/** 商户退款号 */
@Schema(description = "商户退款号")
private String bizRefundNo;
/**
* 支付通道
* @see PayChannelEnum
*/
@Schema(description = "异步通道")
@Schema(description = "支付通道")
private String channel;
/** 退款金额 */
@Schema(description = "退款金额")
private Integer amount;
/**
* 退款状态
* @see RefundStatusEnum
*/
@Schema(description = "退款状态")
private String status;
/** 退款成功时间 */
@Schema(description = "退款成功时间")
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime refundTime;
private LocalDateTime finishTime;
/** 退款创建时间 */
@Schema(description = "退款创建时间")
@JsonSerialize(using = LocalDateTimeToTimestampSerializer.class)
private LocalDateTime createTime;
/** 商户扩展参数,回调时会原样返回 */
@Schema(description = "商户扩展参数,回调时会原样返回")
private String attach;
/** 签名 */
@Schema(description = "签名")
private String sign;
}

View File

@@ -77,7 +77,7 @@ public class ClientNoticeAssistService {
.setRefundNo(order.getRefundNo())
.setChannel(order.getChannel())
.setAmount(order.getAmount())
.setRefundTime(order.getFinishTime())
.setFinishTime(order.getFinishTime())
.setCreateTime(order.getCreateTime())
.setStatus(order.getStatus())
.setAttach(orderExtra.getAttach());

View File

@@ -108,6 +108,7 @@ public class ClientNoticeService {
taskManager.save(task);
} catch (Exception e) {
log.error("注册支付消息通知任务失败数据错误订单ID{}",order.getId());
log.error("错误内容",e);
throw new RuntimeException(e);
}
// 同时触发一次通知, 如果成功发送, 任务结束

View File

@@ -41,7 +41,7 @@ public class PayExpiredTimeService {
repository.store(payOrder.getId(), expiredTime);
}
catch (Exception e) {
log.error("注册支付单超时关闭失败");
log.error("注册支付单超时关闭失败",e);
throw new RetryableException();
}
}

View File

@@ -155,7 +155,7 @@ public class PayService {
// 支付操作
payStrategy.doPayHandler();
} catch (Exception e) {
// 记录错误原因
// 记录错误原因, 此处没有事务, 所以可以正常更新
payOrder.setErrorMsg(e.getMessage());
payOrderService.updateById(payOrder);
throw e;

View File

@@ -19,6 +19,7 @@ import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralRec
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff;
import cn.bootx.platform.daxpay.service.core.payment.reconcile.factory.ReconcileStrategyFactory;
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
import cn.bootx.platform.daxpay.util.OrderNoGenerateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -55,15 +56,8 @@ public class ReconcileService {
*/
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public ReconcileOrder create(LocalDate date, String channel) {
// 构建对账策略
AbsReconcileStrategy reconcileStrategy = ReconcileStrategyFactory.create(channel);
// 生成批次号
String seqNo = reconcileStrategy.generateSequence(date);
ReconcileOrder order = new ReconcileOrder()
.setBatchNo(seqNo)
.setBatchNo(OrderNoGenerateUtil.reconciliation())
.setChannel(channel)
.setDate(date);
reconcileOrderManager.save(order);

View File

@@ -1,14 +1,12 @@
package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.common.sequence.func.Sequence;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfigService;
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayReconcileService;
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralReconcileRecord;
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
import cn.bootx.platform.daxpay.service.handler.sequence.DaxPaySequenceHandler;
import cn.hutool.core.date.DatePattern;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
@@ -17,7 +15,6 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@@ -38,9 +35,6 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
private final AliPayConfigService configService;
private final DaxPaySequenceHandler daxPaySequenceHandler;
/**
* 策略标识
*
@@ -51,21 +45,6 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
return PayChannelEnum.ALI;
}
/**
* 生成对账序列号
* 规则:通道简称 + yyyyMMdd + 两位流水号
* 例子wx2024012001、ali2024012002
*/
@Override
public String generateSequence(LocalDate date) {
String prefix = getChannel().getReconcilePrefix();
String dateStr = LocalDateTimeUtil.format(date, DatePattern.PURE_DATE_PATTERN);
Sequence sequence = daxPaySequenceHandler.alipayReconcileSequence(dateStr);
String key = String.format("%02d", sequence.next());
return prefix + dateStr + key;
}
/**
* 对账前处理, 主要是初始化支付SDK配置
*/

View File

@@ -1,16 +1,13 @@
package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.common.sequence.func.Sequence;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig;
import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayConfigService;
import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayReconcileService;
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralReconcileRecord;
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
import cn.bootx.platform.daxpay.service.handler.sequence.DaxPaySequenceHandler;
import cn.bootx.platform.daxpay.service.sdk.union.api.UnionPayKit;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
@@ -19,7 +16,6 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
@@ -41,22 +37,8 @@ public class UnionPayReconcileStrategy extends AbsReconcileStrategy {
private final UnionPayReconcileService reconcileService;
private final DaxPaySequenceHandler daxPaySequenceHandler;
private UnionPayKit unionPayKit;
/**
* 生成对账序列号
*/
@Override
public String generateSequence(LocalDate date) {
String prefix = getChannel().getReconcilePrefix();
String dateStr = LocalDateTimeUtil.format(date, DatePattern.PURE_DATE_PATTERN);
Sequence sequence = daxPaySequenceHandler.unionPayReconcileSequence(dateStr);
String key = String.format("%02d", sequence.next());
return prefix + dateStr + key;
}
/**
* 对账前处理, 主要是初始化支付SDK配置
*/

View File

@@ -1,17 +1,12 @@
package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.common.sequence.func.Sequence;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.service.core.channel.wechat.convert.WeChatConvert;
import cn.bootx.platform.daxpay.service.core.channel.wechat.dao.WeChatPayRecordManager;
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayRecord;
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WechatPayReconcileService;
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralReconcileRecord;
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
import cn.bootx.platform.daxpay.service.handler.sequence.DaxPaySequenceHandler;
import cn.hutool.core.date.DatePattern;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
@@ -20,10 +15,8 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
@@ -42,8 +35,6 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
private final WeChatPayConfigService weChatPayConfigService;
private final DaxPaySequenceHandler daxPaySequenceHandler;
private WeChatPayConfig config;
/**
@@ -56,21 +47,6 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
return PayChannelEnum.WECHAT;
}
/**
* 生成对账序列号
* 生成批次号
* 规则:通道简称 + yyyyMMdd + 两位流水号
* 例子wx2024012001、ali2024012002
*/
@Override
public String generateSequence(LocalDate date) {
String prefix = getChannel().getReconcilePrefix();
String dateStr = LocalDateTimeUtil.format(date, DatePattern.PURE_DATE_PATTERN);
Sequence sequence = daxPaySequenceHandler.wechatReconcileSequence(dateStr);
String key = String.format("%02d", sequence.next());
return prefix + dateStr + key;
}
/**
* 对账前处理, 主要是初始化支付SDK配置
*/

View File

@@ -108,6 +108,7 @@ public class RefundAssistService {
.setOrderId(payOrder.getId())
.setOrderNo(payOrder.getOrderNo())
.setBizOrderNo(payOrder.getBizOrderNo())
.setOutOrderNo(payOrder.getOutOrderNo())
.setRefundNo(OrderNoGenerateUtil.refund())
.setBizRefundNo(refundParam.getBizRefundNo())
.setChannel(payOrder.getChannel())
@@ -137,7 +138,7 @@ public class RefundAssistService {
public void updateOrder(RefundOrder refundOrder){
RefundLocal asyncRefundInfo = PaymentContextLocal.get().getRefundInfo();
refundOrder.setStatus(asyncRefundInfo.getStatus().getCode())
.setRefundNo(asyncRefundInfo.getOutRefundNo());
.setOutRefundNo(asyncRefundInfo.getOutRefundNo());
// 退款成功更新退款时间
if (Objects.equals(refundOrder.getStatus(), SUCCESS.getCode())){
// TODO 读取网关返回的退款时间和完成时间

View File

@@ -100,8 +100,6 @@ public class RefundService {
refundAssistService.checkAndParam(param, payOrder);
// 通过退款参数获取退款策略
AbsRefundStrategy refundStrategy = RefundStrategyFactory.create(payOrder.getChannel());
// 设置支付订单数据
refundStrategy.setPayOrder(payOrder);
// 进行退款前预处理
refundStrategy.doBeforeRefundHandler();
// 退款操作的预处理, 对支付订单进行预扣款, 返回创建成功的退款订单, 成功后才可以进行下一阶段的操作
@@ -110,8 +108,8 @@ public class RefundService {
try {
// 执行退款策略
refundStrategy.doRefundHandler();
}
catch (Exception e) {
} catch (Exception e) {
log.error("退款出现错误", e);
// 记录处理失败状态
PaymentContextLocal.get().getRefundInfo().setStatus(RefundStatusEnum.FAIL);
// 更新退款失败的记录
@@ -153,7 +151,7 @@ public class RefundService {
.orElseThrow(() -> new DataNotExistException("支付订单不存在"));
RefundOrderExtra refundOrderExtra = refundOrderExtraManager.findById(refundOrder.getId())
.orElseThrow(() -> new DataNotExistException("退款订单扩展信息不存在"));
AbsRefundStrategy refundStrategy = RefundStrategyFactory.create(refundOrder.getRefundNo());
AbsRefundStrategy refundStrategy = RefundStrategyFactory.create(refundOrder.getChannel());
// 设置退款订单对象
refundStrategy.setRefundOrder(refundOrder);
// 退款前准备操作
@@ -165,6 +163,7 @@ public class RefundService {
refundStrategy.doRefundHandler();
}
catch (Exception e) {
log.error("重新退款失败:", e);
// 记录处理失败状态
PaymentContextLocal.get().getRefundInfo().setStatus(RefundStatusEnum.FAIL);
// 记录退款失败的记录

View File

@@ -53,6 +53,6 @@ public class UnionRefundStrategy extends AbsRefundStrategy {
@Override
public void doRefundHandler() {
UnionPayKit unionPayKit = unionPayConfigService.initPayService(unionPayConfig);
unionPayRefundService.refund(this.getRefundOrder(), this.getPayOrder(), unionPayKit);
unionPayRefundService.refund(this.getRefundOrder(), unionPayKit);
}
}

View File

@@ -63,7 +63,7 @@ public class RefundRepairService {
}
try {
// 获取关联支付单
PayOrder payOrder = payOrderQueryService.findById(refundOrder.getId())
PayOrder payOrder = payOrderQueryService.findById(refundOrder.getOrderId())
.orElseThrow(() -> new RuntimeException("支付单不存在"));
// 根据不同的类型执行对应的修复逻辑

View File

@@ -32,7 +32,7 @@ public class RefundSyncResult {
private String outRefundNo;
/** 退款完成时间(通常用于接收网关返回的时间) */
private LocalDateTime refundTime;
private LocalDateTime finishTime;
/** 错误提示码 */
private String errorCode;

View File

@@ -107,7 +107,7 @@ public class RefundSyncService {
if (Objects.isNull(repairInfo.getSource())){
repairInfo.setSource(PayRepairSourceEnum.SYNC);
}
repairInfo.setFinishTime(syncResult.getRefundTime());
repairInfo.setFinishTime(syncResult.getFinishTime());
repairResult = this.repairHandler(syncResult, refundOrder);
}
} catch (PayFailureException e) {

View File

@@ -45,9 +45,11 @@ public class PayCloseRecord extends MpCreateEntity implements EntityBaseFunction
@DbColumn(comment = "是否关闭成功")
private boolean closed;
/** 错误码 */
@DbColumn(comment = "错误码")
private String code;
/** 错误消息 */
@DbColumn(comment = "错误消息")
private String errorMsg;

View File

@@ -76,12 +76,15 @@ public class PaySyncRecord extends MpCreateEntity implements EntityBaseFunction<
@DbColumn(comment = "是否进行修复")
private boolean repair;
/** 修复单号 */
@DbColumn(comment = "修复单号")
private String repairNo;
/** 错误码 */
@DbColumn(comment = "错误码")
private String errorCode;
/** 错误消息 */
@DbColumn(comment = "错误消息")
private String errorMsg;

View File

@@ -0,0 +1,20 @@
package cn.bootx.platform.daxpay.service.dto.order.refund;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 退款订单信息
* @author xxm
* @since 2024/4/28
*/
@Data
@Accessors(chain = true)
@Schema(title = "退款订单信息")
public class RefundOrderDetailDto {
@Schema(description = "退款订单")
RefundOrderDto refundOrder;
@Schema(description = "退款订单扩展信息")
RefundOrderExtraDto refundOrderExtra;
}

View File

@@ -68,10 +68,6 @@ public class RefundOrderDto extends BaseDto {
@Schema(description = "退款原因")
private String reason;
/** 退款发起时间 */
@Schema(description = "退款发起时间")
private LocalDateTime refundTime;
@Schema(description = "退款结束时间")
private LocalDateTime finishTime;

View File

@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.service.dto.record.close;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.table.modify.annotation.DbColumn;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -18,36 +19,36 @@ import lombok.experimental.Accessors;
@Schema(title = "支付关闭记录")
public class PayCloseRecordDto extends BaseDto {
/** 支付记录id */
@Schema(description = "支付记录id")
private Long paymentId;
/** 订单号 */
@DbColumn(comment = "订单号")
private String orderNo;
/** 业务号 */
@Schema(description = "业务")
private String businessNo;
/** 商户订单号 */
@DbColumn(comment = "商户订单")
private String bizOrderNo;
/**
* 关闭的异步支付通道, 可以为空
* @see PayChannelEnum#getCode()
* 关闭的支付通道
* @see PayChannelEnum
*/
@Schema(description = "关闭的异步支付通道")
private String asyncChannel;
@DbColumn(comment = "关闭的异步支付通道")
private String channel;
/**
* 是否关闭成功
*/
@Schema(description = "是否关闭成功")
@DbColumn(comment = "是否关闭成功")
private boolean closed;
/** 错误码 */
@DbColumn(comment = "错误码")
private String code;
/** 错误消息 */
@Schema(description = "错误消息")
@DbColumn(comment = "错误消息")
private String errorMsg;
/** 客户端IP */
@Schema(description = "客户端IP")
@DbColumn(comment = "客户端IP")
private String clientIp;
/** 请求链路ID */
@Schema(description = "请求链路ID")
private String reqId;
}

View File

@@ -4,7 +4,9 @@ import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.service.code.PayRepairSourceEnum;
import cn.bootx.platform.daxpay.service.code.PayRepairWayEnum;
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
import cn.bootx.platform.daxpay.service.code.RefundRepairWayEnum;
import cn.bootx.table.modify.annotation.DbColumn;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -23,21 +25,25 @@ public class PayRepairRecordDto extends BaseDto {
/**
* 修复号
* 如果一次修复产生的修复记录只有一条, 则该字段为与ID一致
* 如果一次修复产生的修复记录有多个, 则使用这个ID作为关联
* 如果一次修复产生的修复记录有多个记录, 使用这个作为关联
*/
@Schema(description = "修复号")
private String repairNo;
/** 支付ID/退款ID */
@Schema(description = "业务ID")
private Long orderId;
@Schema(description = "本地订单ID")
private Long tradeId;
/** 支付业务号/退款号 业务号 */
@Schema(description = "业务号")
private String orderNo;
/**
* 本地交易号, 支付号/退款号
*/
@Schema(description = "本地业务号")
private String tradeNo;
/** 类型 支付修复/退款修复 */
/**
* 修复类型 支付修复/退款修复
* @see PaymentTypeEnum
*/
@Schema(description = "修复类型")
private String repairType;
@@ -49,32 +55,28 @@ public class PayRepairRecordDto extends BaseDto {
private String repairSource;
/**
* 修复类型
* 修复方式
* @see PayRepairWayEnum
* @see RefundRepairWayEnum
*/
@Schema(description = "修复类型")
@Schema(description = "修复方式")
private String repairWay;
/** 修复的异步通道 */
@Schema(description = "修复的异步通道")
private String asyncChannel;
private String channel;
/**
* 修复前状态
* @see PayStatusEnum
*/
@Schema(description = "修复前订单状态")
@Schema(description = "修复前状态")
private String beforeStatus;
/**
* 修复后状态
* @see PayStatusEnum
*/
@Schema(description = "修复后订单状态")
@Schema(description = "修复后状态")
private String afterStatus;
/** 金额变动 */
@Schema(description = "金额变动")
private Integer amount;
}

View File

@@ -4,6 +4,8 @@ import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.code.RefundSyncStatusEnum;
import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.mysql.annotation.DbMySqlFieldType;
import cn.bootx.table.modify.mysql.constants.MySqlFieldTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -22,19 +24,32 @@ import lombok.experimental.Accessors;
@Schema(title = "支付同步订单")
public class PaySyncRecordDto extends BaseDto {
/** 本地订单ID */
/** 本地交易号 */
@Schema(description = "本地订单ID")
private String orderId;
private String tradeNo;
/** 本地业务号 */
@Schema(description = "本地业务")
private String orderNo;
/** 商户交易号 */
@Schema(description = "商户交易")
private String bizTradeNo;
/** 网关订单号 */
@Schema(description = "网关订单")
private String gatewayOrderNo;
/** 三方交易号 */
@Schema(description = "三方交易")
private String outTradeNo;
/** 同步类型 */
/**
* 三方支付返回状态
* @see PaySyncStatusEnum
* @see RefundSyncStatusEnum
*/
@Schema(description = "网关返回状态")
private String outTradeStatus;
/**
* 同步类型 支付/退款
* @see PaymentTypeEnum
*/
@Schema(description = "同步类型")
private String syncType;
@@ -43,38 +58,32 @@ public class PaySyncRecordDto extends BaseDto {
* @see PayChannelEnum#getCode()
*/
@Schema(description = "同步的异步通道")
private String asyncChannel;
private String channel;
/** 通知消息 */
/** 网关返回的同步消息 */
@DbMySqlFieldType(MySqlFieldTypeEnum.LONGTEXT)
@Schema(description = "通知消息")
@Schema(description = "同步消息")
private String syncInfo;
/**
* 网关返回状态
* @see PaySyncStatusEnum
* @see RefundSyncStatusEnum
*/
@Schema(description = "网关返回状态")
private String gatewayStatus;
/**
* 支付单如果状态不一致, 是否进行修复
*/
@Schema(description = "是否进行修复")
private boolean repairOrder;
private boolean repair;
/** 修复单号 */
@Schema(description = "修复单号")
private String repairOrderNo;
private String repairNo;
/** 错误码 */
@Schema(description = "错误码")
private String errorCode;
/** 错误消息 */
@Schema(description = "错误消息")
private String errorMsg;
/** 客户端IP */
@Schema(description = "客户端IP")
private String clientIp;
/** 请求链路ID */
@Schema(description = "请求链路ID")
private String reqId;
}

View File

@@ -25,12 +25,6 @@ public abstract class AbsReconcileStrategy implements PayStrategy {
/** 对账订单明细 */
private List<ReconcileDetail> reconcileDetails;
/**
* 生成对账序列号
*/
public abstract String generateSequence(LocalDate date);
/**
* 对账前处理, 主要是初始化支付SDK配置
*/

View File

@@ -15,9 +15,6 @@ import lombok.Setter;
@Setter
public abstract class AbsRefundStrategy implements PayStrategy{
/** 支付订单 */
private PayOrder payOrder = null;
/** 退款订单 */
private RefundOrder refundOrder = null;

View File

@@ -1,37 +0,0 @@
package cn.bootx.platform.daxpay.service.handler.sequence;
import cn.bootx.platform.common.sequence.func.Sequence;
import cn.bootx.platform.common.sequence.util.SequenceUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
/**
* 序列生成器配置类
* @author xxm
* @since 2024/2/28
*/
@Configuration
@RequiredArgsConstructor
public class DaxPaySequenceHandler {
/**
* 支付宝对账单序列生成器
*/
public Sequence alipayReconcileSequence(String date) {
return SequenceUtil.create(1,1,1,"AlipayReconcileSequence"+date);
}
/**
* 微信对账单序列生成器
*/
public Sequence wechatReconcileSequence(String date) {
return SequenceUtil.create(1,1,1,"WechatReconcileSequence"+date);
}
/**
* 云闪付对账单序列生成器
*/
public Sequence unionPayReconcileSequence(String date) {
return SequenceUtil.create(1,1,1,"UnionPayReconcileSequence"+date);
}
}