mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-03 11:06:46 +00:00
feat 退款订单定时同步任务
This commit is contained in:
185
README.md
185
README.md
@@ -213,3 +213,188 @@ QQ扫码加入QQ交流群
|
||||
## 🍷License
|
||||
|
||||
Apache License Version 2.0
|
||||
|
||||
# 🚀Dromara成员项目
|
||||
|
||||
<style>
|
||||
.member-project {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
|
||||
.member-project a {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.member-project a img {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="member-project">
|
||||
<a href="https://gitee.com/dromara/TLog" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/tlog.png" alt="TLog" title="一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/liteFlow" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/liteflow.png" alt="liteFlow" title="轻量,快速,稳定,可编排的组件式流程引擎">
|
||||
</a>
|
||||
<a href="https://hutool.cn/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/hutool.jpg" alt="hutool" title="小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。">
|
||||
</a>
|
||||
<a href="https://sa-token.cc/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/sa-token.png" alt="sa-token" title="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/hmily" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/hmily.png" alt="hmily" title="高性能一站式分布式事务解决方案。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/Raincat" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/raincat.png" alt="Raincat" title="强一致性分布式事务解决方案。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/myth" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/myth.png" alt="myth" title="可靠消息分布式事务解决方案。">
|
||||
</a>
|
||||
<a href="https://cubic.jiagoujishu.com/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/cubic.png" alt="cubic" title="一站式问题定位平台,以agent的方式无侵入接入应用,完整集成arthas功能模块,致力于应用级监控,帮助开发人员快速定位问题">
|
||||
</a>
|
||||
<a href="https://maxkey.top/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/maxkey.png" alt="maxkey" title="业界领先的身份管理和认证产品">
|
||||
</a>
|
||||
<a href="http://forest.dtflyx.com/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/forest-logo.png" alt="forest" title="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端">
|
||||
</a>
|
||||
<a href="https://jpom.top/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/jpom.png" alt="jpom" title="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件">
|
||||
</a>
|
||||
<a href="https://su.usthe.com/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/sureness.png" alt="sureness" title="面向 REST API 的高性能认证鉴权框架">
|
||||
</a>
|
||||
<a href="https://easy-es.cn/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/easy-es2.png" alt="easy-es" title="傻瓜级ElasticSearch搜索引擎ORM框架">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/northstar" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/northstar_logo.png" alt="northstar" title="Northstar盈富量化交易平台">
|
||||
</a>
|
||||
<a href="https://hertzbeat.com/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/hertzbeat-brand.svg" alt="hertzbeat" title="易用友好的云监控系统">
|
||||
</a>
|
||||
<a href="https://dromara.gitee.io/fast-request/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/fast-request.png" alt="fast-request" title="Idea 版 Postman,为简化调试API而生">
|
||||
</a>
|
||||
<a href="https://www.jeesuite.com/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/mendmix.png" alt="mendmix" title="开源分布式云原生架构一站式解决方案">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/koalas-rpc" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/koalas-rpc2.png" alt="koalas-rpc" title="企业生产级百亿日PV高可用可拓展的RPC框架。">
|
||||
</a>
|
||||
<a href="https://async.sizegang.cn/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/gobrs-async.png" alt="gobrs-async" title="配置极简功能强大的异步任务动态编排框架">
|
||||
</a>
|
||||
<a href="https://dynamictp.cn/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/dynamic-tp.png" alt="dynamic-tp" title="基于配置中心的轻量级动态可监控线程池">
|
||||
</a>
|
||||
<a href="https://www.x-easypdf.cn" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/x-easypdf.png" alt="x-easypdf" title="一个用搭积木的方式构建pdf的框架(基于pdfbox)">
|
||||
</a>
|
||||
<a href="http://dromara.gitee.io/image-combiner" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/image-combiner.png" alt="image-combiner" title="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大">
|
||||
</a>
|
||||
<a href="https://www.herodotus.cn/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/dante-cloud2.png" alt="dante-cloud" title="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。">
|
||||
</a>
|
||||
<a href="http://www.mtruning.club" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/go-view.png" alt="go-view" title="低代码数据可视化开发平台">
|
||||
</a>
|
||||
<a href="https://tangyh.top/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/lamp-cloud.png" alt="lamp-cloud" title="微服务中后台快速开发平台,支持租户(SaaS)模式、非租户模式">
|
||||
</a>
|
||||
<a href="https://www.redisfront.com/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/redis-front.png" alt="redis-front" title="RedisFront 是一款开源免费的跨平台 Redis 桌面客户端工具, 支持单机模式, 集群模式, 哨兵模式以及 SSH 隧道连接, 可轻松管理Redis缓存数据.">
|
||||
</a>
|
||||
<a href="https://www.yuque.com/u34495/mivcfg" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/electron-egg.png" alt="electron-egg" title="一个入门简单、跨平台、企业级桌面软件开发框架">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/open-capacity-platform" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/open-capacity-platform.jpg" alt="open-capacity-platform" title="简称ocp是基于Spring Cloud的企业级微服务框架(用户权限管理,配置中心管理,应用管理,....)">
|
||||
</a>
|
||||
<a href="http://easy-trans.fhs-opensource.top/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/easy_trans.png" alt="Easy-Trans" title="Easy-Trans 一个注解搞定数据翻译,减少30%SQL代码量">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/neutrino-proxy" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/neutrino-proxy.svg" alt="neutrino-proxy" title="一款基于 Netty 的、开源的内网穿透神器。">
|
||||
</a>
|
||||
<a href="https://chatgpt.cn.obiscr.com/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/chatgpt.png" alt="chatgpt" title="一个支持在 JetBrains 系列 IDE 上运行的 ChatGPT 的插件。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/zyplayer-doc" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/zyplayer-doc.png" alt="zyplayer-doc" title="zyplayer-doc是一款适合团队和个人使用的WIKI文档管理工具,同时还包含数据库文档、Api接口文档。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/payment-spring-boot" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/payment-spring-boot.png" alt="payment-spring-boot" title="最全最好用的微信支付V3 Spring Boot 组件。">
|
||||
</a>
|
||||
<a href="https://www.j2eefast.com/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/j2eefast.png" alt="j2eefast" title="J2eeFAST 是一个致力于中小企业 Java EE 企业级快速开发平台,我们永久开源!">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/data-compare" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/dataCompare.png" alt="data-compare" title="数据库比对工具:hive 表数据比对,mysql、Doris 数据比对,实现自动化配置进行数据比对,避免频繁写sql 进行处理,低代码(Low-Code) 平台">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/open-giteye-api" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/open-giteye-api.svg" alt="open-giteye-api" title="giteye.net 是专为开源作者设计的数据图表服务工具类站点,提供了包括 Star 趋势图、贡献者列表、Gitee指数等数据图表服务。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/RuoYi-Vue-Plus" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/RuoYi-Vue-Plus.png" alt="RuoYi-Vue-Plus" title="后台管理系统 重写 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 src="https://x-file-storage.xuyanwu.cn/assets/link/RuoYi-Cloud-Plus.png" alt="RuoYi-Cloud-Plus" title="微服务管理系统 重写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 src="https://x-file-storage.xuyanwu.cn/assets/link/stream-query.png" alt="stream-query" title="允许完全摆脱 Mapper 的 mybatis-plus 体验!封装 stream 和 lambda 操作进行数据返回处理。">
|
||||
</a>
|
||||
<a href="https://wind.kim/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/sms4j.png" alt="sms4j" title="短信聚合工具,让发送短信变的更简单。">
|
||||
</a>
|
||||
<a href="https://cloudeon.top/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/cloudeon.png" alt="cloudeon" title="简化kubernetes上大数据集群的运维管理">
|
||||
</a>
|
||||
<a href="https://github.com/dromara/hodor" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/hodor.png" alt="hodor" title="Hodor是一个专注于任务编排和高可用性的分布式任务调度系统。">
|
||||
</a>
|
||||
<a href="http://nsrule.com/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/test-hub.png" alt="test-hub" title="流程编排,插件驱动,测试无限可能">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/disjob" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/disjob-2.png" alt="disjob" title="Disjob是一个分布式的任务调度框架">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/binlog4j" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/Binlog4j.png" alt="binlog4j" title="轻量级 Mysql Binlog 客户端, 提供宕机续读, 高可用集群等特性">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/yft-design" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/yft-design.png" alt="yft-design" title="基于 Canvas 的开源版 创客贴 支持导出json,svg, image文件。">
|
||||
</a>
|
||||
<a href="https://x-file-storage.xuyanwu.cn" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/logo3.svg" alt="x-file-storage" title="">
|
||||
</a>
|
||||
<a href="https://wemq.nicholasld.cn" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/WeMQ.png" alt="WeMQAQ" title="开源、高性能、安全、功能强大的物联网调试和管理解决方案。">
|
||||
</a>
|
||||
<a href="https://www.yuque.com/may-fly/mayfly-go" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/mayfly-go.png" alt="Mayfly-Go" title="web版 linux、数据库、redis、mongo统一管理操作平台。">
|
||||
</a>
|
||||
<a href="https://akali.yomahub.com" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/Akali.png" alt="Akali" title="Akali(阿卡丽),轻量级本地化热点检测/降级框架,10秒钟即可接入使用!大流量下的神器">
|
||||
</a>
|
||||
<a href="https://dbswitch.gitee.io/docs-site/#/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/dbswitch.png" alt="dbswitch" title="异构数据库迁移同步工具,dbswitch提供源端数据库向目的端数据的全量与增量迁移同步功能">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/easyAi" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/easyAi.png" alt="easyAi" title="java傻瓜ai框架,无需任何算法知识,通过简单的api调用就可以实现常用的图像内物体的识别,定位等图像ai服务,及自然语言分类处理服务。面向java开发程序员,不依赖任何第三方库,第三方接口,独立包。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/tianai-captcha" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/tianai-captcha.png" alt="tianai-captcha" title="可能是java界最好的开源行为验证码[滑块验证码、点选验证码、行为验证码、旋转验证码, 滑动验证码]">
|
||||
</a>
|
||||
<a href="https://dromara.org/zh/projects/" target="_blank">
|
||||
<img src="https://x-file-storage.xuyanwu.cn/assets/link/dromara.png" alt="dromara" title="让每一位开源爱好者,体会到开源的快乐。">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
@@ -37,4 +37,12 @@ public class PayOrderManager extends BaseManager<PayOrderMapper, PayOrder> {
|
||||
QueryWrapper<PayOrder> generator = QueryGenerator.generator(query);
|
||||
return page(mpPage, generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制更新 (忽略版本号)
|
||||
*/
|
||||
public void updateForceById(PayOrder payOrder) {
|
||||
payOrder.setVersion(null);
|
||||
this.updateById(payOrder);
|
||||
}
|
||||
}
|
||||
|
@@ -56,4 +56,17 @@ public class PayOrderService {
|
||||
}
|
||||
payOrderManager.updateById(payOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用强制更新
|
||||
*/
|
||||
public void updateForceById(PayOrder payOrder){
|
||||
// 如果是异步支付且支付订单完成, 需要删除订单超时任务记录
|
||||
if (payOrder.isAsyncPay() && ORDER_FINISH.contains(payOrder.getStatus())){
|
||||
expiredTimeService.cancelExpiredTime(payOrder.getId());
|
||||
}
|
||||
payOrder.setVersion(null);
|
||||
payOrderManager.updateForceById(payOrder);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.common.query.generator.QueryGenerator;
|
||||
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
|
||||
import cn.bootx.platform.daxpay.service.param.order.RefundOrderQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
@@ -12,6 +13,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@@ -46,4 +49,15 @@ public class RefundOrderManager extends BaseManager<RefundOrderMapper, RefundOrd
|
||||
public boolean existsByRefundNo(String refundNo){
|
||||
return this.existedByField(RefundOrder::getRefundNo,refundNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询退款中的支付订单
|
||||
*/
|
||||
public List<RefundOrder> findAllByProgress() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return lambdaQuery()
|
||||
.le(RefundOrder::getRefundTime,now)
|
||||
.eq(RefundOrder::getStatus, RefundStatusEnum.PROGRESS)
|
||||
.list();
|
||||
}
|
||||
}
|
||||
|
@@ -42,7 +42,7 @@ public class PayCallbackService {
|
||||
public void payCallback() {
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
// 加锁
|
||||
LockInfo lock = lockTemplate.lock("callback:payment:" + callbackInfo.getOrderId());
|
||||
LockInfo lock = lockTemplate.lock("callback:payment:" + callbackInfo.getOrderId(),10000, 200);
|
||||
if (Objects.isNull(lock)){
|
||||
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.IGNORE).setMsg("回调正在处理中,忽略本次回调请求");
|
||||
log.warn("订单号: {} 回调正在处理中,忽略本次回调请求", callbackInfo.getOrderId());
|
||||
|
@@ -39,7 +39,7 @@ public class RefundCallbackService {
|
||||
|
||||
CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo();
|
||||
// 加锁
|
||||
LockInfo lock = lockTemplate.lock("callback:refund:" + callbackInfo.getOrderId());
|
||||
LockInfo lock = lockTemplate.lock("callback:refund:" + callbackInfo.getOrderId(),10000, 200);
|
||||
if (Objects.isNull(lock)){
|
||||
callbackInfo.setCallbackStatus(PayCallbackStatusEnum.IGNORE).setMsg("回调正在处理中,忽略本次回调请求");
|
||||
log.warn("订单号: {} 回调正在处理中,忽略本次回调请求", callbackInfo.getOrderId());
|
||||
|
@@ -63,7 +63,7 @@ public class PayCloseService {
|
||||
payOrder = payOrderQueryService.findByBusinessNo(param.getBusinessNo())
|
||||
.orElseThrow(() -> new PayFailureException("未查询到支付订单"));
|
||||
}
|
||||
LockInfo lock = lockTemplate.lock("payment:close:" + payOrder.getId());
|
||||
LockInfo lock = lockTemplate.lock("payment:close:" + payOrder.getId(),10000, 50);
|
||||
if (Objects.isNull(lock)){
|
||||
throw new RepetitiveOperationException("支付订单已在关闭中,请勿重复发起");
|
||||
}
|
||||
|
@@ -189,7 +189,7 @@ public class ClientNoticeService {
|
||||
private void run(Long taskId){
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
// 开启分布式锁
|
||||
LockInfo lock = lockTemplate.lock(KEY + ":" + taskId,2000, 50);
|
||||
LockInfo lock = lockTemplate.lock(KEY + ":" + taskId,10000, 200);
|
||||
if (Objects.isNull(lock)){
|
||||
throw new RepetitiveOperationException("支付同步处理中,请勿重复操作");
|
||||
}
|
||||
|
@@ -1,54 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.pay.task;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
|
||||
import cn.bootx.platform.daxpay.param.pay.PaySyncParam;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.pay.dao.PayExpiredTimeRepository;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.sync.service.PaySyncService;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 待支付订单的状态同步, 先不进行启用
|
||||
* @author xxm
|
||||
* @since 2024/1/5
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayWaitOrderSyncTask {
|
||||
private final PayExpiredTimeRepository repository;
|
||||
|
||||
private final PaySyncService paySyncService;
|
||||
|
||||
private final LockTemplate lockTemplate;
|
||||
|
||||
public void task(){
|
||||
log.debug("开始同步支付订单状态");
|
||||
// 从超时订单列表中获取到未超时的订单号
|
||||
Set<String> keys = repository.getNormalKeysBy30Day();
|
||||
for (String key : keys) {
|
||||
LockInfo lock = lockTemplate.lock("payment:sync:" + key,10000,200);
|
||||
if (Objects.isNull(lock)){
|
||||
throw new RepetitiveOperationException("支付同步处理中,请勿重复操作");
|
||||
}
|
||||
try {
|
||||
Long paymentId = Long.parseLong(key);
|
||||
PaySyncParam paySyncParam = new PaySyncParam();
|
||||
paySyncParam.setPaymentId(paymentId);
|
||||
// 执行网关同步, 网关同步时会对支付的进行状态的处理
|
||||
paySyncService.sync(paySyncParam);
|
||||
} catch (Exception e) {
|
||||
log.error("同步支付订单异常", e);
|
||||
} finally {
|
||||
lockTemplate.releaseLock(lock);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -17,16 +17,15 @@ import cn.bootx.platform.daxpay.service.core.record.repair.entity.PayRepairRecor
|
||||
import cn.bootx.platform.daxpay.service.core.record.repair.service.PayRepairRecordService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsPayRepairStrategy;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -48,11 +47,20 @@ public class PayRepairService {
|
||||
|
||||
private final PayRepairRecordService recordService;
|
||||
|
||||
private final LockTemplate lockTemplate;
|
||||
|
||||
/**
|
||||
* 修复支付单
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public PayRepairResult repair(PayOrder order, PayRepairWayEnum repairType){
|
||||
// 添加分布式锁
|
||||
LockInfo lock = lockTemplate.lock("repair:pay:" + order.getId(), 10000, 200);
|
||||
if (Objects.isNull(lock)){
|
||||
log.warn("当前支付定单正在修复中: {}", order.getId());
|
||||
return new PayRepairResult();
|
||||
}
|
||||
|
||||
// 1. 获取支付单管理的通道支付订单
|
||||
Map<String, PayChannelOrder> channelOrderMap = channelOrderManager.findAllByPaymentId(order.getId())
|
||||
.stream()
|
||||
|
@@ -23,6 +23,8 @@ import cn.bootx.platform.daxpay.service.core.record.repair.entity.PayRepairRecor
|
||||
import cn.bootx.platform.daxpay.service.core.record.repair.service.PayRepairRecordService;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsRefundRepairStrategy;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -56,54 +58,67 @@ public class RefundRepairService {
|
||||
|
||||
private final PayRepairRecordService recordService;
|
||||
|
||||
private final LockTemplate lockTemplate;
|
||||
|
||||
/**
|
||||
* 修复退款单
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public RefundRepairResult repair(RefundOrder refundOrder, RefundRepairWayEnum repairType){
|
||||
|
||||
// 获取关联支付单
|
||||
PayOrder payOrder = payOrderQueryService.findById(refundOrder.getPaymentId())
|
||||
.orElseThrow(() -> new RuntimeException("支付单不存在"));
|
||||
// 关联支付通道支付单
|
||||
Map<String, PayChannelOrder> payChannelOrderMap = payChannelOrderManager.findAllByPaymentId(refundOrder.getPaymentId())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(PayChannelOrder::getChannel, Function.identity(), CollectorsFunction::retainLatest));
|
||||
// 异步通道退款单
|
||||
Map<String, RefundChannelOrder> refundChannelOrderMap = refundChannelOrderManager.findAllByRefundId(refundOrder.getId())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(RefundChannelOrder::getChannel, Function.identity(), CollectorsFunction::retainLatest));
|
||||
|
||||
// 2 初始化修复参数
|
||||
List<String> channels = new ArrayList<>(payChannelOrderMap.keySet());
|
||||
List<AbsRefundRepairStrategy> repairStrategies = RefundRepairStrategyFactory.createAsyncLast(channels);
|
||||
for (AbsRefundRepairStrategy repairStrategy : repairStrategies) {
|
||||
PayChannelOrder payChannelOrder = payChannelOrderMap.get(repairStrategy.getChannel().getCode());
|
||||
RefundChannelOrder refundChannelOrder = refundChannelOrderMap.get(repairStrategy.getChannel().getCode());
|
||||
repairStrategy.initRepairParam(refundOrder, refundChannelOrder, payOrder, payChannelOrder);
|
||||
// 添加分布式锁
|
||||
LockInfo lock = lockTemplate.lock("repair:refund:" + refundOrder.getId(), 10000, 200);
|
||||
if (Objects.isNull(lock)){
|
||||
log.warn("当前退款单正在修复中: {}", refundOrder.getId());
|
||||
return new RefundRepairResult();
|
||||
}
|
||||
try {
|
||||
// 获取关联支付单
|
||||
PayOrder payOrder = payOrderQueryService.findById(refundOrder.getPaymentId())
|
||||
.orElseThrow(() -> new RuntimeException("支付单不存在"));
|
||||
// 关联支付通道支付单
|
||||
Map<String, PayChannelOrder> payChannelOrderMap = payChannelOrderManager.findAllByPaymentId(refundOrder.getPaymentId())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(PayChannelOrder::getChannel, Function.identity(), CollectorsFunction::retainLatest));
|
||||
// 异步通道退款单
|
||||
Map<String, RefundChannelOrder> refundChannelOrderMap = refundChannelOrderManager.findAllByRefundId(refundOrder.getId())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(RefundChannelOrder::getChannel, Function.identity(), CollectorsFunction::retainLatest));
|
||||
|
||||
// 根据不同的类型执行对应的修复逻辑
|
||||
RefundRepairResult repairResult = new RefundRepairResult();
|
||||
if (Objects.requireNonNull(repairType) == RefundRepairWayEnum.REFUND_SUCCESS) {
|
||||
repairResult = this.success(refundOrder,payOrder,repairStrategies);
|
||||
} else if (repairType == RefundRepairWayEnum.REFUND_FAIL) {
|
||||
repairResult = this.close(refundOrder,payOrder,repairStrategies);
|
||||
} else {
|
||||
log.error("走到了理论上讲不会走到的分支");
|
||||
// 2 初始化修复参数
|
||||
List<String> channels = new ArrayList<>(payChannelOrderMap.keySet());
|
||||
List<AbsRefundRepairStrategy> repairStrategies = RefundRepairStrategyFactory.createAsyncLast(channels);
|
||||
for (AbsRefundRepairStrategy repairStrategy : repairStrategies) {
|
||||
PayChannelOrder payChannelOrder = payChannelOrderMap.get(repairStrategy.getChannel()
|
||||
.getCode());
|
||||
RefundChannelOrder refundChannelOrder = refundChannelOrderMap.get(repairStrategy.getChannel()
|
||||
.getCode());
|
||||
repairStrategy.initRepairParam(refundOrder, refundChannelOrder, payOrder, payChannelOrder);
|
||||
}
|
||||
|
||||
// 根据不同的类型执行对应的修复逻辑
|
||||
RefundRepairResult repairResult = new RefundRepairResult();
|
||||
if (Objects.requireNonNull(repairType) == RefundRepairWayEnum.REFUND_SUCCESS) {
|
||||
repairResult = this.success(refundOrder, payOrder, repairStrategies);
|
||||
} else if (repairType == RefundRepairWayEnum.REFUND_FAIL) {
|
||||
repairResult = this.close(refundOrder, payOrder, repairStrategies);
|
||||
} else {
|
||||
log.error("走到了理论上讲不会走到的分支");
|
||||
}
|
||||
|
||||
// 设置修复ID并保存修复记录
|
||||
repairResult.setRepairNo(IdUtil.getSnowflakeNextIdStr());
|
||||
// 支付修复记录
|
||||
PayRepairRecord payRepairRecord = this.payRepairRecord(payOrder, repairType, repairResult);
|
||||
// 退款修复记录
|
||||
PayRepairRecord refundRepairRecord = this.refundRepairRecord(refundOrder, repairType, repairResult);
|
||||
|
||||
// 发送通知
|
||||
clientNoticeService.registerRefundNotice(refundOrder, null, new ArrayList<>(refundChannelOrderMap.values()));
|
||||
recordService.saveAllRecord(Arrays.asList(payRepairRecord, refundRepairRecord));
|
||||
return repairResult;
|
||||
} finally {
|
||||
lockTemplate.releaseLock(lock);
|
||||
}
|
||||
|
||||
// 设置修复ID并保存修复记录
|
||||
repairResult.setRepairNo(IdUtil.getSnowflakeNextIdStr());
|
||||
// 支付修复记录
|
||||
PayRepairRecord payRepairRecord = this.payRepairRecord(payOrder, repairType, repairResult);
|
||||
// 退款修复记录
|
||||
PayRepairRecord refundRepairRecord = this.refundRepairRecord(refundOrder, repairType, repairResult);
|
||||
|
||||
// 发送通知
|
||||
clientNoticeService.registerRefundNotice(refundOrder, null, new ArrayList<>(refundChannelOrderMap.values()));
|
||||
recordService.saveAllRecord(Arrays.asList(payRepairRecord, refundRepairRecord));
|
||||
return repairResult;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -88,7 +88,7 @@ public class PaySyncService {
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public SyncResult syncPayOrder(PayOrder payOrder) {
|
||||
// 加锁
|
||||
LockInfo lock = lockTemplate.lock("sync:payment" + payOrder.getId(),10000,200);
|
||||
LockInfo lock = lockTemplate.lock("sync:pay" + payOrder.getId(),10000,200);
|
||||
if (Objects.isNull(lock)){
|
||||
throw new RepetitiveOperationException("支付同步处理中,请勿重复操作");
|
||||
}
|
||||
|
@@ -0,0 +1,27 @@
|
||||
package cn.bootx.platform.daxpay.service.task;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.task.service.RefundSyncTaskService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 退款定时同步任务 一分钟一次, 查询退款中的订单进行同步
|
||||
* @author xxm
|
||||
* @since 2024/3/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@DisallowConcurrentExecution
|
||||
@PersistJobDataAfterExecution
|
||||
@RequiredArgsConstructor
|
||||
public class RefundSyncTask implements Job {
|
||||
|
||||
private final RefundSyncTaskService refundSyncTaskService;
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
refundSyncTaskService.syncTask();
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package cn.bootx.platform.daxpay.service.task.service;
|
||||
|
||||
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.payment.sync.service.RefundSyncService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 定时
|
||||
* @author xxm
|
||||
* @since 2024/3/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RefundSyncTaskService {
|
||||
|
||||
private final RefundSyncService refundSyncService;
|
||||
|
||||
private final RefundOrderManager refundOrderManager;
|
||||
|
||||
/**
|
||||
* 同步任务
|
||||
*/
|
||||
public void syncTask(){
|
||||
// 查询退款中的退款订单
|
||||
List<RefundOrder> list = refundOrderManager.findAllByProgress();
|
||||
for (RefundOrder refundOrder : list) {
|
||||
try {
|
||||
// 调用同步方法
|
||||
refundSyncService.syncRefundOrder(refundOrder);
|
||||
} catch (Exception e) {
|
||||
log.warn("退款执行同步失败, ID: {}",refundOrder.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user