/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
*
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.service;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.IsvInfo;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.entity.PayInterfaceConfig;
import com.jeequan.jeepay.core.model.params.IsvParams;
import com.jeequan.jeepay.core.model.params.IsvsubMchParams;
import com.jeequan.jeepay.core.model.params.NormalMchParams;
import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig;
import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams;
import com.jeequan.jeepay.core.model.params.alipay.AlipayNormalMchParams;
import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvParams;
import com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams;
import com.jeequan.jeepay.pay.model.*;
import com.jeequan.jeepay.pay.util.ChannelCertConfigKitBean;
import com.jeequan.jeepay.service.impl.IsvInfoService;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.MchInfoService;
import com.jeequan.jeepay.service.impl.PayInterfaceConfigService;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/*
* 商户/服务商 配置信息上下文服务
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:41
*/
@Service
public class ConfigContextService {
/** <商户ID, 商户配置项> **/
private static final Map mchInfoConfigContextMap = new ConcurrentHashMap<>();
/** <应用ID, 商户配置上下文> **/
private static final Map mchAppConfigContextMap = new ConcurrentHashMap<>();
/** <服务商号, 服务商配置上下文> **/
private static final Map isvConfigContextMap = new ConcurrentHashMap<>();
@Autowired private MchInfoService mchInfoService;
@Autowired private MchAppService mchAppService;
@Autowired private IsvInfoService isvInfoService;
@Autowired private PayInterfaceConfigService payInterfaceConfigService;
@Autowired private ChannelCertConfigKitBean channelCertConfigKitBean;
/** 获取 [商户配置信息] **/
public synchronized MchInfoConfigContext getMchInfoConfigContext(String mchNo){
MchInfoConfigContext mchInfoConfigContext = mchInfoConfigContextMap.get(mchNo);
//无此数据, 需要初始化
if(mchInfoConfigContext == null){
initMchInfoConfigContext(mchNo);
}
return mchInfoConfigContextMap.get(mchNo);
}
/** 获取 [商户应用支付参数配置信息] **/
public synchronized MchAppConfigContext getMchAppConfigContext(String mchNo, String appId){
MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(appId);
//无此数据, 需要初始化
if(mchAppConfigContext == null){
initMchAppConfigContext(mchNo, appId);
}
return mchAppConfigContextMap.get(appId);
}
/** 获取 [ISV支付参数配置信息] **/
public synchronized IsvConfigContext getIsvConfigContext(String isvNo){
IsvConfigContext isvConfigContext = isvConfigContextMap.get(isvNo);
//无此数据, 需要初始化
if(isvConfigContext == null){
initIsvConfigContext(isvNo);
}
return isvConfigContextMap.get(isvNo);
}
/** 初始化 [商户配置信息] **/
public synchronized void initMchInfoConfigContext(String mchNo){
//商户主体信息
MchInfo mchInfo = mchInfoService.getById(mchNo);
if(mchInfo == null){ // 查询不到商户主体, 可能已经删除
MchInfoConfigContext mchInfoConfigContext = mchInfoConfigContextMap.get(mchNo);
// 删除所有的商户应用
if(mchInfoConfigContext != null){
mchInfoConfigContext.getAppMap().forEach((k, v) -> mchAppConfigContextMap.remove(k));
}
mchInfoConfigContextMap.remove(mchNo);
return ;
}
MchInfoConfigContext mchInfoConfigContext = new MchInfoConfigContext();
// 设置商户信息
mchInfoConfigContext.setMchNo(mchInfo.getMchNo());
mchInfoConfigContext.setMchType(mchInfo.getType());
mchInfoConfigContext.setMchInfo(mchInfo);
mchAppService.list(MchApp.gw().eq(MchApp::getMchNo, mchNo)).stream().forEach( mchApp -> mchInfoConfigContext.putMchApp(mchApp));
mchInfoConfigContextMap.put(mchNo, mchInfoConfigContext);
}
/** 初始化 [商户应用支付参数配置信息] **/
public synchronized void initMchAppConfigContext(String mchNo, String appId){
// 获取商户的配置信息
MchInfoConfigContext mchInfoConfigContext = getMchInfoConfigContext(mchNo);
if(mchInfoConfigContext == null){ // 商户信息不存在
return;
}
//商户应用信息
MchApp mchApp = mchInfoConfigContext.getMchApp(appId);
if(mchApp == null){ //说明商户主体信息不存在缓存
mchApp = mchAppService.getById(appId);
if(mchApp == null){ // DB查询为空
mchAppConfigContextMap.remove(appId); //清除缓存信息
mchInfoConfigContext.getAppMap().remove(appId); //清除主体信息中的appId
return ;
}
//更新商户信息主体中的商户应用
mchInfoConfigContext.putMchApp(mchApp);
}
//商户主体信息
MchInfo mchInfo = mchInfoConfigContext.getMchInfo();
MchAppConfigContext mchAppConfigContext = new MchAppConfigContext();
// 设置商户信息
mchAppConfigContext.setAppId(appId);
mchAppConfigContext.setMchNo(mchInfo.getMchNo());
mchAppConfigContext.setMchType(mchInfo.getType());
mchAppConfigContext.setMchInfo(mchInfo);
mchAppConfigContext.setMchApp(mchApp);
// 查询商户的所有支持的参数配置
List allConfigList = payInterfaceConfigService.list(PayInterfaceConfig.gw()
.select(PayInterfaceConfig::getIfCode, PayInterfaceConfig::getIfParams)
.eq(PayInterfaceConfig::getState, CS.YES)
.eq(PayInterfaceConfig::getInfoType, CS.INFO_TYPE_MCH_APP)
.eq(PayInterfaceConfig::getInfoId, appId)
);
// 普通商户
if(mchInfo.getType() == CS.MCH_TYPE_NORMAL){
for (PayInterfaceConfig payInterfaceConfig : allConfigList) {
mchAppConfigContext.getNormalMchParamsMap().put(
payInterfaceConfig.getIfCode(),
NormalMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams())
);
}
//放置alipay client
AlipayNormalMchParams alipayParams = mchAppConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.ALIPAY, AlipayNormalMchParams.class);
if(alipayParams != null){
mchAppConfigContext.setAlipayClientWrapper(buildAlipayClientWrapper(
alipayParams.getUseCert(), alipayParams.getSandbox(), alipayParams.getAppId(), alipayParams.getPrivateKey(),
alipayParams.getAlipayPublicKey(), alipayParams.getSignType(), alipayParams.getAppPublicCert(),
alipayParams.getAlipayPublicCert(), alipayParams.getAlipayRootCert()
)
);
}
//放置 wxJavaService
WxpayNormalMchParams wxpayParams = mchAppConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.WXPAY, WxpayNormalMchParams.class);
if(wxpayParams != null){
mchAppConfigContext.setWxServiceWrapper(buildWxServiceWrapper(wxpayParams.getMchId(), wxpayParams.getAppId(),
wxpayParams.getAppSecret(), wxpayParams.getKey(), wxpayParams.getApiVersion(), wxpayParams.getApiV3Key(),
wxpayParams.getSerialNo(), wxpayParams.getCert(), wxpayParams.getApiClientKey()));
}
}else{ //服务商模式商户
for (PayInterfaceConfig payInterfaceConfig : allConfigList) {
mchAppConfigContext.getIsvsubMchParamsMap().put(
payInterfaceConfig.getIfCode(),
IsvsubMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams())
);
}
//放置 当前商户的 服务商信息
mchAppConfigContext.setIsvConfigContext(getIsvConfigContext(mchInfo.getIsvNo()));
}
mchAppConfigContextMap.put(appId, mchAppConfigContext);
}
/** 初始化 [ISV支付参数配置信息] **/
public synchronized void initIsvConfigContext(String isvNo){
IsvConfigContext isvConfigContext = new IsvConfigContext();
IsvInfo isvInfo = isvInfoService.getById(isvNo);
if(isvInfo == null){
//查询出所有商户的配置信息并更新
mchInfoService.list(MchInfo.gw().select(MchInfo::getMchNo).eq(MchInfo::getIsvNo, isvNo)).forEach(mchInfoItem -> {
//将更新已存在缓存的商户配置信息 (每个商户下存储的为同一个 服务商配置的对象指针)
MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(mchInfoItem.getMchNo());
if(mchAppConfigContext != null){
mchAppConfigContext.setIsvConfigContext(null);
}
});
isvConfigContextMap.remove(isvNo); // 服务商有商户不可删除, 此处不再更新商户下的配置信息
return ;
}
// 设置商户信息
isvConfigContext.setIsvNo(isvInfo.getIsvNo());
isvConfigContext.setIsvInfo(isvInfo);
// 查询商户的所有支持的参数配置
List allConfigList = payInterfaceConfigService.list(PayInterfaceConfig.gw()
.select(PayInterfaceConfig::getIfCode, PayInterfaceConfig::getIfParams)
.eq(PayInterfaceConfig::getState, CS.YES)
.eq(PayInterfaceConfig::getInfoType, CS.INFO_TYPE_ISV)
.eq(PayInterfaceConfig::getInfoId, isvNo)
);
for (PayInterfaceConfig payInterfaceConfig : allConfigList) {
isvConfigContext.getIsvParamsMap().put(
payInterfaceConfig.getIfCode(),
IsvParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams())
);
}
//放置alipay client
AlipayIsvParams alipayParams = isvConfigContext.getIsvParamsByIfCode(CS.IF_CODE.ALIPAY, AlipayIsvParams.class);
if(alipayParams != null){
isvConfigContext.setAlipayClientWrapper(buildAlipayClientWrapper(
alipayParams.getUseCert(), alipayParams.getSandbox(), alipayParams.getAppId(), alipayParams.getPrivateKey(),
alipayParams.getAlipayPublicKey(), alipayParams.getSignType(), alipayParams.getAppPublicCert(),
alipayParams.getAlipayPublicCert(), alipayParams.getAlipayRootCert()
)
);
}
//放置 wxJavaService
WxpayIsvParams wxpayParams = isvConfigContext.getIsvParamsByIfCode(CS.IF_CODE.WXPAY, WxpayIsvParams.class);
if(wxpayParams != null){
isvConfigContext.setWxServiceWrapper(buildWxServiceWrapper(wxpayParams.getMchId(), wxpayParams.getAppId(),
wxpayParams.getAppSecret(), wxpayParams.getKey(), wxpayParams.getApiVersion(), wxpayParams.getApiV3Key(),
wxpayParams.getSerialNo(), wxpayParams.getCert(), wxpayParams.getApiClientKey()));
}
isvConfigContextMap.put(isvNo, isvConfigContext);
//查询出所有商户的配置信息并更新
mchInfoService.list(MchInfo.gw().select(MchInfo::getMchNo).eq(MchInfo::getIsvNo, isvNo)).forEach(mchInfoItem -> {
//将更新已存在缓存的商户配置信息 (每个商户下存储的为同一个 服务商配置的对象指针)
MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(mchInfoItem.getMchNo());
if(mchAppConfigContext != null){
mchAppConfigContext.setIsvConfigContext(isvConfigContext);
}
});
}
/*
* 构建支付宝client 包装类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:46
*/
private AlipayClientWrapper buildAlipayClientWrapper(Byte useCert, Byte sandbox, String appId, String privateKey, String alipayPublicKey, String signType, String appCert,
String alipayPublicCert, String alipayRootCert){
//避免空值
sandbox = sandbox == null ? CS.NO : sandbox;
AlipayClient alipayClient = null;
if(useCert != null && useCert == CS.YES){ //证书的方式
CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
certAlipayRequest.setServerUrl(sandbox == CS.YES ? AlipayConfig.SANDBOX_SERVER_URL : AlipayConfig.PROD_SERVER_URL);
certAlipayRequest.setAppId(appId);
certAlipayRequest.setPrivateKey(privateKey);
certAlipayRequest.setFormat(AlipayConfig.FORMAT);
certAlipayRequest.setCharset(AlipayConfig.CHARSET);
certAlipayRequest.setSignType(signType);
certAlipayRequest.setCertPath(channelCertConfigKitBean.getCertFilePath(appCert));
certAlipayRequest.setAlipayPublicCertPath(channelCertConfigKitBean.getCertFilePath(alipayPublicCert));
certAlipayRequest.setRootCertPath(channelCertConfigKitBean.getCertFilePath(alipayRootCert));
try {
alipayClient = new DefaultAlipayClient(certAlipayRequest);
} catch (AlipayApiException e) {
e.printStackTrace();
}
}else{
alipayClient = new DefaultAlipayClient(sandbox == CS.YES ? AlipayConfig.SANDBOX_SERVER_URL : AlipayConfig.PROD_SERVER_URL
, appId, privateKey, AlipayConfig.FORMAT, AlipayConfig.CHARSET,
alipayPublicKey, signType);
}
return new AlipayClientWrapper(useCert, alipayClient);
}
private WxServiceWrapper buildWxServiceWrapper(String mchId, String appId, String appSecret, String mchKey, String apiVersion, String apiV3Key,
String serialNo, String cert, String apiClientKey){
WxPayConfig wxPayConfig = new WxPayConfig();
wxPayConfig.setMchId(mchId);
wxPayConfig.setAppId(appId);
wxPayConfig.setMchKey(mchKey);
if (CS.PAY_IF_VERSION.WX_V2.equals(apiVersion)) { // 微信API V2
wxPayConfig.setSignType(WxPayConstants.SignType.MD5);
} else if (CS.PAY_IF_VERSION.WX_V3.equals(apiVersion)) { // 微信API V3
wxPayConfig.setApiV3Key(apiV3Key);
wxPayConfig.setCertSerialNo(serialNo);
wxPayConfig.setPrivateCertPath(channelCertConfigKitBean.getCertFilePath(cert));
wxPayConfig.setPrivateKeyPath(channelCertConfigKitBean.getCertFilePath(apiClientKey));
}
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(wxPayConfig); //微信配置信息
WxMpDefaultConfigImpl wxMpConfigStorage = new WxMpDefaultConfigImpl();
wxMpConfigStorage.setAppId(appId);
wxMpConfigStorage.setSecret(appSecret);
WxMpService wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(wxMpConfigStorage); //微信配置信息
return new WxServiceWrapper(apiVersion, wxPayService, wxMpService);
}
}