Commit 252369f9 authored by terrfly's avatar terrfly
Browse files

支付网关支持商户应用配置项的下单操作;

parent bc3a2fa5
......@@ -25,7 +25,7 @@ import com.jeequan.jeepay.pay.rqrs.payorder.payway.YsfBarOrderRQ;
import com.jeequan.jeepay.pay.rqrs.payorder.payway.YsfBarOrderRS;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.util.ApiResBuilder;
import com.jeequan.jeepay.pay.model.MchConfigContext;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
......@@ -50,7 +50,7 @@ public class YsfBar extends YsfpayPaymentService {
return null;
}
public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchConfigContext mchConfigContext) throws Exception {
public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception {
String logPrefix = "【云闪付条码(unionpay)支付】";
YsfBarOrderRQ bizRQ = (YsfBarOrderRQ) rq;
......@@ -68,7 +68,7 @@ public class YsfBar extends YsfpayPaymentService {
reqParams.put("termInfo", "{\"ip\": \""+StringUtils.defaultIfEmpty(payOrder.getClientIp(), "127.0.0.1")+"\"}"); //终端信息
// 发送请求
JSONObject resJSON = packageParamAndReq("/gateway/api/pay/micropay", reqParams, logPrefix, mchConfigContext.getIsvConfigContext(), mchConfigContext);
JSONObject resJSON = packageParamAndReq("/gateway/api/pay/micropay", reqParams, logPrefix, mchAppConfigContext.getIsvConfigContext(), mchAppConfigContext);
//请求 & 响应成功, 判断业务逻辑
String respCode = resJSON.getString("respCode"); //应答码
String respMsg = resJSON.getString("respMsg"); //应答信息
......
......@@ -25,7 +25,7 @@ import com.jeequan.jeepay.pay.rqrs.payorder.payway.YsfJsapiOrderRS;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.util.ApiResBuilder;
import com.jeequan.jeepay.pay.model.IsvConfigContext;
import com.jeequan.jeepay.pay.model.MchConfigContext;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
......@@ -44,7 +44,7 @@ public class YsfJsapi extends YsfpayPaymentService {
return null;
}
public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, IsvConfigContext isvConfigContext, MchConfigContext mchConfigContext) throws Exception {
public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, IsvConfigContext isvConfigContext, MchAppConfigContext mchAppConfigContext) throws Exception {
String logPrefix = "【云闪付(unionpay)jsapi支付】";
JSONObject reqParams = new JSONObject();
YsfJsapiOrderRS res = ApiResBuilder.buildSuccess(YsfJsapiOrderRS.class);
......@@ -61,7 +61,7 @@ public class YsfJsapi extends YsfpayPaymentService {
//客户端IP
reqParams.put("customerIp", StringUtils.defaultIfEmpty(payOrder.getClientIp(), "127.0.0.1"));
// 发送请求并返回订单状态
JSONObject resJSON = packageParamAndReq("/gateway/api/pay/unifiedorder", reqParams, logPrefix, isvConfigContext, mchConfigContext);
JSONObject resJSON = packageParamAndReq("/gateway/api/pay/unifiedorder", reqParams, logPrefix, isvConfigContext, mchAppConfigContext);
//请求 & 响应成功, 判断业务逻辑
String respCode = resJSON.getString("respCode"); //应答码
String respMsg = resJSON.getString("respMsg"); //应答信息
......
......@@ -18,10 +18,12 @@ package com.jeequan.jeepay.pay.ctrl;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.ctrls.AbstractCtrl;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.pay.model.MchConfigContext;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.AbstractMchAppRQ;
import com.jeequan.jeepay.pay.rqrs.AbstractRQ;
import com.jeequan.jeepay.pay.service.ConfigContextService;
import com.jeequan.jeepay.pay.service.ValidateService;
......@@ -59,29 +61,40 @@ public abstract class ApiController extends AbstractCtrl {
//获取请求RQ, and 通用验证
T bizRQ = getRQ(cls);
// 转换为 JSON
JSONObject bizReqJSON = (JSONObject)JSONObject.toJSON(bizRQ);
AbstractMchAppRQ abstractMchAppRQ = (AbstractMchAppRQ)bizRQ;
// [2]. 业务校验, 包括: 验签, 商户状态是否可用, 是否支持该支付方式下单等。
String mchNo = bizReqJSON.getString("mchNo");
//业务校验, 包括: 验签, 商户状态是否可用, 是否支持该支付方式下单等。
String mchNo = abstractMchAppRQ.getMchNo();
String appId = abstractMchAppRQ.getAppId();
String sign = bizRQ.getSign();
if(StringUtils.isAnyEmpty(mchNo, sign)){
if(StringUtils.isAnyBlank(mchNo, appId, sign)){
throw new BizException("参数有误!");
}
MchConfigContext mchConfigContext = configContextService.getMchConfigContext(mchNo);
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(mchNo, appId);
MchInfo mchInfo = mchConfigContext == null ? null : mchConfigContext.getMchInfo();
MchInfo mchInfo = mchAppConfigContext == null ? null : mchAppConfigContext.getMchInfo();
if(mchInfo == null || mchInfo.getState() != CS.YES){
throw new BizException("商户不存在或商户状态不可用");
}
MchApp mchApp = mchAppConfigContext == null ? null : mchAppConfigContext.getMchApp();
if(mchInfo == null || mchInfo.getState() != CS.YES){
throw new BizException("商户应用不存在或商户状态不可用");
}
if(!mchApp.getMchNo().equals(mchNo)){
throw new BizException("商户应用与商户号不匹配");
}
// 验签
String privateKey = mchInfo.getPrivateKey();
String appSecret = mchApp.getAppSecret();
// 转换为 JSON
JSONObject bizReqJSON = (JSONObject)JSONObject.toJSON(bizRQ);
bizReqJSON.remove("sign");
if(!sign.equalsIgnoreCase(JeepayKit.getSign(bizReqJSON, privateKey))){
if(!sign.equalsIgnoreCase(JeepayKit.getSign(bizReqJSON, appSecret))){
throw new BizException("验签失败");
}
......
......@@ -17,6 +17,7 @@ package com.jeequan.jeepay.pay.ctrl.payorder;
import cn.hutool.core.date.DateUtil;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.entity.MchPayPassage;
import com.jeequan.jeepay.core.entity.PayOrder;
......@@ -29,7 +30,7 @@ import com.jeequan.jeepay.pay.channel.IPaymentService;
import com.jeequan.jeepay.pay.ctrl.ApiController;
import com.jeequan.jeepay.pay.exception.ChannelException;
import com.jeequan.jeepay.pay.model.IsvConfigContext;
import com.jeequan.jeepay.pay.model.MchConfigContext;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.mq.queue.MqQueue4ChannelOrderQuery;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ;
......@@ -102,6 +103,7 @@ public abstract class AbstractPayOrderController extends ApiController {
}
String mchNo = bizRQ.getMchNo();
String appId = bizRQ.getAppId();
// 只有新订单模式,进行校验
if(isNewOrder && payOrderService.count(PayOrder.gw().eq(PayOrder::getMchNo, mchNo).eq(PayOrder::getMchOrderNo, bizRQ.getMchOrderNo())) > 0){
......@@ -116,18 +118,19 @@ public abstract class AbstractPayOrderController extends ApiController {
}
//获取支付参数 (缓存数据) 和 商户信息
MchConfigContext mchConfigContext = configContextService.getMchConfigContext(mchNo);
if(mchConfigContext == null){
throw new BizException("获取商户信息失败");
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(mchNo, appId);
if(mchAppConfigContext == null){
throw new BizException("获取商户应用信息失败");
}
MchInfo mchInfo = mchConfigContext.getMchInfo();
MchInfo mchInfo = mchAppConfigContext.getMchInfo();
MchApp mchApp = mchAppConfigContext.getMchApp();
//收银台支付并且只有新订单需要走这里, 收银台二次下单的wayCode应该为实际支付方式。
if(isNewOrder && CS.PAY_WAY_CODE.QR_CASHIER.equals(wayCode)){
//生成订单
payOrder = genPayOrder(bizRQ, mchInfo, null);
payOrder = genPayOrder(bizRQ, mchInfo, mchApp, null);
String payOrderId = payOrder.getPayOrderId();
//订单入库 订单状态: 生成状态 此时没有和任何上游渠道产生交互。
payOrderService.save(payOrder);
......@@ -147,12 +150,12 @@ public abstract class AbstractPayOrderController extends ApiController {
}
//获取支付接口
IPaymentService paymentService = checkMchWayCodeAndGetService(mchConfigContext, wayCode);
IPaymentService paymentService = checkMchWayCodeAndGetService(mchAppConfigContext, wayCode);
String ifCode = paymentService.getIfCode();
//生成订单
if(isNewOrder){
payOrder = genPayOrder(bizRQ, mchInfo, ifCode);
payOrder = genPayOrder(bizRQ, mchInfo, mchApp, ifCode);
}else{
payOrder.setIfCode(ifCode);
}
......@@ -169,7 +172,7 @@ public abstract class AbstractPayOrderController extends ApiController {
}
//调起上游支付接口
bizRS = (UnifiedOrderRS) paymentService.pay(bizRQ, payOrder, mchConfigContext);
bizRS = (UnifiedOrderRS) paymentService.pay(bizRQ, payOrder, mchAppConfigContext);
//处理上游返回数据
this.processChannelMsg(bizRS.getChannelRetMsg(), payOrder);
......@@ -197,7 +200,7 @@ public abstract class AbstractPayOrderController extends ApiController {
}
}
private PayOrder genPayOrder(UnifiedOrderRQ rq, MchInfo mchInfo, String ifCode){
private PayOrder genPayOrder(UnifiedOrderRQ rq, MchInfo mchInfo, MchApp mchApp, String ifCode){
PayOrder payOrder = new PayOrder();
payOrder.setPayOrderId(SeqKit.genPayOrderId()); //生成订单ID
......@@ -206,6 +209,7 @@ public abstract class AbstractPayOrderController extends ApiController {
payOrder.setMchName(mchInfo.getMchShortName()); //商户名称(简称)
payOrder.setMchType(mchInfo.getType()); //商户类型
payOrder.setMchOrderNo(rq.getMchOrderNo()); //商户订单号
payOrder.setAppId(mchApp.getAppId()); //商户应用appId
payOrder.setIfCode(ifCode); //接口代码
payOrder.setWayCode(rq.getWayCode()); //支付方式
payOrder.setAmount(rq.getAmount()); //订单金额
......@@ -233,10 +237,10 @@ public abstract class AbstractPayOrderController extends ApiController {
* 校验: 商户的支付方式是否可用
* 返回: 支付接口
* **/
private IPaymentService checkMchWayCodeAndGetService(MchConfigContext mchConfigContext, String wayCode){
private IPaymentService checkMchWayCodeAndGetService(MchAppConfigContext mchAppConfigContext, String wayCode){
// 根据支付方式, 查询出 该商户 可用的支付接口
MchPayPassage mchPayPassage = mchPayPassageService.findMchPayPassage(mchConfigContext.getMchNo(), wayCode);
MchPayPassage mchPayPassage = mchPayPassageService.findMchPayPassage(mchAppConfigContext.getMchNo(), wayCode);
if(mchPayPassage == null){
throw new BizException("该支付方式商户未开通");
}
......@@ -252,20 +256,20 @@ public abstract class AbstractPayOrderController extends ApiController {
throw new BizException("接口不支持该支付方式");
}
if(mchConfigContext.getMchType() == MchInfo.TYPE_NORMAL){ //普通商户
if(mchAppConfigContext.getMchType() == MchInfo.TYPE_NORMAL){ //普通商户
if(mchConfigContext == null || mchConfigContext.getNormalMchParamsByIfCode(ifCode) == null){
throw new BizException("商户参数未配置");
if(mchAppConfigContext == null || mchAppConfigContext.getNormalMchParamsByIfCode(ifCode) == null){
throw new BizException("商户应用参数未配置");
}
}else if(mchConfigContext.getMchType() == MchInfo.TYPE_ISVSUB){ //特约商户
}else if(mchAppConfigContext.getMchType() == MchInfo.TYPE_ISVSUB){ //特约商户
mchConfigContext = configContextService.getMchConfigContext(mchConfigContext.getMchNo());
mchAppConfigContext = configContextService.getMchAppConfigContext(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId());
if(mchConfigContext == null || mchConfigContext.getIsvsubMchParamsByIfCode(ifCode) == null){
if(mchAppConfigContext == null || mchAppConfigContext.getIsvsubMchParamsByIfCode(ifCode) == null){
throw new BizException("特约商户参数未配置");
}
IsvConfigContext isvConfigContext = configContextService.getIsvConfigContext(mchConfigContext.getMchInfo().getIsvNo());
IsvConfigContext isvConfigContext = configContextService.getIsvConfigContext(mchAppConfigContext.getMchInfo().getIsvNo());
if(isvConfigContext == null || isvConfigContext.getIsvParamsByIfCode(ifCode) == null){
throw new BizException("服务商参数未配置");
......@@ -359,7 +363,7 @@ public abstract class AbstractPayOrderController extends ApiController {
bizRS.setErrMsg(bizRS.getChannelRetMsg() != null ? bizRS.getChannelRetMsg().getChannelErrMsg() : null);
}
return ApiRes.okWithSign(bizRS, configContextService.getMchConfigContext(bizRQ.getMchNo()).getMchInfo().getPrivateKey());
return ApiRes.okWithSign(bizRS, configContextService.getMchAppConfigContext(bizRQ.getMchNo(), bizRQ.getAppId()).getMchApp().getAppSecret());
}
......
......@@ -21,7 +21,7 @@ import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.exception.ResponseException;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.pay.channel.IChannelNoticeService;
import com.jeequan.jeepay.pay.model.MchConfigContext;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.service.ConfigContextService;
import com.jeequan.jeepay.pay.service.PayMchNotifyService;
......@@ -102,14 +102,11 @@ public class ChannelNoticeController extends AbstractCtrl {
return this.toReturnPage("支付订单不存在");
}
//查询出商户的配置信息
String mchNo = payOrder.getMchNo();
//查询出商户配置参数
MchConfigContext mchConfigContext = configContextService.getMchConfigContext(mchNo);
//查询出商户应用的配置信息
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(payOrder.getMchNo(), payOrder.getAppId());
//调起接口的回调判断
ChannelRetMsg notifyResult = payNotifyService.doNotice(request, mutablePair.getRight(), payOrder, mchConfigContext, IChannelNoticeService.NoticeTypeEnum.DO_RETURN);
ChannelRetMsg notifyResult = payNotifyService.doNotice(request, mutablePair.getRight(), payOrder, mchAppConfigContext, IChannelNoticeService.NoticeTypeEnum.DO_RETURN);
// 返回null 表明出现异常, 无需处理通知下游等操作。
if(notifyResult == null || notifyResult.getChannelState() == null || notifyResult.getResponseEntity() == null){
......@@ -130,7 +127,7 @@ public class ChannelNoticeController extends AbstractCtrl {
//包含通知地址时
if(hasReturnUrl){
// 重定向
response.sendRedirect(payMchNotifyService.createReturnUrl(payOrder, mchConfigContext.getMchInfo().getPrivateKey()));
response.sendRedirect(payMchNotifyService.createReturnUrl(payOrder, mchAppConfigContext.getMchInfo().getPrivateKey()));
return null;
}else{
......@@ -202,14 +199,11 @@ public class ChannelNoticeController extends AbstractCtrl {
return payNotifyService.doNotifyOrderNotExists(request);
}
//查询出商户的配置信息
String mchNo = payOrder.getMchNo();
//查询出商户配置参数
MchConfigContext mchConfigContext = configContextService.getMchConfigContext(mchNo);
//查询出商户应用的配置信息
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(payOrder.getMchNo(), payOrder.getAppId());
//调起接口的回调判断
ChannelRetMsg notifyResult = payNotifyService.doNotice(request, mutablePair.getRight(), payOrder, mchConfigContext, IChannelNoticeService.NoticeTypeEnum.DO_NOTIFY);
ChannelRetMsg notifyResult = payNotifyService.doNotice(request, mutablePair.getRight(), payOrder, mchAppConfigContext, IChannelNoticeService.NoticeTypeEnum.DO_NOTIFY);
// 返回null 表明出现异常, 无需处理通知下游等操作。
if(notifyResult == null || notifyResult.getChannelState() == null || notifyResult.getResponseEntity() == null){
......
......@@ -61,7 +61,7 @@ public class QueryOrderController extends AbstractPayOrderController {
}
QueryPayOrderRS bizRes = QueryPayOrderRS.buildByPayOrder(payOrder);
return ApiRes.okWithSign(bizRes, configContextService.getMchConfigContext(rq.getMchNo()).getMchInfo().getPrivateKey());
return ApiRes.okWithSign(bizRes, configContextService.getMchAppConfigContext(rq.getMchNo(), rq.getAppId()).getMchApp().getAppSecret());
}
}
......@@ -75,7 +75,7 @@ public class UnifiedOrderController extends AbstractPayOrderController {
res.setPayData(bizRes.buildPayData());
}
return ApiRes.okWithSign(res, configContextService.getMchConfigContext(rq.getMchNo()).getMchInfo().getPrivateKey());
return ApiRes.okWithSign(res, configContextService.getMchAppConfigContext(rq.getMchNo(), rq.getAppId()).getMchApp().getAppSecret());
}
......
......@@ -25,7 +25,7 @@ import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.core.utils.StringKit;
import com.jeequan.jeepay.pay.channel.IChannelUserService;
import com.jeequan.jeepay.pay.ctrl.payorder.AbstractPayOrderController;
import com.jeequan.jeepay.pay.model.MchConfigContext;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.ChannelUserIdRQ;
import com.jeequan.jeepay.pay.service.ConfigContextService;
import com.jeequan.jeepay.service.impl.SysConfigService;
......@@ -71,6 +71,7 @@ public class ChannelUserIdController extends AbstractPayOrderController {
JSONObject jsonObject = new JSONObject();
jsonObject.put("mchNo", rq.getMchNo());
jsonObject.put("appId", rq.getAppId());
jsonObject.put("ifCode", ifCode);
jsonObject.put("redirectUrl", rq.getRedirectUrl());
......@@ -78,8 +79,8 @@ public class ChannelUserIdController extends AbstractPayOrderController {
String callbackUrl = sysConfigService.getDBApplicationConfig().genMchChannelUserIdApiOauth2RedirectUrlEncode(jsonObject);
//获取商户配置信息
MchConfigContext mchConfigContext = configContextService.getMchConfigContext(rq.getMchNo());
String redirectUrl = channelUserService.buildUserRedirectUrl(callbackUrl, mchConfigContext);
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(rq.getMchNo(), rq.getAppId());
String redirectUrl = channelUserService.buildUserRedirectUrl(callbackUrl, mchAppConfigContext);
response.sendRedirect(redirectUrl);
}
......@@ -92,6 +93,7 @@ public class ChannelUserIdController extends AbstractPayOrderController {
JSONObject callbackData = JSON.parseObject(JeepayKit.aesDecode(aesData));
String mchNo = callbackData.getString("mchNo");
String appId = callbackData.getString("appId");
String ifCode = callbackData.getString("ifCode");
String redirectUrl = callbackData.getString("redirectUrl");
......@@ -103,10 +105,10 @@ public class ChannelUserIdController extends AbstractPayOrderController {
}
//获取商户配置信息
MchConfigContext mchConfigContext = configContextService.getMchConfigContext(mchNo);
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(mchNo, appId);
//获取渠道用户ID
String channelUserId = channelUserService.getChannelUserId(getReqParamJSON(), mchConfigContext);
String channelUserId = channelUserService.getChannelUserId(getReqParamJSON(), mchAppConfigContext);
//同步跳转
response.sendRedirect(StringKit.appendUrlQuery(redirectUrl, JsonKit.newJson("channelUserId", channelUserId)));
......
......@@ -28,7 +28,7 @@ import com.jeequan.jeepay.pay.rqrs.payorder.payway.AliJsapiOrderRQ;
import com.jeequan.jeepay.pay.rqrs.payorder.payway.WxJsapiOrderRQ;
import com.jeequan.jeepay.pay.service.PayMchNotifyService;
import com.jeequan.jeepay.pay.service.ConfigContextService;
import com.jeequan.jeepay.pay.model.MchConfigContext;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.service.impl.PayOrderService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -65,11 +65,11 @@ public class QrCashierController extends AbstractPayOrderController {
String redirectUrlEncode = sysConfigService.getDBApplicationConfig().genOauth2RedirectUrlEncode(payOrder.getPayOrderId());
//获取商户配置信息
MchConfigContext mchConfigContext = configContextService.getMchConfigContext(payOrder.getMchNo());
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(payOrder.getMchNo(), payOrder.getAppId());
//获取接口并返回数据
IChannelUserService channelUserService = getServiceByWayCode(getWayCode(), "ChannelUserService", IChannelUserService.class);
return ApiRes.ok(channelUserService.buildUserRedirectUrl(redirectUrlEncode, mchConfigContext));
return ApiRes.ok(channelUserService.buildUserRedirectUrl(redirectUrlEncode, mchAppConfigContext));
}
......@@ -85,9 +85,9 @@ public class QrCashierController extends AbstractPayOrderController {
String wayCode = getWayCode();
//获取商户配置信息
MchConfigContext mchConfigContext = configContextService.getMchConfigContext(payOrder.getMchNo());
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(payOrder.getMchNo(), payOrder.getAppId());
IChannelUserService channelUserService = getServiceByWayCode(wayCode, "ChannelUserService", IChannelUserService.class);
return ApiRes.ok(channelUserService.getChannelUserId(getReqParamJSON(), mchConfigContext));
return ApiRes.ok(channelUserService.getChannelUserId(getReqParamJSON(), mchAppConfigContext));
}
......@@ -106,7 +106,7 @@ public class QrCashierController extends AbstractPayOrderController {
resOrder.setMchOrderNo(payOrder.getMchOrderNo());
resOrder.setMchName(payOrder.getMchName());
resOrder.setAmount(payOrder.getAmount());
resOrder.setReturnUrl(payMchNotifyService.createReturnUrl(payOrder, configContextService.getMchConfigContext(payOrder.getMchNo()).getMchInfo().getPrivateKey()));
resOrder.setReturnUrl(payMchNotifyService.createReturnUrl(payOrder, configContextService.getMchAppConfigContext(payOrder.getMchNo(), payOrder.getAppId()).getMchApp().getAppSecret()));
return ApiRes.ok(resOrder);
}
......
......@@ -15,6 +15,7 @@
*/
package com.jeequan.jeepay.pay.model;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.model.params.IsvsubMchParams;
import com.jeequan.jeepay.core.model.params.NormalMchParams;
......@@ -24,23 +25,25 @@ import java.util.HashMap;
import java.util.Map;
/*
* 商户支付参数信息
* 用户 放置到内存, 避免多次查询操作
* 商户应用支付参数信息
* 放置到内存, 避免多次查询操作
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:29
*/
@Data
public class MchConfigContext {
public class MchAppConfigContext {
/** 商户信息缓存 */
private String mchNo;
private String appId;
private Byte mchType;
private MchInfo mchInfo;
private MchApp mchApp;
/** 商户支付配置信息缓存 */
/** 商户支付配置信息缓存, <接口代码, 支付参数> */
private Map<String, NormalMchParams> normalMchParamsMap = new HashMap<>();
private Map<String, IsvsubMchParams> isvsubMchParamsMap = new HashMap<>();
......
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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.model;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.entity.MchInfo;
import lombok.Data;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/*
* 商户配置信息
* 放置到内存, 避免多次查询操作
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:29
*/
@Data
public class MchInfoConfigContext {
/** 商户信息缓存 */
private String mchNo;
private Byte mchType;
private MchInfo mchInfo;
private Map<String, MchApp> appMap = new ConcurrentHashMap<>();
/** 重置商户APP **/
public void putMchApp(MchApp mchApp){
appMap.put(mchApp.getAppId(), mchApp);
}
/** get商户APP **/
public MchApp getMchApp(String appId){
return appMap.get(appId);
}
}
......@@ -15,6 +15,7 @@
*/
package com.jeequan.jeepay.pay.mq.topic;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.service.ConfigContextService;
import lombok.extern.slf4j.Slf4j;
......@@ -40,14 +41,30 @@ public class MqTopic4ModifyMchInfo extends ActiveMQTopic{
super(CS.MQ.TOPIC_MODIFY_MCH_INFO);
}
/** 接收 更新系统配置项的消息 **/
/** 接收 [商户配置信息] 的消息
* 已知推送节点:
* 1. 更新商户基本资料和状态
* 2. 删除商户时
* **/
@JmsListener(destination = CS.MQ.TOPIC_MODIFY_MCH_INFO, containerFactory = "jmsListenerContainer")
public void receive(String mchNo) {
log.info("重置商户信息, msg={}", mchNo);
configContextService.initMchConfigContext(mchNo);
log.info("接收 [商户配置信息] 的消息, msg={}", mchNo);
configContextService.initMchInfoConfigContext(mchNo);
}
/** 接收 [商户应用支付参数配置信息] 的消息
* 已知推送节点:
* 1. 更新商户应用配置
* 2. 删除商户应用配置
* **/
@JmsListener(destination = CS.MQ.TOPIC_MODIFY_MCH_APP, containerFactory = "jmsListenerContainer")
public void receiveMchApp(String mchNoAndAppId) {
log.info("接收 [商户应用支付参数配置信息] 的消息, msg={}", mchNoAndAppId);
JSONObject jsonObject = (JSONObject) JSONObject.parse(mchNoAndAppId);
configContextService.initMchAppConfigContext(jsonObject.getString("mchNo"), jsonObject.getString("appId"));
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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.rqrs;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/*
*
* 通用RQ, 包含mchNo和appId 必填项
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/16 10:30
*/
@Data
public class AbstractMchAppRQ extends AbstractRQ {
/** 商户号 **/
@NotBlank(message="商户号不能为空")
private String mchNo;
/** 商户应用ID **/
@NotBlank(message="商户应用ID不能为空")
private String appId;
}
......@@ -27,7 +27,7 @@ import javax.validation.constraints.NotBlank;
* @date 2021/6/8 17:40
*/
@Data
public class ChannelUserIdRQ extends AbstractRQ{
public class ChannelUserIdRQ extends AbstractMchAppRQ{
/** 商户号 **/
@NotBlank(message="商户号不能为空")
......
......@@ -27,11 +27,7 @@ import javax.validation.constraints.NotBlank;
* @date 2021/6/8 17:40
*/
@Data
public class QueryPayOrderRQ extends AbstractRQ{
/** 商户号 **/
@NotBlank(message="商户号不能为空")
private String mchNo;
public class QueryPayOrderRQ extends AbstractMchAppRQ{
/** 商户订单号 **/
private String mchOrderNo;
......
......@@ -17,7 +17,7 @@ package com.jeequan.jeepay.pay.rqrs.payorder;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.rqrs.AbstractRQ;
import com.jeequan.jeepay.pay.rqrs.AbstractMchAppRQ;
import com.jeequan.jeepay.pay.rqrs.payorder.payway.*;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
......@@ -36,15 +36,7 @@ import javax.validation.constraints.NotNull;
* @date 2021/6/8 17:33
*/
@Data
public class UnifiedOrderRQ extends AbstractRQ {
/** 商户号 **/
@NotBlank(message="商户号不能为空")
private String mchNo;
/** 商户应用ID **/
@NotBlank(message="商户应用ID不能为空")
private String appId;
public class UnifiedOrderRQ extends AbstractMchAppRQ {
/** 商户订单号 **/
@NotBlank(message="商户订单号不能为空")
......
......@@ -18,7 +18,7 @@ package com.jeequan.jeepay.pay.service;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.pay.channel.IPayOrderQueryService;
import com.jeequan.jeepay.pay.model.MchConfigContext;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.service.impl.PayOrderService;
import lombok.extern.slf4j.Slf4j;
......@@ -58,11 +58,10 @@ public class ChannelOrderReissueService {
return null;
}
//查询出商户的配置信息
String mchNo = payOrder.getMchNo();
MchConfigContext mchConfigContext = configContextService.getMchConfigContext(mchNo);
//查询出商户应用的配置信息
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(payOrder.getMchNo(), payOrder.getAppId());
ChannelRetMsg channelRetMsg = queryService.query(payOrder, mchConfigContext);
ChannelRetMsg channelRetMsg = queryService.query(payOrder, mchAppConfigContext);
if(channelRetMsg == null){
log.error("channelRetMsg is null");
return null;
......
......@@ -25,6 +25,7 @@ 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;
......@@ -35,13 +36,10 @@ 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.config.SystemYmlConfig;
import com.jeequan.jeepay.pay.model.AlipayClientWrapper;
import com.jeequan.jeepay.pay.model.IsvConfigContext;
import com.jeequan.jeepay.pay.model.MchConfigContext;
import com.jeequan.jeepay.pay.model.WxServiceWrapper;
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;
......@@ -50,7 +48,6 @@ import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
......@@ -65,29 +62,49 @@ import java.util.concurrent.ConcurrentHashMap;
@Service
public class ConfigContextService {
private static final Map<String, MchConfigContext> mchConfigContextMap = new ConcurrentHashMap<>();
/** <商户ID, 商户配置项> **/
private static final Map<String, MchInfoConfigContext> mchInfoConfigContextMap = new ConcurrentHashMap<>();
/** <应用ID, 商户配置上下文> **/
private static final Map<String, MchAppConfigContext> mchAppConfigContextMap = new ConcurrentHashMap<>();
/** <服务商号, 服务商配置上下文> **/
private static final Map<String, IsvConfigContext> isvConfigContextMap = new ConcurrentHashMap<>();
@Autowired private MchInfoService mchInfoService;
@Autowired private MchAppService mchAppService;
@Autowired private IsvInfoService isvInfoService;
@Autowired private PayInterfaceConfigService payInterfaceConfigService;
@Autowired private SystemYmlConfig mainConfig;
@Autowired private ChannelCertConfigKitBean channelCertConfigKitBean;
/** 获取支付参数 **/
public synchronized MchConfigContext getMchConfigContext(String mchNo){
MchConfigContext mchConfigContext = mchConfigContextMap.get(mchNo);
/** 获取 [商户配置信息] **/
public synchronized MchInfoConfigContext getMchInfoConfigContext(String mchNo){
MchInfoConfigContext mchInfoConfigContext = mchInfoConfigContextMap.get(mchNo);
//无此数据, 需要初始化
if(mchConfigContext == null){
initMchConfigContext(mchNo);
if(mchInfoConfigContext == null){
initMchInfoConfigContext(mchNo);
}
return mchInfoConfigContextMap.get(mchNo);
}
return mchConfigContextMap.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);
......@@ -101,34 +118,80 @@ public class ConfigContextService {
}
/** 获取支付参数 **/
public synchronized void initMchConfigContext(String mchNo){
/** 初始化 [商户配置信息] **/
public synchronized void initMchInfoConfigContext(String mchNo){
MchConfigContext mchConfigContext = new MchConfigContext();
//商户主体信息
MchInfo mchInfo = mchInfoService.getById(mchNo);
if(mchInfo == null){
mchConfigContextMap.remove(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));
}
/** 初始化 [商户应用支付参数配置信息] **/
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); //清除缓存信息
return ;
}
//更新商户信息主体中的商户应用
mchInfoConfigContext.putMchApp(mchApp);
}
//商户主体信息
MchInfo mchInfo = mchInfoConfigContext.getMchInfo();
MchAppConfigContext mchAppConfigContext = new MchAppConfigContext();
// 设置商户信息
mchConfigContext.setMchNo(mchInfo.getMchNo());
mchConfigContext.setMchType(mchInfo.getType());
mchConfigContext.setMchInfo(mchInfo);
mchAppConfigContext.setMchNo(mchInfo.getMchNo());
mchAppConfigContext.setMchType(mchInfo.getType());
mchAppConfigContext.setMchInfo(mchInfo);
mchAppConfigContext.setMchApp(mchApp);
// 查询商户的所有支持的参数配置
List<PayInterfaceConfig> allConfigList = payInterfaceConfigService.list(PayInterfaceConfig.gw()
.select(PayInterfaceConfig::getIfCode, PayInterfaceConfig::getIfParams)
.eq(PayInterfaceConfig::getState, CS.YES)
.eq(PayInterfaceConfig::getInfoType, CS.INFO_TYPE_MCH)
.eq(PayInterfaceConfig::getInfoId, mchNo)
.eq(PayInterfaceConfig::getInfoType, CS.INFO_TYPE_MCH_APP)
.eq(PayInterfaceConfig::getInfoId, appId)
);
// 普通商户
if(mchInfo.getType() == CS.MCH_TYPE_NORMAL){
for (PayInterfaceConfig payInterfaceConfig : allConfigList) {
mchConfigContext.getNormalMchParamsMap().put(
mchAppConfigContext.getNormalMchParamsMap().put(
payInterfaceConfig.getIfCode(),
NormalMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams())
);
......@@ -136,10 +199,10 @@ public class ConfigContextService {
//放置alipay client
AlipayNormalMchParams alipayParams = mchConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.ALIPAY, AlipayNormalMchParams.class);
AlipayNormalMchParams alipayParams = mchAppConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.ALIPAY, AlipayNormalMchParams.class);
if(alipayParams != null){
mchConfigContext.setAlipayClientWrapper(buildAlipayClientWrapper(
mchAppConfigContext.setAlipayClientWrapper(buildAlipayClientWrapper(
alipayParams.getUseCert(), alipayParams.getSandbox(), alipayParams.getAppId(), alipayParams.getPrivateKey(),
alipayParams.getAlipayPublicKey(), alipayParams.getSignType(), alipayParams.getAppPublicCert(),
alipayParams.getAlipayPublicCert(), alipayParams.getAlipayRootCert()
......@@ -149,9 +212,9 @@ public class ConfigContextService {
}
//放置 wxJavaService
WxpayNormalMchParams wxpayParams = mchConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.WXPAY, WxpayNormalMchParams.class);
WxpayNormalMchParams wxpayParams = mchAppConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.WXPAY, WxpayNormalMchParams.class);
if(wxpayParams != null){
mchConfigContext.setWxServiceWrapper(buildWxServiceWrapper(wxpayParams.getMchId(), wxpayParams.getAppId(),
mchAppConfigContext.setWxServiceWrapper(buildWxServiceWrapper(wxpayParams.getMchId(), wxpayParams.getAppId(),
wxpayParams.getAppSecret(), wxpayParams.getKey(), wxpayParams.getApiVersion(), wxpayParams.getApiV3Key(),
wxpayParams.getSerialNo(), wxpayParams.getCert(), wxpayParams.getApiClientKey()));
}
......@@ -159,22 +222,22 @@ public class ConfigContextService {
}else{ //服务商模式商户
for (PayInterfaceConfig payInterfaceConfig : allConfigList) {
mchConfigContext.getIsvsubMchParamsMap().put(
mchAppConfigContext.getIsvsubMchParamsMap().put(
payInterfaceConfig.getIfCode(),
IsvsubMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams())
);
}
//放置 当前商户的 服务商信息
mchConfigContext.setIsvConfigContext(getIsvConfigContext(mchInfo.getIsvNo()));
mchAppConfigContext.setIsvConfigContext(getIsvConfigContext(mchInfo.getIsvNo()));
}
mchConfigContextMap.put(mchNo, mchConfigContext);
mchAppConfigContextMap.put(appId, mchAppConfigContext);
}
/** 初始化 **/
/** 初始化 [ISV支付参数配置信息] **/
public synchronized void initIsvConfigContext(String isvNo){
IsvConfigContext isvConfigContext = new IsvConfigContext();
......@@ -185,9 +248,9 @@ public class ConfigContextService {
mchInfoService.list(MchInfo.gw().select(MchInfo::getMchNo).eq(MchInfo::getIsvNo, isvNo)).forEach(mchInfoItem -> {
//将更新已存在缓存的商户配置信息 (每个商户下存储的为同一个 服务商配置的对象指针)
MchConfigContext mchConfigContext = mchConfigContextMap.get(mchInfoItem.getMchNo());
if(mchConfigContext != null){
mchConfigContext.setIsvConfigContext(null);
MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(mchInfoItem.getMchNo());
if(mchAppConfigContext != null){
mchAppConfigContext.setIsvConfigContext(null);
}
});
isvConfigContextMap.remove(isvNo); // 服务商有商户不可删除, 此处不再更新商户下的配置信息
......@@ -238,9 +301,9 @@ public class ConfigContextService {
mchInfoService.list(MchInfo.gw().select(MchInfo::getMchNo).eq(MchInfo::getIsvNo, isvNo)).forEach(mchInfoItem -> {
//将更新已存在缓存的商户配置信息 (每个商户下存储的为同一个 服务商配置的对象指针)
MchConfigContext mchConfigContext = mchConfigContextMap.get(mchInfoItem.getMchNo());
if(mchConfigContext != null){
mchConfigContext.setIsvConfigContext(isvConfigContext);
MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(mchInfoItem.getMchNo());
if(mchAppConfigContext != null){
mchAppConfigContext.setIsvConfigContext(isvConfigContext);
}
});
......
......@@ -110,7 +110,7 @@ public class PayMchNotifyService {
/**
* 创建响应URL
*/
public String createReturnUrl(PayOrder payOrder, String mchKey) {
public String createReturnUrl(PayOrder payOrder, String appSecret) {
if(StringUtils.isEmpty(payOrder.getReturnUrl())){
return "";
......@@ -121,7 +121,7 @@ public class PayMchNotifyService {
jsonObject.put("reqTime", System.currentTimeMillis()); //添加请求时间
// 报文签名
jsonObject.put("sign", JeepayKit.getSign(jsonObject, mchKey)); // 签名
jsonObject.put("sign", JeepayKit.getSign(jsonObject, appSecret)); // 签名
// 生成跳转地址
return StringKit.appendUrlQuery(payOrder.getReturnUrl(), jsonObject);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment