Commit f608cd83 authored by zhuxiao's avatar zhuxiao
Browse files

优化微信V3支付

parent 2af0f6ec
......@@ -25,6 +25,7 @@ import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams;
import com.jeequan.jeepay.pay.channel.AbstractPaymentService;
import com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel;
import com.jeequan.jeepay.pay.model.WxServiceWrapper;
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
import com.jeequan.jeepay.pay.rqrs.payorder.UnifiedOrderRQ;
......@@ -116,53 +117,59 @@ public class WxpayPaymentService extends AbstractPaymentService {
/**
* 构建微信APIV3接口 统一下单请求数据
* @author terrfly
* @param payOrder
* @return
*/
public JSONObject buildV3OrderRequest(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) {
public WxpayV3OrderRequestModel buildV3OrderRequestModel(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) {
String payOrderId = payOrder.getPayOrderId();
// 微信统一下单请求对象
JSONObject reqJSON = new JSONObject();
reqJSON.put("out_trade_no", payOrderId);
reqJSON.put("description", payOrder.getSubject());
WxpayV3OrderRequestModel result = new WxpayV3OrderRequestModel();
result.setOutTradeNo(payOrderId);
result.setDescription(payOrder.getSubject());
// 订单失效时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,示例值:2018-06-08T10:34:56+08:00
reqJSON.put("time_expire", String.format("%sT%s+08:00", DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATE_FORMAT), DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_TIME_FORMAT)));
result.setTimeExpire(String.format("%sT%s+08:00", DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATE_FORMAT), DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_TIME_FORMAT)));
reqJSON.put("notify_url", getNotifyUrl(payOrderId));
result.setNotifyUrl(getNotifyUrl(payOrderId));
JSONObject amount = new JSONObject();
amount.put("total", payOrder.getAmount().intValue());
amount.put("currency", "CNY");
reqJSON.put("amount", amount);
// 订单金额
result.setAmount(new WxpayV3OrderRequestModel.Amount().setCurrency("CNY").setTotal(payOrder.getAmount().intValue()));
JSONObject sceneInfo = new JSONObject();
sceneInfo.put("payer_client_ip", payOrder.getClientIp());
reqJSON.put("scene_info", sceneInfo);
// 场景信息
result.setSceneInfo(new WxpayV3OrderRequestModel.SceneInfo().setPayerClientIp(payOrder.getClientIp()));
//订单分账, 将冻结商户资金。
if(isDivisionOrder(payOrder)){
JSONObject settleInfo = new JSONObject();
settleInfo.put("profit_sharing", true);
reqJSON.put("settle_info", settleInfo);
result.setSettleInfo(new WxpayV3OrderRequestModel.SettleInfo().setProfitSharing(true));
}
WxPayService wxPayService = configContextQueryService.getWxServiceWrapper(mchAppConfigContext).getWxPayService();
if(mchAppConfigContext.isIsvsubMch()){ // 特约商户
WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode());
reqJSON.put("sp_appid", wxPayService.getConfig().getAppId());
reqJSON.put("sp_mchid", wxPayService.getConfig().getMchId());
reqJSON.put("sub_mchid", isvsubMchParams.getSubMchId());
// 服务商相关参数
result.setSpAppid(wxPayService.getConfig().getAppId());
result.setSpMchid(wxPayService.getConfig().getMchId());
result.setSubMchid(isvsubMchParams.getSubMchId());
if (StringUtils.isNotBlank(isvsubMchParams.getSubMchAppId())) {
reqJSON.put("sub_appid", isvsubMchParams.getSubMchAppId());
result.setSubAppid(isvsubMchParams.getSubMchAppId());
}
}else { // 普通商户
reqJSON.put("appid", wxPayService.getConfig().getAppId());
reqJSON.put("mchid", wxPayService.getConfig().getMchId());
result.setNormalMchid(wxPayService.getConfig().getMchId());
result.setNormalAppid(wxPayService.getConfig().getAppId());
}
return reqJSON;
return result;
}
}
......@@ -24,6 +24,7 @@ import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.PemUtils;
import com.github.binarywang.wxpay.v3.util.SignUtils;
import com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
......@@ -56,11 +57,6 @@ public class WxpayV3Util {
ISV_URL_MAP.put(WxPayConstants.TradeType.MWEB, "/v3/pay/partner/transactions/h5");
}
public static JSONObject unifiedOrderV3(String reqUrl, JSONObject reqJSON, WxPayService wxPayService) throws WxPayException {
String response = wxPayService.postV3(PAY_BASE_URL + reqUrl, reqJSON.toJSONString());
return JSONObject.parseObject(getPayInfo(response, wxPayService.getConfig()));
}
public static JSONObject queryOrderV3(String url, WxPayService wxPayService) throws WxPayException {
String response = wxPayService.getV3(PAY_BASE_URL + url);
return JSON.parseObject(response);
......@@ -90,81 +86,41 @@ public class WxpayV3Util {
}
public static String getPayInfo(String response, WxPayConfig wxPayConfig) throws WxPayException {
try {
JSONObject resJSON = JSON.parseObject(response);
String timestamp = String.valueOf(System.currentTimeMillis() / 1000L);
String nonceStr = SignUtils.genRandomStr();
String prepayId = resJSON.getString("prepay_id");
switch(wxPayConfig.getTradeType()) {
case WxPayConstants.TradeType.JSAPI: {
Map<String, String> payInfo = new HashMap<>(); // 如果用JsonObject会出现签名错误
String appid = wxPayConfig.getAppId(); // 用户在服务商appid下的唯一标识
if (StringUtils.isNotEmpty(wxPayConfig.getSubAppId())) {
appid = wxPayConfig.getSubAppId(); // 用户在子商户appid下的唯一标识
}
payInfo.put("appId", appid);
payInfo.put("timeStamp", timestamp);
payInfo.put("nonceStr", nonceStr);
payInfo.put("package", "prepay_id=" + prepayId);
payInfo.put("signType", "RSA");
String beforeSign = String.format("%s\n%s\n%s\n%s\n", appid, timestamp, nonceStr, "prepay_id=" + prepayId);
payInfo.put("paySign", SignUtils.sign(beforeSign, PemUtils.loadPrivateKey(new FileInputStream(wxPayConfig.getPrivateKeyPath()))));
// 签名以后在增加prepayId参数
payInfo.put("prepayId", prepayId);
return JSON.toJSONString(payInfo);
}
case WxPayConstants.TradeType.MWEB: {
return response;
}
case WxPayConstants.TradeType.APP: {
Map<String, String> payInfo = new HashMap<>();
// APP支付绑定的是微信开放平台上的账号,APPID为开放平台上绑定APP后发放的参数
String wxAppId = wxPayConfig.getAppId();
// 此map用于参与调起sdk支付的二次签名,格式全小写,timestamp只能是10位,格式固定,切勿修改
String partnerId = wxPayConfig.getMchId();
if (StringUtils.isNotEmpty(wxPayConfig.getSubAppId())) {
wxAppId = wxPayConfig.getSubAppId();
partnerId = wxPayConfig.getSubMchId();
}
String packageValue = "Sign=WXPay";
// 此map用于客户端与微信服务器交互
String beforeSign = String.format("%s\n%s\n%s\n%s\n", wxAppId, timestamp, nonceStr, prepayId);
payInfo.put("sign", SignUtils.sign(beforeSign, PemUtils.loadPrivateKey(new FileInputStream(wxPayConfig.getPrivateKeyPath()))));
payInfo.put("prepayId", prepayId);
payInfo.put("partnerId", partnerId);
payInfo.put("appId", wxAppId);
payInfo.put("package", packageValue);
payInfo.put("timeStamp", timestamp);
payInfo.put("nonceStr", nonceStr);
return JSON.toJSONString(payInfo);
}
case WxPayConstants.TradeType.NATIVE:
return response;
default:
return null;
}
} catch (Exception e) {
throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
/**
* 功能描述:
* 统一调起微信支付请求
* @param model
* @param wxPayService
* @param isIsvsubMch
* @param tradeType
* @param wxCallBack
* @Return: java.lang.String
* @Author: terrfly
* @Date: 2022/4/25 12:38
*/
public static String commonReqWx(WxpayV3OrderRequestModel model, WxPayService wxPayService, boolean isIsvsubMch, String tradeType, WxCallBack wxCallBack) throws WxPayException {
// 请求地址
String reqUrl = PAY_BASE_URL + NORMALMCH_URL_MAP.get(tradeType);
if(isIsvsubMch){ // 特约商户
reqUrl = PAY_BASE_URL + ISV_URL_MAP.get(tradeType);
}
}
public static JSONObject processIsvPayer(String subAppId, String openId) {
JSONObject payer = new JSONObject();
// 子商户subAppId不为空
if (StringUtils.isNotBlank(subAppId)) {
payer.put("sub_openid", openId); // 用户在子商户appid下的唯一标识
}else {
payer.put("sp_openid", openId); // 用户在服务商appid下的唯一标识
// 调起http请求
String response = wxPayService.postV3(reqUrl, JSON.toJSONString(model));
JSONObject wxRes = JSON.parseObject(response);
if(wxCallBack != null){
return wxCallBack.genPayInfo(wxRes);
}
return payer;
return response;
}
public interface WxCallBack{
/** 生成返回数据 */
String genPayInfo(JSONObject wxRes);
}
}
/*
* 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.channel.wxpay.model;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import lombok.experimental.Accessors;
/**
*
* 微信V3支付请求参数类
* @author terrfly
* @site https://www.jeequan.com
* @date 2022/4/25 11:52
*/
@Data
@Accessors(chain = true)
public class WxpayV3OrderRequestModel {
/** 服务商应用ID */
@JSONField(name = "sp_appid")
private String spAppid;
/** 服务商户号 */
@JSONField(name = "sp_mchid")
private String spMchid;
/** 子商户号 */
@JSONField(name = "sub_mchid")
private String subMchid;
/** 子商户应用ID */
@JSONField(name = "sub_appid")
private String subAppid;
/** 普通商户: 商户号 */
@JSONField(name = "mchid")
private String normalMchid;
/** 普通商户: appId */
@JSONField(name = "appid")
private String normalAppid;
/** 商户订单号 */
@JSONField(name = "out_trade_no")
private String outTradeNo;
/** 商品描述 */
private String description;
/** 交易结束时间 */
@JSONField(name = "time_expire")
private String timeExpire;
/** 附加数据 */
private String attach;
/** 通知地址 */
@JSONField(name = "notify_url")
private String notifyUrl;
/** 订单优惠标记 */
@JSONField(name = "goods_tag")
private String goodsTag;
/** 结算信息 */
@JSONField(name = "settle_info")
private SettleInfo settleInfo;
/** 订单金额 */
private Amount amount;
/** 支付者 */
private Payer payer;
/** 场景信息 */
@JSONField(name = "scene_info")
private SceneInfo sceneInfo;
/** 场景信息 **/
@Data
@Accessors(chain = true)
public static class SceneInfo{
/** 用户终端IP */
@JSONField(name = "payer_client_ip")
private String payerClientIp;
/** 商户端设备号 */
@JSONField(name = "device_id")
private String deviceId;
/** 商户端设备号 */
@JSONField(name = "h5_info")
private H5Info h5Info;
/** H5场景信息 */
@Data
@Accessors(chain = true)
public static class H5Info{
/** 场景类型 */
@JSONField(name = "type")
private String type;
}
}
/** 结算信息 **/
@Data
@Accessors(chain = true)
public static class SettleInfo{
/** 用户服务标识 */
@JSONField(name = "profit_sharing")
private Boolean profitSharing;
}
/** 支付者 **/
@Data
@Accessors(chain = true)
public static class Payer{
/** 普通商户的: 用户服务标识 */
@JSONField(name = "openid")
private String normalOpenId;
/** 用户服务标识 */
@JSONField(name = "sp_openid")
private String spOpenid;
/** 用户子标识 */
@JSONField(name = "sub_openid")
private String subOpenid;
}
/** 订单金额 **/
@Data
@Accessors(chain = true)
public static class Amount{
/** 总金额 */
private Integer total;
/** 货币类似 */
private String currency;
}
}
......@@ -15,14 +15,21 @@
*/
package com.jeequan.jeepay.pay.channel.wxpay.paywayV3;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.PemUtils;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams;
import com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams;
import com.jeequan.jeepay.pay.channel.wxpay.WxpayPaymentService;
import com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit;
import com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util;
import com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.model.WxServiceWrapper;
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
......@@ -33,6 +40,10 @@ import com.jeequan.jeepay.pay.util.ApiResBuilder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 微信 app支付
*
......@@ -53,25 +64,9 @@ public class WxApp extends WxpayPaymentService {
WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);
WxPayService wxPayService = wxServiceWrapper.getWxPayService();
wxPayService.getConfig().setTradeType(WxPayConstants.TradeType.APP);
// 构造请求数据
JSONObject reqJSON = buildV3OrderRequest(payOrder, mchAppConfigContext);
// wxPayConfig 添加子商户参数
if(mchAppConfigContext.isIsvsubMch()){
wxPayService.getConfig().setSubMchId(reqJSON.getString("sub_mchid"));
if (StringUtils.isNotBlank(reqJSON.getString("sub_appid"))) {
wxPayService.getConfig().setSubAppId(reqJSON.getString("sub_appid"));
}
}
String reqUrl; // 请求地址
if(mchAppConfigContext.isIsvsubMch()){ // 特约商户
reqUrl = WxpayV3Util.ISV_URL_MAP.get(WxPayConstants.TradeType.APP);
}else {
reqUrl = WxpayV3Util.NORMALMCH_URL_MAP.get(WxPayConstants.TradeType.APP);
}
WxpayV3OrderRequestModel wxpayV3OrderRequestModel = buildV3OrderRequestModel(payOrder, mchAppConfigContext);
// 构造函数响应数据
WxAppOrderRS res = ApiResBuilder.buildSuccess(WxAppOrderRS.class);
......@@ -79,12 +74,51 @@ public class WxApp extends WxpayPaymentService {
res.setChannelRetMsg(channelRetMsg);
// 调起上游接口:
// 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭
// 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。
try {
JSONObject resJSON = WxpayV3Util.unifiedOrderV3(reqUrl, reqJSON, wxPayService);
String payInfo = WxpayV3Util.commonReqWx(wxpayV3OrderRequestModel, wxPayService, mchAppConfigContext.isIsvsubMch(), WxPayConstants.TradeType.APP,
(JSONObject wxRes) -> {
// 普通商户,App支付与公众号支付 同一个应用只能配置其中一个
String resultAppId = wxpayV3OrderRequestModel.getNormalAppid();
String resultMchId = wxpayV3OrderRequestModel.getNormalMchid();
// 特约商户,App支付与公众号支付 同一个应用只能配置其中一个
if(mchAppConfigContext.isIsvsubMch()){
resultAppId = wxpayV3OrderRequestModel.getSubAppid();
resultMchId = wxpayV3OrderRequestModel.getSubMchid();
}
WxPayUnifiedOrderV3Result wxPayUnifiedOrderV3Result = new WxPayUnifiedOrderV3Result();
wxPayUnifiedOrderV3Result.setPrepayId(wxRes.getString("prepay_id"));
try {
FileInputStream fis = new FileInputStream(wxPayService.getConfig().getPrivateKeyPath());
WxPayUnifiedOrderV3Result.AppResult appResult =
wxPayUnifiedOrderV3Result.getPayInfo(TradeTypeEnum.APP, resultAppId, resultMchId,
PemUtils.loadPrivateKey(fis));
JSONObject jsonRes = (JSONObject) JSON.toJSON(appResult);
jsonRes.put("package", jsonRes.getString("packageValue"));
jsonRes.remove("packageValue");
try {
fis.close();
} catch (IOException e) {
}
return JSON.toJSONString(jsonRes);
} catch (FileNotFoundException e) {
return null;
}
}
);
res.setPayInfo(resJSON.toJSONString());
res.setPayData(payInfo);
// 支付中
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING);
......
......@@ -26,6 +26,7 @@ import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.pay.channel.wxpay.WxpayPaymentService;
import com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit;
import com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util;
import com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.model.WxServiceWrapper;
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
......@@ -58,25 +59,12 @@ public class WxH5 extends WxpayPaymentService {
WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);
WxPayService wxPayService = wxServiceWrapper.getWxPayService();
wxPayService.getConfig().setTradeType(WxPayConstants.TradeType.MWEB);
// 构造请求数据
JSONObject reqJSON = buildV3OrderRequest(payOrder, mchAppConfigContext);
WxpayV3OrderRequestModel wxpayV3OrderRequestModel = buildV3OrderRequestModel(payOrder, mchAppConfigContext);
JSONObject sceneInfo = reqJSON.getJSONObject("scene_info");
JSONObject h5Info = new JSONObject();
h5Info.put("type", "iOS, Android, Wap");
sceneInfo.put("h5_info", h5Info);
reqJSON.put("scene_info", sceneInfo);
String reqUrl; // 请求地址
if(mchAppConfigContext.isIsvsubMch()){ // 特约商户
reqUrl = WxpayV3Util.ISV_URL_MAP.get(WxPayConstants.TradeType.MWEB);
}else {
reqUrl = WxpayV3Util.NORMALMCH_URL_MAP.get(WxPayConstants.TradeType.MWEB);
}
// 场景信息
wxpayV3OrderRequestModel.getSceneInfo().setH5Info(new WxpayV3OrderRequestModel.SceneInfo.H5Info().setType("iOS, Android, Wap"));
// 构造函数响应数据
WxH5OrderRS res = ApiResBuilder.buildSuccess(WxH5OrderRS.class);
......@@ -84,10 +72,10 @@ public class WxH5 extends WxpayPaymentService {
res.setChannelRetMsg(channelRetMsg);
// 调起上游接口:
// 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭
// 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。
try {
JSONObject resJSON = WxpayV3Util.unifiedOrderV3(reqUrl, reqJSON, wxPayService);
String payInfo = WxpayV3Util.commonReqWx(wxpayV3OrderRequestModel, wxPayService, mchAppConfigContext.isIsvsubMch(), WxPayConstants.TradeType.MWEB, null);
JSONObject resJSON = JSONObject.parseObject(payInfo);
// 拼接returnUrl
String payUrl = String.format("%s&redirect_url=%s", resJSON.getString("h5_url"), URLEncodeUtil.encode(getReturnUrlOnlyJump(payOrder.getPayOrderId())));
......
......@@ -15,14 +15,21 @@
*/
package com.jeequan.jeepay.pay.channel.wxpay.paywayV3;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.PemUtils;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams;
import com.jeequan.jeepay.pay.channel.wxpay.WxpayPaymentService;
import com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit;
import com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util;
import com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.model.WxServiceWrapper;
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
......@@ -34,6 +41,10 @@ import com.jeequan.jeepay.pay.util.ApiResBuilder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 微信 jsapi支付
*
......@@ -56,28 +67,24 @@ public class WxJsapi extends WxpayPaymentService {
WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq;
WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);
WxPayService wxPayService = wxServiceWrapper.getWxPayService();
wxPayService.getConfig().setTradeType(WxPayConstants.TradeType.JSAPI);
// 构造请求数据
JSONObject reqJSON = buildV3OrderRequest(payOrder, mchAppConfigContext);
WxpayV3OrderRequestModel wxpayV3OrderRequestModel = buildV3OrderRequestModel(payOrder, mchAppConfigContext);
// 特约商户
if(mchAppConfigContext.isIsvsubMch()) {
// wxPayConfig 添加子商户参数
if(mchAppConfigContext.isIsvsubMch()){
wxPayService.getConfig().setSubMchId(reqJSON.getString("sub_mchid"));
if (StringUtils.isNotBlank(reqJSON.getString("sub_appid"))) {
wxPayService.getConfig().setSubAppId(reqJSON.getString("sub_appid"));
// 子商户subAppId不为空
if(StringUtils.isNotBlank(wxpayV3OrderRequestModel.getSubAppid())){
wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setSubOpenid(bizRQ.getOpenid()));
}else{ // 使用的服务商配置的公众号appId获取
wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setSpOpenid(bizRQ.getOpenid()));
}
}
String reqUrl;
if(mchAppConfigContext.isIsvsubMch()){ // 特约商户
reqUrl = WxpayV3Util.ISV_URL_MAP.get(WxPayConstants.TradeType.JSAPI);
reqJSON.put("payer", WxpayV3Util.processIsvPayer(reqJSON.getString("sub_appid"), bizRQ.getOpenid()));
}else {
reqUrl = WxpayV3Util.NORMALMCH_URL_MAP.get(WxPayConstants.TradeType.JSAPI);
JSONObject payer = new JSONObject();
payer.put("openid", bizRQ.getOpenid());
reqJSON.put("payer", payer);
}else{ //普通商户 设置openId即可。
wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setNormalOpenId(bizRQ.getOpenid()));
}
// 构造函数响应数据
......@@ -89,9 +96,47 @@ public class WxJsapi extends WxpayPaymentService {
// 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭
// 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。
try {
JSONObject resJSON = WxpayV3Util.unifiedOrderV3(reqUrl, reqJSON, wxPayService);
// 调起接口 modify 20220425 by terrfly : 改为统一调用的方式, 将返回数据包放置在业务层进行处理 。
String payInfo = WxpayV3Util.commonReqWx(wxpayV3OrderRequestModel, wxPayService, mchAppConfigContext.isIsvsubMch(), WxPayConstants.TradeType.JSAPI,
(JSONObject wxRes) -> {
// 普通商户
String resultAppId = wxpayV3OrderRequestModel.getNormalAppid();
// 特约商户
if(mchAppConfigContext.isIsvsubMch()){
resultAppId = StringUtils.defaultIfEmpty(wxpayV3OrderRequestModel.getSubAppid(), wxpayV3OrderRequestModel.getSpAppid());
}
WxPayUnifiedOrderV3Result wxPayUnifiedOrderV3Result = new WxPayUnifiedOrderV3Result();
wxPayUnifiedOrderV3Result.setPrepayId(wxRes.getString("prepay_id"));
try {
FileInputStream fis = new FileInputStream(wxPayService.getConfig().getPrivateKeyPath());
WxPayUnifiedOrderV3Result.JsapiResult jsapiResult =
wxPayUnifiedOrderV3Result.getPayInfo(TradeTypeEnum.JSAPI, resultAppId, null,
PemUtils.loadPrivateKey(fis));
JSONObject jsonRes = (JSONObject)JSON.toJSON(jsapiResult);
jsonRes.put("package", jsonRes.getString("packageValue"));
jsonRes.remove("packageValue");
try {
fis.close();
} catch (IOException e) {
}
return JSON.toJSONString(jsonRes);
} catch (FileNotFoundException e) {
return null;
}
}
);
res.setPayInfo(resJSON.toJSONString());
res.setPayInfo(payInfo);
// 支付中
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING);
......
......@@ -15,14 +15,21 @@
*/
package com.jeequan.jeepay.pay.channel.wxpay.paywayV3;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.PemUtils;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams;
import com.jeequan.jeepay.pay.channel.wxpay.WxpayPaymentService;
import com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit;
import com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util;
import com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.model.WxServiceWrapper;
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
......@@ -34,6 +41,10 @@ import com.jeequan.jeepay.pay.util.ApiResBuilder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 微信 小程序
*
......@@ -56,29 +67,25 @@ public class WxLite extends WxpayPaymentService {
WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq;
WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);
WxPayService wxPayService = wxServiceWrapper.getWxPayService();
wxPayService.getConfig().setTradeType(WxPayConstants.TradeType.JSAPI);
// 构造请求数据
JSONObject reqJSON = buildV3OrderRequest(payOrder, mchAppConfigContext);
WxpayV3OrderRequestModel wxpayV3OrderRequestModel = buildV3OrderRequestModel(payOrder, mchAppConfigContext);
// 特约商户
if(mchAppConfigContext.isIsvsubMch()) {
// wxPayConfig 添加子商户参数
if(mchAppConfigContext.isIsvsubMch()){
wxPayService.getConfig().setSubMchId(reqJSON.getString("sub_mchid"));
if (StringUtils.isNotBlank(reqJSON.getString("sub_appid"))) {
wxPayService.getConfig().setSubAppId(reqJSON.getString("sub_appid"));
// 子商户subAppId不为空
if (StringUtils.isNotBlank(wxpayV3OrderRequestModel.getSubAppid())) {
wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setSubOpenid(bizRQ.getOpenid())); // 用户在子商户appid下的唯一标识
}else {
wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setSpOpenid(bizRQ.getOpenid()));
}
}
String reqUrl; // 请求地址
if(mchAppConfigContext.isIsvsubMch()){ // 特约商户
reqUrl = WxpayV3Util.ISV_URL_MAP.get(WxPayConstants.TradeType.JSAPI);
reqJSON.put("payer", WxpayV3Util.processIsvPayer(reqJSON.getString("sub_appid"), bizRQ.getOpenid()));
}else {
reqUrl = WxpayV3Util.NORMALMCH_URL_MAP.get(WxPayConstants.TradeType.JSAPI);
}else{ // 普通商户
JSONObject payer = new JSONObject();
payer.put("openid", bizRQ.getOpenid());
reqJSON.put("payer", payer);
//openId
wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setNormalOpenId(bizRQ.getOpenid()));
}
// 构造函数响应数据
......@@ -87,12 +94,48 @@ public class WxLite extends WxpayPaymentService {
res.setChannelRetMsg(channelRetMsg);
// 调起上游接口:
// 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭
// 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。
try {
JSONObject resJSON = WxpayV3Util.unifiedOrderV3(reqUrl, reqJSON, wxPayService);
String payInfo = WxpayV3Util.commonReqWx(wxpayV3OrderRequestModel, wxPayService, mchAppConfigContext.isIsvsubMch(), WxPayConstants.TradeType.JSAPI,
(JSONObject wxRes) -> {
// 普通商户
String resultAppId = wxpayV3OrderRequestModel.getNormalAppid();
// 特约商户
if(mchAppConfigContext.isIsvsubMch()){
resultAppId = StringUtils.defaultIfEmpty(wxpayV3OrderRequestModel.getSubAppid(), wxpayV3OrderRequestModel.getSpAppid());
}
// 使用wxjava公共函数,生成
WxPayUnifiedOrderV3Result wxPayUnifiedOrderV3Result = new WxPayUnifiedOrderV3Result();
wxPayUnifiedOrderV3Result.setPrepayId(wxRes.getString("prepay_id"));
try {
FileInputStream fis = new FileInputStream(wxPayService.getConfig().getPrivateKeyPath());
WxPayUnifiedOrderV3Result.JsapiResult jsapiResult =
wxPayUnifiedOrderV3Result.getPayInfo(TradeTypeEnum.JSAPI, resultAppId, null,
PemUtils.loadPrivateKey(fis));
JSONObject jsonRes = (JSONObject) JSON.toJSON(jsapiResult);
jsonRes.put("package", jsonRes.getString("packageValue"));
jsonRes.remove("packageValue");
try {
fis.close();
} catch (IOException e) {
}
return JSON.toJSONString(jsonRes);
} catch (FileNotFoundException e) {
return null;
}
}
);
res.setPayInfo(resJSON.toJSONString());
res.setPayInfo(payInfo);
// 支付中
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING);
......
......@@ -24,6 +24,7 @@ import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.pay.channel.wxpay.WxpayPaymentService;
import com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayKit;
import com.jeequan.jeepay.pay.channel.wxpay.kits.WxpayV3Util;
import com.jeequan.jeepay.pay.channel.wxpay.model.WxpayV3OrderRequestModel;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.model.WxServiceWrapper;
import com.jeequan.jeepay.pay.rqrs.AbstractRS;
......@@ -59,15 +60,7 @@ public class WxNative extends WxpayPaymentService {
WxPayService wxPayService = wxServiceWrapper.getWxPayService();
// 构造请求数据
JSONObject reqJSON = buildV3OrderRequest(payOrder, mchAppConfigContext);
wxPayService.getConfig().setTradeType(WxPayConstants.TradeType.NATIVE);
String reqUrl;
if(mchAppConfigContext.isIsvsubMch()){ // 特约商户
reqUrl = WxpayV3Util.ISV_URL_MAP.get(WxPayConstants.TradeType.NATIVE);
}else {
reqUrl = WxpayV3Util.NORMALMCH_URL_MAP.get(WxPayConstants.TradeType.NATIVE);
}
WxpayV3OrderRequestModel wxpayV3OrderRequestModel = buildV3OrderRequestModel(payOrder, mchAppConfigContext);
// 构造函数响应数据
WxNativeOrderRS res = ApiResBuilder.buildSuccess(WxNativeOrderRS.class);
......@@ -75,10 +68,10 @@ public class WxNative extends WxpayPaymentService {
res.setChannelRetMsg(channelRetMsg);
// 调起上游接口:
// 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭
// 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。
try {
JSONObject resJSON = WxpayV3Util.unifiedOrderV3(reqUrl, reqJSON, wxPayService);
String payInfo = WxpayV3Util.commonReqWx(wxpayV3OrderRequestModel, wxPayService, mchAppConfigContext.isIsvsubMch(), WxPayConstants.TradeType.NATIVE, null);
JSONObject resJSON = JSONObject.parseObject(payInfo);
String codeUrl = resJSON.getString("code_url");
if (CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ //二维码图片地址
......
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