diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumPayVersion.java b/mallinkService/src/main/java/com/iformall/enums/EnumPayVersion.java index f3b46ac3a..054090d37 100644 --- a/mallinkService/src/main/java/com/iformall/enums/EnumPayVersion.java +++ b/mallinkService/src/main/java/com/iformall/enums/EnumPayVersion.java @@ -6,7 +6,7 @@ package com.iformall.enums; public enum EnumPayVersion { WX_PAY_V2(1, "微信支付2.0,老版本"), - WX_PAY_V3(2, "微信支付3.0,暂时还未接"), + WX_PAY_V3(2, "微信支付3.0"), WX_PAY_V3_SFT(7,"对接电商收付通版本"), DY_PAY_V2(3,"抖音支付2.0,对接商品库"), NEU_POS_V1(4,"东软POS支付1.0版本"), diff --git a/mallinkService/src/main/java/com/iformall/pay/WxPayV3.java b/mallinkService/src/main/java/com/iformall/pay/WxPayV3.java index ea22bc9c8..fa4a09a49 100644 --- a/mallinkService/src/main/java/com/iformall/pay/WxPayV3.java +++ b/mallinkService/src/main/java/com/iformall/pay/WxPayV3.java @@ -14,6 +14,14 @@ import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.v3.util.AesUtils; import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTCombineCloseReq; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTCombinePayCommonMiniAppReq; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTPayCommonMiniAppReq; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTPayQueryReq; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3CombinePayCommonMiniAppReq; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3PayCommonMiniAppReq; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3PayQueryReq; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,6 +33,22 @@ public class WxPayV3 { //查询商家转账到零钱 private static final String MERCHANT_TRANSFER_QUERY_URL = "https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no/%s"; + //小程序下单-普通支付 + private static final String PAY_COMMON_MINIAPP_URL = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi"; + //小程序下单-普通支付-查询 + private static final String PAY_COMMON_QUERY_URL = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/%s"; + //小程序下单-合单支付 + private static final String PAY_COMBINE_MINIAPP_URL = "https://api.mch.weixin.qq.com/v3/combine-transactions/jsapi"; + //小程序下单-合单支付-查询 + private static final String PAY_COMBINE_QUERY_URL = "https://api.mch.weixin.qq.com/v3/combine-transactions/out-trade-no/%s"; + //小程序下单-普通支付-关闭订单 + private static final String PAY_COMMON_CLOSE_ORDER_URL = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/%s/close"; + //小程序下单-合单支付-关闭订单 + private static final String PAY_COMBINE_CLOSE_ORDER_URL = "https://api.mch.weixin.qq.com/v3/combine-transactions/out-trade-no/%s/close"; + //小程序下单-分账 + private static final String SHARE_URL = "https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/orders"; + + private WxPayV3() { } @@ -84,4 +108,55 @@ public class WxPayV3 { return payService.postV3WithWechatpaySerial(String.format(MERCHANT_TRANSFER_QUERY_URL, batchNo), JSON.toJSONString(param)); } + /** + * 普通支付-小程序下单 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_1.shtml + * @throws WxPayException + */ + public static String payCommonWithMiniApp(WxPayService payService,V3PayCommonMiniAppReq payReq) throws WxPayException { + return payService.postV3WithWechatpaySerial(PAY_COMMON_MINIAPP_URL, JSON.toJSONString(payReq)); + } + + /** + * 普通支付-查询https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_2.shtml + * @throws WxPayException + */ + public static String payCommonQuery(WxPayService payService,V3PayQueryReq payQuery) throws WxPayException { + return payService.postV3WithWechatpaySerial(String.format(PAY_COMMON_QUERY_URL, payQuery.getOut_trade_no()), JSON.toJSONString(payQuery)); + } + + /** + * 合单支付-小程序下单https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter5_1_4.shtml + * @throws WxPayException + */ + public static String payCombineCommonWithMiniApp(WxPayService payService,V3CombinePayCommonMiniAppReq payReq) throws WxPayException { + return payService.postV3WithWechatpaySerial(PAY_COMBINE_MINIAPP_URL, JSON.toJSONString(payReq)); + } + + /** + * 合单支付-查询 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter5_1_11.shtml + * @throws WxPayException + */ + public static String payCombineQuery(WxPayService payService,V3PayQueryReq payQuery) throws WxPayException { + return payService.postV3WithWechatpaySerial(String.format(PAY_COMBINE_QUERY_URL, payQuery.getOut_trade_no()), null); + + } + + /** + * 普通支付-关闭 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_3.shtml + * @throws WxPayException + */ + public static String payCommonClose(WxPayService payService,SFTPayQueryReq payQuery) throws WxPayException { + return payService.postV3WithWechatpaySerial(String.format(PAY_COMMON_CLOSE_ORDER_URL, payQuery.getOut_trade_no()), JSON.toJSONString(payQuery)); + + } + + /** + * 合单支付-关闭 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter5_1_12.shtml + * @throws WxPayException + */ + public static String payCombineClose(WxPayService payService,SFTCombineCloseReq closeOrder) throws WxPayException { + return payService.postV3WithWechatpaySerial(String.format(PAY_COMBINE_CLOSE_ORDER_URL, closeOrder.getCombine_out_trade_no()), JSON.toJSONString(closeOrder)); + } + + } diff --git a/mallinkService/src/main/java/com/iformall/service/pay/PayServiceFactory.java b/mallinkService/src/main/java/com/iformall/service/pay/PayServiceFactory.java index 8d8f2a81a..7c9797725 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/PayServiceFactory.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/PayServiceFactory.java @@ -10,15 +10,14 @@ import com.iformall.service.pay.service.refund.wx.v3.WxRefundV3AdapterService; import com.iformall.service.pay.service.share.douyin.TtPayShareService; import com.iformall.service.pay.service.share.wx.sft.WxPayShareSFTService; import com.iformall.service.pay.service.share.wx.v2.WxPayShareService; -import com.iformall.service.pay.service.share.wx.v3.WxPayShareV3Service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.iformall.common.ErrorCode; import com.iformall.enums.EnumPayWay; import com.iformall.exception.MallinkException; import com.iformall.service.pay.service.cashout.CashOutAdapterService; -import com.iformall.service.pay.service.cashout.wx.v2.WxCashOutAdapterService; -import com.iformall.service.pay.service.cashout.wx.v3.WxCashOutV3AdapterService; +import com.iformall.service.pay.service.cashout.wx.sft.WxCashOutSFTAdapterService; +import com.iformall.service.pay.service.cashout.wx.v2.WxCashOutQYFKAdapterService; import com.iformall.service.pay.service.pay.CDrivingPayService; import com.iformall.service.pay.service.pay.CPassivePayService; import com.iformall.service.pay.service.pay.PayAdapterService; @@ -28,6 +27,7 @@ import com.iformall.service.pay.service.pay.wx.sft.miniApp.appPay.WxMiniAppPaySF import com.iformall.service.pay.service.pay.wx.v2.h5.WxH5PayService; import com.iformall.service.pay.service.pay.wx.v2.miniApp.appPay.WxMiniAppPayAdapterService; import com.iformall.service.pay.service.pay.wx.v2.miniApp.maPay.WxMiniMaPayAdapterService; +import com.iformall.service.pay.service.pay.wx.v3.miniApp.appPay.WxMiniAppPayV3AdapterService; import com.iformall.service.pay.service.refund.RefundPayAdapterService; import com.iformall.service.pay.service.share.PayShareAdapterService; @@ -48,6 +48,8 @@ public class PayServiceFactory { WxMiniAppPayAdapterService wxMiniAppPayService; @Autowired WxMiniAppPaySFTAdapterService wxMiniAppPaySFTAdapterService; + @Autowired + WxMiniAppPayV3AdapterService wxMiniAppPayV3AdapterService; @Autowired WxMiniMaPayAdapterService wxMiniAppMaPayService; @@ -77,9 +79,9 @@ public class PayServiceFactory { TtRefundAdapterService ttRefundService; @Autowired - WxCashOutAdapterService wxCashOutService; + WxCashOutQYFKAdapterService wxCashOutService; @Autowired - WxCashOutV3AdapterService wxCashOutV3AdapterService; + WxCashOutSFTAdapterService wxCashOutSFTAdapterService; @@ -88,7 +90,11 @@ public class PayServiceFactory { serviceMap = new ConcurrentHashMap(); serviceMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxMiniAppPayService); serviceMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode()+"_"+EnumPayVersion.WX_PAY_V3_SFT.getCode(), wxMiniAppPaySFTAdapterService); + serviceMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxMiniAppPayV3AdapterService); + serviceMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxMiniAppMaPayService); + serviceMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxMiniAppMaPayService); + //电商收付通没有收款码支付 //serviceMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V3_SFT.getCode(), wxMiniAppMaPayService); serviceMap.put(EnumPayWay.PAY_WAY_WECHAT_WAP.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxH5PayService); serviceMap.put(EnumPayWay.PAY_WAY_WECHAT_WAP.getCode()+"_"+EnumPayVersion.WX_PAY_V3_SFT.getCode(), wxH5PaySFTService); @@ -160,8 +166,8 @@ public class PayServiceFactory { cashoutMap = new ConcurrentHashMap(); cashoutMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxCashOutService); cashoutMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxCashOutService); - cashoutMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode()+"_"+EnumPayVersion.WX_PAY_V3_SFT.getCode(), wxCashOutV3AdapterService); - cashoutMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V3_SFT.getCode(), wxCashOutV3AdapterService); + cashoutMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode()+"_"+EnumPayVersion.WX_PAY_V3_SFT.getCode(), wxCashOutSFTAdapterService); + cashoutMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V3_SFT.getCode(), wxCashOutSFTAdapterService); } return cashoutMap; } diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v3/WxCashOutV3AdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/sft/WxCashOutSFTAdapterService.java similarity index 99% rename from mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v3/WxCashOutV3AdapterService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/sft/WxCashOutSFTAdapterService.java index 9e8c3ecc5..4ed7c09b1 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v3/WxCashOutV3AdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/sft/WxCashOutSFTAdapterService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.cashout.wx.v3; +package com.iformall.service.pay.service.cashout.wx.sft; import java.io.UnsupportedEncodingException; import java.util.ArrayList; @@ -60,7 +60,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j @Service -public class WxCashOutV3AdapterService implements CashOutAdapterService{ +public class WxCashOutSFTAdapterService implements CashOutAdapterService{ @Autowired WxAppinfoService wxAppinfoService; diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v2/WxCashOutAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v2/WxCashOutAdapterService.java index 95b3ea0df..ad5bba214 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v2/WxCashOutAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v2/WxCashOutAdapterService.java @@ -58,6 +58,12 @@ import com.iformall.utils.XmlUtil; import lombok.extern.slf4j.Slf4j; + +/** + * 商家转账到零钱(因会自动开通运营账户,暂时无法使用) + * @author iformall + * + */ @Slf4j @Service public class WxCashOutAdapterService implements CashOutAdapterService{ diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v2/WxCashOutQYFKAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v2/WxCashOutQYFKAdapterService.java new file mode 100644 index 000000000..593d43a22 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v2/WxCashOutQYFKAdapterService.java @@ -0,0 +1,317 @@ +package com.iformall.service.pay.service.cashout.wx.v2; + +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.iformall.common.ErrorCode; +import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxCashOut; +import com.iformall.domain.po.WxPayAccount; +import com.iformall.enums.EnumCashOutStatus; +import com.iformall.exception.MallinkException; +import com.iformall.pay.WxCashOutP; +import com.iformall.pay.WxCashOutQueryP; +import com.iformall.pay.WxPay; +import com.iformall.pay.WxPayment; +import com.iformall.service.pay.service.cashout.CashOutAdapterService; +import com.iformall.service.pay.service.cashout.entity.CashOutAdapterResult; +import com.iformall.utils.BeanUtils; +import com.iformall.utils.Utility; +import lombok.extern.slf4j.Slf4j; + +/** + * 企业付款到零钱 + * @author iformall + * + */ +@Slf4j +@Service +public class WxCashOutQYFKAdapterService implements CashOutAdapterService{ + + JSONObject errorRefundReqMap = JSON.parseObject("{\n" + + " \"NO_AUTH\": {\n" + + " \"detail\": \"没有该接口权限\",\n" + + " \"reason\": \"1. 用户账号被冻结,无法付款;2. 产品权限没有开通或者被风控冻结;3. 此IP地址不允许调用接口,如有需要请登录微信支付商户平台更改配置\",\n" + + " \"resolution\": \"请根据具体的错误返回描述做对应处理,如返回描述不够明确,请参考此处的错误原因做排查。\"\n" + + " },\n" + + " \"AMOUNT_LIMIT\": {\n" + + " \"detail\": \"金额超限\",\n" + + " \"reason\": \"1. 被微信风控拦截,最低单笔付款限额调整为5元。2. 低于最低单笔付款限额或者高于最高单笔付款限额\",\n" + + " \"resolution\": \"目前最低付款金额为1元,最高10万元,请确认是否付款金额超限。\"\n" + + " },\n" + + " \"PARAM_ERROR\": {\n" + + " \"detail\": \"参数错误\",\n" + + " \"reason\": \"1. 请求参数校验错误 2. 字符中包含非utf8字符 3. 商户号和appid没有绑定关系\\t\",\n" + + " \"resolution\": \"请参照原因检查您的请求参数是否正确\"\n" + + " },\n" + + " \"OPENID_ERROR\": {\n" + + " \"detail\": \"Openid错误\",\n" + + " \"reason\": \"Openid格式错误或者不属于商家公众账号\",\n" + + " \"resolution\": \"Openid与appid是有一一映射关系的,请确保正确使用。\"\n" + + " },\n" + + " \"SEND_FAILED\": {\n" + + " \"detail\": \"付款错误\",\n" + + " \"reason\": \"付款错误,请查单确认付款结果\",\n" + + " \"resolution\": \"请查单确认付款结果,以查单结果为准。\"\n" + + " },\n" + + " \"NOTENOUGH\": {\n" + + " \"detail\": \"余额不足\",\n" + + " \"reason\": \"您的付款帐号余额不足或资金未到账\\t\",\n" + + " \"resolution\": \"如果要继续付款必须使用原商户订单号重试\"\n" + + " },\n" + + " \"SYSTEMERROR\": {\n" + + " \"detail\": \"系统繁忙,请稍后再试\",\n" + + " \"reason\": \"微信内部接口调用发生错误\",\n" + + " \"resolution\": \"请先调用查询接口,查看此次付款结果,如结果为不明确状态(如订单号不存在),请务必使用原商户订单号进行重试。\"\n" + + " },\n" + + " \"NAME_MISMATCH\": {\n" + + " \"detail\": \"姓名校验出错\",\n" + + " \"reason\": \"收款人身份校验不通过\",\n" + + " \"resolution\": \"如果要继续付款必须使用原商户订单号重试\"\n" + + " },\n" + + " \"SIGN_ERROR\": {\n" + + " \"detail\": \"签名错误\",\n" + + " \"reason\": \"校验签名错误\",\n" + + " \"resolution\": \"请检查您的请求参数和签名密钥KEY是否正确,如果要继续付款必须使用原商户订单号重试\"\n" + + " },\n" + + " \"XML_ERROR\": {\n" + + " \"detail\": \"Post内容出错\",\n" + + " \"reason\": \"Post请求数据不是合法的xml格式内容\",\n" + + " \"resolution\": \"格式问题,请检查请求格式是否正确。\"\n" + + " },\n" + + " \"FATAL_ERROR\": {\n" + + " \"detail\": \"两次请求参数不一致\",\n" + + " \"reason\": \"两次请求商户单号一样,但是参数不一致\",\n" + + " \"resolution\": \"重入必须保证所有参数值都不变\"\n" + + " },\n" + + " \"FREQ_LIMIT\": {\n" + + " \"detail\": \"超过频率限制,请稍后再试\",\n" + + " \"reason\": \"接口请求频率超时接口限制\",\n" + + " \"resolution\": \"调用接口过于频繁,请稍后再试,如果要继续付款必须使用原商户订单号重试\"\n" + + " },\n" + + " \"MONEY_LIMIT\": {\n" + + " \"detail\": \"已经达到今日付款总额上限/已达到付款给此用户额度上限\",\n" + + " \"reason\": \"请关注接口的付款限额条件\",\n" + + " \"resolution\": \"付款额度已经超限,请参考接口使用条件,如果要继续付款必须使用原商户订单号重试\"\n" + + " },\n" + + " \"CA_ERROR\": {\n" + + " \"detail\": \"商户API证书校验出错\",\n" + + " \"reason\": \"请求没带商户API证书或者带上了错误的商户API证书\",\n" + + " \"resolution\": \"您使用的调用证书有误,请确认是否使用了正确的证书,可以前往商户平台重新下载,证书需与商户号对应,如果要继续付款必须使用原商户订单号重试\"\n" + + " },\n" + + " \"V2_ACCOUNT_SIMPLE_BAN\": {\n" + + " \"detail\": \"无法给未实名用户付款\",\n" + + " \"reason\": \"用户微信支付账户未实名,无法付款\",\n" + + " \"resolution\": \"不支持给未实名用户付款,如果要继续付款必须使用原商户订单号重试\"\n" + + " },\n" + + " \"PARAM_IS_NOT_UTF8\": {\n" + + " \"detail\": \"请求参数中包含非utf8编码字符\",\n" + + " \"reason\": \"接口规范要求所有请求参数都必须为utf8编码\",\n" + + " \"resolution\": \"微信接口使用编码是UTF-8,请确认,如果要继续付款必须使用原商户订单号重试\"\n" + + " },\n" + + " \"SENDNUM_LIMIT\": {\n" + + " \"detail\": \"该用户今日付款次数超过限制,如有需要请进入【微信支付商户平台-产品中心-企业付款到零钱-产品设置】进行修改\",\n" + + " \"reason\": \"该用户今日付款次数超过限制,如有需要请进入【微信支付商户平台-产品中心-企业付款到零钱-产品设置】进行修改\",\n" + + " \"resolution\": \"向用户付款的次数超限了,请参考接口使用条件,如果要继续付款必须使用原商户订单号重试\"\n" + + " },\n" + + " \"RECV_ACCOUNT_NOT_ALLOWED\": {\n" + + " \"detail\": \"收款账户不在收款账户列表\",\n" + + " \"reason\": \"收款账户不在收款账户列表\",\n" + + " \"resolution\": \"请登陆商户平台,查看产品中心企业付款到零钱的产品配置\"\n" + + " },\n" + + " \"PAY_CHANNEL_NOT_ALLOWED\": {\n" + + " \"detail\": \"本商户号未配置API发起能力\",\n" + + " \"reason\": \"本商户号未配置API发起能力\",\n" + + " \"resolution\": \"请登陆商户平台,查看产品中心企业付款到零钱的产品配置\"\n" + + " }\n" + + "}"); + + JSONObject errorQueryReqMap = JSON.parseObject("{\n" + + " \"CA_ERROR\": {\n" + + " \"detail\": \"请求未携带证书,或请求携带的证书出错\",\n" + + " \"reason\": \"请求未携带证书,或请求携带的证书出错\",\n" + + " \"resolution\": \"到商户平台下载证书,请求带上证书后重试。\"\n" + + " },\n" + + " \"SIGN_ERROR\": {\n" + + " \"detail\": \"商户签名错误\",\n" + + " \"reason\": \"商户签名错误\",\n" + + " \"resolution\": \"按文档要求重新生成签名后再重试。\"\n" + + " },\n" + + " \"FREQ_LIMIT\": {\n" + + " \"detail\": \"受频率限制\",\n" + + " \"reason\": \"受频率限制\\t\",\n" + + " \"resolution\": \"请对请求做频率控制\"\n" + + " },\n" + + " \"XML_ERROR\": {\n" + + " \"detail\": \"请求的xml格式错误,或者post的数据为空\",\n" + + " \"reason\": \"请求的xml格式错误,或者post的数据为空\",\n" + + " \"resolution\": \"检查请求串,确认无误后重试。\"\n" + + " },\n" + + " \"PARAM_ERROR\": {\n" + + " \"detail\": \"参数错误\",\n" + + " \"reason\": \"参数错误\",\n" + + " \"resolution\": \"请查看err_code_des,修改设置错误的参数。\"\n" + + " },\n" + + " \"SYSTEMERROR\": {\n" + + " \"detail\": \"系统繁忙,请再试\",\n" + + " \"reason\": \"系统繁忙,请再试\\t\",\n" + + " \"resolution\": \"系统繁忙\"\n" + + " },\n" + + " \"NOT_FOUND\": {\n" + + " \"detail\": \"1、指定单号数据不存在 2、指定单号数据不存在,单据查询超过有效期\",\n" + + " \"reason\": \"1、指定单号数据不存在 2、指定单号数据不存在,单据查询超过有效期\",\n" + + " \"resolution\": \"1、查询单号对应的数据不存在,请使用正确的商户订单号查询2、如需查询超过有效期的单据,请登录到商户平台进行查询。\"\n" + + " }\n" + + "}"); + + /** + * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2 + * + * 在wx_pay_account里面要设置merchant_cert_path,登陆特约商户的商户后台,账号中心-API安全。 + */ + @Override + public CashOutAdapterResult cashOut(WxAppinfo appInfo, WxPayAccount payAccount, WxCashOut cashOut) { + if (StringUtils.isBlank(payAccount.getMerchantCertPath())) { + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付失败。商户证书为空。请联系管理员配置。", null); + } + if (StringUtils.isBlank(payAccount.getMerchantApiKey())) { + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付失败。商户密钥为空。请联系管理员配置。", null); + } + WxCashOutP wxCashOutP = generateWxCashOutP(payAccount, appInfo, cashOut); + Map signMap = null; + try { + signMap = BeanUtils.toStringMap(wxCashOutP); + } catch (Exception e) { + log.error("零钱支付命令生辰: " + e.getMessage(),e); + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付签名异常", null); + } + + String signAgent = WxPayment.createSign(signMap, payAccount.getMerchantApiKey()); + signMap.put("sign", signAgent); + String response = null; + try { + response = WxPay.transfers(signMap, payAccount.getMerchantCertPath(), payAccount.getSubMchId()); + } catch (Exception e) { + log.error("零钱支付异常: " + e.getMessage(),e); + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "微信零钱支付接口调用异常", null); + } + log.info("微信零钱支付:" + wxCashOutP.toString() +", response: " + response.toString()); + return getReusltFromp(response,cashOut); + +// if (payAccount.getType() == EnumPayMode.MCH.getCode()) { + // 普通商户模式 +// } + } + + private WxCashOutP generateWxCashOutP(WxPayAccount payAccount,WxAppinfo appInfo,WxCashOut cashOut) { + String noncestr = Utility.generate32UUID(); + WxCashOutP wxCashOutP = new WxCashOutP(); + wxCashOutP.setMch_appid(appInfo.getAppId()); + wxCashOutP.setMchid(payAccount.getSubMchId()); + wxCashOutP.setNonce_str(noncestr); + wxCashOutP.setAmount(cashOut.getTotalFee()); + wxCashOutP.setCheck_name("NO_CHECK"); + wxCashOutP.setDesc("客户结算"); + wxCashOutP.setOpenid(cashOut.getReciveOpenId()); + wxCashOutP.setPartner_trade_no(String.valueOf(cashOut.getId())); + return wxCashOutP; + } + + private CashOutAdapterResult getReusltFromp(String response,WxCashOut cashOut) throws MallinkException{ + Map returnMap = WxPayment.xmlToMap(response); + String result_no = returnMap.get("result_code"); + if ("SUCCESS".equals(result_no)) { + log.info("微信零钱支付申请成功: " + returnMap.toString()); + String wxPayNo = returnMap.get("payment_no"); + String payTime = returnMap.get("payment_time"); + cashOut.setWxPayNo(wxPayNo); + cashOut.setWxPayTime(payTime); + return new CashOutAdapterResult(true,EnumCashOutStatus.SUCCESS.getCode(),"微信零钱支付申请成功",returnMap); + } else { + log.error("微信零钱支付申请失败: " + response); + String errMsg = ""; + JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); + if (errObj != null) { + errMsg = errObj.toJSONString(); + } else { + errMsg = returnMap.get("err_code_des"); + } + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), errMsg, returnMap); + } + } + + @Override + public CashOutAdapterResult queryCashOut(WxAppinfo appInfo, WxPayAccount payAccount, WxCashOut cashOut) { + if (StringUtils.isBlank(payAccount.getMerchantCertPath())) { + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付失败。商户证书为空。请联系管理员配置。", null); + } + WxCashOutQueryP wxCashOutP = generateQueryWxCashOutP(payAccount, appInfo, cashOut); + Map signMap = null; + try { + signMap = BeanUtils.toStringMap(wxCashOutP); + } catch (Exception e) { + log.error("零钱支付命令生辰: " + e.getMessage(),e); + throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "零钱支付签名异常"); + } + + String signAgent = WxPayment.createSign(signMap, payAccount.getMerchantApiKey()); + signMap.put("sign", signAgent); + String response = null; + try { + response = WxPay.getTransferInfo(signMap, payAccount.getMerchantCertPath(), payAccount.getSubMchId()); + } catch (Exception e) { + log.error("零钱支付查询异常: " + e.getMessage(),e); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "微信零钱支付查询接口异常"); + } + log.info("微信零钱支付查询:" + wxCashOutP.toString() + ", response: " + response.toString()); + return getReusltFromQueryp(response,cashOut); + } + + private WxCashOutQueryP generateQueryWxCashOutP(WxPayAccount payAccount,WxAppinfo appInfo,WxCashOut cashOut) { + String noncestr = Utility.generate32UUID(); + WxCashOutQueryP wxCashOutQueryP = new WxCashOutQueryP(); + wxCashOutQueryP.setAppid(appInfo.getAppId()); + wxCashOutQueryP.setMch_id(payAccount.getSubMchId()); + wxCashOutQueryP.setNonce_str(noncestr); + wxCashOutQueryP.setPartner_trade_no(String.valueOf(cashOut.getId())); + return wxCashOutQueryP; + } + + private CashOutAdapterResult getReusltFromQueryp(String response,WxCashOut cashOut) throws MallinkException{ + Map returnMap = WxPayment.xmlToMap(response); + String result_no = returnMap.get("result_code"); + if ("SUCCESS".equals(result_no)) { + String realStatus = returnMap.get("status"); + if ("SUCCESS".equals(realStatus) || "PROCESSING".equals(realStatus)) { + String detailId = returnMap.get("detail_id"); + cashOut.setWxPayNo(detailId); + String wxPayTime = returnMap.get("transfer_time"); + cashOut.setWxPayTime(wxPayTime); + return new CashOutAdapterResult(true,EnumCashOutStatus.SUCCESS.getCode(),"微信零钱支付查询成功",returnMap); + }else if("FAILED".equals(realStatus)) { + String msg = returnMap.get("reason"); + return new CashOutAdapterResult(false,EnumCashOutStatus.FAIL.getCode(),msg,returnMap); + }else { + log.error("微信零钱支付查询失败,微信返回未知状态: " + response); + throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "微信零钱支付查询失败, 微信返回未知状态:"+realStatus); + } + } else { + log.error("微信零钱支付查询失败: " + response); + String errMsg = returnMap.get("err_code_des"); + String errCode = returnMap.get("err_code"); + if ("NOT_FOUND".equals(errCode)) { + return new CashOutAdapterResult(false,EnumCashOutStatus.FAIL.getCode(),errMsg,returnMap); + } +// JSONObject errObj = errorQueryReqMap.getJSONObject(result_no); +// if (errObj != null) { +// errMsg = errObj.toJSONString(); +// } else { +// errMsg = returnMap.get("err_code_des"); +// } + throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "微信零钱支付查询失败:"+errMsg); + } + } + +} \ No newline at end of file diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/BaseWxPayAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/BaseWxPayAdapterService.java index dcb5f2458..ba8a06b9b 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/BaseWxPayAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/BaseWxPayAdapterService.java @@ -34,6 +34,7 @@ import com.iformall.pay.WxPayOrderSQ; import com.iformall.pay.WxPayment; import com.iformall.service.QrCodeService; import com.iformall.service.helper.WxPayOrderServiceHelper; +import com.iformall.service.order.entity.WxComposeChildOrderShare; import com.iformall.service.pay.service.pay.PayAdapterService; import com.iformall.service.pay.service.pay.entity.PayAdapterResult; import com.iformall.service.pay.service.pay.entity.PayQueryAdapterResult; @@ -56,6 +57,11 @@ public class BaseWxPayAdapterService { @Autowired MaUtil maUtil; + + protected String getMerchantUid(WxPayOrder payOrder,WxOrder order) { + WxComposeChildOrderShare share = payOrder.getChildOrderShare(order.getId()); + return share.getMerchantUid(); + } protected File getQrCode(WxAppinfo appinfo,String pageUrl,int type,String sceneParam) throws WxErrorException { boolean isFmOpen = false; diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/sft/miniApp/appPay/WxMiniAppPaySFTAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/sft/miniApp/appPay/WxMiniAppPaySFTAdapterService.java index 3e09c5fa1..85215fb08 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/sft/miniApp/appPay/WxMiniAppPaySFTAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/sft/miniApp/appPay/WxMiniAppPaySFTAdapterService.java @@ -88,11 +88,6 @@ public class WxMiniAppPaySFTAdapterService extends BaseWxPaySFTAdapterService i return req; } - private String getMerchantUid(WxPayOrder payOrder,WxOrder order) { - WxComposeChildOrderShare share = payOrder.getChildOrderShare(order.getId()); - return share.getMerchantUid(); - } - private SFTCombinePayCommonMiniAppReq generateCombinePayReqeust(WxPayAccount payAccount,WxComposeOrder composeOrder,List childOrders,String productName, WxPayOrder record,WxAppinfo appInfo,String openId,String appId,Date currentDate,EnumPayShare isShare) throws Exception { @@ -122,13 +117,13 @@ public class WxMiniAppPaySFTAdapterService extends BaseWxPaySFTAdapterService i PayAdapterResult par = new PayAdapterResult(); if (StringUtils.isBlank(response)) { par.setSuccess(false); - par.setMsg("pay v3 has no response."); + par.setMsg("pay SFT has no response."); }else { JSONObject result = JSON.parseObject(response); String prepayId = result.getString("prepay_id"); if (StringUtils.isBlank(prepayId)) { par.setSuccess(false); - par.setMsg("pay v3 has no response."); + par.setMsg("pay SFT has no response."); }else { par.setSuccess(true); par.setMsg("success."); @@ -180,8 +175,8 @@ public class WxMiniAppPaySFTAdapterService extends BaseWxPaySFTAdapterService i } else { throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"因电商收付通合单查询无法处理,暂时不支持合单支付"); //合单支付/小程序支付 -// CombinePayCommonMiniAppReq payReq = generateCombinePayReqeust(payAccount,composeOrder,childOrders,productName,record,appInfo,openId,appInfo.getAppId(),currentDate,isShare); -// String response = WxPayV3.payCombineCommonWithMiniApp(payService, payReq); +// SFTCombinePayCommonMiniAppReq payReq = generateCombinePayReqeust(payAccount,composeOrder,childOrders,productName,record,appInfo,openId,appInfo.getAppId(),currentDate,isShare); +// String response = WxPayV3SFT.payCombineCommonWithMiniApp(payService, payReq); // log.info("pay order v3," + payReq.toString() + ", response: " + response.toString()); // return getOrderPResult(response); } @@ -233,8 +228,8 @@ public class WxMiniAppPaySFTAdapterService extends BaseWxPaySFTAdapterService i req.setOut_trade_no(String.valueOf(oldRecord.getId())); String response = WxPayV3SFT.payCommonQuery(payService, req); if (StringUtils.isBlank(response)){ - log.error("pay common v3 query response is null."+JSON.toJSONString(req)); - throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"pay common v3 query response is null."+JSON.toJSONString(req)); + log.error("pay common sft query response is null."+JSON.toJSONString(req)); + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"pay common sft query response is null."+JSON.toJSONString(req)); } return getPayCommonQueryResult(response); }else { diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombineCloseItemOrder.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombineCloseItemOrder.java new file mode 100644 index 000000000..9aa739afe --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombineCloseItemOrder.java @@ -0,0 +1,11 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import lombok.Data; + +@Data +public class V3CombineCloseItemOrder { + + private String mchid;//子单发起方商户号,必须与发起方appid有绑定关系 + private String out_trade_no;//子单商户订单号 + private String sub_mchid;//二级商户号,服务商子商户的商户号,被合单方。直连商户不用传二级商户号 +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombineCloseReq.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombineCloseReq.java new file mode 100644 index 000000000..ccf20b396 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombineCloseReq.java @@ -0,0 +1,39 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import java.util.ArrayList; +import java.util.List; +import com.alibaba.fastjson.annotation.JSONField; +import com.iformall.domain.po.WxPayAccount; +import com.iformall.domain.po.WxPayOrder; +import com.iformall.service.order.entity.WxComposeChildOrderShare; +import lombok.Data; + +@Data +public class V3CombineCloseReq { + + private String combine_appid;//合单发起方的appid + + @JSONField(serialize = false) + private String combine_out_trade_no;//不放到body + + private List sub_orders; + + public void initSubOrders(WxPayAccount payAccount,WxPayOrder payOrder) { + List childs = payOrder.getAllChilds(); + if (null != childs) { + List suborders = new ArrayList(); + for (WxComposeChildOrderShare child : childs) { + V3CombineCloseItemOrder ccio = new V3CombineCloseItemOrder(); + ccio.setMchid(payAccount.getMchId()); + ccio.setSub_mchid(child.getMerchantUid()); + ccio.setOut_trade_no(String.valueOf(child.getOrderId())); + suborders.add(ccio); + } + if (suborders.size() > 0) { + this.setSub_orders(suborders); + } + } + } + + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombineItemOrder.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombineItemOrder.java new file mode 100644 index 000000000..d13710ef0 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombineItemOrder.java @@ -0,0 +1,33 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxOrder; +import com.iformall.domain.po.WxPayAccount; + +import lombok.Data; + +@Data +public class V3CombineItemOrder { + + private String mchid;//子单发起方商户号,必须与发起方appid有绑定关系 + private String attach;//附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用 + private V3CombinePayAmountReq amount;//订单金额 + private String out_trade_no;//子单商户订单号 + private String sub_mchid;//二级商户号,服务商子商户的商户号,被合单方。直连商户不用传二级商户号 + private String description;//商品描述,需传入应用市场上的APP名字-实际商品名称 + private V3PaySettleReq settle_info;//结算信息 + + public void initByWxOrder(WxPayAccount payAccount,WxOrder order,String subMchId,WxAppinfo appInfo,String productName,String extParam) { + this.mchid = payAccount.getMchId(); + this.attach = extParam; + V3CombinePayAmountReq amount = new V3CombinePayAmountReq(); + amount.setTotal_amount(order.getPayment()); + this.setAmount(amount); + this.out_trade_no = String.valueOf(order.getId()); + this.sub_mchid = subMchId; + this.description = appInfo.getName()+"-"+productName; + V3PaySettleReq settle = new V3PaySettleReq(); + settle.setProfit_sharing(true); + this.setSettle_info(settle); + } +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombinePayAmountReq.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombinePayAmountReq.java new file mode 100644 index 000000000..c186d6c12 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombinePayAmountReq.java @@ -0,0 +1,11 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import lombok.Data; + +@Data +public class V3CombinePayAmountReq { + + private int total_amount;//总金额,单位为分。 + private String currency="CNY";//货币类型 + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombinePayCommonMiniAppReq.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombinePayCommonMiniAppReq.java new file mode 100644 index 000000000..9e308da98 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombinePayCommonMiniAppReq.java @@ -0,0 +1,17 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import java.util.List; + +import lombok.Data; + +@Data +public class V3CombinePayCommonMiniAppReq { + + private String combine_appid;//合单发起方的appid + private String combine_mchid;//合单发起方商户号,服务商和电商模式下,传服务商商户号 + private String combine_out_trade_no;//合单支付总订单号 + private List sub_orders;//商品描述 + private V3CombinePayerReq combine_payer_info;// 支付者信息 + private String sub_appid;//子商户申请的应用ID + private String notify_url;//接收微信支付异步通知回调地址 +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombinePayerReq.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombinePayerReq.java new file mode 100644 index 000000000..e1c811e0c --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3CombinePayerReq.java @@ -0,0 +1,10 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import lombok.Data; + +@Data +public class V3CombinePayerReq { + + private String sub_openid;//使用合单appid获取的对应用户openid + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayAmountReq.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayAmountReq.java new file mode 100644 index 000000000..cbef43b71 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayAmountReq.java @@ -0,0 +1,11 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import lombok.Data; + +@Data +public class V3PayAmountReq { + + private int total;//总金额,单位为分。 + private String currency="CNY";//货币类型 + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayCommonMiniAppReq.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayCommonMiniAppReq.java new file mode 100644 index 000000000..e4b38a30f --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayCommonMiniAppReq.java @@ -0,0 +1,18 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import lombok.Data; + +@Data +public class V3PayCommonMiniAppReq { + + private String sp_appid;//服务商应用ID + private String sp_mchid;//服务商户号 + private String sub_appid;//子商户申请的应用ID + private String sub_mchid;//二级商户号 + private String description;//商品描述 + private String out_trade_no;//商户订单号 + private String notify_url;//通知地址,不允许携带查询串 + private V3PaySettleReq settle_info;//结算信息 + private V3PayAmountReq amount;//订单金额 + private V3PayerReq payer;//支付者 +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayQueryReq.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayQueryReq.java new file mode 100644 index 000000000..7554b7b18 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayQueryReq.java @@ -0,0 +1,16 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import com.alibaba.fastjson.annotation.JSONField; + +import lombok.Data; + +@Data +public class V3PayQueryReq { + + private String sp_mchid;//服务商户号。 + private String sub_mchid;//二级商户号 + + @JSONField(serialize = false) + private String out_trade_no;//商户订单号 + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PaySettleReq.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PaySettleReq.java new file mode 100644 index 000000000..aa5b8fe2f --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PaySettleReq.java @@ -0,0 +1,10 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import lombok.Data; + +@Data +public class V3PaySettleReq { + + private boolean profit_sharing;//是否指定分账 + private int subsidy_amount;//补差金额;profit_sharing为true时,该金额才生效 +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayerReq.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayerReq.java new file mode 100644 index 000000000..e6a68845e --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/entity/V3PayerReq.java @@ -0,0 +1,10 @@ +package com.iformall.service.pay.service.pay.wx.v3.entity; + +import lombok.Data; + +@Data +public class V3PayerReq { + + private String sub_openid;//用户在子商户appid下的唯一标识 + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/miniApp/appPay/WxMiniAppPayV3AdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/miniApp/appPay/WxMiniAppPayV3AdapterService.java new file mode 100644 index 000000000..d0ac4fdb6 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/miniApp/appPay/WxMiniAppPayV3AdapterService.java @@ -0,0 +1,303 @@ +package com.iformall.service.pay.service.pay.wx.v3.miniApp.appPay; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import com.iformall.domain.po.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.service.WxPayService; +import com.iformall.common.ErrorCode; +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.enums.EnumOrderStatus; +import com.iformall.enums.EnumPayMchType; +import com.iformall.enums.EnumPayMode; +import com.iformall.enums.EnumPayShare; +import com.iformall.enums.EnumPayStatus; +import com.iformall.exception.MallinkException; +import com.iformall.pay.WxPay; +import com.iformall.pay.WxPayOrderP; +import com.iformall.pay.WxPayOrderSP; +import com.iformall.pay.WxPayV3; +import com.iformall.pay.WxPayV3SFT; +import com.iformall.pay.WxPayment; +import com.iformall.service.helper.WxPayOrderServiceHelper; +import com.iformall.service.order.entity.WxComposeOrder; +import com.iformall.service.pay.entity.PayExtraParam; +import com.iformall.service.pay.service.pay.CDrivingPayService; +import com.iformall.service.pay.service.pay.entity.PayAdapterResult; +import com.iformall.service.pay.service.pay.entity.PayQueryAdapterResult; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTCombineItemOrder; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTCombinePayCommonMiniAppReq; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTCombinePayerReq; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTPayAmountReq; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTPayCommonMiniAppReq; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTPayQueryReq; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTPaySettleReq; +import com.iformall.service.pay.service.pay.wx.sft.entity.SFTPayerReq; +import com.iformall.service.pay.service.pay.wx.v2.BaseWxPayV2AdapterService; +import com.iformall.service.pay.service.pay.wx.v3.BaseWxPayV3AdapterService; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3CombineItemOrder; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3CombinePayCommonMiniAppReq; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3CombinePayerReq; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3PayAmountReq; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3PayCommonMiniAppReq; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3PayQueryReq; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3PaySettleReq; +import com.iformall.service.pay.service.pay.wx.v3.entity.V3PayerReq; +import com.iformall.utils.BeanUtils; +import com.iformall.utils.MaUtil; +import com.iformall.utils.MapUtil; +import com.iformall.utils.Utility; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class WxMiniAppPayV3AdapterService extends BaseWxPayV3AdapterService implements CDrivingPayService{ + + @Autowired + MaUtil maUtil; + + private V3PayCommonMiniAppReq generatePayCommonRequest(WxPayAccount payAccount,WxComposeOrder composeOrder,String productName, WxPayOrder record,String openId,WxAppinfo appInfo,Date currentDate) throws Exception { + V3PayCommonMiniAppReq req = new V3PayCommonMiniAppReq(); + req.setSp_appid(String.valueOf(appInfo.getParentAppId())); + req.setSp_mchid(payAccount.getMchId()); + req.setSub_appid(appInfo.getAppId()); + req.setSub_mchid(getMerchantUid(record,composeOrder.getSingleOrder())); + req.setDescription(appInfo.getName()+"-"+productName); + req.setOut_trade_no(String.valueOf(composeOrder.getMainOrderId())); + req.setNotify_url(payAccount.getPayNotifyV3Url()); + + V3PaySettleReq settle = new V3PaySettleReq(); + settle.setProfit_sharing(true); + req.setSettle_info(settle); + + V3PayAmountReq amout = new V3PayAmountReq(); + amout.setTotal(record.getPayAmount()); + req.setAmount(amout); + + V3PayerReq payer = new V3PayerReq(); + payer.setSub_openid(openId); + req.setPayer(payer); + + return req; + } + + private PayAdapterResult getOrderPResult(String response,WxPayOrder record) { + PayAdapterResult par = new PayAdapterResult(); + if (StringUtils.isBlank(response)) { + par.setSuccess(false); + par.setMsg("pay v3 has no response."); + }else { + JSONObject result = JSON.parseObject(response); + String prepayId = result.getString("prepay_id"); + if (StringUtils.isBlank(prepayId)) { + par.setSuccess(false); + par.setMsg("pay v3 has no response."); + }else { + par.setSuccess(true); + par.setMsg("success."); + record.setPrepayId(prepayId); + record.setUpdateTime(new Date()); + } + } + return par; + } + + private V3CombinePayCommonMiniAppReq generateCombinePayReqeust(WxPayAccount payAccount,WxComposeOrder composeOrder,List childOrders,String productName, + WxPayOrder record,WxAppinfo appInfo,String openId,String appId,Date currentDate,EnumPayShare isShare) throws Exception { + + V3CombinePayCommonMiniAppReq req = new V3CombinePayCommonMiniAppReq(); + req.setCombine_appid(appInfo.getAppId()); + req.setCombine_mchid(payAccount.getMchId()); + req.setCombine_out_trade_no(String.valueOf(composeOrder.getMainOrderId())); + + List suborders = new ArrayList(); + for (WxOrder order : childOrders) { + V3CombineItemOrder so = new V3CombineItemOrder(); + String subMchId = getMerchantUid(record,order); + so.initByWxOrder(payAccount, order, subMchId, appInfo, productName, String.valueOf(record.getId())); + suborders.add(so); + } + req.setSub_orders(suborders); + + V3CombinePayerReq payer = new V3CombinePayerReq(); + payer.setSub_openid(openId); + req.setCombine_payer_info(payer); + + req.setNotify_url(payAccount.getPayNotifyV3Url()); + return req; + } + + @Override + public PayAdapterResult pay(WxPayAccount payAccount,WxPayOrder record,WxComposeOrder composeOrder,List childOrders, + String productName,EnumPayShare isShare,WxAppinfo appInfo,Date currentDate, PayExtraParam params) throws Exception { + if (null == params ) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"openId为空"); + } + String openId = (String) params.getValue("openId"); + if (StringUtils.isBlank(openId) ) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"openId为空"); + } + + if (payAccount.getType() == EnumPayMode.MCH.getCode()) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"当前支付配置非服务商模式,不能使用该产品."); + } + + //只能直连模式, + if (payAccount.getMchType() != EnumPayMchType.DIRECT.getCode()) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"当前支付版本不支持非直连模式"); + } + + WxPayService payService = maUtil.getWxPayService(appInfo, payAccount); + + if (null == childOrders || childOrders.size() <= 0 ) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"子订单为空"); + } + /* + * 普通支付/小程序支付 + * https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_2_3.shtml + */ + if (childOrders.size() == 1) { + V3PayCommonMiniAppReq payReq = generatePayCommonRequest(payAccount,composeOrder,productName,record,openId,appInfo,currentDate); + String response = WxPayV3.payCommonWithMiniApp(payService, payReq); + log.info("pay order v3, " + payReq.toString() + ", response: " + response.toString()); + return getOrderPResult(response,record); + } else { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"合单查询无法处理,暂时不支持合单支付"); + //合单支付/小程序支付 +// V3CombinePayCommonMiniAppReq payReq = generateCombinePayReqeust(payAccount,composeOrder,childOrders,productName,record,appInfo,openId,appInfo.getAppId(),currentDate,isShare); +// String response = WxPayV3.payCombineCommonWithMiniApp(payService, payReq); +// log.info("pay order v3," + payReq.toString() + ", response: " + response.toString()); +// return getOrderPResult(response); + } + } + + private PayQueryAdapterResult getPayCommonQueryResult(String response) { + JSONObject result = JSON.parseObject(response); + String transtionId = result.getString("transaction_id"); + String tradeState = result.getString("trade_state"); + String tradeStateDesc = result.getString("trade_state_desc"); + String successTime = result.getString("success_time"); + EnumPayStatus payStatus = WxPayOrderServiceHelper.getPayStatus(tradeState); + if (null == payStatus) { + throw new MallinkException(ErrorCode.PAY_ORDER_ERROR.getCode(), "订单查询微信支付状态非法["+tradeState+"]"); + } + if (StringUtils.isBlank(tradeStateDesc)) { + tradeStateDesc = payStatus.getMessage(); + } + PayQueryAdapterResult qresult = new PayQueryAdapterResult(payStatus.getCode(), tradeStateDesc,null, response,transtionId,successTime); + return qresult; + } + + private PayQueryAdapterResult getPayCombineQueryResult(String response) { + JSONObject result = JSON.parseObject(response); + //TODO 只有各子订单的状态,没有统一的状态,暂时无法处理 + JSONArray subOrders = result.getJSONArray("sub_orders"); + + ///######待处理 + String transtionId = result.getString("transaction_id"); + String tradeState = result.getString("trade_state"); + String tradeStateDesc = result.getString("trade_state_desc"); + String successTime = result.getString("success_time"); + EnumPayStatus payStatus = WxPayOrderServiceHelper.getPayStatus(tradeState); + if (null == payStatus) { + throw new MallinkException(ErrorCode.PAY_ORDER_ERROR.getCode(), "订单查询微信支付状态非法["+tradeState+"]"); + } + PayQueryAdapterResult qresult = new PayQueryAdapterResult(payStatus.getCode(), tradeStateDesc,null, response,transtionId,successTime); + return qresult; + } + + @Override + public PayQueryAdapterResult queryPayStatus(WxPayOrder oldRecord, WxAppinfo appInfo, + WxPayAccount payAccount) throws Exception { + WxPayService payService = maUtil.getWxPayService(appInfo, payAccount); + V3PayQueryReq req = new V3PayQueryReq(); + if (!oldRecord.isMulity()) { + req.setSp_mchid(payAccount.getMchId()); + req.setSub_mchid(oldRecord.getSingleChildOrderShare().getMerchantUid()); + req.setOut_trade_no(String.valueOf(oldRecord.getId())); + String response = WxPayV3.payCommonQuery(payService, req); + if (StringUtils.isBlank(response)){ + log.error("pay common v3 query response is null."+JSON.toJSONString(req)); + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"pay common v3 query response is null."+JSON.toJSONString(req)); + } + return getPayCommonQueryResult(response); + }else { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"合单查询无法处理,暂时不支持合单支付查询"); +// req.setOut_trade_no(String.valueOf(oldRecord.getId())); +// String response = WxPayV3.payCombineQuery(payService, req); +// if (StringUtils.isBlank(response)){ +// log.error("pay combine v3 query response is null."+JSON.toJSONString(req)); +// throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"pay common v3 query response is null."+JSON.toJSONString(req)); +// } +// return getPayCombineQueryResult(response); + } + } + + @Override + public int queryPayStatus(PayQueryAdapterResult statusObject, String orderOutNo) throws Exception { + return getPayCommonQueryResult((String)statusObject.getData()).getCode(); + } + + @Override + public int queryPayStatusCode(WxPayOrder oldRecord, WxAppinfo appInfo, WxPayAccount payAccount) + throws Exception { + return queryPayStatus(oldRecord, appInfo, payAccount).getCode(); + } + + @Override + public PayAdapterResult payOrderClose(WxAppinfo appInfo, WxPayOrder record,WxPayAccount payAccount) throws Exception { + WxPayService payService = maUtil.getWxPayService(appInfo, payAccount); + if (!record.isMulity()) { + SFTPayQueryReq req = new SFTPayQueryReq(); + req.setSp_mchid(payAccount.getMchId()); + req.setSub_mchid(record.getSingleChildOrderShare().getMerchantUid()); + req.setOut_trade_no(String.valueOf(record.getId())); + WxPayV3SFT.payCommonClose(payService, req); + return new PayAdapterResult(true, "close success", req, null); + }else { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"因合单查询无法处理,暂时不支持合单支付关闭"); + +// CombineCloseReq req = new CombineCloseReq(); +// req.setCombine_appid(appInfo.getAppId()); +// req.setCombine_out_trade_no(String.valueOf(record.getId())); +// req.initSubOrders(payAccount, record); +// +// String response = WxPayV3.payCombineClose(payService, req); +// return new PayAdapterResult(true, "close success", req, null); + } + } + + @Override + public PayAdapterResult payOrderReverse(WxAppinfo appInfo, WxPayOrder record, WxPayAccount payAccount) + throws Exception { + return super.payOrderReverse(appInfo, record, payAccount,payAccount.getSubMchId()); + } + + @Override + public PayAdapterResult payOrderPush(String openId,WxAppinfo appInfo, WxBatchOrder batchOrder,WxPayOrder payOrder) throws Exception { + return null; + } + + @Override + public File getQrcode(WxAppinfo appinfo,String pageUrl,int type,String sceneParam) throws Exception{ + return super.getQrCode(appinfo, pageUrl, type, sceneParam); + } + + @Override + public PayAdapterResult noCreatePay(WxPayOrder record, WxComposeOrder composeOrder, List childOrders) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR); + } + +}