mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-10-13 21:30:25 +00:00
feat 支付流程支持商户和应用
This commit is contained in:
@@ -146,7 +146,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.bootx</groupId>
|
||||
<artifactId>mybatis-table-modify-mysql-boot-starter</artifactId>
|
||||
<version>1.5.3.alpha1</version>
|
||||
<version>${mybatis-table-modify.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 监控 -->
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.daxpay;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import io.minio.credentials.MinioClientConfigProvider;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
|
@@ -0,0 +1,38 @@
|
||||
package cn.bootx.platform.daxpay.code;
|
||||
|
||||
/**
|
||||
* 商户和应用相关编码
|
||||
*
|
||||
* @author xxm
|
||||
* @date 2023/6/12
|
||||
*/
|
||||
public interface MchAndAppCode {
|
||||
|
||||
/* 商户状态 */
|
||||
/** 正常 */
|
||||
String MCH_STATE_NORMAL = "normal";
|
||||
|
||||
/** 停用 */
|
||||
String MCH_STATE_FORBIDDEN = "forbidden";
|
||||
|
||||
/** 封禁 */
|
||||
String MCH_STATE_BANNED = "banned";
|
||||
|
||||
/* 商户应用状态 */
|
||||
/** 正常 */
|
||||
String MCH_APP_STATE_NORMAL = "normal";
|
||||
|
||||
/** 停用 */
|
||||
String MCH_APP_STATE_FORBIDDEN = "forbidden";
|
||||
|
||||
/** 封禁 */
|
||||
String MCH_APP_STATE_BANNED = "banned";
|
||||
|
||||
/* 应用关联支付配置状态 */
|
||||
/** 正常 */
|
||||
String PAY_CONFIG_STATE_NORMAL = "normal";
|
||||
|
||||
/** 停用 */
|
||||
String PAY_CONFIG_STATE_FORBIDDEN = "forbidden";
|
||||
|
||||
}
|
@@ -42,20 +42,6 @@ public class AlipayConfigController {
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "启用指定的支付宝配置")
|
||||
@PostMapping("/setUpActivity")
|
||||
public ResResult<Void> setUpActivity(Long id) {
|
||||
alipayConfigService.setUpActivity(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "清除指定的支付宝配置")
|
||||
@PostMapping("/clearActivity")
|
||||
public ResResult<Void> clearActivity(Long id) {
|
||||
alipayConfigService.clearActivity(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "分页")
|
||||
@GetMapping("/page")
|
||||
public ResResult<PageResult<AlipayConfigDto>> page(PageParam pageParam, AlipayConfigQuery param) {
|
||||
|
@@ -44,10 +44,10 @@ public class CashierController {
|
||||
}
|
||||
|
||||
@Operation(summary = "扫码聚合支付(单渠道)")
|
||||
@GetMapping("/aggregatePay")
|
||||
public ModelAndView aggregatePay(String key, @RequestHeader(USER_AGENT) String ua) {
|
||||
@GetMapping("/aggregatePay/{mchAppCode}")
|
||||
public ModelAndView aggregatePay(String key,@PathVariable String mchAppCode, @RequestHeader(USER_AGENT) String ua) {
|
||||
try {
|
||||
String url = cashierService.aggregatePay(key, ua);
|
||||
String url = cashierService.aggregatePay(key, mchAppCode, ua);
|
||||
return new ModelAndView("redirect:" + url);
|
||||
}
|
||||
catch (PayUnsupportedMethodException e) {
|
||||
@@ -56,9 +56,9 @@ public class CashierController {
|
||||
}
|
||||
|
||||
@Operation(summary = "微信jsapi支付(回调)")
|
||||
@GetMapping("/wxJsapiPay")
|
||||
public ModelAndView wxJsapiPay(String code, String state) {
|
||||
Map<String, String> map = cashierService.wxJsapiPay(code, state);
|
||||
@GetMapping("/wxJsapiPay/{mchAppCode}")
|
||||
public ModelAndView wxJsapiPay(String code, @PathVariable String mchAppCode, String state) {
|
||||
Map<String, String> map = cashierService.wxJsapiPay(code,mchAppCode,state);
|
||||
// 跳转页面, 调起微信jsapi支付
|
||||
return new ModelAndView("wechatJsapiPay").addAllObjects(map);
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ import cn.bootx.platform.common.core.rest.Res;
|
||||
import cn.bootx.platform.common.core.rest.ResResult;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.daxpay.core.merchant.service.MchAppPayConfigService;
|
||||
import cn.bootx.platform.daxpay.core.merchant.service.MchApplicationService;
|
||||
import cn.bootx.platform.daxpay.core.merchant.service.MchAppService;
|
||||
import cn.bootx.platform.daxpay.dto.merchant.MchAppPayConfigResult;
|
||||
import cn.bootx.platform.daxpay.dto.merchant.MchApplicationDto;
|
||||
import cn.bootx.platform.daxpay.param.merchant.MchApplicationParam;
|
||||
@@ -28,7 +28,7 @@ import java.util.List;
|
||||
@RequiredArgsConstructor
|
||||
public class MchApplicationController {
|
||||
|
||||
private final MchApplicationService applicationService;
|
||||
private final MchAppService applicationService;
|
||||
|
||||
private final MchAppPayConfigService appPayConfigService;
|
||||
|
||||
|
@@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -36,19 +37,19 @@ public class PayCallbackController {
|
||||
|
||||
@SneakyThrows
|
||||
@Operation(summary = "支付宝回调")
|
||||
@PostMapping("/alipay")
|
||||
public String aliPay(HttpServletRequest request) {
|
||||
@PostMapping("/alipay/{appCode}")
|
||||
public String aliPay(@PathVariable String appCode, HttpServletRequest request) {
|
||||
Map<String, String> stringStringMap = AliPayApi.toMap(request);
|
||||
return aliPayCallbackService.payCallback(stringStringMap);
|
||||
return aliPayCallbackService.payCallback(appCode, stringStringMap);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Operation(summary = "微信支付回调")
|
||||
@PostMapping("/wechat")
|
||||
public String wechat(HttpServletRequest request) {
|
||||
@PostMapping("/wechat/{appCode}")
|
||||
public String wechat(@PathVariable String appCode, HttpServletRequest request) {
|
||||
String xmlMsg = HttpKit.readData(request);
|
||||
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
|
||||
return weChatPayCallbackService.payCallback(params);
|
||||
return weChatPayCallbackService.payCallback(appCode, params);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
*/
|
||||
@Tag(name = "统一支付")
|
||||
@RestController
|
||||
@RequestMapping("/uni_pay")
|
||||
@RequestMapping("/uniPay")
|
||||
@AllArgsConstructor
|
||||
public class PayController {
|
||||
|
||||
|
@@ -41,20 +41,6 @@ public class WeChatPayConfigController {
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "设置启用的微信支付配置")
|
||||
@PostMapping("/setUpActivity")
|
||||
public ResResult<Void> setUpActivity(Long id) {
|
||||
weChatPayConfigService.setUpActivity(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "清除指定的微信支付配置")
|
||||
@PostMapping("/clearActivity")
|
||||
public ResResult<Void> clearActivity(Long id) {
|
||||
weChatPayConfigService.clearActivity(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "分页")
|
||||
@GetMapping("/page")
|
||||
public ResResult<PageResult<WeChatPayConfigDto>> page(PageParam pageParam, WeChatPayConfigParam param) {
|
||||
|
@@ -68,8 +68,8 @@ public class CashierService {
|
||||
}
|
||||
// 构建支付方式参数
|
||||
PayWayParam payWayParam = new PayWayParam().setPayChannel(param.getPayChannel())
|
||||
.setPayWay(param.getPayWay())
|
||||
.setAmount(param.getAmount());
|
||||
.setPayWay(param.getPayWay())
|
||||
.setAmount(param.getAmount());
|
||||
|
||||
// 处理附加参数
|
||||
HashMap<String, String> map = new HashMap<>(1);
|
||||
@@ -80,8 +80,8 @@ public class CashierService {
|
||||
payWayParam.setExtraParamsJson(extraParamsJson);
|
||||
|
||||
PayParam payParam = new PayParam().setTitle(param.getTitle())
|
||||
.setBusinessId(param.getBusinessId())
|
||||
.setPayWayList(Collections.singletonList(payWayParam));
|
||||
.setBusinessId(param.getBusinessId())
|
||||
.setPayWayList(Collections.singletonList(payWayParam));
|
||||
PayResult payResult = payService.pay(payParam);
|
||||
|
||||
if (Objects.equals(PayStatusCode.TRADE_REFUNDED, payResult.getPayStatus())) {
|
||||
@@ -93,16 +93,17 @@ public class CashierService {
|
||||
/**
|
||||
* 扫码发起自动支付
|
||||
*/
|
||||
public String aggregatePay(String key, String ua) {
|
||||
public String aggregatePay(String key, String mchAppCode, String ua) {
|
||||
CashierSinglePayParam cashierSinglePayParam = new CashierSinglePayParam()
|
||||
.setPayWay(PayWayEnum.QRCODE.getCode());
|
||||
.setMchAppCode(mchAppCode)
|
||||
.setPayWay(PayWayEnum.QRCODE.getCode());
|
||||
// 判断是哪种支付方式
|
||||
if (ua.contains(PayChannelEnum.UA_ALI_PAY)) {
|
||||
cashierSinglePayParam.setPayChannel(PayChannelEnum.ALI.getCode());
|
||||
}
|
||||
else if (ua.contains(PayChannelEnum.UA_WECHAT_PAY)) {
|
||||
// 跳转微信授权页面, 调用jsapi进行支付
|
||||
return this.wxJsapiAuth(key);
|
||||
return this.wxJsapiAuth(key,mchAppCode);
|
||||
}
|
||||
else {
|
||||
throw new PayUnsupportedMethodException();
|
||||
@@ -110,8 +111,8 @@ public class CashierService {
|
||||
|
||||
AggregatePayInfo aggregatePayInfo = aggregateService.getAggregateInfo(key);
|
||||
cashierSinglePayParam.setTitle(aggregatePayInfo.getTitle())
|
||||
.setAmount(aggregatePayInfo.getAmount())
|
||||
.setBusinessId(aggregatePayInfo.getBusinessId());
|
||||
.setAmount(aggregatePayInfo.getAmount())
|
||||
.setBusinessId(aggregatePayInfo.getBusinessId());
|
||||
PayResult payResult = this.singlePay(cashierSinglePayParam);
|
||||
return payResult.getAsyncPayInfo().getPayBody();
|
||||
}
|
||||
@@ -119,13 +120,13 @@ public class CashierService {
|
||||
/**
|
||||
* 微信jsapi支付 - 跳转到授权页面
|
||||
*/
|
||||
private String wxJsapiAuth(String key) {
|
||||
WeChatPayConfig config = weChatPayConfigManager.findActivity()
|
||||
.orElseThrow(() -> new PayFailureException("未找到启用的微信支付配置"));
|
||||
WxMpService wxMpService = getWxMpService(config.getAppId(), config.getAppSecret());
|
||||
private String wxJsapiAuth(String key, String mchAppCode) {
|
||||
WeChatPayConfig config = weChatPayConfigManager.findByMchAppCode(mchAppCode)
|
||||
.orElseThrow(() -> new PayFailureException("未找到启用的微信支付配置"));
|
||||
WxMpService wxMpService = getWxMpService(config.getWxAppId(), config.getAppSecret());
|
||||
// 回调地址为 结算台微信jsapi支付的回调地址
|
||||
SystemParameter systemParameter = systemParamManager.findByParamKey(WeChatPayCode.JSAPI_REDIRECT_URL)
|
||||
.orElseThrow(() -> new PayFailureException("微信支付回调地址参数不存在"));
|
||||
.orElseThrow(() -> new PayFailureException("微信支付回调地址参数不存在"));
|
||||
String url = systemParameter.getValue() + "cashier/wxJsapiPay";
|
||||
return wxMpService.getOAuth2Service().buildAuthorizationUrl(url, WxConsts.OAuth2Scope.SNSAPI_BASE, key);
|
||||
}
|
||||
@@ -133,28 +134,29 @@ public class CashierService {
|
||||
/**
|
||||
* 微信jsapi支付 - 回调发起预支付, 同时调起微信页面jsapi支付
|
||||
* @param code 微信授权码, 用来获取id
|
||||
* @param mchAppCode 商户应用编码
|
||||
* @param state 聚合支付参数记录的key
|
||||
* @return 页面中调起jsapi支付的参数
|
||||
*/
|
||||
@SneakyThrows
|
||||
public Map<String, String> wxJsapiPay(String code, String state) {
|
||||
WeChatPayConfig config = weChatPayConfigManager.findActivity()
|
||||
.orElseThrow(() -> new PayFailureException("未找到启用的微信支付配置"));
|
||||
WxMpService wxMpService = this.getWxMpService(config.getAppId(), config.getAppSecret());
|
||||
public Map<String, String> wxJsapiPay(String code, String mchAppCode, String state) {
|
||||
WeChatPayConfig config = weChatPayConfigManager.findByMchAppCode(mchAppCode)
|
||||
.orElseThrow(() -> new PayFailureException("未找到启用的微信支付配置"));
|
||||
WxMpService wxMpService = this.getWxMpService(config.getWxAppId(), config.getAppSecret());
|
||||
WxOAuth2AccessToken accessToken = wxMpService.getOAuth2Service().getAccessToken(code);
|
||||
String openId = accessToken.getOpenId();
|
||||
AggregatePayInfo aggregatePayInfo = aggregateService.getAggregateInfo(state);
|
||||
// 构造微信API支付参数
|
||||
CashierSinglePayParam cashierSinglePayParam = new CashierSinglePayParam()
|
||||
.setPayChannel(PayChannelEnum.WECHAT.getCode())
|
||||
.setPayWay(PayWayEnum.JSAPI.getCode())
|
||||
.setTitle(aggregatePayInfo.getTitle())
|
||||
.setAmount(aggregatePayInfo.getAmount())
|
||||
.setOpenId(openId)
|
||||
.setBusinessId(aggregatePayInfo.getBusinessId());
|
||||
.setPayChannel(PayChannelEnum.WECHAT.getCode())
|
||||
.setPayWay(PayWayEnum.JSAPI.getCode())
|
||||
.setTitle(aggregatePayInfo.getTitle())
|
||||
.setAmount(aggregatePayInfo.getAmount())
|
||||
.setOpenId(openId)
|
||||
.setBusinessId(aggregatePayInfo.getBusinessId());
|
||||
PayResult payResult = this.singlePay(cashierSinglePayParam);
|
||||
|
||||
return WxPayKit.prepayIdCreateSign(payResult.getAsyncPayInfo().getPayBody(), config.getAppId(),
|
||||
return WxPayKit.prepayIdCreateSign(payResult.getAsyncPayInfo().getPayBody(), config.getWxAppId(),
|
||||
config.getApiKeyV2(), SignType.HMACSHA256);
|
||||
}
|
||||
|
||||
@@ -183,8 +185,8 @@ public class CashierService {
|
||||
}
|
||||
// 发起支付
|
||||
PayParam payParam = new PayParam().setTitle(param.getTitle())
|
||||
.setBusinessId(param.getBusinessId())
|
||||
.setPayWayList(param.getPayWayList());
|
||||
.setBusinessId(param.getBusinessId())
|
||||
.setPayWayList(param.getPayWayList());
|
||||
PayResult payResult = payService.pay(payParam);
|
||||
|
||||
if (Objects.equals(PayStatusCode.TRADE_REFUNDED, payResult.getPayStatus())) {
|
||||
|
@@ -10,7 +10,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@@ -23,28 +22,11 @@ import java.util.Optional;
|
||||
@RequiredArgsConstructor
|
||||
public class AlipayConfigManager extends BaseManager<AlipayConfigMapper, AlipayConfig> {
|
||||
|
||||
private Optional<AlipayConfig> alipayConfig;
|
||||
|
||||
@Override
|
||||
public AlipayConfig saveOrUpdate(AlipayConfig entity) {
|
||||
this.clearCache();
|
||||
return super.saveOrUpdate(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlipayConfig updateById(AlipayConfig alipayConfig) {
|
||||
this.clearCache();
|
||||
return super.updateById(alipayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用的支付宝配置
|
||||
* 获取关联的的支付宝配置
|
||||
*/
|
||||
public Optional<AlipayConfig> findActivity() {
|
||||
if (Objects.isNull(alipayConfig)) {
|
||||
alipayConfig = findByField(AlipayConfig::getActivity, Boolean.TRUE);
|
||||
}
|
||||
return alipayConfig;
|
||||
public Optional<AlipayConfig> findByMchAppCode(String mchAppCOde) {
|
||||
return findByField(AlipayConfig::getMchAppCode, mchAppCOde);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,21 +40,4 @@ public class AlipayConfigManager extends BaseManager<AlipayConfigMapper, AlipayC
|
||||
.page(mpPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有启用的支付配置
|
||||
*/
|
||||
public void removeAllActivity() {
|
||||
this.clearCache();
|
||||
lambdaUpdate().eq(AlipayConfig::getActivity, Boolean.TRUE)
|
||||
.set(AlipayConfig::getActivity, Boolean.FALSE)
|
||||
.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
*/
|
||||
public void clearCache() {
|
||||
alipayConfig = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,10 +2,12 @@ package cn.bootx.platform.daxpay.core.channel.alipay.entity;
|
||||
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbTable;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlIndex;
|
||||
import cn.bootx.platform.common.core.annotation.BigField;
|
||||
import cn.bootx.platform.common.core.annotation.EncryptionField;
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.code.paymodel.AliPayCode;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.convert.AlipayConvert;
|
||||
import cn.bootx.platform.daxpay.dto.channel.alipay.AlipayConfigDto;
|
||||
import cn.bootx.platform.daxpay.param.channel.alipay.AlipayConfigParam;
|
||||
@@ -35,13 +37,16 @@ public class AlipayConfig extends MpBaseEntity implements EntityBaseFunction<Ali
|
||||
@DbColumn(comment = "名称")
|
||||
private String name;
|
||||
|
||||
/** 商户Id */
|
||||
@DbColumn(comment = "商户Id")
|
||||
private Long merchantId;
|
||||
/** 商户编码 */
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
@DbColumn(comment = "商户编码")
|
||||
private String mchCode;
|
||||
|
||||
/** 商户应用Id */
|
||||
@DbColumn(comment = "商户应用Id")
|
||||
private Long mchAppId;
|
||||
/** 商户应用编码 */
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
@DbMySqlIndex(comment = "商户应用编码唯一索引")
|
||||
@DbColumn(comment = "商户应用编码")
|
||||
private String mchAppCode;
|
||||
|
||||
/** 支付宝商户appId */
|
||||
@DbColumn(comment = "支付宝商户appId")
|
||||
@@ -61,7 +66,10 @@ public class AlipayConfig extends MpBaseEntity implements EntityBaseFunction<Ali
|
||||
@DbColumn(comment = "")
|
||||
private String serverUrl;
|
||||
|
||||
/** 认证类型 证书/公钥 */
|
||||
/**
|
||||
* 认证类型 证书/公钥
|
||||
* @see AliPayCode#AUTH_TYPE_KEY
|
||||
*/
|
||||
@DbColumn(comment = "认证类型")
|
||||
private Integer authType;
|
||||
|
||||
@@ -111,13 +119,9 @@ public class AlipayConfig extends MpBaseEntity implements EntityBaseFunction<Ali
|
||||
@DbColumn(comment = "可用支付方式")
|
||||
private String payWays;
|
||||
|
||||
/** 是否启用 */
|
||||
@DbColumn(comment = "是否启用")
|
||||
private Boolean activity;
|
||||
|
||||
/** 状态 暂时没什么用 */
|
||||
@DbColumn(comment = "状态 暂时没什么用")
|
||||
private Integer state;
|
||||
/** 状态 */
|
||||
@DbColumn(comment = "状态")
|
||||
private String state;
|
||||
|
||||
/** 备注 */
|
||||
@DbColumn(comment = "备注")
|
||||
|
@@ -57,9 +57,13 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
|
||||
return PayStatusCode.NOTIFY_TRADE_FAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证信息格式
|
||||
* @param mchAppCode 商户应用编码
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean verifyNotify() {
|
||||
public boolean verifyNotify(String mchAppCode) {
|
||||
Map<String, String> params = PARAMS.get();
|
||||
String callReq = JSONUtil.toJsonStr(params);
|
||||
String appId = params.get(AliPayCode.APP_ID);
|
||||
@@ -67,7 +71,8 @@ public class AliPayCallbackService extends AbsPayCallbackStrategy {
|
||||
log.error("支付宝回调报文 appId 为空 {}", callReq);
|
||||
return false;
|
||||
}
|
||||
AlipayConfig alipayConfig = alipayConfigManager.findActivity().orElseThrow(DataNotExistException::new);
|
||||
AlipayConfig alipayConfig = alipayConfigManager.findByMchAppCode(mchAppCode)
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
if (alipayConfig == null) {
|
||||
log.error("支付宝支付配置不存在: {}", callReq);
|
||||
return false;
|
||||
|
@@ -1,15 +1,19 @@
|
||||
package cn.bootx.platform.daxpay.core.channel.alipay.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.BizException;
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.dto.KeyValue;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.code.pay.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.paymodel.AliPayWay;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.dao.AlipayConfigManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.alipay.entity.AlipayConfig;
|
||||
import cn.bootx.platform.daxpay.core.merchant.dao.MchAppPayConfigManager;
|
||||
import cn.bootx.platform.daxpay.core.merchant.entity.MchAppPayConfig;
|
||||
import cn.bootx.platform.daxpay.core.merchant.service.MchAppService;
|
||||
import cn.bootx.platform.daxpay.dto.channel.alipay.AlipayConfigDto;
|
||||
import cn.bootx.platform.daxpay.exception.payment.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.channel.alipay.AlipayConfigParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.alipay.AlipayConfigQuery;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
@@ -21,7 +25,6 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -37,42 +40,28 @@ public class AlipayConfigService {
|
||||
|
||||
private final AlipayConfigManager alipayConfigManager;
|
||||
|
||||
private final MchAppService mchAppService;
|
||||
|
||||
private final MchAppPayConfigManager mchAppPayConfigManager;
|
||||
|
||||
/**
|
||||
* 添加支付宝配置
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void add(AlipayConfigParam param) {
|
||||
// 是否有管理关系判断
|
||||
if (mchAppService.checkMatch(param.getMchCode(), param.getMchAppCode())) {
|
||||
throw new BizException("应用信息与商户信息不匹配");
|
||||
}
|
||||
AlipayConfig alipayConfig = AlipayConfig.init(param);
|
||||
alipayConfig.setActivity(false).setState(1);
|
||||
alipayConfigManager.save(alipayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置启用的支付宝配置
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void setUpActivity(Long id) {
|
||||
AlipayConfig alipayConfig = alipayConfigManager.findById(id).orElseThrow(DataNotExistException::new);
|
||||
if (Objects.equals(alipayConfig.getActivity(), Boolean.TRUE)) {
|
||||
return;
|
||||
}
|
||||
alipayConfigManager.removeAllActivity();
|
||||
alipayConfig.setActivity(true);
|
||||
alipayConfigManager.updateById(alipayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除启用状态
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void clearActivity(Long id) {
|
||||
AlipayConfig alipayConfig = alipayConfigManager.findById(id)
|
||||
.orElseThrow(() -> new PayFailureException("支付宝配置不存在"));
|
||||
if (Objects.equals(alipayConfig.getActivity(), Boolean.FALSE)) {
|
||||
return;
|
||||
}
|
||||
alipayConfig.setActivity(false);
|
||||
alipayConfigManager.updateById(alipayConfig);
|
||||
// 保存关联关系
|
||||
MchAppPayConfig mchAppPayConfig = new MchAppPayConfig().setAppCode(alipayConfig.getMchAppCode())
|
||||
.setConfigId(alipayConfig.getId())
|
||||
.setChannel(PayChannelEnum.ALI.getCode())
|
||||
.setState(alipayConfig.getState());
|
||||
mchAppPayConfigManager.save(mchAppPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -11,7 +11,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@@ -24,30 +23,10 @@ import java.util.Optional;
|
||||
@RequiredArgsConstructor
|
||||
public class WeChatPayConfigManager extends BaseManager<WeChatPayConfigMapper, WeChatPayConfig> {
|
||||
|
||||
private Optional<WeChatPayConfig> weChatPayConfig;
|
||||
|
||||
@Override
|
||||
public WeChatPayConfig saveOrUpdate(WeChatPayConfig entity) {
|
||||
this.clearCache();
|
||||
return super.saveOrUpdate(entity);
|
||||
public Optional<WeChatPayConfig> findByMchAppCode(String mchAppCode){
|
||||
return findByField(WeChatPayConfig::getMchAppCode,mchAppCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeChatPayConfig updateById(WeChatPayConfig weChatPayConfig) {
|
||||
this.clearCache();
|
||||
return super.updateById(weChatPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用的微信配置
|
||||
*/
|
||||
public Optional<WeChatPayConfig> findActivity() {
|
||||
if (Objects.isNull(weChatPayConfig)) {
|
||||
weChatPayConfig = findByField(WeChatPayConfig::getActivity, Boolean.TRUE);
|
||||
}
|
||||
return weChatPayConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
@@ -55,25 +34,9 @@ public class WeChatPayConfigManager extends BaseManager<WeChatPayConfigMapper, W
|
||||
Page<WeChatPayConfig> mpPage = MpUtil.getMpPage(pageParam, WeChatPayConfig.class);
|
||||
return lambdaQuery().select(WeChatPayConfig.class, MpUtil::excludeBigField)
|
||||
.like(StrUtil.isNotBlank(param.getName()), WeChatPayConfig::getName, param.getName())
|
||||
.like(StrUtil.isNotBlank(param.getAppId()), WeChatPayConfig::getAppId, param.getAppId())
|
||||
.like(StrUtil.isNotBlank(param.getAppId()), WeChatPayConfig::getMchId, param.getMchId())
|
||||
.like(StrUtil.isNotBlank(param.getAppId()), WeChatPayConfig::getWxAppId, param.getAppId())
|
||||
.like(StrUtil.isNotBlank(param.getAppId()), WeChatPayConfig::getWxMchId, param.getMchId())
|
||||
.orderByDesc(MpIdEntity::getId)
|
||||
.page(mpPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有的被启用的
|
||||
*/
|
||||
public void removeAllActivity() {
|
||||
this.clearCache();
|
||||
lambdaUpdate().eq(WeChatPayConfig::getActivity, Boolean.TRUE).set(WeChatPayConfig::getActivity, Boolean.FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
*/
|
||||
public void clearCache() {
|
||||
weChatPayConfig = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.core.channel.wechat.entity;
|
||||
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbTable;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlIndex;
|
||||
import cn.bootx.platform.common.core.annotation.BigField;
|
||||
import cn.bootx.platform.common.core.annotation.EncryptionField;
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
@@ -35,24 +36,28 @@ public class WeChatPayConfig extends MpBaseEntity implements EntityBaseFunction<
|
||||
@DbColumn(comment = "名称")
|
||||
private String name;
|
||||
|
||||
/** 微信商户号 */
|
||||
@DbColumn(comment = "微信商户号")
|
||||
private String mchId;
|
||||
/** 商户编码 */
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
@DbColumn(comment = "商户编码")
|
||||
private String mchCode;
|
||||
|
||||
/** 商户应用Id */
|
||||
/** 商户应用编码 */
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
@DbMySqlIndex(comment = "商户应用编码唯一索引")
|
||||
@DbColumn(comment = "商户应用编码")
|
||||
private String mchAppCode;
|
||||
|
||||
/** 微信商户Id */
|
||||
@DbColumn(comment = "微信商户号")
|
||||
private String wxMchId;
|
||||
|
||||
/** 微信商户应用Id */
|
||||
@DbColumn(comment = "商户应用Id")
|
||||
private Long mchAppId;
|
||||
private Long wxMchAppId;
|
||||
|
||||
/** 微信应用appId */
|
||||
@DbColumn(comment = "微信应用appId")
|
||||
private String appId;
|
||||
|
||||
// /**
|
||||
// * api版本
|
||||
// * @see WeChatPayCode#API_V2
|
||||
// */
|
||||
// @DbColumn(comment = "api版本")
|
||||
// private String apiVersion;
|
||||
private String wxAppId;
|
||||
|
||||
/** 商户平台「API安全」中的 APIv2 密钥 */
|
||||
@TableField(updateStrategy = FieldStrategy.IGNORED)
|
||||
@@ -116,13 +121,12 @@ public class WeChatPayConfig extends MpBaseEntity implements EntityBaseFunction<
|
||||
@DbColumn(comment = "可用支付方式")
|
||||
private String payWays;
|
||||
|
||||
/** 是否启用 */
|
||||
@DbColumn(comment = "是否启用")
|
||||
private Boolean activity;
|
||||
|
||||
/** 状态 */
|
||||
/**
|
||||
* 状态
|
||||
* @see cn.bootx.platform.daxpay.code.MchAndAppCode#PAY_CONFIG_STATE_NORMAL
|
||||
*/
|
||||
@DbColumn(comment = "状态")
|
||||
private Integer state;
|
||||
private String state;
|
||||
|
||||
/** 备注 */
|
||||
@DbColumn(comment = "备注")
|
||||
|
@@ -73,7 +73,7 @@ public class WeChatPayCallbackService extends AbsPayCallbackStrategy {
|
||||
* 验证回调消息
|
||||
*/
|
||||
@Override
|
||||
public boolean verifyNotify() {
|
||||
public boolean verifyNotify(String mchAppCode) {
|
||||
Map<String, String> params = PARAMS.get();
|
||||
String callReq = JSONUtil.toJsonStr(params);
|
||||
log.info("微信发起回调 报文: {}", callReq);
|
||||
@@ -83,8 +83,8 @@ public class WeChatPayCallbackService extends AbsPayCallbackStrategy {
|
||||
log.warn("微信回调报文 appId 为空 {}", callReq);
|
||||
return false;
|
||||
}
|
||||
//
|
||||
WeChatPayConfig weChatPayConfig = weChatPayConfigManager.findActivity().orElseThrow(DataNotExistException::new);
|
||||
|
||||
WeChatPayConfig weChatPayConfig = weChatPayConfigManager.findByMchAppCode(mchAppCode).orElseThrow(DataNotExistException::new);
|
||||
if (weChatPayConfig == null) {
|
||||
log.warn("微信支付配置不存在: {}", callReq);
|
||||
return false;
|
||||
|
@@ -45,8 +45,8 @@ public class WeChatPayCancelService {
|
||||
public void cancelRemote(Payment payment, WeChatPayConfig weChatPayConfig) {
|
||||
// 只有部分需要调用微信网关进行关闭
|
||||
Map<String, String> params = CloseOrderModel.builder()
|
||||
.appid(weChatPayConfig.getAppId())
|
||||
.mch_id(weChatPayConfig.getMchId())
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.out_trade_no(String.valueOf(payment.getId()))
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.build()
|
||||
@@ -66,8 +66,8 @@ public class WeChatPayCancelService {
|
||||
// 设置退款号
|
||||
AsyncRefundLocal.set(IdUtil.getSnowflakeNextIdStr());
|
||||
Map<String, String> params = RefundModel.builder()
|
||||
.appid(weChatPayConfig.getAppId())
|
||||
.mch_id(weChatPayConfig.getMchId())
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.out_trade_no(String.valueOf(payment.getId()))
|
||||
.out_refund_no(AsyncRefundLocal.get())
|
||||
.total_fee(totalFee)
|
||||
@@ -79,7 +79,7 @@ public class WeChatPayCancelService {
|
||||
byte[] fileBytes = uploadService.getFileBytes(weChatPayConfig.getP12());
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes);
|
||||
// 证书密码为 微信商户号
|
||||
String xmlResult = WxPayApi.orderRefund(false, params, inputStream, weChatPayConfig.getMchId());
|
||||
String xmlResult = WxPayApi.orderRefund(false, params, inputStream, weChatPayConfig.getWxMchId());
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
this.verifyErrorMsg(result);
|
||||
}
|
||||
|
@@ -1,13 +1,18 @@
|
||||
package cn.bootx.platform.daxpay.core.channel.wechat.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.BizException;
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.dto.KeyValue;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.code.pay.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.paymodel.WeChatPayWay;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.dao.WeChatPayConfigManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.core.merchant.dao.MchAppPayConfigManager;
|
||||
import cn.bootx.platform.daxpay.core.merchant.entity.MchAppPayConfig;
|
||||
import cn.bootx.platform.daxpay.core.merchant.service.MchAppService;
|
||||
import cn.bootx.platform.daxpay.dto.channel.wechat.WeChatPayConfigDto;
|
||||
import cn.bootx.platform.daxpay.exception.payment.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.channel.wechat.WeChatPayConfigParam;
|
||||
@@ -20,7 +25,6 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -35,15 +39,27 @@ import java.util.stream.Collectors;
|
||||
public class WeChatPayConfigService {
|
||||
|
||||
private final WeChatPayConfigManager weChatPayConfigManager;
|
||||
private final MchAppService mchAppService;
|
||||
private final MchAppPayConfigManager mchAppPayConfigManager;
|
||||
|
||||
/**
|
||||
* 添加微信支付配置
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void add(WeChatPayConfigParam param) {
|
||||
// 是否有管理关系判断
|
||||
if (mchAppService.checkMatch(param.getMchCode(), param.getMchAppCode())) {
|
||||
throw new BizException("应用信息与商户信息不匹配");
|
||||
}
|
||||
|
||||
WeChatPayConfig weChatPayConfig = WeChatPayConfig.init(param);
|
||||
weChatPayConfig.setActivity(false);
|
||||
weChatPayConfigManager.save(weChatPayConfig);
|
||||
// 保存关联关系
|
||||
MchAppPayConfig mchAppPayConfig = new MchAppPayConfig().setAppCode(weChatPayConfig.getMchAppCode())
|
||||
.setConfigId(weChatPayConfig.getId())
|
||||
.setChannel(PayChannelEnum.WECHAT.getCode())
|
||||
.setState(weChatPayConfig.getState());
|
||||
mchAppPayConfigManager.save(mchAppPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,35 +88,6 @@ public class WeChatPayConfigService {
|
||||
return MpUtil.convert2DtoPageResult(weChatPayConfigManager.page(pageParam, param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置启用的支付宝配置
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void setUpActivity(Long id) {
|
||||
WeChatPayConfig weChatPayConfig = weChatPayConfigManager.findById(id)
|
||||
.orElseThrow(() -> new PayFailureException("微信支付配置不存在"));
|
||||
if (Objects.equals(weChatPayConfig.getActivity(), Boolean.TRUE)) {
|
||||
return;
|
||||
}
|
||||
weChatPayConfigManager.removeAllActivity();
|
||||
weChatPayConfig.setActivity(true);
|
||||
weChatPayConfigManager.updateById(weChatPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除启用状态
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void clearActivity(Long id) {
|
||||
WeChatPayConfig weChatPayConfig = weChatPayConfigManager.findById(id)
|
||||
.orElseThrow(() -> new PayFailureException("微信支付配置不存在"));
|
||||
if (Objects.equals(weChatPayConfig.getActivity(), Boolean.TRUE)) {
|
||||
return;
|
||||
}
|
||||
weChatPayConfig.setActivity(false);
|
||||
weChatPayConfigManager.updateById(weChatPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取
|
||||
*/
|
||||
|
@@ -169,8 +169,8 @@ public class WeChatPayService {
|
||||
*/
|
||||
private String barCode(String amount, Payment payment, String authCode, WeChatPayConfig weChatPayConfig) {
|
||||
Map<String, String> params = MicroPayModel.builder()
|
||||
.appid(weChatPayConfig.getAppId())
|
||||
.mch_id(weChatPayConfig.getMchId())
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.body(payment.getTitle())
|
||||
.auth_code(authCode)
|
||||
@@ -226,8 +226,8 @@ public class WeChatPayService {
|
||||
// 过期时间
|
||||
payment.setExpiredTime(PayWaylUtil.getPaymentExpiredTime(weChatPayConfig.getExpireTime()));
|
||||
return UnifiedOrderModel.builder()
|
||||
.appid(weChatPayConfig.getAppId())
|
||||
.mch_id(weChatPayConfig.getMchId())
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.time_start(LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN))
|
||||
// 反正v2版本的超时时间无效
|
||||
|
@@ -32,8 +32,8 @@ public class WeChatPaySyncService {
|
||||
public PaySyncResult syncPayStatus(Long paymentId, WeChatPayConfig weChatPayConfig) {
|
||||
PaySyncResult paySyncResult = new PaySyncResult().setPaySyncStatus(PaySyncStatus.FAIL);
|
||||
Map<String, String> params = UnifiedOrderModel.builder()
|
||||
.appid(weChatPayConfig.getAppId())
|
||||
.mch_id(weChatPayConfig.getMchId())
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.out_trade_no(String.valueOf(paymentId))
|
||||
.build()
|
||||
|
@@ -21,4 +21,4 @@ public interface MchApplicationConvert {
|
||||
|
||||
MchApplicationDto convert(MchApplication in);
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 商户应用
|
||||
*
|
||||
@@ -19,7 +21,14 @@ import org.springframework.stereotype.Repository;
|
||||
*/
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class MchApplicationManager extends BaseManager<MchApplicationMapper, MchApplication> {
|
||||
public class MchAppManager extends BaseManager<MchApplicationMapper, MchApplication> {
|
||||
|
||||
/**
|
||||
* 根据编码查询
|
||||
*/
|
||||
public Optional<MchApplication> findByCode(String code) {
|
||||
return findByField(MchApplication::getCode, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
@@ -27,8 +36,7 @@ public class MchApplicationManager extends BaseManager<MchApplicationMapper, Mch
|
||||
public Page<MchApplication> page(PageParam pageParam, MchApplicationParam param) {
|
||||
Page<MchApplication> mpPage = MpUtil.getMpPage(pageParam, MchApplication.class);
|
||||
QueryWrapper<MchApplication> wrapper = QueryGenerator.generator(param, this.getEntityClass());
|
||||
wrapper.select(this.getEntityClass(), MpUtil::excludeBigField)
|
||||
.orderByDesc(MpUtil.getColumnName(MchApplication::getId));
|
||||
wrapper.select(this.getEntityClass(), MpUtil::excludeBigField).orderByDesc(MpUtil.getColumnName(MchApplication::getId));
|
||||
return this.page(mpPage, wrapper);
|
||||
}
|
||||
|
@@ -13,4 +13,4 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
@Mapper
|
||||
public interface MchApplicationMapper extends BaseMapper<MchApplication> {
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -25,6 +26,13 @@ import java.util.stream.Collectors;
|
||||
@RequiredArgsConstructor
|
||||
public class MerchantInfoManager extends BaseManager<MerchantInfoMapper, MerchantInfo> {
|
||||
|
||||
/**
|
||||
* 根据编码查询
|
||||
*/
|
||||
public Optional<MerchantInfo> findByCode(String code) {
|
||||
return findByField(MerchantInfo::getCode, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
@@ -40,10 +48,10 @@ public class MerchantInfoManager extends BaseManager<MerchantInfoMapper, Merchan
|
||||
* 下拉列表
|
||||
*/
|
||||
public List<KeyValue> findDropdown() {
|
||||
return lambdaQuery().select(MerchantInfo::getMchNo, MerchantInfo::getMchName)
|
||||
return lambdaQuery().select(MerchantInfo::getCode, MerchantInfo::getName)
|
||||
.list()
|
||||
.stream()
|
||||
.map(mch -> new KeyValue(mch.getMchNo(), mch.getMchName()))
|
||||
.map(mch -> new KeyValue(mch.getCode(), mch.getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.core.merchant.entity;
|
||||
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbTable;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlIndex;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
@@ -21,9 +22,10 @@ import lombok.experimental.Accessors;
|
||||
@TableName("pay_mch_app_config")
|
||||
public class MchAppPayConfig extends MpBaseEntity {
|
||||
|
||||
/** 关联应用ID */
|
||||
@DbColumn(comment = "关联应用ID")
|
||||
private Long appId;
|
||||
/** 关联应用编码 */
|
||||
@DbMySqlIndex(comment = "关联应用编码索引")
|
||||
@DbColumn(comment = "关联应用编码")
|
||||
private String appCode;
|
||||
|
||||
/** 关联配置ID */
|
||||
@DbColumn(comment = "关联配置ID")
|
||||
|
@@ -2,7 +2,7 @@ package cn.bootx.platform.daxpay.core.merchant.entity;
|
||||
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbTable;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.MySqlIndex;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlIndex;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.constants.MySqlIndexType;
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
@@ -15,6 +15,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
|
||||
/**
|
||||
* 商户应用
|
||||
@@ -24,16 +25,17 @@ import lombok.experimental.Accessors;
|
||||
*/
|
||||
@DbTable(comment = "商户应用")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@MySqlIndex(columns = "app_no", type = MySqlIndexType.UNIQUE, comment = "应用编码唯一索引")
|
||||
@DbMySqlIndex(fields = MchApplication.Fields.code, type = MySqlIndexType.UNIQUE, comment = "应用编码唯一索引")
|
||||
@Data
|
||||
@FieldNameConstants
|
||||
@Accessors(chain = true)
|
||||
@TableName("pay_mch_app")
|
||||
public class MchApplication extends MpBaseEntity implements EntityBaseFunction<MchApplicationDto> {
|
||||
|
||||
/** 应用编码 */
|
||||
@DbColumn(comment = "应用编码")
|
||||
@TableField(updateStrategy = FieldStrategy.IGNORED)
|
||||
private String appNo;
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
private String code;
|
||||
|
||||
/** 名称 */
|
||||
@DbColumn(comment = "名称")
|
||||
@@ -41,11 +43,14 @@ public class MchApplication extends MpBaseEntity implements EntityBaseFunction<M
|
||||
|
||||
/** 商户号 */
|
||||
@DbColumn(comment = "商户号")
|
||||
@TableField(updateStrategy = FieldStrategy.IGNORED)
|
||||
private String mchNo;
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
private String mchCode;
|
||||
|
||||
/** 状态类型 */
|
||||
@DbColumn(comment = "状态类型")
|
||||
/**
|
||||
* 状态
|
||||
* @see cn.bootx.platform.daxpay.code.MchAndAppCode
|
||||
*/
|
||||
@DbColumn(comment = "状态")
|
||||
private String state;
|
||||
|
||||
/** 备注 */
|
||||
|
@@ -2,7 +2,7 @@ package cn.bootx.platform.daxpay.core.merchant.entity;
|
||||
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbTable;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.MySqlIndex;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlIndex;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.constants.MySqlIndexType;
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
@@ -17,13 +17,15 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
|
||||
import static cn.bootx.platform.daxpay.core.merchant.entity.MerchantInfo.Fields.code;
|
||||
|
||||
/**
|
||||
* 商户
|
||||
*
|
||||
* @author xxm
|
||||
* @date 2023-05-17
|
||||
*/
|
||||
@MySqlIndex(columns = "mch_no", type = MySqlIndexType.UNIQUE, comment = "商户号唯一索引")
|
||||
@DbMySqlIndex(fields = code, type = MySqlIndexType.UNIQUE, comment = "商户号唯一索引")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@FieldNameConstants
|
||||
@Data
|
||||
@@ -35,15 +37,15 @@ public class MerchantInfo extends MpBaseEntity implements EntityBaseFunction<Mer
|
||||
/** 商户号 */
|
||||
@DbColumn(comment = "商户号")
|
||||
@TableField(updateStrategy = FieldStrategy.IGNORED)
|
||||
private String mchNo;
|
||||
private String code;
|
||||
|
||||
/** 商户名称 */
|
||||
@DbColumn(comment = "商户名称")
|
||||
private String mchName;
|
||||
private String name;
|
||||
|
||||
/** 商户简称 */
|
||||
@DbColumn(comment = "商户简称")
|
||||
private String mchShortName;
|
||||
private String shortName;
|
||||
|
||||
/** 类型 */
|
||||
@DbColumn(comment = "类型")
|
||||
@@ -57,7 +59,10 @@ public class MerchantInfo extends MpBaseEntity implements EntityBaseFunction<Mer
|
||||
@DbColumn(comment = "联系人手机号")
|
||||
private String contactTel;
|
||||
|
||||
/** 状态类型 */
|
||||
/**
|
||||
* 状态类型
|
||||
* @see cn.bootx.platform.daxpay.code.MchAndAppCode
|
||||
*/
|
||||
@DbColumn(comment = "状态类型")
|
||||
private String state;
|
||||
|
||||
|
@@ -34,7 +34,7 @@ public class MchAppPayConfigService {
|
||||
* 根据应用ID删除
|
||||
*/
|
||||
public void deleteByAppId(Long appId) {
|
||||
mchAppPayConfigManager.deleteByField(MchAppPayConfig::getAppId, appId);
|
||||
mchAppPayConfigManager.deleteByField(MchAppPayConfig::getAppCode, appId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,7 +45,7 @@ public class MchAppPayConfigService {
|
||||
List<PayChannelConfig> channels = channelConfigManager.findAllByOrder();
|
||||
// 查询当前应用所拥有的配置, 进行合并生成相关信息
|
||||
|
||||
val mchAppPayConfigMap = mchAppPayConfigManager.findAllByField(MchAppPayConfig::getAppId, appId)
|
||||
val mchAppPayConfigMap = mchAppPayConfigManager.findAllByField(MchAppPayConfig::getAppCode, appId)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(MchAppPayConfig::getChannel, Function.identity()));
|
||||
// 进行排序并返回
|
||||
|
@@ -5,8 +5,10 @@ import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.core.util.ResultConvertUtil;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.core.merchant.dao.MchApplicationManager;
|
||||
import cn.bootx.platform.daxpay.core.merchant.dao.MchAppManager;
|
||||
import cn.bootx.platform.daxpay.core.merchant.dao.MerchantInfoManager;
|
||||
import cn.bootx.platform.daxpay.core.merchant.entity.MchApplication;
|
||||
import cn.bootx.platform.daxpay.core.merchant.entity.MerchantInfo;
|
||||
import cn.bootx.platform.daxpay.dto.merchant.MchApplicationDto;
|
||||
import cn.bootx.platform.daxpay.param.merchant.MchApplicationParam;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
@@ -18,6 +20,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 商户应用
|
||||
@@ -28,9 +31,11 @@ import java.util.List;
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MchApplicationService {
|
||||
public class MchAppService {
|
||||
|
||||
private final MchApplicationManager mchApplicationManager;
|
||||
private final MchAppManager mchAppManager;
|
||||
|
||||
private final MerchantInfoManager mchManager;
|
||||
|
||||
private final MchAppPayConfigService appPayConfigService;
|
||||
|
||||
@@ -38,40 +43,39 @@ public class MchApplicationService {
|
||||
* 添加
|
||||
*/
|
||||
public void add(MchApplicationParam param) {
|
||||
MchApplication mchApplication = MchApplication.init(param);
|
||||
mchApplication.setAppNo(IdUtil.getSnowflakeNextIdStr());
|
||||
mchApplicationManager.save(mchApplication);
|
||||
MchApplication mchApp = MchApplication.init(param);
|
||||
mchApp.setCode(IdUtil.getSnowflakeNextIdStr());
|
||||
mchAppManager.save(mchApp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改
|
||||
*/
|
||||
public void update(MchApplicationParam param) {
|
||||
MchApplication mchApplication = mchApplicationManager.findById(param.getId())
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
BeanUtil.copyProperties(param, mchApplication, CopyOptions.create().ignoreNullValue());
|
||||
mchApplicationManager.updateById(mchApplication);
|
||||
MchApplication mchApp = mchAppManager.findById(param.getId()).orElseThrow(DataNotExistException::new);
|
||||
BeanUtil.copyProperties(param, mchApp, CopyOptions.create().ignoreNullValue());
|
||||
mchAppManager.updateById(mchApp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public PageResult<MchApplicationDto> page(PageParam pageParam, MchApplicationParam mchApplicationParam) {
|
||||
return MpUtil.convert2DtoPageResult(mchApplicationManager.page(pageParam, mchApplicationParam));
|
||||
return MpUtil.convert2DtoPageResult(mchAppManager.page(pageParam, mchApplicationParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单条
|
||||
*/
|
||||
public MchApplicationDto findById(Long id) {
|
||||
return mchApplicationManager.findById(id).map(MchApplication::toDto).orElseThrow(DataNotExistException::new);
|
||||
return mchAppManager.findById(id).map(MchApplication::toDto).orElseThrow(DataNotExistException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部
|
||||
*/
|
||||
public List<MchApplicationDto> findAll() {
|
||||
return ResultConvertUtil.dtoListConvert(mchApplicationManager.findAll());
|
||||
return ResultConvertUtil.dtoListConvert(mchAppManager.findAll());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,7 +84,21 @@ public class MchApplicationService {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Long id) {
|
||||
appPayConfigService.deleteByAppId(id);
|
||||
mchApplicationManager.deleteById(id);
|
||||
mchAppManager.deleteById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证商户号和商户应用是否匹配
|
||||
*/
|
||||
public boolean checkMatch(String mchCode, String mchAppCode) {
|
||||
MerchantInfo merchantInfo = mchManager.findByCode(mchCode).orElseThrow(DataNotExistException::new);
|
||||
MchApplication mchApp = mchAppManager.findByCode(mchAppCode).orElseThrow(DataNotExistException::new);
|
||||
|
||||
// 商户与应用是否有关联关系
|
||||
if (!Objects.equals(mchApp.getMchCode(), merchantInfo.getCode())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@@ -36,7 +36,7 @@ public class MerchantInfoService {
|
||||
*/
|
||||
public void add(MerchantInfoParam param) {
|
||||
MerchantInfo merchantInfo = MerchantInfo.init(param);
|
||||
merchantInfo.setMchNo("M" + System.currentTimeMillis());
|
||||
merchantInfo.setCode("M" + System.currentTimeMillis());
|
||||
merchantInfoManager.save(merchantInfo);
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,9 @@
|
||||
package cn.bootx.platform.daxpay.core.notify.entity;
|
||||
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbComment;
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbTable;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlFieldType;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.constants.MySqlFieldTypeEnum;
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.code.pay.PayChannelEnum;
|
||||
@@ -21,32 +25,44 @@ import java.time.LocalDateTime;
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@DbTable(comment = "回调记录")
|
||||
@Accessors(chain = true)
|
||||
@TableName("pay_pay_notify_record")
|
||||
public class PayNotifyRecord extends MpBaseEntity implements EntityBaseFunction<PayNotifyRecordDto> {
|
||||
|
||||
/** 支付记录id */
|
||||
@DbComment("支付记录id")
|
||||
private Long paymentId;
|
||||
|
||||
/** 商户应用编码 */
|
||||
@DbComment("商户应用编码")
|
||||
private String mchAppCode;
|
||||
|
||||
/**
|
||||
* 支付通道
|
||||
* @see PayChannelEnum#getCode()
|
||||
*/
|
||||
@DbComment("支付通道")
|
||||
private String payChannel;
|
||||
|
||||
/** 通知消息 */
|
||||
@DbMySqlFieldType(MySqlFieldTypeEnum.LONGTEXT)
|
||||
@DbComment("通知消息")
|
||||
private String notifyInfo;
|
||||
|
||||
/**
|
||||
* 处理状态
|
||||
* @see PayStatusCode#NOTIFY_PROCESS_SUCCESS
|
||||
*/
|
||||
@DbComment("处理状态")
|
||||
private String status;
|
||||
|
||||
/** 提示信息 */
|
||||
@DbComment("提示信息")
|
||||
private String msg;
|
||||
|
||||
/** 回调时间 */
|
||||
@DbComment("回调时间")
|
||||
private LocalDateTime notifyTime;
|
||||
|
||||
@Override
|
||||
|
@@ -41,6 +41,8 @@ public class PaymentBuilder {
|
||||
String ip = ServletUtil.getClientIP(request);
|
||||
// 基础信息
|
||||
payment.setBusinessId(payParam.getBusinessId())
|
||||
.setMchCode(payParam.getMchCode())
|
||||
.setMchAppCode(payment.getMchAppCode())
|
||||
.setTitle(payParam.getTitle())
|
||||
.setDescription(payParam.getDescription());
|
||||
|
||||
|
@@ -36,12 +36,12 @@ public abstract class AbsPayCallbackStrategy {
|
||||
/**
|
||||
* 支付回调
|
||||
*/
|
||||
public String payCallback(Map<String, String> params) {
|
||||
public String payCallback(String appCode, Map<String, String> params) {
|
||||
PARAMS.set(params);
|
||||
try {
|
||||
log.info("支付回调处理: {}", params);
|
||||
// 验证消息
|
||||
if (!this.verifyNotify()) {
|
||||
if (!this.verifyNotify(appCode)) {
|
||||
return null;
|
||||
}
|
||||
// 去重处理
|
||||
@@ -49,9 +49,10 @@ public abstract class AbsPayCallbackStrategy {
|
||||
return this.getReturnMsg();
|
||||
}
|
||||
// 调用统一回调处理
|
||||
PayCallbackResult result = payCallbackService.callback(this.getPaymentId(), this.getTradeStatus(), params);
|
||||
PayCallbackResult result = payCallbackService.callback(appCode, this.getPaymentId(), this.getTradeStatus(),
|
||||
params);
|
||||
// 记录回调记录
|
||||
this.saveNotifyRecord(result);
|
||||
this.saveNotifyRecord(appCode, result);
|
||||
}
|
||||
finally {
|
||||
PARAMS.remove();
|
||||
@@ -76,8 +77,9 @@ public abstract class AbsPayCallbackStrategy {
|
||||
|
||||
/**
|
||||
* 验证信息格式
|
||||
* @param mchAppCode 商户应用编码
|
||||
*/
|
||||
public abstract boolean verifyNotify();
|
||||
public abstract boolean verifyNotify(String mchAppCode);
|
||||
|
||||
/**
|
||||
* 获取paymentId
|
||||
@@ -98,10 +100,11 @@ public abstract class AbsPayCallbackStrategy {
|
||||
/**
|
||||
* 保存回调记录
|
||||
*/
|
||||
public void saveNotifyRecord(PayCallbackResult result) {
|
||||
public void saveNotifyRecord(String appCode, PayCallbackResult result) {
|
||||
PayNotifyRecord payNotifyRecord = new PayNotifyRecord().setNotifyInfo(JSONUtil.toJsonStr(PARAMS.get()))
|
||||
.setNotifyTime(LocalDateTime.now())
|
||||
.setPaymentId(this.getPaymentId())
|
||||
.setMchAppCode(appCode)
|
||||
.setPayChannel(this.getPayChannel().getCode())
|
||||
.setStatus(result.getCode())
|
||||
.setMsg(result.getMsg());
|
||||
|
@@ -44,10 +44,11 @@ public class PayCallbackService {
|
||||
|
||||
/**
|
||||
* 统一回调处理
|
||||
* @see PayStatusCode
|
||||
* @param appCode
|
||||
* @param tradeStatus 支付状态
|
||||
* @see PayStatusCode
|
||||
*/
|
||||
public PayCallbackResult callback(Long paymentId, String tradeStatus, Map<String, String> map) {
|
||||
public PayCallbackResult callback(String appCode, Long paymentId, String tradeStatus, Map<String, String> map) {
|
||||
|
||||
// 获取payment和paymentParam数据
|
||||
Payment payment = paymentService.findById(paymentId).orElse(null);
|
||||
|
@@ -1,8 +1,15 @@
|
||||
package cn.bootx.platform.daxpay.core.pay.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.BizException;
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.common.core.util.ValidationUtil;
|
||||
import cn.bootx.platform.daxpay.code.MchAndAppCode;
|
||||
import cn.bootx.platform.daxpay.code.pay.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.core.merchant.dao.MchAppManager;
|
||||
import cn.bootx.platform.daxpay.core.merchant.dao.MerchantInfoManager;
|
||||
import cn.bootx.platform.daxpay.core.merchant.entity.MchApplication;
|
||||
import cn.bootx.platform.daxpay.core.merchant.entity.MerchantInfo;
|
||||
import cn.bootx.platform.daxpay.core.pay.builder.PayEventBuilder;
|
||||
import cn.bootx.platform.daxpay.core.pay.builder.PaymentBuilder;
|
||||
import cn.bootx.platform.daxpay.core.pay.factory.PayStrategyFactory;
|
||||
@@ -15,8 +22,8 @@ import cn.bootx.platform.daxpay.exception.payment.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.exception.payment.PayNotExistedException;
|
||||
import cn.bootx.platform.daxpay.exception.payment.PayUnsupportedMethodException;
|
||||
import cn.bootx.platform.daxpay.mq.PaymentEventSender;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
|
||||
import cn.bootx.platform.daxpay.util.PayWaylUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -45,6 +52,10 @@ public class PayService {
|
||||
|
||||
private final PaymentEventSender eventSender;
|
||||
|
||||
private final MchAppManager mchAppManager;
|
||||
|
||||
private final MerchantInfoManager mchManager;
|
||||
|
||||
/**
|
||||
* 支付方法(同步/异步/组合支付) 同步支付:都只会在第一次执行中就完成支付,例如钱包、积分都是调用完就进行了扣减,完成了支付记录
|
||||
* 异步支付:例如支付宝、微信,发起支付后还需要跳转第三方平台进行支付,支付后通常需要进行回调,之后才完成支付记录
|
||||
@@ -58,7 +69,8 @@ public class PayService {
|
||||
ValidationUtil.validateParam(payParam);
|
||||
// 异步支付方式检查
|
||||
PayWaylUtil.validationAsyncPayMode(payParam);
|
||||
|
||||
// 商户和应用信息检测
|
||||
this.checkMchAndApp(payParam);
|
||||
// 获取并校验支付状态
|
||||
Payment payment = this.getAndCheckPaymentByBusinessId(payParam.getBusinessId());
|
||||
|
||||
@@ -222,6 +234,30 @@ public class PayService {
|
||||
return paymentService.save(payment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户和应用信息检测
|
||||
*/
|
||||
private void checkMchAndApp(PayParam payParam) {
|
||||
MerchantInfo merchantInfo = mchManager.findByCode(payParam.getMchCode())
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
MchApplication mchApp = mchAppManager.findByCode(payParam.getMchAppCode()).orElseThrow(DataNotExistException::new);
|
||||
|
||||
// 商户与应用是否有关联关系
|
||||
if (!Objects.equals(mchApp.getMchCode(), merchantInfo.getCode())) {
|
||||
throw new BizException("商户应用编码与商户不匹配");
|
||||
}
|
||||
|
||||
// 商户是否可用状态
|
||||
if (!Objects.equals(MchAndAppCode.MCH_STATE_NORMAL, merchantInfo.getState())) {
|
||||
throw new BizException("商户状态不可用");
|
||||
}
|
||||
|
||||
// 应用是否可用状态
|
||||
if (!Objects.equals(MchAndAppCode.MCH_APP_STATE_NORMAL, mchApp.getState())) {
|
||||
throw new BizException("商户应用状态不可用");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验支付状态,支付成功则返回,支付失败则抛出对应的异常
|
||||
*/
|
||||
@@ -229,17 +265,17 @@ public class PayService {
|
||||
// 根据订单查询支付记录
|
||||
Payment payment = paymentService.findByBusinessId(businessId).orElse(null);
|
||||
if (Objects.nonNull(payment)) {
|
||||
// 支付失败
|
||||
List<String> trades = Arrays.asList(TRADE_FAIL, TRADE_CANCEL);
|
||||
if (trades.contains(payment.getPayStatus())) {
|
||||
// 支付失败类型状态
|
||||
List<String> tradesStatus = Arrays.asList(TRADE_FAIL, TRADE_CANCEL);
|
||||
if (tradesStatus.contains(payment.getPayStatus())) {
|
||||
throw new PayFailureException("支付失败或已经被撤销");
|
||||
}
|
||||
// 退款状态
|
||||
trades = Arrays.asList(TRADE_REFUNDING, TRADE_REFUNDED);
|
||||
if (trades.contains(payment.getPayStatus())) {
|
||||
// 退款类型状态
|
||||
tradesStatus = Arrays.asList(TRADE_REFUNDING, TRADE_REFUNDED);
|
||||
if (tradesStatus.contains(payment.getPayStatus())) {
|
||||
throw new PayFailureException("支付失败或已经被撤销");
|
||||
}
|
||||
// 支付超时
|
||||
// 支付超时状态
|
||||
if (Objects.nonNull(payment.getExpiredTime())
|
||||
&& LocalDateTimeUtil.ge(LocalDateTime.now(), payment.getExpiredTime())) {
|
||||
throw new PayFailureException("支付已超时");
|
||||
|
@@ -91,13 +91,13 @@ public class AliPayStrategy extends AbsPayStrategy {
|
||||
throw new PayAmountAbnormalException();
|
||||
}
|
||||
// 检查并获取支付宝支付配置
|
||||
this.initAlipayConfig();
|
||||
this.initAlipayConfig(this.getPayParam().getMchAppCode());
|
||||
aliPayService.validation(this.getPayWayParam(), alipayConfig);
|
||||
// 如果没有显式传入同步回调地址, 使用默认配置
|
||||
if (StrUtil.isBlank(aliPayParam.getReturnUrl())) {
|
||||
aliPayParam.setReturnUrl(alipayConfig.getReturnUrl());
|
||||
}
|
||||
this.initAlipayConfig();
|
||||
this.initAlipayConfig(this.getPayParam().getMchAppCode());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +148,7 @@ public class AliPayStrategy extends AbsPayStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void doCancelHandler() {
|
||||
this.initAlipayConfig();
|
||||
this.initAlipayConfig(this.getPayParam().getMchAppCode());
|
||||
// 撤销支付
|
||||
aliPayCancelService.cancelRemote(this.getPayment());
|
||||
// 调用关闭本地支付记录
|
||||
@@ -168,7 +168,7 @@ public class AliPayStrategy extends AbsPayStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void doRefundHandler() {
|
||||
this.initAlipayConfig();
|
||||
this.initAlipayConfig(this.getPayParam().getMchAppCode());
|
||||
aliPayCancelService.refund(this.getPayment(), this.getPayWayParam().getAmount());
|
||||
aliPaymentService.updatePayRefund(this.getPayment().getId(), this.getPayWayParam().getAmount());
|
||||
paymentService.updateRefundSuccess(this.getPayment(), this.getPayWayParam().getAmount(), PayChannelEnum.ALI);
|
||||
@@ -179,16 +179,17 @@ public class AliPayStrategy extends AbsPayStrategy {
|
||||
*/
|
||||
@Override
|
||||
public PaySyncResult doSyncPayStatusHandler() {
|
||||
this.initAlipayConfig();
|
||||
this.initAlipayConfig(this.getPayParam().getMchAppCode());
|
||||
return alipaySyncService.syncPayStatus(this.getPayment());
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化支付宝配置信息
|
||||
*/
|
||||
private void initAlipayConfig() {
|
||||
private void initAlipayConfig(String mchAppCode) {
|
||||
// 检查并获取支付宝支付配置
|
||||
this.alipayConfig = alipayConfigManager.findActivity().orElseThrow(() -> new PayFailureException("支付配置不存在"));
|
||||
this.alipayConfig = alipayConfigManager.findByMchAppCode(mchAppCode)
|
||||
.orElseThrow(() -> new PayFailureException("支付配置不存在"));
|
||||
this.initApiConfig(this.alipayConfig);
|
||||
}
|
||||
|
||||
|
@@ -95,7 +95,7 @@ public class WeChatPayStrategy extends AbsPayStrategy {
|
||||
}
|
||||
|
||||
// 检查并获取微信支付配置
|
||||
this.initWeChatPayConfig();
|
||||
this.initWeChatPayConfig(this.getPayParam().getMchAppCode());
|
||||
weChatPayService.validation(this.getPayWayParam(), weChatPayConfig);
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ public class WeChatPayStrategy extends AbsPayStrategy {
|
||||
@Override
|
||||
public void doCancelHandler() {
|
||||
// 检查并获取微信支付配置
|
||||
this.initWeChatPayConfig();
|
||||
this.initWeChatPayConfig(this.getPayParam().getMchAppCode());
|
||||
weChatPayCancelService.cancelRemote(this.getPayment(), weChatPayConfig);
|
||||
// 调用关闭本地支付记录
|
||||
this.doCloseHandler();
|
||||
@@ -167,7 +167,7 @@ public class WeChatPayStrategy extends AbsPayStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void doRefundHandler() {
|
||||
this.initWeChatPayConfig();
|
||||
this.initWeChatPayConfig(this.getPayParam().getMchAppCode());
|
||||
WeChatPayment weChatPayment = weChatPaymentManager.findByPaymentId(this.getPayment().getId())
|
||||
.orElseThrow(() -> new PayFailureException("微信支付记录不存在"));
|
||||
weChatPayCancelService.refund(this.getPayment(), weChatPayment, this.getPayWayParam().getAmount(),
|
||||
@@ -182,17 +182,17 @@ public class WeChatPayStrategy extends AbsPayStrategy {
|
||||
@Override
|
||||
public PaySyncResult doSyncPayStatusHandler() {
|
||||
// 检查并获取微信支付配置
|
||||
this.initWeChatPayConfig();
|
||||
this.initWeChatPayConfig(this.getPayParam().getMchAppCode());
|
||||
return weChatPaySyncService.syncPayStatus(this.getPayment().getId(), this.weChatPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化微信支付
|
||||
*/
|
||||
private void initWeChatPayConfig() {
|
||||
private void initWeChatPayConfig(String appCode) {
|
||||
// 检查并获取微信支付配置
|
||||
this.weChatPayConfig = Optional.ofNullable(this.weChatPayConfig)
|
||||
.orElse(weChatPayConfigManager.findActivity().orElseThrow(() -> new PayFailureException("支付配置不存在")));
|
||||
.orElse(weChatPayConfigManager.findByMchAppCode(appCode).orElseThrow(() -> new PayFailureException("支付配置不存在")));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.core.payment.entity;
|
||||
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbTable;
|
||||
import cn.bootx.platform.common.core.annotation.BigField;
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
@@ -26,6 +28,7 @@ import java.util.List;
|
||||
* @author xxm
|
||||
* @date 2020/12/8
|
||||
*/
|
||||
@DbTable(isAppend = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@FieldNameConstants
|
||||
@@ -36,6 +39,14 @@ public class Payment extends MpBaseEntity implements EntityBaseFunction<PaymentD
|
||||
/** 关联的业务id */
|
||||
private String businessId;
|
||||
|
||||
/** 商户编码 */
|
||||
@DbColumn(comment = "商户编码")
|
||||
private String mchCode;
|
||||
|
||||
/** 商户应用编码 */
|
||||
@DbColumn(comment = "商户应用编码")
|
||||
private String mchAppCode;
|
||||
|
||||
/** 标题 */
|
||||
private String title;
|
||||
|
||||
|
@@ -25,6 +25,12 @@ public class AlipayConfigDto extends BaseDto implements Serializable {
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "商户编码")
|
||||
private String mchCode;
|
||||
|
||||
@Schema(description = "商户应用编码")
|
||||
private String mchAppCode;
|
||||
|
||||
@Schema(description = "支付宝商户appId")
|
||||
@SensitiveInfo
|
||||
private String appId;
|
||||
@@ -77,7 +83,7 @@ public class AlipayConfigDto extends BaseDto implements Serializable {
|
||||
private Boolean activity;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private Integer state;
|
||||
private String state;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.dto.channel.wechat;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.dto.BaseDto;
|
||||
import cn.bootx.platform.daxpay.code.paymodel.WeChatPayCode;
|
||||
import cn.bootx.platform.starter.data.perm.sensitive.SensitiveInfo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
@@ -32,12 +31,6 @@ public class WeChatPayConfigDto extends BaseDto implements Serializable {
|
||||
@SensitiveInfo
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* @see WeChatPayCode#API_V2
|
||||
*/
|
||||
// @Schema(description = "api版本")
|
||||
// private String apiVersion;
|
||||
|
||||
@Schema(description = "商户平台「API安全」中的 APIv2 密钥")
|
||||
@SensitiveInfo
|
||||
private String apiKeyV2;
|
||||
|
@@ -19,7 +19,7 @@ import lombok.experimental.Accessors;
|
||||
public class MchApplicationDto extends BaseDto {
|
||||
|
||||
@Schema(description = "应用编码")
|
||||
private String appNo;
|
||||
private String code;
|
||||
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
|
@@ -19,13 +19,13 @@ import lombok.experimental.Accessors;
|
||||
public class MerchantInfoDto extends BaseDto {
|
||||
|
||||
@Schema(description = "商户号")
|
||||
private String mchNo;
|
||||
private String code;
|
||||
|
||||
@Schema(description = "商户名称")
|
||||
private String mchName;
|
||||
private String name;
|
||||
|
||||
@Schema(description = "商户简称")
|
||||
private String mchShortName;
|
||||
private String shortName;
|
||||
|
||||
@Schema(description = "类型")
|
||||
private String type;
|
||||
|
@@ -24,12 +24,15 @@ public class PaymentDto extends BaseDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3269223993950227228L;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "关联的业务id")
|
||||
private String businessId;
|
||||
|
||||
@Schema(description = "商户编码")
|
||||
private String mchNo;
|
||||
|
||||
@Schema(description = "商户应用编码")
|
||||
private String mchAppNo;
|
||||
|
||||
@Schema(description = "标题")
|
||||
private String title;
|
||||
|
||||
@@ -40,10 +43,10 @@ public class PaymentDto extends BaseDto implements Serializable {
|
||||
private boolean asyncPayMode;
|
||||
|
||||
/**
|
||||
* @see PayChannelCode
|
||||
* @see cn.bootx.platform.daxpay.code.pay.PayChannelEnum#ASYNC_TYPE_CODE
|
||||
*/
|
||||
@Schema(description = "异步支付通道")
|
||||
private Integer asyncPayChannel;
|
||||
private String asyncPayChannel;
|
||||
|
||||
/**
|
||||
* @see PayStatusCode
|
||||
|
@@ -19,6 +19,9 @@ import java.util.List;
|
||||
@Schema(title = "结算台组合支付参数")
|
||||
public class CashierCombinationPayParam {
|
||||
|
||||
@Schema(description = "商户应用编码")
|
||||
private String mchAppCode;
|
||||
|
||||
@Schema(description = "标题")
|
||||
private String title;
|
||||
|
||||
|
@@ -17,6 +17,9 @@ import java.math.BigDecimal;
|
||||
@Schema(title = "结算台单支付参数")
|
||||
public class CashierSinglePayParam {
|
||||
|
||||
@Schema(description = "商户应用编码")
|
||||
private String mchAppCode;
|
||||
|
||||
@Schema(description = "标题")
|
||||
private String title;
|
||||
|
||||
|
@@ -22,6 +22,12 @@ public class AlipayConfigParam implements Serializable {
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "商户编码")
|
||||
private String mchCode;
|
||||
|
||||
@Schema(description = "商户应用编码")
|
||||
private String mchAppCode;
|
||||
|
||||
@Schema(description = "支付宝商户appId")
|
||||
private String appId;
|
||||
|
||||
@@ -65,7 +71,7 @@ public class AlipayConfigParam implements Serializable {
|
||||
private boolean sandbox;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private Integer state;
|
||||
private String state;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
@@ -24,6 +24,12 @@ public class WeChatPayConfigParam {
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "商户编码")
|
||||
private String mchCode;
|
||||
|
||||
@Schema(description = "商户应用编码")
|
||||
private String mchAppCode;
|
||||
|
||||
@Schema(description = "微信商户号")
|
||||
private String mchId;
|
||||
|
||||
|
@@ -23,15 +23,15 @@ public class MerchantInfoParam {
|
||||
|
||||
@QueryParam(type = LIKE)
|
||||
@Schema(description = "商户号")
|
||||
private String mchNo;
|
||||
private String code;
|
||||
|
||||
@QueryParam(type = LIKE)
|
||||
@Schema(description = "商户名称")
|
||||
private String mchName;
|
||||
private String name;
|
||||
|
||||
@QueryParam(type = LIKE)
|
||||
@Schema(description = "商户简称")
|
||||
private String mchShortName;
|
||||
private String shortName;
|
||||
|
||||
@Schema(description = "类型")
|
||||
private String type;
|
||||
|
@@ -23,6 +23,10 @@ public class PayParam implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3895679513150533566L;
|
||||
|
||||
@Schema(description = "商户编码")
|
||||
@NotEmpty(message = "商户应用不可为空")
|
||||
private String mchCode;
|
||||
|
||||
@Schema(description = "商户应用编码")
|
||||
@NotEmpty(message = "商户应用编码不可为空")
|
||||
private String mchAppCode;
|
||||
|
@@ -58,7 +58,9 @@ public class PayWaylUtil {
|
||||
* 判断是否有异步支付
|
||||
*/
|
||||
public boolean isNotSync(List<PayWayParam> payWayParams) {
|
||||
return payWayParams.stream().map(PayWayParam::getPayChannel).noneMatch(PayChannelEnum.ASYNC_TYPE_CODE::contains);
|
||||
return payWayParams.stream()
|
||||
.map(PayWayParam::getPayChannel)
|
||||
.noneMatch(PayChannelEnum.ASYNC_TYPE_CODE::contains);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +109,7 @@ public class PayWaylUtil {
|
||||
*/
|
||||
public void validationAmount(List<PayWayParam> payModeList) {
|
||||
for (PayWayParam payWayParam : payModeList) {
|
||||
// 同时满足支付金额小于等于零
|
||||
// 支付金额小于等于零
|
||||
if (BigDecimalUtil.compareTo(payWayParam.getAmount(), BigDecimal.ZERO) < 1) {
|
||||
throw new PayAmountAbnormalException();
|
||||
}
|
||||
|
2
pom.xml
2
pom.xml
@@ -71,7 +71,7 @@
|
||||
<ding-talk.version>1.3.81</ding-talk.version>
|
||||
<lock4j.version>2.2.4</lock4j.version>
|
||||
<ip2region.version>2.7.0</ip2region.version>
|
||||
<mybatis-table-modify.version>1.5.3.alpha1</mybatis-table-modify.version>
|
||||
<mybatis-table-modify.version>1.5.3</mybatis-table-modify.version>
|
||||
</properties>
|
||||
|
||||
<!-- 项目依赖版本管理 -->
|
||||
|
Reference in New Issue
Block a user