Commit de3de82d authored by dingzhiwei's avatar dingzhiwei
Browse files

初始化Jeepay项目

parent 40dcaf4a
/*
* 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.payorder.payway;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/*
* 支付方式: WX_BAR
*
* @author zhuxiao
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class WxBarOrderRQ extends UnifiedOrderRQ {
/** 用户 支付条码 **/
@NotBlank(message = "支付条码不能为空")
private String authCode;
/** 构造函数 **/
public WxBarOrderRQ(){
this.setWayCode(CS.PAY_WAY_CODE.WX_BAR); //默认 wx_bar, 避免validate出现问题
}
}
/*
* 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.payorder.payway;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRS;
import lombok.Data;
/*
* 支付方式: WX_BAR
*
* @author zhuxiao
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class WxBarOrderRS extends UnifiedOrderRS {
@Override
public String buildPayDataType(){
return CS.PAY_DATA_TYPE.NONE;
}
@Override
public String buildPayData(){
return "";
}
}
package com.jeequan.jeepay.pay.rqrs.payorder.payway;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.rqrs.payorder.CommonPayDataRQ;
import lombok.Data;
/*
* 支付方式: WX_H5
*
* @author zhuxiao
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class WxH5OrderRQ extends CommonPayDataRQ {
/** 构造函数 **/
public WxH5OrderRQ() {
this.setWayCode(CS.PAY_WAY_CODE.WX_H5);
}
}
/*
* 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.payorder.payway;
import com.jeequan.jeepay.pay.rqrs.payorder.CommonPayDataRS;
import lombok.Data;
/*
* 支付方式: WX_H5
*
* @author zhuxiao
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class WxH5OrderRS extends CommonPayDataRS {
}
/*
* 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.payorder.payway;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/*
* 支付方式: WX_JSAPI
*
* @author zhuxiao
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class WxJsapiOrderRQ extends UnifiedOrderRQ {
/** 微信openid **/
@NotBlank(message = "openid不能为空")
private String openid;
/** 构造函数 **/
public WxJsapiOrderRQ(){
this.setWayCode(CS.PAY_WAY_CODE.WX_JSAPI);
}
}
/*
* 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.payorder.payway;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRS;
import lombok.Data;
/*
* 支付方式: WX_JSAPI
*
* @author zhuxiao
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class WxJsapiOrderRS extends UnifiedOrderRS {
/** 预支付数据包 **/
private String payInfo;
@Override
public String buildPayDataType(){
return CS.PAY_DATA_TYPE.WX_APP;
}
@Override
public String buildPayData(){
return payInfo;
}
}
/*
* 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.payorder.payway;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.rqrs.payorder.CommonPayDataRQ;
import lombok.Data;
/*
* 支付方式: WX_NATIVE
*
* @author zhuxiao
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class WxNativeOrderRQ extends CommonPayDataRQ {
/** 构造函数 **/
public WxNativeOrderRQ() {
this.setWayCode(CS.PAY_WAY_CODE.WX_NATIVE);
}
}
/*
* 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.payorder.payway;
import com.jeequan.jeepay.pay.rqrs.payorder.CommonPayDataRS;
import lombok.Data;
/*
* 支付方式: WX_NATIVE
*
* @author zhuxiao
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class WxNativeOrderRS extends CommonPayDataRS {
}
/*
* 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.payorder.payway;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/*
* 支付方式: YSF_BAR
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class YsfBarOrderRQ extends UnifiedOrderRQ {
/** 用户 支付条码 **/
@NotBlank(message = "支付条码不能为空")
private String authCode;
/** 构造函数 **/
public YsfBarOrderRQ(){
this.setWayCode(CS.PAY_WAY_CODE.YSF_BAR);
}
}
/*
* 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.payorder.payway;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRS;
import lombok.Data;
/*
* 支付方式: YSF_BAR
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class YsfBarOrderRS extends UnifiedOrderRS {
@Override
public String buildPayDataType(){
return CS.PAY_DATA_TYPE.NONE;
}
@Override
public String buildPayData(){
return "";
}
}
/*
* 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.payorder.payway;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ;
import lombok.Data;
/*
* 支付方式: YSF_JSAPI
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class YsfJsapiOrderRQ extends UnifiedOrderRQ {
/** 构造函数 **/
public YsfJsapiOrderRQ(){
this.setWayCode(CS.PAY_WAY_CODE.YSF_JSAPI);
}
}
/*
* 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.payorder.payway;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.utils.JsonKit;
import com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRS;
import lombok.Data;
/*
* 支付方式: YSF_JSAPI
*
* @author pangxiaoyu
* @site https://www.jeepay.vip
* @date 2021/6/8 17:34
*/
@Data
public class YsfJsapiOrderRS extends UnifiedOrderRS {
/** 调起支付插件的云闪付订单号 **/
private String redirectUrl;
@Override
public String buildPayDataType(){
return CS.PAY_DATA_TYPE.YSF_APP;
}
@Override
public String buildPayData(){
return JsonKit.newJson("redirectUrl", redirectUrl).toString();
}
}
/*
* 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.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.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.service.impl.PayOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/*
* 查询上游订单, & 补单服务实现类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:40
*/
@Service
@Slf4j
public class ChannelOrderReissueService {
@Autowired private ConfigContextService configContextService;
@Autowired private PayOrderService payOrderService;
@Autowired private PayMchNotifyService payMchNotifyService;
/** 处理订单 **/
public ChannelRetMsg processPayOrder(PayOrder payOrder){
try {
String payOrderId = payOrder.getPayOrderId();
//查询支付接口是否存在
IPayOrderQueryService queryService = SpringBeansUtil.getBean(payOrder.getIfCode() + "PayOrderQueryService", IPayOrderQueryService.class);
// 支付通道接口实现不存在
if(queryService == null){
log.error("{} interface not exists!", payOrder.getIfCode());
return null;
}
//查询出商户的配置信息
String mchNo = payOrder.getMchNo();
MchConfigContext mchConfigContext = configContextService.getMchConfigContext(mchNo);
ChannelRetMsg channelRetMsg = queryService.query(payOrder, mchConfigContext);
if(channelRetMsg == null){
log.error("channelRetMsg is null");
return null;
}
log.info("补单[{}]查询结果为:{}", payOrderId, channelRetMsg);
// 查询成功
if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS) {
if (payOrderService.updateIng2Success(payOrderId, channelRetMsg.getChannelOrderId())) {
// 通知商户系统
if(StringUtils.isNotEmpty(payOrder.getNotifyUrl())){
payMchNotifyService.payOrderNotify(payOrderService.getById(payOrderId));
}
}
}else if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_FAIL){ //确认失败
//1. 更新支付订单表为失败状态
payOrderService.updateIng2Fail(payOrderId, channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelErrCode(), channelRetMsg.getChannelErrMsg());
}
return channelRetMsg;
} catch (Exception e) { //继续下一次迭代查询
log.error("error payOrderId = {}", payOrder.getPayOrderId(), e);
return null;
}
}
}
/*
* 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.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.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.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.util.ChannelCertConfigKitBean;
import com.jeequan.jeepay.service.impl.IsvInfoService;
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.io.File;
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 {
private static final Map<String, MchConfigContext> mchConfigContextMap = new ConcurrentHashMap<>();
private static final Map<String, IsvConfigContext> isvConfigContextMap = new ConcurrentHashMap<>();
@Autowired private MchInfoService mchInfoService;
@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);
//无此数据, 需要初始化
if(mchConfigContext == null){
initMchConfigContext(mchNo);
}
return mchConfigContextMap.get(mchNo);
}
/** 获取支付参数 **/
public synchronized IsvConfigContext getIsvConfigContext(String isvNo){
IsvConfigContext isvConfigContext = isvConfigContextMap.get(isvNo);
//无此数据, 需要初始化
if(isvConfigContext == null){
initIsvConfigContext(isvNo);
}
return isvConfigContextMap.get(isvNo);
}
/** 获取支付参数 **/
public synchronized void initMchConfigContext(String mchNo){
MchConfigContext mchConfigContext = new MchConfigContext();
MchInfo mchInfo = mchInfoService.getById(mchNo);
if(mchInfo == null){
mchConfigContextMap.remove(mchNo);
return ;
}
// 设置商户信息
mchConfigContext.setMchNo(mchInfo.getMchNo());
mchConfigContext.setMchType(mchInfo.getType());
mchConfigContext.setMchInfo(mchInfo);
// 查询商户的所有支持的参数配置
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)
);
// 普通商户
if(mchInfo.getType() == CS.MCH_TYPE_NORMAL){
for (PayInterfaceConfig payInterfaceConfig : allConfigList) {
mchConfigContext.getNormalMchParamsMap().put(
payInterfaceConfig.getIfCode(),
NormalMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams())
);
}
//放置alipay client
AlipayNormalMchParams alipayParams = mchConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.ALIPAY, AlipayNormalMchParams.class);
if(alipayParams != null){
mchConfigContext.setAlipayClientWrapper(buildAlipayClientWrapper(
alipayParams.getUseCert(), alipayParams.getSandbox(), alipayParams.getAppId(), alipayParams.getPrivateKey(),
alipayParams.getAlipayPublicKey(), alipayParams.getSignType(), alipayParams.getAppPublicCert(),
alipayParams.getAlipayPublicCert(), alipayParams.getAlipayRootCert()
)
);
}
//放置 wxJavaService
WxpayNormalMchParams wxpayParams = mchConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.WXPAY, WxpayNormalMchParams.class);
if(wxpayParams != null){
mchConfigContext.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) {
mchConfigContext.getIsvsubMchParamsMap().put(
payInterfaceConfig.getIfCode(),
IsvsubMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams())
);
}
//放置 当前商户的 服务商信息
mchConfigContext.setIsvConfigContext(getIsvConfigContext(mchInfo.getIsvNo()));
}
mchConfigContextMap.put(mchNo, mchConfigContext);
}
/** 初始化 **/
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 -> {
//将更新已存在缓存的商户配置信息 (每个商户下存储的为同一个 服务商配置的对象指针)
MchConfigContext mchConfigContext = mchConfigContextMap.get(mchInfoItem.getMchNo());
if(mchConfigContext != null){
mchConfigContext.setIsvConfigContext(null);
}
});
isvConfigContextMap.remove(isvNo); // 服务商有商户不可删除, 此处不再更新商户下的配置信息
return ;
}
// 设置商户信息
isvConfigContext.setIsvNo(isvInfo.getIsvNo());
isvConfigContext.setIsvInfo(isvInfo);
// 查询商户的所有支持的参数配置
List<PayInterfaceConfig> 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 -> {
//将更新已存在缓存的商户配置信息 (每个商户下存储的为同一个 服务商配置的对象指针)
MchConfigContext mchConfigContext = mchConfigContextMap.get(mchInfoItem.getMchNo());
if(mchConfigContext != null){
mchConfigContext.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);
}
}
/*
* 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.service;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.entity.MchNotifyRecord;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.pay.mq.queue.MqQueue4PayOrderMchNotify;
import com.jeequan.jeepay.pay.rqrs.QueryPayOrderRS;
import com.jeequan.jeepay.service.impl.MchInfoService;
import com.jeequan.jeepay.service.impl.MchNotifyRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
/*
* 商户通知 service
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:43
*/
@Slf4j
@Service
public class PayMchNotifyService {
@Autowired private MchNotifyRecordService mchNotifyRecordService;
@Autowired private MchInfoService mchInfoService;
@Autowired private MqQueue4PayOrderMchNotify mqPayOrderMchNotifyQueue;
/** 商户通知信息, 只有订单是终态,才会发送通知, 如明确成功和明确失败 **/
public void payOrderNotify(PayOrder dbPayOrder){
try {
// 通知地址为空
if(StringUtils.isEmpty(dbPayOrder.getNotifyUrl())){
return ;
}
//获取到通知对象
MchNotifyRecord mchNotifyRecord = mchNotifyRecordService.findByPayOrder(dbPayOrder.getPayOrderId());
if(mchNotifyRecord != null){
log.info("当前已存在通知消息, 不再发送。");
return ;
}
//构建数据
MchInfo mchInfo = mchInfoService.getById(dbPayOrder.getMchNo());
// 封装通知url
String notifyUrl = createNotifyUrl(dbPayOrder, mchInfo.getPrivateKey());
mchNotifyRecord = new MchNotifyRecord();
mchNotifyRecord.setOrderId(dbPayOrder.getPayOrderId());
mchNotifyRecord.setOrderType(MchNotifyRecord.TYPE_PAY_ORDER);
mchNotifyRecord.setMchNo(dbPayOrder.getMchNo());
mchNotifyRecord.setMchOrderNo(dbPayOrder.getMchOrderNo()); //商户订单号
mchNotifyRecord.setIsvNo(dbPayOrder.getIsvNo());
mchNotifyRecord.setNotifyUrl(notifyUrl);
mchNotifyRecord.setResResult("");
mchNotifyRecord.setNotifyCount(0);
mchNotifyRecord.setState(MchNotifyRecord.STATE_ING); // 通知中
mchNotifyRecordService.save(mchNotifyRecord);
//推送到MQ
Long notifyId = mchNotifyRecord.getNotifyId();
mqPayOrderMchNotifyQueue.send(notifyId + "");
} catch (Exception e) {
log.error("推送失败!", e);
}
}
/**
* 创建响应URL
*/
public String createNotifyUrl(PayOrder payOrder, String mchKey) {
QueryPayOrderRS queryPayOrderRS = QueryPayOrderRS.buildByPayOrder(payOrder);
JSONObject jsonObject = (JSONObject)JSONObject.toJSON(queryPayOrderRS);
jsonObject.put("reqTime", System.currentTimeMillis()); //添加请求时间
// 先对原文签名
String reqSign = JeepayKit.getSign(jsonObject, mchKey);
jsonObject.put("sign", reqSign); // 签名
// 生成参数串
String param = JeepayKit.genUrlParams(jsonObject);
//响应结果
return payOrder.getNotifyUrl() + "?" + param;
}
/**
* 创建响应URL
*/
public String createReturnUrl(PayOrder payOrder, String mchKey) {
if(StringUtils.isEmpty(payOrder.getReturnUrl())){
return "";
}
QueryPayOrderRS queryPayOrderRS = QueryPayOrderRS.buildByPayOrder(payOrder);
JSONObject jsonObject = (JSONObject)JSONObject.toJSON(queryPayOrderRS);
jsonObject.put("reqTime", System.currentTimeMillis()); //添加请求时间
jsonObject.keySet().stream().forEach(key -> jsonObject.put(key, ( jsonObject.getString(key) == null ? null : URLEncoder.encode(jsonObject.getString(key))) ));
// 先对原文签名
String reqSign = JeepayKit.getSign(jsonObject, mchKey);
jsonObject.put("sign", reqSign); // 签名
// 生成参数串
String param = JeepayKit.genUrlParams(jsonObject);
//响应结果
return payOrder.getReturnUrl() + "?" + param;
}
}
/*
* 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.service;
import com.jeequan.jeepay.core.exception.BizException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.Set;
/*
* 通用 Validator
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:47
*/
@Service
public class ValidateService {
@Autowired private Validator validator;
public void validate(Object obj){
Set<ConstraintViolation<Object>> resultSet = validator.validate(obj);
if(resultSet == null || resultSet.isEmpty()){
return ;
}
resultSet.stream().forEach(item -> {throw new BizException(item.getMessage());});
}
}
/*
* 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.task;
import com.jeequan.jeepay.service.impl.PayOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/*
* 订单过期定时任务
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:47
*/
@Slf4j
@Component
public class PayOrderExpiredTask {
@Autowired private PayOrderService payOrderService;
@Scheduled(cron="0 0/1 * * * ?") // 每分钟执行一次
public void start() {
int updateCount = payOrderService.updateOrderExpired();
log.info("处理订单超时{}条.", updateCount);
}
}
/*
* 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.task;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.pay.service.ChannelOrderReissueService;
import com.jeequan.jeepay.service.impl.PayOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
/*
* 补单定时任务
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:47
*/
@Slf4j
@Component
public class PayOrderReissueTask {
private static final int QUERY_PAGE_SIZE = 100; //每次查询数量
@Autowired private PayOrderService payOrderService;
@Autowired private ChannelOrderReissueService channelOrderReissueService;
@Scheduled(cron="0 0/1 * * * ?") // 每分钟执行一次
public void start() {
//当前时间 减去10分钟。
Date offsetDate = DateUtil.offsetMinute(new Date(), -10);
//查询条件: 支付中的订单 & ( 订单创建时间 + 10分钟 >= 当前时间 )
LambdaQueryWrapper<PayOrder> lambdaQueryWrapper = PayOrder.gw().eq(PayOrder::getState, PayOrder.STATE_ING).le(PayOrder::getCreatedAt, offsetDate);
int currentPageIndex = 1; //当前页码
while(true){
try {
IPage<PayOrder> payOrderIPage = payOrderService.page(new Page(currentPageIndex, QUERY_PAGE_SIZE), lambdaQueryWrapper);
if(payOrderIPage == null || payOrderIPage.getRecords().isEmpty()){ //本次查询无结果, 不再继续查询;
break;
}
for(PayOrder payOrder: payOrderIPage.getRecords()){
channelOrderReissueService.processPayOrder(payOrder);
}
//已经到达页码最大量,无需再次查询
if(payOrderIPage.getPages() <= currentPageIndex){
break;
}
currentPageIndex++;
} catch (Exception e) { //出现异常,直接退出,避免死循环。
log.error("error", e);
break;
}
}
}
}
/*
* 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.util;
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
/*
* api响应结果构造器
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:45
*/
public class ApiResBuilder {
/** 构建自定义响应对象, 默认响应成功 **/
public static <T extends AbstractRS> T buildSuccess(Class<? extends AbstractRS> T){
try {
T result = (T)T.newInstance();
return result;
} catch (Exception e) { return null; }
}
}
package com.jeequan.jeepay.pay.util;
import com.jeequan.jeepay.pay.config.SystemYmlConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.File;
/*
* 支付平台 获取系统文件工具类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/6/8 17:45
*/
@Component
public class ChannelCertConfigKitBean {
@Autowired private SystemYmlConfig systemYmlConfig;
public String getCertFilePath(String certFilePath){
return systemYmlConfig.getOssFile().getPrivatePath() + File.separator + certFilePath;
}
public File getCertFile(String certFilePath){
return new File(getCertFilePath(certFilePath));
}
}
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