feat 聚合支付处理, 增加h5嵌入式项目支持

This commit is contained in:
bootx
2024-02-10 22:50:24 +08:00
parent fcc73d680e
commit 7d65add2ca
68 changed files with 1246 additions and 305 deletions

View File

@@ -1,115 +1,13 @@
2.0.1:
- [ ] 支付回调通知和退款回调通知功能
- [ ] 增加收银台演示功能, 金额固定, 不允许进行修改
- [ ] 增加聚合支付(直接支付模式)演示功能,
2.0.1 里程碑
- 支持各类回调通知
- 现金、钱包、储值卡功能进行重构
-
2.0.0 重构进度
- 已经完成的
- [x] 参数签名和验签机制
- [x] 开放接口供第三方调用
- [x] 将零散的上下文对象进行抽取为统一的上下文对象
- [x] 拆分原有的策略类,实现粒度更细
- [x] 去除用户概念,作为独立的支付网关使用,不与其他系统产生耦合性
- 2023-12-31:
- [x] 支付关闭相关逻辑
- [x] 各支付通道补充相关未实现的逻辑
- [x] 支付订单修复逻辑, 用于回调和同步不一致的情况处理
- 2024-01-01:
- [x] 支付订单修复逻辑, 用于回调和支付同步后不一致的情况处理
- 2024-01-02:
- [x] 添加管理端的各类`Controller`
- [x] 支持定时同步支付中订单状态, 借助订单超时任务
- 2024-01-03:
- [x] 支付流程联调
- [x] 支付同步和支付修复流程优化
- [x] 支付平台全局性配置
- 2024-01-04:
- [x] 支付同步时, 如果订单已经超时, 但状态还是待支付, 触发修复操作关闭订单
- [x] 发起支付时, 如果已经超过订单超时时间, 但状态还是待支付, 触发同步和修复操作
- [x] 支付宝关闭支付订单,如果网关已经关闭,会返回错误导致本地订单无法关闭
- [x] 增加支付单关闭记录功能
- [x] 支付单存在异步支付时, 支付时间需要读取支付网关的返回的时间
- [x] 同步记录/关闭记录/修复记录 增加记录请求ID
- 2024-01-05:
- [x] 支付同步日志记录, 无论同步成功还是失败, 以及修复成功还是失败, 都需要记录日志
- [x] 超时自动取消功能联调, 先用spring定时任务实现, 通过支付同步实现
- [x] 支付同步和修复时, 对一些模糊状态进行处理, 例如支付宝返回的订单未查到
- [x] 待支付支付单定时同步状态, 先用spring定时任务实现, 通过支付同步实现
- [x] 退款功能联调
- 2024-01-06:
- [x] 订单取消/修复/取消/同步等操作添加分布式锁, 防止出现重复操作
- [x] 增加支付修复记录
- 2024-01-07:
- [x] 抽取签名工具类
- [x] 增加消息通知机制(通知客户端)
- 2024-01-08:
- [x] (前端) 更新代码为platform最新版本
- [x] (前端) 接口配置
- 2024-01-09:
- [x] (前端) 支付配置
- 2024-01-10:
- [x] 支付常量数据维护
- [x] (前端) 支付回调记录
- 2024-01-11:
- [x] (前端) 支付关闭记录
- [x] (前端) 支付修复记录
- 2024-01-12:
- [x] (前端) 支付订单
- [x] (前端) 退款订单
- [x] (前端) 支付通道配置列表
- 2024-01-13:
- [x] (前端) 微信/支付宝支付通道配置
- [x] 支付通道支持停用
- [x] ~~请求支付网关时区退款号以R开头, 用于与支付ID的区分~~
- [x] (前端) 平台配置
- 2024-01-15:
- [x] 优化支付相关订单和记录的查询条件
- [x] 开放接口新增查询类接口
- 2024-01-16:
- [x] 支付单涉及退款状态同步逻辑
- 2024-01-17:
- [x] 支付宝和微信支付对账下载接口
- 2024-01-21:
- [x] (对账) 微信对账文件解析
- [x] (对账) 支付宝对账文件解析
- [x] (对账) 对账策略类和定时任务
- [x] (对账) 对账记录和明细保存
- 2024-01-22:
- [x] (对账) 通用结构对账结构转换
- [x] (对账) 对账列表页、操作按钮(手动创建、执行、重试)
- 2024-01-23:
- [x] 支付对账收尾
- [x] 支付退款调整为订单+明细
- 2024-01-24:
- [x] 支付策略优化通道支付单和可退款信息相关关系
- [x] 支付退款默认为退款中状态, 根据返回数据或回调来完成退款操作
- [x] 拆分支付回调为支付和退款回调
- 2024-01-25:
- [x] 支付修复策略优化存储记录信息
- [x] 去除各通道支付记录,统一为通道支付记录
- 2024-01-26:
- [x] 优化支付修复时的触发来源的获取
- [x] 优化支付回调处理, 处理各种错误
- [x] 调整支付修复策略, 拆分为支付和退款修复两大类
- 2024-01-28:
- [x] 支付宝对账单下载异常排查-支付宝每日都会生成对账单, 哪怕为空, 也会生成
- [x] 订单修复记录前端显示调整
- 2044-01-30:
- [x] 退款接口更改为先落库, 后更新, 同时退款余额先先进行扣减, 根据退款状态进行处理
- [x] 增加退款同步策略, 对退款中的状态的退款订单进行处理
- [x] 修改退款补偿处理, 更改为退款粒度为整个退款单, 要不全部成功, 要不全部失败
- [x] 支付通道对出现疑似退款的订单进行**报错提醒**, 通过退款同步进行补偿
- 2024-01-31:
- [x] 微信退款同步策略
- [x] 支付和退款同步时, 填充完成时间和网关订单号
- 2024-02-01:
- [x] 支付切换异步方式时, 订单未更换
- [x] 支付同步时, 支付宝未支付订单无法自动关闭
- [x] 调整订单页面查询条件
- 2024-02-02:
- [ ] 接入SDK编写
- [ ] 接入支付网关的演示项目
- 2.0.1 版本内容
- 2.0.x 版本内容
- [ ] 退款操作支持重试
- [ ] 支付流程也改为先落库后支付情况, 避免极端情况导致掉单
- [ ] 支付流程涉及异步支付时, 更换支付方式需要控制预防客户重复付款

View File

@@ -41,3 +41,6 @@ https://gitee.com/xiaoym/knife4j
easy_trans 一个注解搞定数据翻译:
https://gitee.com/dromara/easy_trans
vue3-vant4-mobile Vant4脚手架:
https://github.com/xiangshu233/vue3-vant4-mobile

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 傲慢或香橙
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -17,6 +17,9 @@ public class DaxPayDemoProperties {
/** 服务地址 */
private String serverUrl;
/** 前端地址 */
private String frontUrl;
/** 签名方式 */
private SignTypeEnum signType = SignTypeEnum.MD5;

View File

@@ -0,0 +1,62 @@
package cn.bootx.platform.daxpay.demo.controller;
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
import cn.bootx.platform.common.core.rest.Res;
import cn.bootx.platform.common.core.rest.ResResult;
import cn.bootx.platform.daxpay.demo.domain.AggregatePayInfo;
import cn.bootx.platform.daxpay.demo.param.AggregateSimplePayParam;
import cn.bootx.platform.daxpay.demo.result.PayOrderResult;
import cn.bootx.platform.daxpay.demo.service.AggregateService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import static org.springframework.http.HttpHeaders.USER_AGENT;
/**
* 聚合支付
* @author xxm
* @since 2024/2/9
*/
@IgnoreAuth
@Tag(name = "聚合支付")
@RestController
@RequestMapping("/demo/aggregate")
@RequiredArgsConstructor
public class AggregateController {
private final AggregateService aggregateService;
@Operation(summary = "创建聚合支付码")
@PostMapping("/createUrl")
public ResResult<String> createUrl(@RequestBody AggregateSimplePayParam param) {
return Res.ok(aggregateService.createUrl(param));
}
@Operation(summary = "获取聚合支付信息")
@GetMapping("/getInfo")
public ResResult<AggregatePayInfo> getInfo(String code){
return Res.ok(aggregateService.getInfo(code));
}
@Operation(summary = "聚合支付扫码跳转中间页")
@GetMapping("/qrPayPage/{code}")
public ModelAndView qrPayPage(@PathVariable String code,@RequestHeader(USER_AGENT) String ua){
String url = aggregateService.qrPayPage(code, ua);
return new ModelAndView("redirect:" + url);
}
@Operation(summary = "通过聚合支付码发起支付")
@PostMapping("/qrPay")
public ResResult<PayOrderResult> qrPa(String code){
return Res.ok(aggregateService.aliQrPay(code));
}
@Operation(summary = "通过付款码发起支付")
@PostMapping("/barCodePay")
public ResResult<Void> barCodePay(@RequestBody AggregateSimplePayParam param){
return Res.ok();
}
}

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.demo.controller;
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
import cn.bootx.platform.common.core.rest.Res;
import cn.bootx.platform.common.core.rest.ResResult;
import cn.bootx.platform.common.core.util.ValidationUtil;
@@ -16,11 +17,12 @@ import org.springframework.web.bind.annotation.*;
* @author xxm
* @since 2024/2/8
*/
@IgnoreAuth
@Tag(name = "结算台演示")
@RestController
@RequestMapping("/demo/cashier")
@RequiredArgsConstructor
public class DaxPayCashierController {
public class CashierController {
private final DaxPayCashierService cashierService;

View File

@@ -0,0 +1,23 @@
package cn.bootx.platform.daxpay.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 嵌入式h5项目转发控制器, 不用输入 index.html也可以正常访问
* @author xxm
* @since 2024/2/10
*/
@Controller
@RequestMapping
public class RedirectH5Controller {
/**
* 将/h5/*的访问请求代理到/h5/index.html*
*/
@GetMapping("/h5/")
public String toH5(){
return "forward:/h5/index.html";
}
}

View File

@@ -0,0 +1,27 @@
package cn.bootx.platform.daxpay.demo.domain;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 聚合支付发起信息
* @author xxm
* @since 2024/2/9
*/
@Data
@Accessors(chain = true)
@Schema(title = "聚合支付发起信息")
public class AggregatePayInfo {
/** 标题 */
@Schema(description = "标题")
private String title;
/** 订单业务号 */
@Schema(description = "订单业务号")
private String businessNo;
/** 支付金额 */
@Schema(description = "支付金额")
private Integer amount;
}

View File

@@ -0,0 +1,33 @@
package cn.bootx.platform.daxpay.demo.param;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
/**
* 聚合简单支付
* @author xxm
* @since 2024/2/9
*/
@Data
@Accessors(chain = true)
@Schema(title = "聚合简单支付")
public class AggregateSimplePayParam {
@Schema(description = "业务号")
@NotNull
private String businessNo;
@Schema(description = "标题")
@NotNull
private String title;
@Schema(description = "金额")
@NotNull
private BigDecimal amount;
@Schema(description = "付款码")
private String authCode;
}

View File

@@ -0,0 +1,29 @@
package cn.bootx.platform.daxpay.demo.result;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 微信Jsapi预支付签名返回信息
* @author xxm
* @since 2024/2/10
*/
@Data
@Accessors(chain = true)
@Schema(title = "微信Jsapi预支付签名返回信息")
public class WxJsapiSignResult {
/** 公众号ID */
private String appId;
/** 时间戳(秒) */
private String timeStamp;
/** 随机串 */
private String nonceStr;
/** 预支付ID, 已经是 prepay_id=xxx 格式 */
private String prePayId;
/** 微信签名方式 */
private String signType;
/** 微信签名 */
private String paySign;
}

View File

@@ -0,0 +1,258 @@
package cn.bootx.platform.daxpay.demo.service;
import cn.bootx.platform.common.core.exception.BizException;
import cn.bootx.platform.common.redis.RedisClient;
import cn.bootx.platform.common.spring.util.WebServletUtil;
import cn.bootx.platform.daxpay.demo.config.DaxPayDemoProperties;
import cn.bootx.platform.daxpay.demo.domain.AggregatePayInfo;
import cn.bootx.platform.daxpay.demo.param.AggregateSimplePayParam;
import cn.bootx.platform.daxpay.demo.result.PayOrderResult;
import cn.bootx.platform.daxpay.demo.result.WxJsapiSignResult;
import cn.bootx.platform.daxpay.sdk.code.AggregatePayEnum;
import cn.bootx.platform.daxpay.sdk.code.PayChannelEnum;
import cn.bootx.platform.daxpay.sdk.code.PayWayEnum;
import cn.bootx.platform.daxpay.sdk.model.assist.WxAccessTokenModel;
import cn.bootx.platform.daxpay.sdk.model.assist.WxAuthUrlModel;
import cn.bootx.platform.daxpay.sdk.model.assist.WxJsapiSignModel;
import cn.bootx.platform.daxpay.sdk.model.pay.PayOrderModel;
import cn.bootx.platform.daxpay.sdk.net.DaxPayKit;
import cn.bootx.platform.daxpay.sdk.param.assist.WxAccessTokenParam;
import cn.bootx.platform.daxpay.sdk.param.assist.WxAuthUrlParam;
import cn.bootx.platform.daxpay.sdk.param.assist.WxJsapiSignParam;
import cn.bootx.platform.daxpay.sdk.param.channel.WeChatPayParam;
import cn.bootx.platform.daxpay.sdk.param.pay.SimplePayParam;
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Optional;
/**
* 聚合支付
* @author xxm
* @since 2024/2/9
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AggregateService {
private final DaxPayDemoProperties daxPayDemoProperties;
private final RedisClient redisClient;
private final String PREFIX_KEY = "payment:aggregate:";
/**
* 创建聚合支付码连接
*/
public String createUrl(AggregateSimplePayParam param) {
int amount = param.getAmount()
.multiply(BigDecimal.valueOf(100))
.intValue();
AggregatePayInfo aggregatePayInfo = new AggregatePayInfo()
.setTitle(param.getTitle())
.setBusinessNo(param.getBusinessNo())
.setAmount(amount);
String code = IdUtil.getSnowflakeNextIdStr();
String serverUrl = daxPayDemoProperties.getServerUrl();
// 有效期五分钟
redisClient.setWithTimeout(PREFIX_KEY + code, JSONUtil.toJsonStr(aggregatePayInfo), 5 * 60 * 1000);
return StrUtil.format("{}/demo/aggregate/qrPayPage/{}", serverUrl,code);
}
/**
* 获取聚合支付信息
*/
public AggregatePayInfo getInfo(String key) {
String jsonStr = Optional.ofNullable(redisClient.get(PREFIX_KEY + key))
.orElseThrow(() -> new BizException("支付超时"));
return JSONUtil.toBean(jsonStr, AggregatePayInfo.class);
}
/**
* 聚合支付扫码跳转中间页
*/
public String qrPayPage(String code, String ua){
// 判断是否过期
boolean exists = redisClient.exists(PREFIX_KEY + code);
if (!exists){
// 跳转到过期页面
return null;
}
// 根据UA判断是什么环境
if (ua.contains(AggregatePayEnum.UA_ALI_PAY.getCode())) {
// 跳转支付宝中间页
return StrUtil.format("{}/#/cashier/alipay", daxPayDemoProperties.getFrontUrl());
}
else if (ua.contains(AggregatePayEnum.UA_WECHAT_PAY.getCode())) {
// 微信重定向到中间页, 因为微信需要授权后才能发起支付
return this.wxJsapiAuth(code);
}
else {
// 跳转到异常页
return null;
}
}
/**
* 微信Jsapi发起支付, 返回预支付信息, 从页面调起支付, 分为下面三个步骤:
* 1. 获取微信OpenId
* 2. 调用支付接口拿到预支付ID
* 3. 对预支付ID签名, 拿到页面调起支付参数并返回
*/
public WxJsapiSignResult wxJsapiPau(String aggregateCode, String authCode) {
// 1. 获取微信OpenId
String openId = this.getOpenId(authCode);
// 2. 发起预支付
PayOrderModel payOrderModel = this.wxJsapiPrePay(aggregateCode, openId);
// 3. 预付订单再次签名, 调用起页面的支付弹窗
WxJsapiSignParam wxJsapiSignParam = new WxJsapiSignParam();
wxJsapiSignParam.setPrepayId(payOrderModel.getPayBody());
DaxPayResult<WxJsapiSignModel> execute = DaxPayKit.execute(wxJsapiSignParam);
// 判断是否支付成功
if (execute.getCode() != 0){
throw new BizException(execute.getMsg());
}
WxJsapiSignResult wxJsapiSignResult = new WxJsapiSignResult();
BeanUtil.copyProperties(execute.getData(), wxJsapiSignResult);
return wxJsapiSignResult;
}
/**
* 支付宝发起支付
*/
public PayOrderResult aliQrPay(String code) {
AggregatePayInfo aggregatePayInfo = getInfo(code);
SimplePayParam simplePayParam = new SimplePayParam();
simplePayParam.setBusinessNo(aggregatePayInfo.getBusinessNo());
simplePayParam.setTitle(aggregatePayInfo.getTitle());
simplePayParam.setAmount(aggregatePayInfo.getAmount());
simplePayParam.setChannel(PayChannelEnum.ALI.getCode());
simplePayParam.setPayWay(PayWayEnum.QRCODE.getCode());
String ip = Optional.ofNullable(WebServletUtil.getRequest())
.map(ServletUtil::getClientIP)
.orElse("127.0.0.1");
simplePayParam.setClientIp(ip);
// 异步回调地址
simplePayParam.setNotifyUrl("http://localhost:9000");
// 同步回调地址
simplePayParam.setReturnUrl("http://localhost:9000");
DaxPayResult<PayOrderModel> execute = DaxPayKit.execute(simplePayParam);
// 判断是否支付成功
if (execute.getCode() != 0){
throw new BizException(execute.getMsg());
}
PayOrderResult payOrderResult = new PayOrderResult();
BeanUtil.copyProperties(execute.getData(),payOrderResult);
return payOrderResult;
}
/**
* 根据付款码判断属于那种支付通道
*/
public PayChannelEnum getPayChannel(String authCode) {
if (StrUtil.isBlank(authCode)) {
throw new BizException("付款码不可为空");
}
String[] wx = { "10", "11", "12", "13", "14", "15" };
String[] ali = { "25", "26", "27", "28", "29", "30" };
// 微信
if (StrUtil.startWithAny(authCode.substring(0, 2), wx)) {
return PayChannelEnum.WECHAT;
}
// 支付宝
else if (StrUtil.startWithAny(authCode.substring(0, 2), ali)) {
return PayChannelEnum.ALI;
}
else {
throw new BizException("不支持的支付方式");
}
}
/**
* 微信jsapi支付 - 跳转到授权页面
*/
private String wxJsapiAuth(String code) {
// 回调地址为 结算台微信jsapi支付的回调地址
WxAuthUrlParam wxAuthUrlParam = new WxAuthUrlParam();
wxAuthUrlParam.setState(code);
String url = StrUtil.format("{}/#/cashier/wxJsapiPay", daxPayDemoProperties.getFrontUrl());
wxAuthUrlParam.setUrl(url);
DaxPayResult<WxAuthUrlModel> execute = DaxPayKit.execute(wxAuthUrlParam);
if (execute.getCode() != 0){
throw new BizException(execute.getMsg());
}
return execute.getData().getUrl();
}
/**
* 获取微信OpenId
*/
private String getOpenId(String authCode) {
// 获取OpenId
WxAccessTokenParam param = new WxAccessTokenParam();
param.setCode(authCode);
DaxPayResult<WxAccessTokenModel> result = DaxPayKit.execute(param);
// 判断是否支付成功
if (result.getCode() != 0){
throw new BizException(result.getMsg());
}
return result.getData().getOpenId();
}
/**
* 调用微信支付, 拿到预支付ID
*/
private PayOrderModel wxJsapiPrePay(String aggregateCode, String openId) {
AggregatePayInfo aggregatePayInfo = getInfo(aggregateCode);
// 拼装支付发起参数
SimplePayParam simplePayParam = new SimplePayParam();
simplePayParam.setBusinessNo(aggregatePayInfo.getBusinessNo());
simplePayParam.setTitle(aggregatePayInfo.getTitle());
simplePayParam.setAmount(aggregatePayInfo.getAmount());
simplePayParam.setChannel(PayChannelEnum.ALI.getCode());
simplePayParam.setPayWay(PayWayEnum.QRCODE.getCode());
// 设置微信专属请求参数
WeChatPayParam weChatPayParam = new WeChatPayParam();
weChatPayParam.setOpenId(openId);
simplePayParam.setChannelParam(weChatPayParam);
String ip = Optional.ofNullable(WebServletUtil.getRequest())
.map(ServletUtil::getClientIP)
.orElse("127.0.0.1");
simplePayParam.setClientIp(ip);
// 异步回调地址
simplePayParam.setNotifyUrl("http://localhost:9000");
// 同步回调地址
simplePayParam.setReturnUrl("http://localhost:9000");
DaxPayResult<PayOrderModel> execute = DaxPayKit.execute(simplePayParam);
// 判断是否支付成功
if (execute.getCode() != 0){
throw new BizException(execute.getMsg());
}
return execute.getData();
}
}

View File

@@ -0,0 +1,23 @@
package cn.bootx.platform.daxpay.sdk.code;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 聚合支付相关枚举
* @author xxm
* @since 2024/2/9
*/
@Getter
@AllArgsConstructor
public enum AggregatePayEnum {
UA_ALI_PAY("Alipay", "支付宝"),
UA_WECHAT_PAY("MicroMessenger", "微信支付");
/** 支付渠道字符编码 */
private final String code;
/** 名称 */
private final String name;
}

View File

@@ -0,0 +1,23 @@
package cn.bootx.platform.daxpay.sdk.model.assist;
import cn.bootx.platform.daxpay.sdk.net.DaxPayResponseModel;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* 微信AccessToken
* @author xxm
* @since 2024/2/10
*/
@Getter
@Setter
@ToString
public class WxAccessTokenModel extends DaxPayResponseModel {
/** 微信AccessToken */
private String accessToken;
/** 微信用户唯一标识 */
private String openId;
}

View File

@@ -0,0 +1,20 @@
package cn.bootx.platform.daxpay.sdk.model.assist;
import cn.bootx.platform.daxpay.sdk.net.DaxPayResponseModel;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* 微信oauth2授权的url连接
* @author xxm
* @since 2024/2/10
*/
@Getter
@Setter
@ToString
public class WxAuthUrlModel extends DaxPayResponseModel {
/** 微信oauth2授权的url连接 */
private String url;
}

View File

@@ -0,0 +1,32 @@
package cn.bootx.platform.daxpay.sdk.model.assist;
import cn.bootx.platform.daxpay.sdk.net.DaxPayResponseModel;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* 微信Jsapi预支付签名返回信息
* @author xxm
* @since 2024/2/10
*/
@Getter
@Setter
@ToString
public class WxJsapiSignModel extends DaxPayResponseModel {
/** 公众号ID */
private String appId;
/** 时间戳(秒) */
private String timeStamp;
/** 随机串 */
private String nonceStr;
/** 预支付ID, 已经是 prepay_id=xxx 格式 */
private String prePayId;
/** 微信签名方式 */
private String signType;
/** 微信签名 */
private String paySign;
}

View File

@@ -14,33 +14,10 @@ import lombok.Setter;
@Setter
public abstract class DaxPayRequest<T extends DaxPayResponseModel> {
/** 方法请求路径 */
public abstract String path();
/**
* 将请求返回结果反序列化为实体类
*/
public abstract DaxPayResult<T> toModel(String json);
/** 客户端ip */
private String clientIp;
/** 商户扩展参数,回调时会原样返回 */
private String attach;
/** 是否不进行同步通知的跳转 */
private boolean notReturn;
/** 同步跳转URL, 部分接口不支持该配置,传输了也不会生效 */
private String returnUrl;
/** 是否不启用异步通知 */
private boolean notNotify;
/** 异步通知地址 */
private String notifyUrl;
/** 签名 */
private String sign;
@@ -50,4 +27,17 @@ public abstract class DaxPayRequest<T extends DaxPayResponseModel> {
/** 请求时间,传输时间戳 */
private Long reqTime = DateUtil.currentSeconds();
/**
* 方法请求路径
* @return 请求路径
*/
public abstract String path();
/**
* 将请求返回结果反序列化为实体类
* @param json json字符串
* @return 反序列后的对象
*/
public abstract DaxPayResult<T> toModel(String json);
}

View File

@@ -0,0 +1,38 @@
package cn.bootx.platform.daxpay.sdk.param.assist;
import cn.bootx.platform.daxpay.sdk.model.assist.WxAccessTokenModel;
import cn.bootx.platform.daxpay.sdk.net.DaxPayRequest;
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.json.JSONUtil;
import lombok.Getter;
import lombok.Setter;
/**
* 获取微信AccessToken参数
* @author xxm
* @since 2024/2/10
*/
@Setter
@Getter
public class WxAccessTokenParam extends DaxPayRequest<WxAccessTokenModel> {
/** 微信code */
private String code;
/**
* 方法请求路径
*/
@Override
public String path() {
return "/unipay/assist/getWxAccessToken";
}
/**
* 将请求返回结果反序列化为实体类
*/
@Override
public DaxPayResult<WxAccessTokenModel> toModel(String json) {
return JSONUtil.toBean(json, new TypeReference<DaxPayResult<WxAccessTokenModel>>() {}, false);
}
}

View File

@@ -0,0 +1,49 @@
package cn.bootx.platform.daxpay.sdk.param.assist;
import cn.bootx.platform.daxpay.sdk.model.assist.WxAuthUrlModel;
import cn.bootx.platform.daxpay.sdk.net.DaxPayRequest;
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.json.JSONUtil;
import lombok.Getter;
import lombok.Setter;
/**
* 构造oauth2授权的url连接
* @author xxm
* @since 2024/2/10
*/
@Setter
@Getter
public class WxAuthUrlParam extends DaxPayRequest<WxAuthUrlModel> {
/** 回调地址 */
private String url;
/**
* 重定向后会带上state参数开发者可以填写a-zA-Z0-9的参数值最多128字节
*/
private String state;
/**
* 方法请求路径
*
* @return 请求路径
*/
@Override
public String path() {
return "/unipay/assist/getWxAuthUrl";
}
/**
* 将请求返回结果反序列化为实体类
*
* @param json json字符串
* @return 反序列后的对象
*/
@Override
public DaxPayResult<WxAuthUrlModel> toModel(String json) {
return JSONUtil.toBean(json, new TypeReference<DaxPayResult<WxAuthUrlModel>>() {}, false);
}
}

View File

@@ -0,0 +1,44 @@
package cn.bootx.platform.daxpay.sdk.param.assist;
import cn.bootx.platform.daxpay.sdk.model.assist.WxJsapiSignModel;
import cn.bootx.platform.daxpay.sdk.net.DaxPayRequest;
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.json.JSONUtil;
import lombok.Getter;
import lombok.Setter;
/**
* 微信预付订单再次签名参数
* @author xxm
* @since 2024/2/10
*/
@Setter
@Getter
public class WxJsapiSignParam extends DaxPayRequest<WxJsapiSignModel>{
/** 预付订单ID */
private String prepayId;
/**
* 方法请求路径
*
* @return 请求路径
*/
@Override
public String path() {
return "/unipay/assist/getWxJsapiPrePay";
}
/**
* 将请求返回结果反序列化为实体类
*
* @param json json字符串
* @return 反序列后的对象
*/
@Override
public DaxPayResult<WxJsapiSignModel> toModel(String json) {
return JSONUtil.toBean(json, new TypeReference<DaxPayResult<WxJsapiSignModel>>() {}, false);
}
}

View File

@@ -23,6 +23,15 @@ public class PayCloseParam extends DaxPayRequest<PayCloseModel> {
/** 业务号 */
private String businessNo;
/** 商户扩展参数,回调时会原样返回 */
private String attach;
/** 是否不启用异步通知 */
private boolean notNotify;
/** 异步通知地址 */
private String notifyUrl;
/**
* 方法请求路径
*/

View File

@@ -39,6 +39,21 @@ public class PayParam extends DaxPayRequest<PayOrderModel> {
/** 支付通道信息参数 */
private List<PayChannelParam> payChannels;
/** 商户扩展参数,回调时会原样返回 */
private String attach;
/** 是否不进行同步通知的跳转 */
private boolean notReturn;
/** 同步跳转URL, 部分接口不支持该配置,传输了也不会生效 */
private String returnUrl;
/** 是否不启用异步通知 */
private boolean notNotify;
/** 异步通知地址 */
private String notifyUrl;
/**
* 方法请求路径
*/

View File

@@ -71,6 +71,21 @@ public class SimplePayParam extends DaxPayRequest<PayOrderModel> {
*/
private ChannelParam channelParam;
/** 商户扩展参数,回调时会原样返回 */
private String attach;
/** 是否不进行同步通知的跳转 */
private boolean notReturn;
/** 同步跳转URL, 部分接口不支持该配置,传输了也不会生效 */
private String returnUrl;
/** 是否不启用异步通知 */
private boolean notNotify;
/** 异步通知地址 */
private String notifyUrl;
/**
* 请求路径
*/

View File

@@ -23,6 +23,21 @@ public class QueryRefundOrderParam extends DaxPayRequest<QueryRefundOrderModel>
/** 退款号 */
private String refundNo;
/** 商户扩展参数,回调时会原样返回 */
private String attach;
/** 是否不进行同步通知的跳转 */
private boolean notReturn;
/** 同步跳转URL, 部分接口不支持该配置,传输了也不会生效 */
private String returnUrl;
/** 是否不启用异步通知 */
private boolean notNotify;
/** 异步通知地址 */
private String notifyUrl;
/**
* 方法请求路径
*/

View File

@@ -44,6 +44,15 @@ public class RefundParam extends DaxPayRequest<RefundModel> {
/** 退款原因 */
private String reason;
/** 商户扩展参数,回调时会原样返回 */
private String attach;
/** 是否不启用异步通知 */
private boolean notNotify;
/** 异步通知地址 */
private String notifyUrl;
/**
* 方法请求路径
*/

View File

@@ -43,6 +43,16 @@ public class SimpleRefundParam extends DaxPayRequest<RefundModel> {
/** 退款原因 */
private String reason;
/** 商户扩展参数,回调时会原样返回 */
private String attach;
/** 是否不启用异步通知 */
private boolean notNotify;
/** 异步通知地址 */
private String notifyUrl;
/**
* 方法请求路径
*/

View File

@@ -39,7 +39,6 @@ public class RefundOrderTest {
RefundParam param = new RefundParam();
param.setClientIp("127.0.0.1");
param.setNotNotify(true);
param.setNotReturn(true);
param.setBusinessNo("P0001");
param.setRefundAll(true);

View File

@@ -1,4 +1,4 @@
package cn.bootx.platform.daxpay.param.pay;
package cn.bootx.platform.daxpay.param;
import cn.bootx.platform.daxpay.serializer.TimestampToLocalDateTimeDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -15,32 +15,13 @@ import java.time.LocalDateTime;
*/
@Data
@Schema(title = "支付公共参数")
public abstract class PayCommonParam {
public abstract class PaymentCommonParam {
/** 客户端ip */
// @NotBlank(message = "客户端ip不可为空")
@Schema(description = "客户端ip")
private String clientIp;
/** 商户扩展参数,回调时会原样返回 */
@Schema(description = "商户扩展参数,回调时会原样返回")
private String attach;
@Schema(description = "是否不进行同步通知的跳转")
private boolean notReturn;
/** 同步通知URL */
@Schema(description = "同步通知URL")
private String returnUrl;
/** 是否不启用异步通知 */
@Schema(description = "是否不启用异步通知")
private boolean notNotify;
/** 异步通知地址 */
@Schema(description = "异步通知地址")
private String notifyUrl;
/** 签名 */
@Schema(description = "签名")
private String sign;

View File

@@ -0,0 +1,22 @@
package cn.bootx.platform.daxpay.param.assist;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 获取微信AccessToken参数
* @author xxm
* @since 2024/2/10
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "获取微信AccessToken参数")
public class WxAccessTokenParam extends PaymentCommonParam {
@Schema(description = "微信code")
private String code;
}

View File

@@ -0,0 +1,28 @@
package cn.bootx.platform.daxpay.param.assist;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 构造oauth2授权的url连接
* @author xxm
* @since 2024/2/10
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "构造oauth2授权的url连接")
public class WxAuthUrlParam extends PaymentCommonParam {
@Schema(description = "回调地址")
private String url;
/**
* 重定向后会带上state参数开发者可以填写a-zA-Z0-9的参数值最多128字节
*/
@Schema(description = "重定向后原样带回,可以为空")
private String state;
}

View File

@@ -0,0 +1,24 @@
package cn.bootx.platform.daxpay.param.assist;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 预付订单再次签名参数
* @author xxm
* @since 2024/2/10
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "预付订单再次签名")
public class WxJsapiPrePayParam extends PaymentCommonParam {
@Schema(description = "预付订单ID")
private String prepayId;
}

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -12,7 +13,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "支付关闭参数")
public class PayCloseParam extends PayCommonParam{
public class PayCloseParam extends PaymentCommonParam {
@Schema(description = "支付单ID")
private Long paymentId;

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import cn.bootx.platform.daxpay.serializer.TimestampToLocalDateTimeDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -21,7 +22,7 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "支付参数")
public class PayParam extends PayCommonParam{
public class PayParam extends PaymentCommonParam {
@Schema(description = "业务号")
@NotBlank(message = "业务号不可为空")
@@ -45,4 +46,23 @@ public class PayParam extends PayCommonParam{
@NotNull(message = "支付通道信息参数不可为空")
@Valid
private List<PayChannelParam> payChannels;
/** 商户扩展参数,回调时会原样返回 */
@Schema(description = "商户扩展参数,回调时会原样返回")
private String attach;
@Schema(description = "是否不进行同步通知的跳转")
private boolean notReturn;
/** 同步通知URL */
@Schema(description = "同步通知URL")
private String returnUrl;
/** 是否不启用异步通知 */
@Schema(description = "是否不启用异步通知")
private boolean notNotify;
/** 异步通知地址 */
@Schema(description = "异步通知地址")
private String notifyUrl;
}

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -12,7 +13,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "支付状态同步参数")
public class PaySyncParam extends PayCommonParam{
public class PaySyncParam extends PaymentCommonParam {
@Schema(description = "支付单ID")
private Long paymentId;

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -12,7 +13,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "支付订单查询参数")
public class QueryPayOrderParam extends PayCommonParam{
public class QueryPayOrderParam extends PaymentCommonParam {
@Schema(description = "支付号")
private Long paymentId;

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -12,7 +13,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "支付单查询参数")
public class QueryPayParam extends PayCommonParam{
public class QueryPayParam extends PaymentCommonParam {
@Schema(description = "支付单ID")
private Long paymentId;

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -12,7 +13,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "查询退款订单参数")
public class QueryRefundOrderParam extends PayCommonParam {
public class QueryRefundOrderParam extends PaymentCommonParam {
@Schema(description = "退款订单ID")
private Long refundId;

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -12,7 +13,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "查询退款订单参数类")
public class QueryRefundParam extends PayCommonParam{
public class QueryRefundParam extends PaymentCommonParam {
@Schema(description = "退款订单ID")
private Long refundId;

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -15,7 +16,7 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "退款参数")
public class RefundParam extends PayCommonParam {
public class RefundParam extends PaymentCommonParam {
@Schema(description = "支付单ID")
private Long paymentId;
@@ -45,5 +46,16 @@ public class RefundParam extends PayCommonParam {
@Schema(description = "退款原因")
private String reason;
/** 商户扩展参数,回调时会原样返回 */
@Schema(description = "商户扩展参数,回调时会原样返回")
private String attach;
/** 是否不启用异步通知 */
@Schema(description = "是否不启用异步通知")
private boolean notNotify;
/** 异步通知地址 */
@Schema(description = "异步通知地址")
private String notifyUrl;
}

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -12,7 +13,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "退款状态同步参数")
public class RefundSyncParam extends PayCommonParam {
public class RefundSyncParam extends PaymentCommonParam {
/**
* 退款订单IDrefundId和refundNo 必传一个, 同时传输时,以 refundId 为准

View File

@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.code.PayWayEnum;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import cn.bootx.platform.daxpay.param.channel.AliPayParam;
import cn.bootx.platform.daxpay.param.channel.VoucherPayParam;
import cn.bootx.platform.daxpay.param.channel.WalletPayParam;
@@ -26,7 +27,7 @@ import java.util.Map;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "简单下单参数")
public class SimplePayParam extends PayCommonParam{
public class SimplePayParam extends PaymentCommonParam {
@Schema(description = "业务号")
@NotBlank(message = "业务号不可为空")
@@ -74,5 +75,22 @@ public class SimplePayParam extends PayCommonParam{
@Schema(description = "附加通道支付参数")
private Map<String, Object> channelParam;
/** 商户扩展参数,回调时会原样返回 */
@Schema(description = "商户扩展参数,回调时会原样返回")
private String attach;
@Schema(description = "是否不进行同步通知的跳转")
private boolean notReturn;
/** 同步通知URL */
@Schema(description = "同步通知URL")
private String returnUrl;
/** 是否不启用异步通知 */
@Schema(description = "是否不启用异步通知")
private boolean notNotify;
/** 异步通知地址 */
@Schema(description = "异步通知地址")
private String notifyUrl;
}

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.param.pay;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import cn.bootx.platform.daxpay.param.channel.AliPayParam;
import cn.bootx.platform.daxpay.param.channel.VoucherPayParam;
import cn.bootx.platform.daxpay.param.channel.WalletPayParam;
@@ -18,7 +19,7 @@ import javax.validation.constraints.NotNull;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(title = "简单退款参数")
public class SimpleRefundParam extends PayCommonParam {
public class SimpleRefundParam extends PaymentCommonParam {
/**
* 优先级高于业务号
@@ -58,4 +59,17 @@ public class SimpleRefundParam extends PayCommonParam {
@Schema(description = "退款原因")
private String reason;
/** 商户扩展参数,回调时会原样返回 */
@Schema(description = "商户扩展参数,回调时会原样返回")
private String attach;
/** 是否不启用异步通知 */
@Schema(description = "是否不启用异步通知")
private boolean notNotify;
/** 异步通知地址 */
@Schema(description = "异步通知地址")
private String notifyUrl;
}

View File

@@ -0,0 +1,22 @@
package cn.bootx.platform.daxpay.result.assist;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 微信AccessToken
* @author xxm
* @since 2024/2/10
*/
@Data
@Accessors(chain = true)
@Schema(title = "微信AccessToken")
public class WxAccessTokenResult {
@Schema(description = "微信AccessToken")
private String accessToken;
@Schema(description = "微信用户唯一标识")
private String openId;
}

View File

@@ -0,0 +1,19 @@
package cn.bootx.platform.daxpay.result.assist;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 微信oauth2授权的url连接
* @author xxm
* @since 2024/2/10
*/
@Data
@Accessors(chain = true)
@Schema(title = "微信oauth2授权的url连接")
public class WxAuthUrlResult {
@Schema(description = "微信oauth2授权的url连接")
private String url;
}

View File

@@ -0,0 +1,31 @@
package cn.bootx.platform.daxpay.result.assist;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 微信Jsapi预支付信息
* @author xxm
* @since 2024/2/10
*/
@Data
@Accessors(chain = true)
@Schema(title = "微信Jsapi预支付信息")
public class WxJsapiPrePayResult {
@Schema(description = "公众号ID")
private String appId;
@Schema(description = "时间戳(秒)")
private String timeStamp;
@Schema(description = "随机串")
private String nonceStr;
@Schema(description = "预支付ID, 已经是 prepay_id=xxx 格式")
private String prePayId;
@Schema(description = "")
private String signType;
@Schema(description = "")
private String paySign;
}

View File

@@ -3,15 +3,12 @@ package cn.bootx.platform.daxpay.gateway.controller;
import cn.bootx.platform.common.core.exception.BizException;
import cn.bootx.platform.common.core.rest.Res;
import cn.bootx.platform.common.core.rest.ResResult;
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
import cn.bootx.platform.daxpay.service.core.timeout.task.PayExpiredTimeTask;
import cn.bootx.platform.daxpay.service.core.timeout.task.PayWaitOrderSyncTask;
import cn.hutool.core.thread.ThreadUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApiConfigKit;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
@@ -31,24 +28,8 @@ import java.util.Objects;
@RequestMapping("/test")
@RequiredArgsConstructor
public class TestController {
private final PayExpiredTimeTask expiredTimeTask;;
private final PayWaitOrderSyncTask waitOrderSyncTask;
private final WeChatPayConfigService weChatPayConfigService;
private final LockTemplate lockTemplate;
@Operation(summary = "同步")
@GetMapping("/sync")
public ResResult<Void> sync(){
waitOrderSyncTask.task();
return Res.ok();
}
@Operation(summary = "超时")
@GetMapping("/expired")
public ResResult<Void> expired(){
expiredTimeTask.task();
return Res.ok();
}
@Operation(summary = "锁测试1")
@GetMapping("/lock1")
// @Lock4j(keys = "#name", acquireTimeout = 50)
@@ -71,13 +52,5 @@ public class TestController {
return Res.ok(name);
}
@Operation(summary = "解析微信退款信息")
@GetMapping("/wxjx")
public ResResult<Void> wxjx(){
WeChatPayConfig config = weChatPayConfigService.getConfig();
String reqInfo = "5WYGjdyCumTyTutbIRILrluT7ahm/8puDs+82ARE3BYaELjmCQ2nsjpM68nQBUHj1x1a0o/5h5k4VI7hz6iEHtBwNwuxIqxesVDX6WtAcBeIR0fACDT+NxefEj1BPFGJqueyA2XxKLuhK8fvO3qiowHcNu3N0QJxSvL5V85wQ3oMnE90VUG8XVTjGBsS6ARaRafyfeHfIyH6ZfH0CBrZlpvM8hzyN1S4T+aNojAaiAQqzgDUGC/TLYgvovgzRmfkRH/dnuxHh4gzh53SqEDSMy1wp/xXQKrbJGjolAbVCVaQ1AHGa4/KZeA6UV7uUYNhGqFDHEqQ1Nqc8lJfcBg9VRMWwJtgCfx3lEilj7LJ/FPRRQKqXUZgcQsKvd87lAU5vQMeYho6mP65nazMLN5sABbAvNNzKMtXkNbL7PxPXy5+FMdj/NDiVCWvCToPpnBfK66rwvdEF4BftEoHYUAnp+WiHnVuposTwkSxQT6vDAkfui2pFOi/PGutHcfeJndUYqLgJgTMTUAApUCUIwMy+3dSeO3kcMT/x4KAPCNIEWE0qfxQOke7aaN3qFqT1p9kkWzlPFrC4FNnCpCMaJktbNQOxAqYHNAp6YHCRGIOmwJ9Rej005G2s+RjyPY3/zBE0VueghtaejszMf4OcrNGCNnXM9/6u/tu3ZeIv8vJnFfgc70GpyrHfgTjupr/cxDqAgfgJlk6aQIRtaAM8lu19zl+s2RP3oHL50G7gNOdtw7pP5shHcLhaf2OQc7IRbmOELGtjh+7fZrrwK6U6/te9JAJcNEY3RdXQ2KgNIiuvAoKHaMXEFL4D+n3wW3AHQVWze2lBZIHcCpTCTwdjjCEWTNFOEzKuzFejJSJOQqQ6gHJ2JrqTuhcE6jetLTtk51LK1C50kMjwt+bIgXbceE7csJSgcMo8/g3w4LmakSNX1kdRI6p2EesM+W/2CKLAKga8TN78Y/v6BhbbdjubpeUtN8+JjM3Wr66I2FeXWxW2Fuh0Enb73rGfrnvhrFVM3L1NeA9Fp1I3nAmWyhULYUZdaiyu8dHjfV3g5HzmOl44iEDMZ14o44QCecjNhtRUtpJLABwP3fXYoNBI7iLQ1alfKvfukh1dzX6gAvbNxTn0jM=";
String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey());
return Res.ok();
}
}

View File

@@ -0,0 +1,63 @@
package cn.bootx.platform.daxpay.gateway.controller;
import cn.bootx.platform.common.core.annotation.CountTime;
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
import cn.bootx.platform.common.core.rest.Res;
import cn.bootx.platform.common.core.rest.ResResult;
import cn.bootx.platform.daxpay.param.assist.WxAccessTokenParam;
import cn.bootx.platform.daxpay.param.assist.WxAuthUrlParam;
import cn.bootx.platform.daxpay.param.assist.WxJsapiPrePayParam;
import cn.bootx.platform.daxpay.result.DaxResult;
import cn.bootx.platform.daxpay.result.assist.WxAccessTokenResult;
import cn.bootx.platform.daxpay.result.assist.WxAuthUrlResult;
import cn.bootx.platform.daxpay.result.assist.WxJsapiPrePayResult;
import cn.bootx.platform.daxpay.service.annotation.PaymentApi;
import cn.bootx.platform.daxpay.service.core.payment.assist.service.UniPayAssistService;
import cn.bootx.platform.daxpay.util.DaxRes;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 支付支撑接口
* @author xxm
* @since 2024/2/10
*/
@IgnoreAuth
@Tag(name = "支付支撑接口")
@RestController
@RequestMapping("/unipay/assist")
@RequiredArgsConstructor
public class UniPayAssistController {
private final UniPayAssistService uniPayAssistService;
@CountTime
@PaymentApi("getWxAuthUrl")
@Operation(summary = "获取微信oauth2授权的url")
@PostMapping("/getWxAuthUrl")
public DaxResult<WxAuthUrlResult> getWxAuthUrl(@RequestBody WxAuthUrlParam param){
return DaxRes.ok(uniPayAssistService.getWxAuthUrl(param));
}
@CountTime
@PaymentApi("getWxAccessToken")
@Operation(summary = "获取微信AccessToken数据")
@PostMapping("/getWxAccessToken")
public ResResult<WxAccessTokenResult> getWxAccessToken(@RequestBody WxAccessTokenParam param){
return Res.ok(uniPayAssistService.getWxAccessToken(param));
}
@CountTime
@PaymentApi("getWxJsapiPrePay")
@Operation(summary = "获取微信预支付信息")
@PostMapping("/getWxJsapiPrePay")
public ResResult<WxJsapiPrePayResult> getWxJsapiPrePay(@RequestBody WxJsapiPrePayParam param){
return Res.ok(uniPayAssistService.getWxJsapiPrePay(param));
}
}

View File

@@ -96,4 +96,5 @@ public class UniPayController {
public DaxResult<SyncResult> syncRefund(@RequestBody RefundSyncParam param){
return DaxRes.ok(payRefundSyncService.sync(param));
}
}

View File

@@ -1,6 +1,7 @@
package cn.bootx.platform.daxpay.gateway.controller;
import cn.bootx.platform.common.core.annotation.CountTime;
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
import cn.bootx.platform.daxpay.param.pay.QueryPayParam;
import cn.bootx.platform.daxpay.param.pay.QueryRefundParam;
import cn.bootx.platform.daxpay.result.DaxResult;
@@ -22,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController;
* @author xxm
* @since 2024/2/7
*/
@IgnoreAuth
@Tag(name = "统一查询接口")
@RestController
@RequestMapping("/uni/query")

View File

@@ -98,17 +98,27 @@
<artifactId>weixin-java-pay</artifactId>
<version>${wxjava.version}</version>
</dependency>
<!-- 微信工具包 -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>${wxjava.version}</version>
</dependency>
<!-- 数据权限 -->
<dependency>
<groupId>cn.bootx.platform</groupId>
<artifactId>common-starter-data-perm</artifactId>
</dependency>
<!-- 测试库 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!-- 分布式锁 -->
<dependency>
<groupId>com.baomidou</groupId>

View File

@@ -0,0 +1,23 @@
package cn.bootx.platform.daxpay.service.code;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 支付网关接口支持回调类型的枚举
* @author xxm
* @since 2024/2/10
*/
@Getter
@AllArgsConstructor
public enum PayApiCallBackTypeEnum {
/** 支持所有回调类型 */
ALL("all"),
/** 支持异步回调通知 */
ASYNC_NOTICE("async_notice"),
/** 不支持退掉通知 */
NONE("none");
private final String code;
}

View File

@@ -32,16 +32,6 @@ import java.time.LocalDateTime;
@TableName("pay_voucher")
public class Voucher extends MpBaseEntity implements EntityBaseFunction<VoucherDto> {
/** 商户编码 */
@TableField(updateStrategy = FieldStrategy.NEVER)
@DbColumn(comment = "商户编码")
private String mchCode;
/** 商户应用编码 */
@TableField(updateStrategy = FieldStrategy.NEVER)
@DbColumn(comment = "商户应用编码")
private String mchAppCode;
/** 卡号 */
@DbColumn(comment = "卡号")
@DbMySqlIndex(comment = "卡号索引")

View File

@@ -1,22 +1,13 @@
package cn.bootx.platform.daxpay.service.core.channel.voucher.service;
import cn.bootx.platform.common.core.exception.BizException;
import cn.bootx.platform.daxpay.service.code.VoucherCode;
import cn.bootx.platform.daxpay.service.core.channel.voucher.dao.VoucherLogManager;
import cn.bootx.platform.daxpay.service.core.channel.voucher.dao.VoucherManager;
import cn.bootx.platform.daxpay.service.core.channel.voucher.entity.Voucher;
import cn.bootx.platform.daxpay.service.param.channel.voucher.VoucherImportParam;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 储值卡
@@ -34,48 +25,6 @@ public class VoucherService {
private final VoucherLogManager voucherLogManager;
/**
* 批量导入
* @param skip 是否跳过已经导入的储值卡,false时将会异常
*/
@Transactional(rollbackFor = Exception.class)
public void importBatch(Boolean skip, String mchCode, String mchAppCode,List<VoucherImportParam> voucherImports) {
List<String> cardNoList = voucherImports.stream()
.map(VoucherImportParam::getCardNo)
.distinct()
.collect(Collectors.toList());
// 卡号不能重复
if (voucherImports.size()!=cardNoList.size()){
throw new BizException("卡号不能重复");
}
// 查询库中是否已经有对应的储值卡号
List<Voucher> vouchersByDB = voucherManager.findByCardNoList(cardNoList);
// 不跳过已经导入的储值卡且存在数据, 抛出异常
if (Objects.equals(skip,true)&& CollUtil.isNotEmpty(vouchersByDB)){
log.warn("数据库中已经存在的卡号:{}",vouchersByDB.stream().map(Voucher::getCardNo).collect(Collectors.toList()));
throw new BizException("要导入的卡号在数据中已经存在");
}
// 导入对应储值卡
List<String> cardNoListByDb = vouchersByDB.stream()
.map(Voucher::getCardNo)
.distinct()
.collect(Collectors.toList());
long batchNo = IdUtil.getSnowflakeNextId();
List<Voucher> vouchers = voucherImports.stream()
.filter(o -> !cardNoListByDb.contains(o.getCardNo()))
.map(o -> {
Voucher voucher = new Voucher();
BeanUtil.copyProperties(o, voucher);
return voucher.setMchCode(mchCode)
.setMchAppCode(mchAppCode)
.setBatchNo(batchNo);
})
.collect(Collectors.toList());
voucherManager.saveAll(vouchers);
// TODO 记录日志
}
/**
* 启用
*/
@@ -104,5 +53,4 @@ public class VoucherService {
voucherManager.changeStatusBatch(ids, VoucherCode.STATUS_FORBIDDEN);
}
}

View File

@@ -6,8 +6,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.util.Optional;
/**
* 钱包配置
* @author xxm
@@ -17,8 +15,4 @@ import java.util.Optional;
@Repository
@RequiredArgsConstructor
public class WalletConfigManager extends BaseManager<WalletConfigMapper, WalletConfig> {
public Optional<WalletConfig> findByMchCode(String mchCode){
return this.findByField(WalletConfig::getMchCode,mchCode);
}
}

View File

@@ -7,9 +7,6 @@ import cn.bootx.platform.daxpay.service.dto.channel.wallet.WalletConfigDto;
import cn.bootx.platform.daxpay.service.param.channel.wechat.WalletConfigParam;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbTable;
import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -29,17 +26,6 @@ import java.math.BigDecimal;
@TableName("pay_wallet_config")
public class WalletConfig extends MpBaseEntity implements EntityBaseFunction<WalletConfigDto> {
/** 商户编码 */
@TableField(updateStrategy = FieldStrategy.NEVER)
@DbColumn(comment = "商户编码")
private String mchCode;
/** 商户应用编码 */
@TableField(updateStrategy = FieldStrategy.NEVER)
@DbMySqlIndex(comment = "商户应用编码唯一索引")
@DbColumn(comment = "商户应用编码")
private String mchAppCode;
/** 默认余额 */
@DbColumn(comment = "默认余额")
private BigDecimal defaultBalance;

View File

@@ -3,7 +3,6 @@ package cn.bootx.platform.daxpay.service.core.channel.wallet.service;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.daxpay.service.core.channel.wallet.dao.WalletConfigManager;
import cn.bootx.platform.daxpay.service.core.channel.wallet.entity.WalletConfig;
import cn.bootx.platform.daxpay.service.dto.channel.wallet.WalletConfigDto;
import cn.bootx.platform.daxpay.service.param.channel.wechat.WalletConfigParam;
import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
@@ -21,15 +20,6 @@ import org.springframework.stereotype.Service;
public class WalletConfigService {
private final WalletConfigManager walletConfigManager;
/**
* 根据应用编码获取钱包配置
*/
public WalletConfigDto findByMchCode(String mchCode){
return walletConfigManager.findByMchCode(mchCode)
.map(WalletConfig::toDto)
.orElse(new WalletConfigDto());
}
/**
* 新增或更新
*/

View File

@@ -63,6 +63,11 @@ public class WeChatPayConfig extends MpBaseEntity implements EntityBaseFunction<
@DbColumn(comment = "同步通知路径")
private String returnUrl;
/** 接口版本, 使用v2还是v3接口 */
@DbColumn(comment = "接口版本")
private String apiVersion;
/** 商户平台「API安全」中的 APIv2 密钥 */
@TableField(updateStrategy = FieldStrategy.ALWAYS)
@BigField

View File

@@ -152,7 +152,7 @@ public class WeChatPayService {
Map<String, String> packageParams = WxPayKit.miniAppPrepayIdCreateSign(weChatPayConfig.getWxAppId(), prepayId,
weChatPayConfig.getApiKeyV2(), SignType.HMACSHA256);
String jsonStr = JacksonUtil.toJson(packageParams);
log.info("小程序支付的参数:" + jsonStr);
log.info("Jsapi支付的参数:" + jsonStr);
return jsonStr ;
}

View File

@@ -68,7 +68,7 @@ public class PayChannelOrder extends MpCreateEntity implements EntityBaseFunctio
* @see WalletPayParam
*/
@DbColumn(comment = "附加支付参数")
@TableField(updateStrategy = FieldStrategy.NEVER)
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String channelExtra;
/**

View File

@@ -47,7 +47,7 @@ public class PayRefundChannelOrder extends MpCreateEntity implements EntityBaseF
private Integer amount;
@DbColumn(comment = "剩余可退余额")
@TableField(updateStrategy = FieldStrategy.NEVER)
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private Integer refundableAmount;
/**

View File

@@ -0,0 +1,88 @@
package cn.bootx.platform.daxpay.service.core.payment.assist.service;
import cn.bootx.platform.daxpay.param.assist.WxAccessTokenParam;
import cn.bootx.platform.daxpay.param.assist.WxAuthUrlParam;
import cn.bootx.platform.daxpay.param.assist.WxJsapiPrePayParam;
import cn.bootx.platform.daxpay.result.assist.WxAccessTokenResult;
import cn.bootx.platform.daxpay.result.assist.WxAuthUrlResult;
import cn.bootx.platform.daxpay.result.assist.WxJsapiPrePayResult;
import cn.bootx.platform.daxpay.service.code.WeChatPayCode;
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
import cn.hutool.core.bean.BeanUtil;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.WxPayKit;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.Objects;
/**
* 支付支撑服务类
* @author xxm
* @since 2024/2/10
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class UniPayAssistService {
private final WeChatPayConfigService weChatPayConfigService;
/**
* 构建微信oauth2授权的url连接
*/
public WxAuthUrlResult getWxAuthUrl(WxAuthUrlParam param) {
WxMpService wxMpService = this.getWxMpService();
String url = wxMpService.getOAuth2Service()
.buildAuthorizationUrl(param.getUrl(), WxConsts.OAuth2Scope.SNSAPI_BASE, param.getState());
return new WxAuthUrlResult().setUrl(url);
}
/**
* 获取微信AccessToken数据
*/
@SneakyThrows
public WxAccessTokenResult getWxAccessToken(WxAccessTokenParam wxAccessToken){
WxMpService wxMpService = this.getWxMpService();
WxOAuth2AccessToken accessToken = wxMpService.getOAuth2Service().getAccessToken(wxAccessToken.getCode());
return new WxAccessTokenResult()
.setAccessToken(accessToken.getAccessToken())
.setOpenId(accessToken.getOpenId());
}
/**
* 获取微信预支付信息
*/
public WxJsapiPrePayResult getWxJsapiPrePay(WxJsapiPrePayParam param){
WeChatPayConfig config = weChatPayConfigService.getConfig();
String apiKey;
if (Objects.equals(config.getApiKeyV2(), WeChatPayCode.API_V3)){
apiKey = config.getApiKeyV3();
} else {
apiKey = config.getApiKeyV2();
}
Map<String, String> map = WxPayKit.prepayIdCreateSign(param.getPrepayId(), config.getWxAppId(), apiKey, SignType.HMACSHA256);
return BeanUtil.toBean(map, WxJsapiPrePayResult.class);
}
/**
* 获取微信公众号API的Service
*/
private WxMpService getWxMpService() {
WeChatPayConfig config = weChatPayConfigService.getConfig();
WxMpService wxMpService = new WxMpServiceImpl();
WxMpDefaultConfigImpl wxMpConfig = new WxMpDefaultConfigImpl();
wxMpConfig.setAppId(config.getWxAppId()); // 设置微信公众号的appid
wxMpConfig.setSecret(config.getAppSecret()); // 设置微信公众号的app corpSecret
wxMpService.setWxMpConfigStorage(wxMpConfig);
return wxMpService;
}
}

View File

@@ -2,7 +2,7 @@ package cn.bootx.platform.daxpay.service.core.payment.common.aop;
import cn.bootx.platform.common.core.util.ValidationUtil;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.param.pay.PayCommonParam;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import cn.bootx.platform.daxpay.service.annotation.PaymentApi;
import cn.bootx.platform.daxpay.service.core.payment.common.service.PaymentSignService;
import lombok.RequiredArgsConstructor;
@@ -32,11 +32,11 @@ public class PaymentVerifySignAop {
throw new PayFailureException("支付方法至少有一个参数,并且需要签名支付参数需要放在第一位");
}
Object param = args[0];
if (param instanceof PayCommonParam){
if (param instanceof PaymentCommonParam){
// 参数校验
ValidationUtil.validateParam(param);
// 验签
paymentSignService.verifySign((PayCommonParam) param);
paymentSignService.verifySign((PaymentCommonParam) param);
} else {
throw new PayFailureException("支付参数需要继承PayCommonParam");
}

View File

@@ -6,7 +6,7 @@ import cn.bootx.platform.daxpay.service.common.context.RequestLocal;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.system.config.entity.PlatformConfig;
import cn.bootx.platform.daxpay.service.core.system.config.service.PlatformConfigService;
import cn.bootx.platform.daxpay.param.pay.PayCommonParam;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
@@ -27,9 +27,9 @@ public class PaymentAssistService {
/**
* 初始化上下文
*/
public void initContext(PayCommonParam payCommonParam){
public void initContext(PaymentCommonParam paymentCommonParam){
this.initPlatform();
this.initRequest(payCommonParam);
this.initRequest(paymentCommonParam);
}
/**
@@ -49,13 +49,13 @@ public class PaymentAssistService {
/**
* 初始化请求相关信息上下文
*/
private void initRequest(PayCommonParam payCommonParam){
private void initRequest(PaymentCommonParam paymentCommonParam){
RequestLocal request = PaymentContextLocal.get().getRequestInfo();
request.setClientIp(payCommonParam.getClientIp())
.setAttach(payCommonParam.getAttach())
.setSign(payCommonParam.getSign())
.setVersion(payCommonParam.getVersion())
.setReqTime(payCommonParam.getReqTime())
request.setClientIp(paymentCommonParam.getClientIp())
// .setAttach(paymentCommonParam.getAttach())
.setSign(paymentCommonParam.getSign())
.setVersion(paymentCommonParam.getVersion())
.setReqTime(paymentCommonParam.getReqTime())
.setReqId(MDC.get(CommonCode.TRACE_ID));
}
}

View File

@@ -2,7 +2,7 @@ package cn.bootx.platform.daxpay.service.core.payment.common.service;
import cn.bootx.platform.daxpay.code.PaySignTypeEnum;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.param.pay.PayCommonParam;
import cn.bootx.platform.daxpay.param.PaymentCommonParam;
import cn.bootx.platform.daxpay.service.common.context.ApiInfoLocal;
import cn.bootx.platform.daxpay.service.common.context.PlatformLocal;
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
@@ -28,7 +28,7 @@ public class PaymentSignService {
/**
* 签名
*/
public void verifySign(PayCommonParam param) {
public void verifySign(PaymentCommonParam param) {
// 先触发上下文的初始化
paymentAssistService.initContext(param);
ApiInfoLocal apiInfo = PaymentContextLocal.get().getApiInfo();

View File

@@ -65,14 +65,13 @@ public class PayRefundAssistService {
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
// 异步回调
if (!param.isNotNotify()){
noticeInfo.setNotifyUrl(param.getReturnUrl());
noticeInfo.setNotifyUrl(param.getNotifyUrl());
if (StrUtil.isNotBlank(param.getNotifyUrl())){
noticeInfo.setNotifyUrl(platform.getNotifyUrl());
}
}
}
/**
* 根据退款参数获取支付订单
*/

View File

@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.service.core.system.config.entity;
import cn.bootx.platform.common.core.function.EntityBaseFunction;
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
import cn.bootx.platform.daxpay.service.code.PayApiCallBackTypeEnum;
import cn.bootx.platform.daxpay.service.core.system.config.convert.PayApiConfigConvert;
import cn.bootx.platform.daxpay.service.dto.system.config.PayApiConfigDto;
import cn.bootx.table.modify.annotation.DbColumn;
@@ -37,6 +38,14 @@ public class PayApiConfig extends MpBaseEntity implements EntityBaseFunction<Pay
@TableField(updateStrategy = FieldStrategy.NEVER)
private String name;
/**
* 支持回调通知
* @see PayApiCallBackTypeEnum
*/
@DbColumn(comment = "支持回调通知")
@TableField(updateStrategy = FieldStrategy.NEVER)
private boolean noticeSupport;
@DbColumn(comment = "是否启用")
private boolean enable;

View File

@@ -1,6 +1,7 @@
package cn.bootx.platform.daxpay.service.dto.system.config;
import cn.bootx.platform.common.core.rest.dto.BaseDto;
import cn.bootx.platform.daxpay.service.code.PayApiCallBackTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -26,6 +27,13 @@ public class PayApiConfigDto extends BaseDto {
@Schema(description = "名称")
private String name;
/**
* 是否支持回调通知
* @see PayApiCallBackTypeEnum
*/
@Schema(description = "是否支持回调通知")
private boolean noticeSupport;
@Schema(description = "是否启用")
private boolean enable;

View File

@@ -111,6 +111,8 @@ bootx:
- '/demo/**'
- '/test/**'
- '/webjars/**'
- '/front/**'
- '/h5/**'
- '/css/**'
- '/error'
- '/favicon.ico'
@@ -156,6 +158,8 @@ dax-pay:
# 演示模块
demo:
# 网关地址
server-url: http://localhost:9000
server-url: http://pay1.bootx.cn
# 前端地址
front-url: http://pay1.bootx.cn/h5
# 签名秘钥
sign-secret: 123456

View File

@@ -42,7 +42,7 @@
<mapstruct.version>1.5.3.Final</mapstruct.version>
<lombok-mapstruct.version>0.2.0</lombok-mapstruct.version>
<table-modify.version>1.5.4</table-modify.version>
<wxjava.version>4.5.2.B</wxjava.version>
<wxjava.version>4.6.0</wxjava.version>
<rocketmq.version>2.2.3</rocketmq.version>
<lock4j.version>2.2.5</lock4j.version>
</properties>