diff --git a/mallinkAdmin/src/main/resources/db/migration/V2022080800001_pay_v3.sql b/mallinkAdmin/src/main/resources/db/migration/V2022080800001_pay_v3.sql new file mode 100644 index 000000000..928c3cc5a --- /dev/null +++ b/mallinkAdmin/src/main/resources/db/migration/V2022080800001_pay_v3.sql @@ -0,0 +1,2 @@ +ALTER TABLE `mallink`.`wx_pay_account` +ADD COLUMN `pay_version` smallint(1) COMMENT '支付版本' AFTER `open_pay`; diff --git a/mallinkCallback/src/main/java/com/iformall/controller/callback/TtPayController.java b/mallinkCallback/src/main/java/com/iformall/controller/callback/TtPayController.java index 682428937..7b3b1ca94 100644 --- a/mallinkCallback/src/main/java/com/iformall/controller/callback/TtPayController.java +++ b/mallinkCallback/src/main/java/com/iformall/controller/callback/TtPayController.java @@ -169,7 +169,7 @@ public class TtPayController extends BaseController { logger.error("未找到订单"+orderId); resultMap.put("err_tips","未找到订单"); }else{ - PayQueryAdapterResult queryResult = payServiceFactory.getPayAdapterService(wxpayOrder.getPayVendor()).queryPayStatus(wxpayOrder, appinfo, payAccount); + PayQueryAdapterResult queryResult = payServiceFactory.getPayAdapterService(wxpayOrder.getPayVendor(),payAccount.getPayVersion()).queryPayStatus(wxpayOrder, appinfo, payAccount); if (EnumPayStatus.PAY_STATUS_SUCCESS.getCode() == queryResult.getCode()) { WxComposeOrder composeOrder = orderFactory.getOrderAdapterService(wxpayOrder.getComposeOrder()).getComposeOrder(wxpayOrder.getOrderId(), wxpayOrder.getTenantId()); wxPayOrderService.handleSuccessOrder(wxpayOrder, composeOrder, queryResult, true,false); diff --git a/mallinkSchedule/src/main/java/com/iformall/schedule/CashOutSchedule.java b/mallinkSchedule/src/main/java/com/iformall/schedule/CashOutSchedule.java index eff52c2c2..ed9fcf1a0 100644 --- a/mallinkSchedule/src/main/java/com/iformall/schedule/CashOutSchedule.java +++ b/mallinkSchedule/src/main/java/com/iformall/schedule/CashOutSchedule.java @@ -124,7 +124,7 @@ public class CashOutSchedule { if (null == payAccount) { return; } - CashOutAdapterResult result = payServiceFactory.getCashOutAdapterService(payWay.getCode()).queryCashOut(appInfo, payAccount, cashout); + CashOutAdapterResult result = payServiceFactory.getCashOutAdapterService(payWay.getCode(),payAccount.getPayVersion()).queryCashOut(appInfo, payAccount, cashout); cashout.setUpdateDate(new Date()); if (result.isSuccess()) { cashout.setStatus(EnumCashOutStatus.SUCCESS.getCode()); diff --git a/mallinkSchedule/src/main/java/com/iformall/schedule/OrderExpiringSchedule.java b/mallinkSchedule/src/main/java/com/iformall/schedule/OrderExpiringSchedule.java index f56dec4ef..eefa4f6e4 100644 --- a/mallinkSchedule/src/main/java/com/iformall/schedule/OrderExpiringSchedule.java +++ b/mallinkSchedule/src/main/java/com/iformall/schedule/OrderExpiringSchedule.java @@ -316,7 +316,7 @@ public class OrderExpiringSchedule { } //Map retMap = WxPayOrderServiceHelper.wxOrderPayStatusMap(wxpayOrder, order, appInfo, payAccount); //int status = WxPayOrderServiceHelper.getPayStatusFromMap(retMap, wxpayOrder.getPayOrderNo()); - PayQueryAdapterResult payResult = payServiceFactory.getPayAdapterService(wxpayOrder.getPayVendor()).queryPayStatus(wxpayOrder, appInfo, payAccount); + PayQueryAdapterResult payResult = payServiceFactory.getPayAdapterService(wxpayOrder.getPayVendor(),payAccount.getPayVersion()).queryPayStatus(wxpayOrder, appInfo, payAccount); //如果是支付成功,并且需要重试成功流程, if (EnumPayStatus.PAY_STATUS_SUCCESS.getCode().intValue() == payResult.getCode()) { if (autoReHandle) { diff --git a/mallinkService/src/main/java/com/iformall/domain/po/WxPayAccount.java b/mallinkService/src/main/java/com/iformall/domain/po/WxPayAccount.java index 8cd635d1e..083c2e295 100644 --- a/mallinkService/src/main/java/com/iformall/domain/po/WxPayAccount.java +++ b/mallinkService/src/main/java/com/iformall/domain/po/WxPayAccount.java @@ -45,8 +45,10 @@ public class WxPayAccount extends TenantEntity { private Integer type; @io.swagger.annotations.ApiModelProperty(value="EnumPayMchType 0:总分1:直连",name="mchType") private Integer mchType; - @io.swagger.annotations.ApiModelProperty(value="抖音用 ",name="openPay") + @io.swagger.annotations.ApiModelProperty(value="开通的支付方式。抖音用 ",name="openPay") private String openPay; + @io.swagger.annotations.ApiModelProperty(value="支付版本 EnumPayVersion",name="payVersion") + private Integer payVersion; @io.swagger.annotations.ApiModelProperty(value="是否开启分账(0:未开启分账1:开启分账)",name="type") private Integer share; @io.swagger.annotations.ApiModelProperty(value="手续费(万分之几,默认60)",name="rate") diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumPayVersion.java b/mallinkService/src/main/java/com/iformall/enums/EnumPayVersion.java new file mode 100644 index 000000000..3f26d6f30 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/enums/EnumPayVersion.java @@ -0,0 +1,37 @@ +package com.iformall.enums; + +/** + * Created by Stormeye on 2018/08/09. + */ +public enum EnumPayVersion { + + WX_PAY_V2(1, "微信支付2.0,老版本"), + WX_PAY_V3(2, "微信支付3.0,对接电商收付通"), + DY_PAY_V2(3,"抖音支付2.0,对接商品库") + ; + + public static EnumPayVersion getEnum(Integer code) { + for (EnumPayVersion value : values()) { + if (value.getCode().equals(code)) { + return value; + } + } + return null; + } + + private Integer code; + private String name; + + EnumPayVersion(Integer code, String name) { + this.code = code; + this.name = name; + } + + public Integer getCode() { + return code; + } + + public String getName() { + return name; + } +} diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java index 611265ff3..9121087a8 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxPayOrderServiceImpl.java @@ -204,8 +204,8 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { PayQueryAdapterResult queryResult = null; int wxpaystatus = 0; try { - queryResult = payServiceFactory.getPayAdapterService(oldRecord.getPayVendor()).queryPayStatus(oldRecord, appInfo, payAccount); - wxpaystatus = payServiceFactory.getPayAdapterService(oldRecord.getPayVendor()).queryPayStatus(queryResult, oldRecord.getPayOrderNo()); + queryResult = payServiceFactory.getPayAdapterService(oldRecord.getPayVendor(),payAccount.getPayVersion()).queryPayStatus(oldRecord, appInfo, payAccount); + wxpaystatus = payServiceFactory.getPayAdapterService(oldRecord.getPayVendor(),payAccount.getPayVersion()).queryPayStatus(queryResult, oldRecord.getPayOrderNo()); } catch (Exception e) { logger.error("pay order service handleWxOrderQuery error: " ,e); throw new MallinkException(ErrorCode.PAY_ORDER_ERROR); @@ -433,7 +433,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { record.setShare(isShare.getCode()); record.setComposeOrder(composeOrder.getComposeOrderType()); // if (isShare == EnumPayShare.YES) { - PayShareAdapterService payShareServie = payServiceFactory.getPayShareAdapterService(payWay.getCode()); + PayShareAdapterService payShareServie = payServiceFactory.getPayShareAdapterService(payWay.getCode(),payAccount.getPayVersion()); // PayShareCalculateAmount recordShareAmount = payShareServie.calculateAmount(record.getPayAmount(), payAccount); // // 分账金额 @@ -481,7 +481,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { } } - PayAdapterService payAdapterService = payServiceFactory.getPayAdapterService(payWay.getCode()); + PayAdapterService payAdapterService = payServiceFactory.getPayAdapterService(payWay.getCode(),payAccount.getPayVersion()); if(!isCreatePay){ PayAdapterResult payResult = payAdapterService.noCreatePay(record,composeOrder,childOrders); @@ -613,7 +613,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { logger.debug("wxPayRecord md5 before:"+record.toString()); String beforemd5 = HashUtil.md5(record.toString()); - PayAdapterResult payResult = payServiceFactory.getPayAdapterService(payWay.getCode()).pay(payAccount, record,composeOrder,"付款码支付",isShare,appInfo, currentDate, params); + PayAdapterResult payResult = payServiceFactory.getPayAdapterService(payWay.getCode(),payAccount.getPayVersion()).pay(payAccount, record,composeOrder,"付款码支付",isShare,appInfo, currentDate, params); String aftermd5 = HashUtil.md5(record.toString()); if (beforemd5.equals(aftermd5)) { logger.error("支付方式["+payWay.getCode()+"]支付接口【pay】过程中 WxPayOrder 未做更新.record:"+record.toString()); @@ -675,10 +675,10 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { } WxAppinfo appInfo = wxAppinfoService.getCAppInfo(record,payWay.getPlat()); - PayAdapterService payService = payServiceFactory.getPayAdapterService(payWay.getCode()); WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); + PayAdapterService payService = payServiceFactory.getPayAdapterService(payWay.getCode(),payAccount.getPayVersion()); PayQueryAdapterResult apiResult = payService.queryPayStatus(record, appInfo, payAccount); - int status = payServiceFactory.getPayAdapterService(payWay.getCode()).queryPayStatus(apiResult, record.getPayOrderNo()); + int status = payServiceFactory.getPayAdapterService(payWay.getCode(),payAccount.getPayVersion()).queryPayStatus(apiResult, record.getPayOrderNo()); boolean isSuccess = true; String msg = ""; if (status == EnumPayStatus.PAY_STATUS_REFUND.getCode().intValue()) { @@ -747,7 +747,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { public ResultData payOrderClose(WxAppinfo appInfo, WxPayOrder record) { WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); try { - PayAdapterResult result = payServiceFactory.getPayAdapterService(record.getPayVendor()).payOrderClose(appInfo, record, payAccount); + PayAdapterResult result = payServiceFactory.getPayAdapterService(record.getPayVendor(),payAccount.getPayVersion()).payOrderClose(appInfo, record, payAccount); if (result.isSuccess()) { record.setPayOrderStatus(EnumPayStatus.PAY_STATUS_CANCEL.getCode()); }else { @@ -784,7 +784,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { WxAppinfo appInfo = wxAppinfoService.getCAppInfo(record,EnumPayWay.getEnum(record.getPayVendor()).getPlat()); WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); try { - PayAdapterResult result = payServiceFactory.getPayAdapterService(record.getPayVendor()).payOrderReverse(appInfo, record, payAccount); + PayAdapterResult result = payServiceFactory.getPayAdapterService(record.getPayVendor(),payAccount.getPayVersion()).payOrderReverse(appInfo, record, payAccount); if (result.isSuccess()) { record.setPayOrderStatus(EnumPayStatus.PAY_STATUS_REVERSE.getCode()); record.setUpdateTime(new Date()); @@ -1059,7 +1059,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { WxPayOrder payOrder = new WxPayOrder(); payOrder.setPayOrderNo(id.toString()); try { - return payServiceFactory.getPayAdapterService(EnumPayWay.PAY_WAY_TT.getCode()).queryPayStatus(payOrder, appInfo, payAccount); + return payServiceFactory.getPayAdapterService(EnumPayWay.PAY_WAY_TT.getCode(),payAccount.getPayVersion()).queryPayStatus(payOrder, appInfo, payAccount); } catch (Exception e) { return new PayQueryAdapterResult(ErrorCode.SYS_SERVER_ERROR.getCode(), e.getMessage(),null,null,null,null); } @@ -1350,7 +1350,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService { // 回调未返回,主动检查支付订单状态 try { WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); - int payStatus = payServiceFactory.getPayAdapterService(record.getPayVendor()).queryPayStatusCode(record, appInfo, payAccount); + int payStatus = payServiceFactory.getPayAdapterService(record.getPayVendor(),payAccount.getPayVersion()).queryPayStatusCode(record, appInfo, payAccount); if (payStatus!=EnumPayStatus.PAY_STATUS_SUCCESS.getCode().intValue() && payStatus!=EnumPayStatus.PAY_STATUS_WAIT.getCode().intValue()) { // 支付订单未成功,返回异常 record.setPayOrderStatus(EnumPayStatus.PAY_STATUS_FAIL.getCode()); diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxProfitSharingOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxProfitSharingOrderServiceImpl.java index 6b1bb320f..9ae57bb74 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxProfitSharingOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxProfitSharingOrderServiceImpl.java @@ -204,7 +204,7 @@ public class WxProfitSharingOrderServiceImpl implements WxProfitSharingOrderServ } - PayShareResult shareResult = payServiceFactory.getPayShareAdapterService(dto.getPayWay()).haveReciversShare(appInfo, payAccount, frecord, + PayShareResult shareResult = payServiceFactory.getPayShareAdapterService(dto.getPayWay(),payAccount.getPayVersion()).haveReciversShare(appInfo, payAccount, frecord, sharingOrder.getTransactionId(), JSONArray.parseArray(JSON.toJSONString(receivers)), EnumProfitSharingOrderType.getEnum(sharingOrder.getType())); WxProfitSharingOrder updSharingOrder = new WxProfitSharingOrder(); updSharingOrder.updateTenantInfo(sharingOrder); @@ -237,7 +237,7 @@ public class WxProfitSharingOrderServiceImpl implements WxProfitSharingOrderServ WxAppinfo appInfo = dto.getAppinfo(); WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); - PayShareResult shareResult = payServiceFactory.getPayShareAdapterService(dto.getPayWay()).noReciverShare(appInfo,payAccount,sharingOrder,sharingOrder.getTransactionId(),sharingOrder.getPayAmount()); + PayShareResult shareResult = payServiceFactory.getPayShareAdapterService(dto.getPayWay(),payAccount.getPayVersion()).noReciverShare(appInfo,payAccount,sharingOrder,sharingOrder.getTransactionId(),sharingOrder.getPayAmount()); WxProfitSharingOrder updSharingOrder = new WxProfitSharingOrder(); updSharingOrder.updateTenantInfo(sharingOrder); @@ -346,7 +346,7 @@ public class WxProfitSharingOrderServiceImpl implements WxProfitSharingOrderServ if (record == null) return new ResultData(ErrorCode.ORDER_IS_NOT_FIND); - PayShareQueryResult shareResult = payServiceFactory.getPayShareAdapterService(dto.getPayWay()).shareQuery(appInfo, payAccount, record); + PayShareQueryResult shareResult = payServiceFactory.getPayShareAdapterService(dto.getPayWay(),payAccount.getPayVersion()).shareQuery(appInfo, payAccount, record); if (!shareResult.isSuccess()) { throw new MallinkException(shareResult.getCode(),shareResult.getMsg()); } @@ -447,11 +447,9 @@ public class WxProfitSharingOrderServiceImpl implements WxProfitSharingOrderServ return new ResultData(ErrorCode.SYS_PARAMETER_ERROR); } - PayShareAdapterService payShareAdapterService = payServiceFactory.getPayShareAdapterService(payWay); - WxAppinfo appInfo = getAppinfo(sharingOrderDto.getTenantId(),payWay); WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); - + PayShareAdapterService payShareAdapterService = payServiceFactory.getPayShareAdapterService(payWay,payAccount.getPayVersion()); //分账检查是否已创建分账订单 WxProfitSharingOrder record = new WxProfitSharingOrder(); @@ -667,7 +665,7 @@ public class WxProfitSharingOrderServiceImpl implements WxProfitSharingOrderServ WxProfitSharingReceiver psReceiverQ = new WxProfitSharingReceiver(); psReceiverQ.updateTenantInfo(payAccount); psReceiverQ.setMerchantId(sharingOrder.getMerchantId()); - psReceiverQ.setSharingType(payServiceFactory.getPayShareAdapterService(dto.getPayWay()).getProfitSharingType()); + psReceiverQ.setSharingType(payServiceFactory.getPayShareAdapterService(dto.getPayWay(),payAccount.getPayVersion()).getProfitSharingType()); psReceiverQ.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_VALID.getCode()); List psReceiverList = wxProfitSharingReceiverMapper.findList(psReceiverQ); if (null == psReceiverList || psReceiverList.size() !=1 ) { @@ -677,7 +675,7 @@ public class WxProfitSharingOrderServiceImpl implements WxProfitSharingOrderServ JSONArray realReceivers = new JSONArray(); psReceiverList.stream().forEach(receiver->{ JSONObject jo = new JSONObject(); - jo.put("type",payServiceFactory.getPayShareAdapterService(dto.getPayWay()).getShareAccount(receiver.getReceiverType()).getMessage()); + jo.put("type",payServiceFactory.getPayShareAdapterService(dto.getPayWay(),payAccount.getPayVersion()).getShareAccount(receiver.getReceiverType()).getMessage()); jo.put("account",receiver.getReceiverAccount()); jo.put("amount", amount); //jo.put("description",receiver.getReceiverComments()); //改为存ID, diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxProfitSharingReceiverServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxProfitSharingReceiverServiceImpl.java index 9ad9c85e3..73cf2accd 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxProfitSharingReceiverServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxProfitSharingReceiverServiceImpl.java @@ -157,7 +157,7 @@ public class WxProfitSharingReceiverServiceImpl implements WxProfitSharingReceiv //receiver.setTrueName(receiverParam.getTrueName()); //添加分账账户 - ShareAccountResult createResult = payServiceFactory.getPayShareAdapterService(payWay.getCode()).createShareAccount(appInfo, payAccount, receiver); + ShareAccountResult createResult = payServiceFactory.getPayShareAdapterService(payWay.getCode(),payAccount.getPayVersion()).createShareAccount(appInfo, payAccount, receiver); if (!createResult.isSuccess()) { return new ResultData(createResult.getCode(), createResult.getMsg()); } @@ -395,7 +395,7 @@ public class WxProfitSharingReceiverServiceImpl implements WxProfitSharingReceiv ))) { //还有别的商户使用这个账号,不从微信服务器申请删除 } else { - ShareAccountResult shareResult = payServiceFactory.getPayShareAdapterService(receiver.getPlat()).deleteShareAccount(appInfo, payAccount, receiver); + ShareAccountResult shareResult = payServiceFactory.getPayShareAdapterService(receiver.getPlat(),payAccount.getPayVersion()).deleteShareAccount(appInfo, payAccount, receiver); if (!shareResult.isSuccess()) { return new ResultData(shareResult.getCode(), shareResult.getMsg()); } diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java index 6dbbcd8e7..eddaf354f 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java @@ -229,7 +229,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { throw new MallinkException(ErrorCode.PAY_ORDER_QUERY_ERROR.getCode(), "payAccount为空[payId:"+appInfo.getPayId()+"]"); } try { - PayQueryAdapterResult queryResult = payServiceFactory.getPayAdapterService(payOrder.getPayVendor()).queryPayStatus(payOrder, appInfo, payAccount); + PayQueryAdapterResult queryResult = payServiceFactory.getPayAdapterService(payOrder.getPayVendor(),payAccount.getPayVersion()).queryPayStatus(payOrder, appInfo, payAccount); if(EnumPayStatus.PAY_STATUS_SUCCESS.getCode() != queryResult.getCode()){ return new ResultData(ErrorCode.PAY_ORDER_ERROR.getCode(),"该订单查询支付状态为未支付成功,无法退款。"); } @@ -350,7 +350,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { throw new MallinkException(ErrorCode.DB_FAIL); } - RefundAdapterResult refundResult = payServiceFactory.getRefundPayAdapterService(payOrder.getPayVendor()).refund(payAccount, appInfo, record, payOrder, payType); + RefundAdapterResult refundResult = payServiceFactory.getRefundPayAdapterService(payOrder.getPayVendor(),payAccount.getPayVersion()).refund(payAccount, appInfo, record, payOrder, payType); if (refundResult.isSuccess()) { record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); wxRefundOrderMapper.updateById(record); @@ -554,7 +554,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { if (null == payAccount) { throw new MallinkException(ErrorCode.PAY_ORDER_QUERY_ERROR.getCode(), "payAccount为空[payId:"+appInfo.getPayId()+"]"); } - RefundAdapterResult refundResult = payServiceFactory.getRefundPayAdapterService(payOrder.getPayVendor()).refund(payAccount, appInfo, record, payOrder, payType); + RefundAdapterResult refundResult = payServiceFactory.getRefundPayAdapterService(payOrder.getPayVendor(),payAccount.getPayVersion()).refund(payAccount, appInfo, record, payOrder, payType); if (refundResult.isSuccess()) { record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); wxRefundOrderMapper.updateById(record); @@ -573,7 +573,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { @Override public ResultData queryRefundOrder(WxAppinfo appInfo, WxRefundOrder record) { WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); - RefundAdapterResult result = payServiceFactory.getRefundPayAdapterService(record.getRefundVendor()).queryRefund(appInfo, payAccount, record); + RefundAdapterResult result = payServiceFactory.getRefundPayAdapterService(record.getRefundVendor(),payAccount.getPayVersion()).queryRefund(appInfo, payAccount, record); if (result.isSuccess()) { return new ResultData(Result.SUCCESS, "退款", result.getData()); }else { @@ -776,7 +776,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { logger.error("退款订单已存在, 无法再提交退款申请"); throw new MallinkException(ErrorCode.REFUND_ORDER_EXIST.getCode(), "退款订单已存在, 无法再提交退款申请"); } - RefundAdapterResult refundResult = payServiceFactory.getRefundPayAdapterService(payOrder.getPayVendor()).refund(payAccount, appInfo, record, payOrder, null); + RefundAdapterResult refundResult = payServiceFactory.getRefundPayAdapterService(payOrder.getPayVendor(),payAccount.getPayVersion()).refund(payAccount, appInfo, record, payOrder, null); if (refundResult.isSuccess()) { record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); wxRefundOrderMapper.updateById(record); @@ -1022,7 +1022,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { @Override @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) public ResultData syncRefundOrder(WxAppinfo appinfo, WxPayAccount payAccount, WxRefundOrder order) { - RefundAdapterResult refundAdapterResult = payServiceFactory.getRefundPayAdapterService(order.getRefundVendor()).queryRefund(appinfo, payAccount, order); + RefundAdapterResult refundAdapterResult = payServiceFactory.getRefundPayAdapterService(order.getRefundVendor(),payAccount.getPayVersion()).queryRefund(appinfo, payAccount, order); if(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode().equals(refundAdapterResult.getCode())){//退款中 退款申请成功 if(EnumRefundStatus.REFUND_WAIT.getCode().equals(order.getRefundOrderStatus())){ 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 aad499a6d..0b644b30e 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/PayServiceFactory.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/PayServiceFactory.java @@ -2,28 +2,34 @@ package com.iformall.service.pay; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; - import com.iformall.enums.EnumAppPlat; +import com.iformall.enums.EnumPayVersion; import com.iformall.service.pay.service.pay.douyin.miniApp.TtMiniAppPayAdapterService; import com.iformall.service.pay.service.refund.douyin.TtRefundAdapterService; +import com.iformall.service.pay.service.refund.wx.v2.WxRefundAdapterService; +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.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.WxCashOutAdapterService; +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.pay.CDrivingPayService; import com.iformall.service.pay.service.pay.CPassivePayService; import com.iformall.service.pay.service.pay.PayAdapterService; -import com.iformall.service.pay.service.pay.wx.h5.WxH5PayService; -import com.iformall.service.pay.service.pay.wx.miniApp.appPay.WxMiniAppPayAdapterService; -import com.iformall.service.pay.service.pay.wx.miniApp.maPay.WxMiniMaPayAdapterService; +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.h5.WxH5PayV3Service; +import com.iformall.service.pay.service.pay.wx.v3.miniApp.appPay.WxMiniAppPayV3AdapterService; +import com.iformall.service.pay.service.pay.wx.v3.miniApp.maPay.WxMiniMaPayV3AdapterService; import com.iformall.service.pay.service.refund.RefundPayAdapterService; -import com.iformall.service.pay.service.refund.wx.WxRefundAdapterService; import com.iformall.service.pay.service.share.PayShareAdapterService; -import com.iformall.service.pay.service.share.wx.WxPayShareService; /** * 支付方式工厂 @@ -32,119 +38,154 @@ import com.iformall.service.pay.service.share.wx.WxPayShareService; @Service public class PayServiceFactory { - private Map serviceMap = null; - private Map qrcodeMap = null; - private Map shareMap = null; - private Map refundMap = null; - private Map cashoutMap = null; + private Map serviceMap = null; + private Map qrcodeMap = null; + private Map shareMap = null; + private Map refundMap = null; + private Map cashoutMap = null; @Autowired WxMiniAppPayAdapterService wxMiniAppPayService; + @Autowired + WxMiniAppPayV3AdapterService wxMiniAppPayV3AdapterService; + @Autowired WxMiniMaPayAdapterService wxMiniAppMaPayService; + @Autowired + WxMiniMaPayV3AdapterService wxMiniMaPayV3AdapterService; + @Autowired WxH5PayService wxH5PayService; + @Autowired + WxH5PayV3Service wxH5PayV3Service; @Autowired TtMiniAppPayAdapterService ttMiniAppPayService; @Autowired WxPayShareService wxShareService; + @Autowired + WxPayShareV3Service wxPayShareV3Service; @Autowired TtPayShareService ttShareService; - @Autowired WxRefundAdapterService wxRefundService; + @Autowired + WxRefundV3AdapterService wxRefundV3AdapterService; @Autowired TtRefundAdapterService ttRefundService; @Autowired WxCashOutAdapterService wxCashOutService; + @Autowired + WxCashOutV3AdapterService wxCashOutV3AdapterService; - private Map getServiceMap() { + private Map getServiceMap() { if (null == serviceMap) { - serviceMap = new ConcurrentHashMap(); - serviceMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode(), wxMiniAppPayService); - serviceMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode(), wxMiniAppMaPayService); - serviceMap.put(EnumPayWay.PAY_WAY_WECHAT_WAP.getCode(), wxH5PayService); - serviceMap.put(EnumPayWay.PAY_WAY_TT.getCode(),ttMiniAppPayService); + 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.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(), wxMiniMaPayV3AdapterService); + 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.getCode(), wxH5PayV3Service); + serviceMap.put(EnumPayWay.PAY_WAY_TT.getCode()+"_"+EnumPayVersion.DY_PAY_V2.getCode(),ttMiniAppPayService); } return serviceMap; } - private Map getQrcodeMap() { + private Map getQrcodeMap() { if (null == qrcodeMap) { - qrcodeMap = new ConcurrentHashMap(); - qrcodeMap.put(EnumAppPlat.WX.getCode(), wxMiniAppPayService); - qrcodeMap.put(EnumAppPlat.TOUTIAO.getCode(),ttMiniAppPayService); + qrcodeMap = new ConcurrentHashMap(); + qrcodeMap.put(EnumAppPlat.WX.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxMiniAppPayService); + qrcodeMap.put(EnumAppPlat.WX.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxMiniAppPayService); + qrcodeMap.put(EnumAppPlat.TOUTIAO.getCode()+"_"+EnumPayVersion.DY_PAY_V2.getCode(),ttMiniAppPayService); } return qrcodeMap; } - private Map getShareMap(){ + private Map getShareMap(){ if (null == shareMap ) { - shareMap = new ConcurrentHashMap(); - shareMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_TT.getCode(), ttShareService); - shareMap.put(EnumPayWay.PAY_WAY_POS_NEU.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_MERCHANT.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_VERRIFY.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_B_MA.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_CAR_STOP.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_SYSTEM_SEND.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_INJECT_SEND.getCode(), ttShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_BATCH_SEND.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_TRADE.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_PASSWD.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_CREDIT.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_GIFTLIST.getCode(), wxShareService); + shareMap = new ConcurrentHashMap(); + shareMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_TT.getCode()+"_"+EnumPayVersion.DY_PAY_V2.getCode(), ttShareService); + shareMap.put(EnumPayWay.PAY_WAY_POS_NEU.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_MERCHANT.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_VERRIFY.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_B_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_CAR_STOP.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_SYSTEM_SEND.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_INJECT_SEND.getCode()+"_"+EnumPayVersion.DY_PAY_V2.getCode(), ttShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_BATCH_SEND.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_TRADE.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_PASSWD.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_CREDIT.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_GIFTLIST.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxShareService); + + shareMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_POS_NEU.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_MERCHANT.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_VERRIFY.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_B_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_CAR_STOP.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_SYSTEM_SEND.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_BATCH_SEND.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_TRADE.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_PASSWD.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_CREDIT.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); + shareMap.put(EnumPayWay.PAY_WAY_NOT_UNPAY_GIFTLIST.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxPayShareV3Service); } return shareMap; } - private Map getRefundMap(){ + private Map getRefundMap(){ if (null == refundMap ) { - refundMap = new ConcurrentHashMap(); - refundMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode(), wxRefundService); - refundMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode(), wxRefundService); - refundMap.put(EnumPayWay.PAY_WAY_TT.getCode(), ttRefundService); + refundMap = new ConcurrentHashMap(); + refundMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxRefundService); + refundMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V2.getCode(), wxRefundService); + refundMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxRefundV3AdapterService); + refundMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxRefundV3AdapterService); + refundMap.put(EnumPayWay.PAY_WAY_TT.getCode()+"_"+EnumPayVersion.DY_PAY_V2.getCode(), ttRefundService); } return refundMap; } - private Map getCashOutMap() { + private Map getCashOutMap() { if (null == cashoutMap ) { - cashoutMap = new ConcurrentHashMap(); - cashoutMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode(), wxCashOutService); - cashoutMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode(), wxCashOutService); + 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.getCode(), wxCashOutV3AdapterService); + cashoutMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode()+"_"+EnumPayVersion.WX_PAY_V3.getCode(), wxCashOutV3AdapterService); } return cashoutMap; } - public PayAdapterService getPayAdapterService(Integer type) throws MallinkException{ - PayAdapterService service = getServiceMap().get(type); + public PayAdapterService getPayAdapterService(Integer type,Integer payVersion) throws MallinkException{ + PayAdapterService service = getServiceMap().get(type+"_"+payVersion); if (null == service) { throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 支付service未找到"); } return service; } - public PayAdapterService getQrcodeService(Integer type) throws MallinkException{ - PayAdapterService service = getQrcodeMap().get(type); + public PayAdapterService getQrcodeService(Integer type,Integer payVersion) throws MallinkException{ + PayAdapterService service = getQrcodeMap().get(type+"_"+payVersion); if (null == service) { throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 支付service未找到"); } return service; } - public CDrivingPayService getCDrivingPayService(Integer type) throws MallinkException{ - PayAdapterService service = getServiceMap().get(type); + public CDrivingPayService getCDrivingPayService(Integer type,Integer payVersion) throws MallinkException{ + PayAdapterService service = getServiceMap().get(type+"_"+payVersion); if (null == service) { throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 支付service未找到"); } @@ -155,8 +196,8 @@ public class PayServiceFactory { } } - public CPassivePayService getCPassivePayService(Integer type) throws MallinkException{ - PayAdapterService service = getServiceMap().get(type); + public CPassivePayService getCPassivePayService(Integer type,Integer payVersion) throws MallinkException{ + PayAdapterService service = getServiceMap().get(type+"_"+payVersion); if (null == service) { throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 支付service未找到"); } @@ -167,24 +208,24 @@ public class PayServiceFactory { } } - public PayShareAdapterService getPayShareAdapterService(Integer type) throws MallinkException{ - PayShareAdapterService shareService = getShareMap().get(type); + public PayShareAdapterService getPayShareAdapterService(Integer type,Integer payVersion) throws MallinkException{ + PayShareAdapterService shareService = getShareMap().get(type+"_"+payVersion); if (null == shareService) { throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 分账service未找到"); } return shareService; } - public RefundPayAdapterService getRefundPayAdapterService(Integer type) throws MallinkException{ - RefundPayAdapterService refundService = getRefundMap().get(type); + public RefundPayAdapterService getRefundPayAdapterService(Integer type,Integer payVersion) throws MallinkException{ + RefundPayAdapterService refundService = getRefundMap().get(type+"_"+payVersion); if (null == refundService) { throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 退款service未找到"); } return refundService; } - public CashOutAdapterService getCashOutAdapterService(Integer type)throws MallinkException { - CashOutAdapterService cashOutService = getCashOutMap().get(type); + public CashOutAdapterService getCashOutAdapterService(Integer type,Integer payVersion)throws MallinkException { + CashOutAdapterService cashOutService = getCashOutMap().get(type+"_"+payVersion); if (null == cashOutService) { throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 零钱service未找到"); } diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/WxCashOutAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v2/WxCashOutAdapterService.java similarity index 99% rename from mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/WxCashOutAdapterService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v2/WxCashOutAdapterService.java index 47d76b87c..8e475839a 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/WxCashOutAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v2/WxCashOutAdapterService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.cashout.wx; +package com.iformall.service.pay.service.cashout.wx.v2; import java.io.UnsupportedEncodingException; import java.util.ArrayList; 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/v3/WxCashOutV3AdapterService.java new file mode 100644 index 000000000..87490788a --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/cashout/wx/v3/WxCashOutV3AdapterService.java @@ -0,0 +1,500 @@ +package com.iformall.service.pay.service.cashout.wx.v3; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +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.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.domain.po.WxAppinfo; +import com.iformall.domain.po.WxCashOut; +import com.iformall.domain.po.WxPayAccount; +import com.iformall.domain.po.WxPayOrder; +import com.iformall.domain.po.WxRefundOrder; +import com.iformall.domain.po.base.TenantEntity; +import com.iformall.enums.EnumAppPlat; +import com.iformall.enums.EnumCashOutStatus; +import com.iformall.enums.EnumPayMode; +import com.iformall.enums.EnumPayType; +import com.iformall.enums.EnumPayWay; +import com.iformall.enums.EnumRefundStatus; +import com.iformall.exception.MallinkException; +import com.iformall.mapper.WxAppinfoMapper; +import com.iformall.mapper.WxPayAccountMapper; +import com.iformall.mapper.WxPayOrderMapper; +import com.iformall.mapper.WxRefundOrderMapper; +import com.iformall.pay.WxCashOutP; +import com.iformall.pay.WxCashOutPV3; +import com.iformall.pay.WxCashOutPV3Item; +import com.iformall.pay.WxCashOutQueryP; +import com.iformall.pay.WxPay; +import com.iformall.pay.WxPayment; +import com.iformall.pay.WxRefundOrderP; +import com.iformall.pay.WxRefundOrderSP; +import com.iformall.service.WxAppinfoService; +import com.iformall.service.pay.service.cashout.CashOutAdapterService; +import com.iformall.service.pay.service.cashout.entity.CashOutAdapterResult; +import com.iformall.service.pay.service.refund.RefundPayAdapterService; +import com.iformall.service.pay.service.refund.entity.RefundAdapterResult; +import com.iformall.service.pay.service.refund.entity.RefundNotifyAdapterResult; +import com.iformall.utils.BeanUtils; +import com.iformall.utils.CipherUtil; +import com.iformall.utils.DateUtils; +import com.iformall.utils.MaUtil; +import com.iformall.utils.Utility; +import com.iformall.utils.XmlUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class WxCashOutV3AdapterService implements CashOutAdapterService{ + + @Autowired + WxAppinfoService wxAppinfoService; + + @Autowired + MaUtil maUtil; + + 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" + + "}"); + + @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.getMerchantKeyPath())) { + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付失败。商户密钥为空。请联系管理员配置。", null); + } + if (StringUtils.isBlank(payAccount.getMerchantApiv3Key())) { + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付失败。商户密钥ApiV3为空。请联系管理员配置。", null); + } + + WxPayService payService = maUtil.getWxPayServiceBySelfModel(appInfo,payAccount); + if (null == payService) { + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付失败。当前小程序未查询到payService。", null); + } + String response = null; + try { + response = WxPay.merchantTranferChange(payService,generateWxCashOutPV3(payAccount, appInfo, cashOut)); + } catch (Exception e) { + log.error("零钱支付异常: " + e.getMessage(),e); + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "微信零钱支付接口调用异常:"+e.getMessage(), null); + } + log.info("微信零钱支付:, response: " + response.toString()); + return generateResult(response,cashOut); + +// if (payAccount.getType() == EnumPayMode.MCH.getCode()) { + // 普通商户模式 +// } + } + + private WxCashOutPV3 generateWxCashOutPV3(WxPayAccount payAccount,WxAppinfo appInfo,WxCashOut cashOut) { + WxCashOutPV3 wxCashOutPv3 = new WxCashOutPV3(); + wxCashOutPv3.setAppid(appInfo.getAppId()); + wxCashOutPv3.setOut_batch_no(String.valueOf(cashOut.getId())); + + StringBuffer bn = new StringBuffer(cashOut.getMerchantName()).append("提现"); + try { + wxCashOutPv3.setBatch_name(new String(bn.toString().getBytes("ISO-8859-1"), "UTF-8")); + } catch (UnsupportedEncodingException e) { + wxCashOutPv3.setBatch_name("tixian"); + } + wxCashOutPv3.setBatch_remark("From FM WxMiniApp"); + wxCashOutPv3.setTotal_amount(cashOut.getTotalFee()); + wxCashOutPv3.setTotal_num(1); + List itemList = new ArrayList(); + WxCashOutPV3Item item = new WxCashOutPV3Item(); + item.setOut_detail_no(Utility.generate32UUID()); + item.setOpenid(cashOut.getReciveOpenId()); + item.setTransfer_amount(cashOut.getTotalFee()); + item.setTransfer_remark("From FM WxMiniApp Tranfer."); + item.setUser_name(cashOut.getRealName()); + itemList.add(item); + wxCashOutPv3.setTransfer_detail_list(itemList); + return wxCashOutPv3; + } + + private CashOutAdapterResult generateResult(String response,WxCashOut cashOut) { + JSONObject result = JSON.parseObject(response); + String batchId = result.getString("batch_id"); + if (!StringUtils.isBlank(batchId)) { + cashOut.setWxPayNo(batchId); + String payTime = result.getString("create_time"); + cashOut.setWxPayTime(payTime); + return new CashOutAdapterResult(true,EnumCashOutStatus.SUCCESS.getCode(),"微信零钱支付申请成功",result); + }else { + //log.error("微信零钱支付申请失败: " + response); + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "微信零钱支付申请失败:微信接口未返回值", result); + } + } + + + @Override + public CashOutAdapterResult queryCashOut(WxAppinfo appInfo, WxPayAccount payAccount, WxCashOut cashOut) { + if (StringUtils.isBlank(payAccount.getMerchantCertPath())) { + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付失败。商户证书为空。请联系管理员配置。", null); + } + if (StringUtils.isBlank(payAccount.getMerchantKeyPath())) { + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付失败。商户密钥为空。请联系管理员配置。", null); + } + if (StringUtils.isBlank(payAccount.getMerchantApiv3Key())) { + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付失败。商户密钥ApiV3为空。请联系管理员配置。", null); + } + WxPayService payService = maUtil.getWxPayServiceBySelfModel(appInfo,payAccount); + if (null == payService) { + return new CashOutAdapterResult(false, EnumCashOutStatus.FAIL.getCode(), "零钱支付失败。当前小程序未查询到payService。", null); + } + String response = null; + try { + response = WxPay.merchantTransferInfo(String.valueOf(cashOut.getId()), payService); + } catch (Exception e) { + log.error("零钱支付查询异常: " + e.getMessage(),e); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "微信零钱支付查询接口异常:"+e.getMessage()); + } + log.info("微信零钱支付查询:"+ response.toString()); + return getReusltFromQuery(response,cashOut); + } + + private CashOutAdapterResult getReusltFromQuery(String response,WxCashOut cashOut) throws MallinkException{ + JSONObject result = JSON.parseObject(response); + JSONObject transferBatch = result.getJSONObject("transfer_batch"); + if (null != transferBatch) { + /** + * WAIT_PAY:待付款,商户员工确认付款阶段 + * ACCEPTED:已受理。批次已受理成功,若发起批量转账的30分钟后,转账批次单仍处于该状态,可能原因是商户账户余额不足等 + * PROCESSING:转账中。已开始处理批次内的转账明细单 + * FINISHED:已完成。批次内的所有转账明细单都已处理完成 + * CLOSED:已关闭。可查询具体的批次关闭原因确认 + */ + String batchStatus = transferBatch.getString("batch_status"); + if ("WAIT_PAY".equals(batchStatus)) { + throw new MallinkException(EnumCashOutStatus.FAIL.getCode(), "待商户付款:"); + }else if ("ACCEPTED".equals(batchStatus)) { + throw new MallinkException(EnumCashOutStatus.FAIL.getCode(), "已受理,待转账:"); + }else if ("PROCESSING".equals(batchStatus)) { + throw new MallinkException(EnumCashOutStatus.FAIL.getCode(), "待转账中"); + }else if ("CLOSED".equals(batchStatus)) { + /** + * MERCHANT_REVOCATION:商户主动撤销 OVERDUE_CLOSE:系统超时关闭 + */ + String close_reason = transferBatch.getString("close_reason"); + if ("MERCHANT_REVOCATION".equals(close_reason)) { + close_reason = "商户主动撤销"; + }else if ("OVERDUE_CLOSE".equals(close_reason)) { + close_reason = "系统超时关闭"; + } + return new CashOutAdapterResult(false,EnumCashOutStatus.FAIL.getCode(),"转账已关闭:"+close_reason,result); + }else if ("FINISHED".equals(batchStatus)) { + String detailId = transferBatch.getString("out_batch_no"); + cashOut.setWxPayNo(detailId); + String wxPayTime = transferBatch.getString("create_time"); + cashOut.setWxPayTime(wxPayTime); + return new CashOutAdapterResult(true,EnumCashOutStatus.SUCCESS.getCode(),"转账已完成",result); + }else { + log.error("微信零钱支付查询失败,微信返回未知状态: " + response); + throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "微信零钱支付查询失败, 微信返回未知状态:"+batchStatus); + } + }else { + log.error("微信零钱支付查询失败,微信未返回值: " + response); + throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "微信零钱支付查询失败,微信未返回值:"); + } + } + + + +// /** +// * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2 +// * +// * 在wx_pay_account里面要设置merchant_cert_path,登陆特约商户的商户后台,账号中心-API安全。 +// */ +// @Deprecated +// @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.merchantTranferChange(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); +// } +// } + +} 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/v2/BaseWxPayAdapterService.java similarity index 99% rename from mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/BaseWxPayAdapterService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v2/BaseWxPayAdapterService.java index 8d7e2c87d..6d8534399 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/v2/BaseWxPayAdapterService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.pay.wx; +package com.iformall.service.pay.service.pay.wx.v2; import java.io.File; import java.util.Date; diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/h5/WxH5PayService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v2/h5/WxH5PayService.java similarity index 95% rename from mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/h5/WxH5PayService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v2/h5/WxH5PayService.java index 84a4e50ea..6a6682706 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/h5/WxH5PayService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v2/h5/WxH5PayService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.pay.wx.h5; +package com.iformall.service.pay.service.pay.wx.v2.h5; import java.io.File; import java.util.Date; @@ -16,7 +16,7 @@ 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.BaseWxPayAdapterService; +import com.iformall.service.pay.service.pay.wx.v2.BaseWxPayAdapterService; @Service public class WxH5PayService extends BaseWxPayAdapterService implements CDrivingPayService{ diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/appPay/WxMiniAppPayAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v2/miniApp/appPay/WxMiniAppPayAdapterService.java similarity index 99% rename from mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/appPay/WxMiniAppPayAdapterService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v2/miniApp/appPay/WxMiniAppPayAdapterService.java index 14ae9705e..e6447184a 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/appPay/WxMiniAppPayAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v2/miniApp/appPay/WxMiniAppPayAdapterService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.pay.wx.miniApp.appPay; +package com.iformall.service.pay.service.pay.wx.v2.miniApp.appPay; import java.io.File; import java.util.Date; @@ -28,7 +28,7 @@ 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.BaseWxPayAdapterService; +import com.iformall.service.pay.service.pay.wx.v2.BaseWxPayAdapterService; import com.iformall.utils.BeanUtils; import com.iformall.utils.MapUtil; import com.iformall.utils.Utility; diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/maPay/WxMiniMaPayAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v2/miniApp/maPay/WxMiniMaPayAdapterService.java similarity index 98% rename from mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/maPay/WxMiniMaPayAdapterService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v2/miniApp/maPay/WxMiniMaPayAdapterService.java index a2e5ad1e4..abe7281fd 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/maPay/WxMiniMaPayAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v2/miniApp/maPay/WxMiniMaPayAdapterService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.pay.wx.miniApp.maPay; +package com.iformall.service.pay.service.pay.wx.v2.miniApp.maPay; import java.io.File; import java.util.Date; @@ -31,7 +31,7 @@ import com.iformall.service.pay.service.pay.CPassivePayService; import com.iformall.service.pay.service.pay.entity.CreateUser; 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.BaseWxPayAdapterService; +import com.iformall.service.pay.service.pay.wx.v2.BaseWxPayAdapterService; import com.iformall.utils.BeanUtils; import com.iformall.utils.Utility; import lombok.extern.slf4j.Slf4j; diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/h5/WxH5PayV3Service.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/h5/WxH5PayV3Service.java new file mode 100644 index 000000000..8039fcea9 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/h5/WxH5PayV3Service.java @@ -0,0 +1,81 @@ +package com.iformall.service.pay.service.pay.wx.v3.h5; + +import java.io.File; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import com.iformall.common.ErrorCode; +import com.iformall.domain.po.*; +import com.iformall.exception.MallinkException; +import org.springframework.stereotype.Service; + +import com.iformall.enums.EnumPayShare; +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.v2.BaseWxPayAdapterService; + +@Service +public class WxH5PayV3Service implements CDrivingPayService{ + + @Override + public PayAdapterResult pay(WxPayAccount payAccount, WxPayOrder record,WxComposeOrder composeOrder,String productName, EnumPayShare isShare, + WxAppinfo appInfo, Date currentDate, PayExtraParam params) throws Exception { + // TODO Auto-generated method stub + return null; + } + + @Override + public PayQueryAdapterResult queryPayStatus(WxPayOrder oldRecord, WxAppinfo appInfo, + WxPayAccount payAccount) throws Exception { + //return super.queryPayStatus(oldRecord, appInfo, payAccount); + return null; + } + + @Override + public int queryPayStatus(PayQueryAdapterResult statusObject, String orderOutNo) throws Exception { + //return super.queryPayStatus(statusObject, orderOutNo); + return 0; + } + + @Override + public int queryPayStatusCode(WxPayOrder oldRecord, WxAppinfo appInfo, WxPayAccount payAccount) + throws Exception { + //return super.queryPayStatusCode(oldRecord, appInfo, payAccount); + return 0; + } + + @Override + public PayAdapterResult payOrderClose(WxAppinfo appInfo, WxPayOrder record, WxPayAccount payAccount) + throws Exception { + // TODO Auto-generated method stub + return null; + } + + @Override + public PayAdapterResult payOrderReverse(WxAppinfo appInfo, WxPayOrder record, WxPayAccount payAccount) + throws Exception { + // TODO Auto-generated method stub + return null; + } + + @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{ + // TODO Auto-generated method stub + return null; + } + + @Override + public PayAdapterResult noCreatePay(WxPayOrder record, WxComposeOrder composeOrder, List childOrders) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR); + } + +} 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..b56b84dcf --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/miniApp/appPay/WxMiniAppPayV3AdapterService.java @@ -0,0 +1,291 @@ +package com.iformall.service.pay.service.pay.wx.v3.miniApp.appPay; + +import java.io.File; +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.stereotype.Service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.iformall.common.ErrorCode; +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.enums.EnumOrderStatus; +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.WxPayment; +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.v2.BaseWxPayAdapterService; +import com.iformall.utils.BeanUtils; +import com.iformall.utils.MapUtil; +import com.iformall.utils.Utility; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class WxMiniAppPayV3AdapterService implements CDrivingPayService{ + + + JSONObject errorMap = JSON.parseObject("{" + + "\"NOAUTH\":{\"detail\":\"商户无此接口权限\",\"reason\":\"商户未开通此接口权限\",\"resolution\":\"请商户前往申请此接口权限\"}," + + "\"NOTENOUGH\":{\"detail\":\"余额不足\",\"reason\":\"用户帐号余额不足\",\"resolution\":\"用户帐号余额不足,请用户充值或更换支付卡后再支付\"}," + + "\"ORDERPAID\":{\"detail\":\"商户订单已支付\",\"reason\":\"商户订单已支付,无需重复操作\",\"resolution\":\"商户订单已支付,无需更多操作\"}," + + "\"ORDERCLOSED\":{\"detail\":\"订单已关闭\",\"reason\":\"当前订单已关闭,无法支付\",\"resolution\":\"当前订单已关闭,请重新下单\"}," + + "\"SYSTEMERROR\":{\"detail\":\"系统错误\t\",\"reason\":\"系统超时\",\"resolution\":\"系统异常,请用相同参数重新调用\"}," + + "\"APPID_NOT_EXIST\":{\"detail\":\"APPID不存在\",\"reason\":\"参数中缺少APPID\",\"resolution\":\"请检查APPID是否正确\"}," + + "\"MCHID_NOT_EXIST\":{\"detail\":\"MCHID不存在\",\"reason\":\"参数中缺少MCHID\",\"resolution\":\"请检查MCHID是否正确\"}," + + "\"APPID_MCHID_NOT_MATCH\":{\"detail\":\"appid和mch_id不匹配\",\"reason\":\"appid和mch_id不匹配\",\"resolution\":\"请确认appid和mch_id是否匹配\"}," + + "\"LACK_PARAMS\":{\"detail\":\"缺少参数\t\",\"reason\":\"缺少必要的请求参数\",\"resolution\":\"请检查参数是否齐全\"}," + + "\"OUT_TRADE_NO_USED\":{\"detail\":\"商户订单号重复\",\"reason\":\"同一笔交易不能多次提交\",\"resolution\":\"请核实商户订单号是否重复提交\"}," + + "\"SIGNERROR\":{\"detail\":\"签名错误\",\"reason\":\"参数签名结果不正确\",\"resolution\":\"请检查签名参数和方法是否都符合签名算法要求\"}," + + "\"XML_FORMAT_ERROR\":{\"detail\":\"XML格式错误\t\",\"reason\":\"XML格式错误\",\"resolution\":\"请检查XML参数格式是否正确\"}," + + "\"REQUIRE_POST_METHOD\":{\"detail\":\"请使用post方法\",\"reason\":\"未使用post传递参数\",\"resolution\":\"请检查请求参数是否通过post方法提交\"}," + + "\"POST_DATA_EMPTY\":{\"detail\":\"post数据为空\",\"reason\":\"post数据不能为空\",\"resolution\":\"请检查post数据是否为空\"}," + + "\"NOT_UTF8\":{\"detail\":\"编码格式错误\",\"reason\":\"未使用指定编码格式\",\"resolution\":\"请使用UTF-8编码格式\"}}"); + + + private WxPayOrderP generateWxPayOrderP(WxPayAccount payAccount,WxComposeOrder composeOrder,String productName, WxPayOrder record,String openId,String appId,Date currentDate) throws Exception { + // 统一下单 普通商户模式 + String noncestr = Utility.generate32UUID(); + WxPayOrderP wxPayOrderP = new WxPayOrderP(); + wxPayOrderP.setOpenid(openId); + wxPayOrderP.setAppid(appId); + wxPayOrderP.setMch_id(payAccount.getMchId()); + wxPayOrderP.setNonce_str(noncestr); + wxPayOrderP.setBody(productName); + wxPayOrderP.setOut_trade_no(record.getPayOrderNo()); + wxPayOrderP.setTotal_fee(composeOrder.getPayment()); + wxPayOrderP.setSpbill_create_ip(record.getIp()); // 终端IP + wxPayOrderP.setGoods_tag(productName); + wxPayOrderP.setNotify_url(payAccount.getPayNotifyUrl()); + wxPayOrderP.setTrade_type(WxPay.TradeType.JSAPI.name()); // 终端类型 + wxPayOrderP.setProduct_id(String.valueOf(composeOrder.getMainOrderId())); // 订单ID + wxPayOrderP.setTime_start(Utility.getDataFormatStringYYYYMMDDHHmmss(currentDate)); + Date futureDate = new Date(); + futureDate.setTime(currentDate.getTime() + 15 * 60 * 1000); + wxPayOrderP.setTime_expire(Utility.getDataFormatStringYYYYMMDDHHmmss(futureDate)); // 15分钟后结束 + Map payOrderMap = BeanUtils.toStringMap(wxPayOrderP); + wxPayOrderP.setSign(WxPayment.createSign(payOrderMap, payAccount.getApiKey())); + return wxPayOrderP; + } + + private PayAdapterResult getOrderPResult(Map returnMap,WxPayOrder record,WxPayAccount payAccount,String noncestr) { + PayAdapterResult par = new PayAdapterResult(); + returnMap.put("payOrderId", String.valueOf(record.getId())); + String result_code = returnMap.get("result_code"); + if ("SUCCESS".equals(result_code)) { + par.setSuccess(true); + par.setMsg("success."); + par.setData(returnMap); + String prepay_id = returnMap.get("prepay_id"); + // update payOrder with prepay_id + record.setPrepayId(prepay_id); + record.setUpdateTime(new Date()); + record.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode()); + + String timestamp = String.valueOf(Utility.getCurrentTimeStamp()); + Map sighMap = MapUtil.getOrderMap(); + sighMap.put("appId", returnMap.get("appid")); + sighMap.put("timeStamp", timestamp); + sighMap.put("nonceStr", noncestr); + sighMap.put("package", "prepay_id=" + prepay_id); + sighMap.put("signType", "MD5"); + String signAgent = WxPayment.createSign(sighMap, payAccount.getApiKey()); + returnMap.put("timeStamp", timestamp); + returnMap.put("nonceStr", noncestr); + returnMap.put("package", "prepay_id=" + prepay_id); + returnMap.put("paySign", signAgent); + log.info("back to UI: " + returnMap.toString()); + } else { + String errMsg = ""; + JSONObject errObj = errorMap.getJSONObject(result_code); + if (errObj != null) { + errMsg = errObj.toJSONString(); + record.setFailReason(errMsg); + } else { + errMsg = returnMap.get("return_msg"); + record.setFailReason(errMsg); + } + record.setUpdateTime(new Date()); + + par.setSuccess(false); + par.setMsg(errMsg); + par.setData(returnMap); + } + + return par; + } + + + + private WxPayOrderSP generateWxPayOrderSP(WxPayAccount payAccount, WxComposeOrder composeOrder,String productName,WxPayOrder record,WxAppinfo appInfo,String openId,String appId,Date currentDate,EnumPayShare isShare) throws Exception { + String noncestr = Utility.generate32UUID(); + WxPayOrderSP wxPayOrderSP = new WxPayOrderSP(); + wxPayOrderSP.setSub_openid(openId); + wxPayOrderSP.setAppid(appInfo.getParentAppId()); + wxPayOrderSP.setMch_id(payAccount.getMchId()); + wxPayOrderSP.setSub_appid(appId); + wxPayOrderSP.setSub_mch_id(payAccount.getSubMchId()); + wxPayOrderSP.setNonce_str(noncestr); + wxPayOrderSP.setBody(productName); + wxPayOrderSP.setOut_trade_no(record.getPayOrderNo()); + wxPayOrderSP.setTotal_fee(composeOrder.getPayment().toString()); + wxPayOrderSP.setSpbill_create_ip(record.getIp()); // 终端IP + wxPayOrderSP.setGoods_tag(productName); // 券ID + wxPayOrderSP.setNotify_url(payAccount.getPayNotifyUrl()); + wxPayOrderSP.setTrade_type(WxPay.TradeType.JSAPI.name()); // 终端类型 + wxPayOrderSP.setProduct_id(String.valueOf(composeOrder.getMainOrderId())); // + wxPayOrderSP.setTime_start(Utility.getDataFormatStringYYYYMMDDHHmmss(currentDate)); + Date futureDate = new Date(); + futureDate.setTime(currentDate.getTime() + 15 * 60 * 1000); + wxPayOrderSP.setTime_expire(Utility.getDataFormatStringYYYYMMDDHHmmss(futureDate)); // 15分钟后结束 + wxPayOrderSP.setSign_type("HMAC-SHA256"); + wxPayOrderSP.setProfit_sharing(null); + if (isShare == EnumPayShare.YES) { + wxPayOrderSP.setProfit_sharing("Y"); + } + Map payOrderMap = BeanUtils.toStringMap(wxPayOrderSP); + wxPayOrderSP.setSign(WxPayment.createSignHMAC(payOrderMap, payAccount.getApiKey())); + return wxPayOrderSP; + } + + private PayAdapterResult getOrderSPResult(Map returnMap,WxPayOrder record,WxPayAccount payAccount,WxAppinfo appInfo,String noncestr) { + PayAdapterResult par = new PayAdapterResult(); + returnMap.put("payOrderId", String.valueOf(record.getId())); + String result_code = returnMap.get("result_code"); + if ("SUCCESS".equals(result_code)) { + par.setSuccess(true); + par.setMsg("success."); + par.setData(returnMap); + + String prepay_id = returnMap.get("prepay_id"); + // update payOrder with prepay_id + record.setPrepayId(prepay_id); + record.setUpdateTime(new Date()); + + String timestamp = String.valueOf(Utility.getCurrentTimeStamp()); + Map sighMap = MapUtil.getOrderMap(); + sighMap.put("appId", appInfo.getAppId()); + sighMap.put("timeStamp", timestamp); + sighMap.put("nonceStr", noncestr); + sighMap.put("package", "prepay_id=" + prepay_id); + sighMap.put("signType", "HMAC-SHA256"); + String signAgent = WxPayment.createSignHMAC(sighMap, payAccount.getApiKey()); + returnMap.put("timeStamp", timestamp); + returnMap.put("nonceStr", noncestr); + returnMap.put("package", "prepay_id=" + prepay_id); + returnMap.put("paySign", signAgent); + returnMap.put("signType", "HMAC-SHA256"); + log.info("back to UI: " + returnMap.toString()); + } else { + String errMsg = ""; + JSONObject errObj = errorMap.getJSONObject(result_code); + if (errObj != null) { + errMsg = errObj.toJSONString(); + record.setFailReason(errMsg); + } else { + errMsg = returnMap.get("return_msg"); + record.setFailReason(errMsg); + } + record.setUpdateTime(new Date()); + par.setSuccess(false); + par.setMsg(errMsg); + par.setData(returnMap); + } + return par; + } + + /** + * https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_8_2.shtml + */ + @Override + public PayAdapterResult pay(WxPayAccount payAccount, WxPayOrder record,WxComposeOrder composeOrder,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()) { + WxPayOrderP wxPayOrderP = generateWxPayOrderP(payAccount,composeOrder,productName,record,openId,appInfo.getAppId(),currentDate); + String response = WxPay.pushOrder(BeanUtils.toStringMap(wxPayOrderP)); + log.info("pay order, wechat pushOrder, " + wxPayOrderP.toString() + ", response: " + response.toString()); + Map returnMap = WxPayment.xmlToMap(response); + return getOrderPResult(returnMap,record,payAccount,wxPayOrderP.getNonce_str()); + + } else { + // 统一下单 // 服务商模式 + WxPayOrderSP wxPayOrderSP = generateWxPayOrderSP(payAccount,composeOrder,productName,record,appInfo,openId,appInfo.getAppId(),currentDate,isShare); + String response = WxPay.pushOrder(BeanUtils.toStringMap(wxPayOrderSP)); + log.info("pay order, wechat pushOrder, " + wxPayOrderSP.toString() + ", response: " + response.toString()); + Map returnMap = WxPayment.xmlToMap(response); + return getOrderSPResult(returnMap,record,payAccount,appInfo,wxPayOrderSP.getNonce_str()); + } + } + + @Override + public PayQueryAdapterResult queryPayStatus(WxPayOrder oldRecord, WxAppinfo appInfo, + WxPayAccount payAccount) throws Exception { + //return super.queryPayStatus(oldRecord,appInfo, payAccount); + return null; + } + + @Override + public int queryPayStatus(PayQueryAdapterResult statusObject, String orderOutNo) throws Exception { + //return super.queryPayStatus(statusObject, orderOutNo); + return 0; + } + + @Override + public int queryPayStatusCode(WxPayOrder oldRecord, WxAppinfo appInfo, WxPayAccount payAccount) + throws Exception { + //return super.queryPayStatusCode(oldRecord, appInfo, payAccount); + return 0; + } + + @Override + public PayAdapterResult payOrderClose(WxAppinfo appInfo, WxPayOrder record,WxPayAccount payAccount) throws Exception { + //return super.closeOrder(appInfo, record, payAccount); + return null; + } + + @Override + public PayAdapterResult payOrderReverse(WxAppinfo appInfo, WxPayOrder record, WxPayAccount payAccount) + throws Exception { + //return super.payOrderReverse(appInfo, record, payAccount); + return null; + } + + @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); + return null; + } + + @Override + public PayAdapterResult noCreatePay(WxPayOrder record, WxComposeOrder composeOrder, List childOrders) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR); + } + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/miniApp/maPay/WxMiniMaPayV3AdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/miniApp/maPay/WxMiniMaPayV3AdapterService.java new file mode 100644 index 000000000..c89233506 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/v3/miniApp/maPay/WxMiniMaPayV3AdapterService.java @@ -0,0 +1,275 @@ +package com.iformall.service.pay.service.pay.wx.v3.miniApp.maPay; + +import java.io.File; +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.iformall.common.ErrorCode; +import com.iformall.common.IdWorker; +import com.iformall.domain.po.base.TenantEntity; +import com.iformall.enums.EnumPayMode; +import com.iformall.enums.EnumPayShare; +import com.iformall.enums.EnumUserIsSubscribe; +import com.iformall.exception.MallinkException; +import com.iformall.mapper.WxCUserBasicInfoMapper; +import com.iformall.mapper.WxCUserMapper; +import com.iformall.mapper.WxMallMapper; +import com.iformall.pay.WxMicroPayOrderP; +import com.iformall.pay.WxMicroPayOrderSP; +import com.iformall.pay.WxPay; +import com.iformall.pay.WxPayment; +import com.iformall.service.WxCUserService; +import com.iformall.service.order.entity.WxComposeOrder; +import com.iformall.service.pay.entity.PayExtraParam; +import com.iformall.service.pay.service.pay.CPassivePayService; +import com.iformall.service.pay.service.pay.entity.CreateUser; +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.v2.BaseWxPayAdapterService; +import com.iformall.utils.BeanUtils; +import com.iformall.utils.Utility; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; + + +@Slf4j +@Service +public class WxMiniMaPayV3AdapterService implements CPassivePayService{ + + private WxMicroPayOrderP generateWxMicroPayOrderP(WxPayAccount payAccount, WxComposeOrder composeOrder, String productName,WxPayOrder record, EnumPayShare isShare, + WxAppinfo appInfo, Date currentDate,String bAppId,String bUserPhone) throws Exception { + String noncestr = Utility.generate32UUID(); + WxMicroPayOrderP wxPayOrderP = new WxMicroPayOrderP(); + wxPayOrderP.setAppid(bAppId); + wxPayOrderP.setMch_id(payAccount.getMchId()); + wxPayOrderP.setDevice_info(bUserPhone); + wxPayOrderP.setNonce_str(noncestr); + wxPayOrderP.setBody(productName); + wxPayOrderP.setOut_trade_no(record.getPayOrderNo()); + wxPayOrderP.setTotal_fee(record.getPayAmount()); + wxPayOrderP.setSpbill_create_ip(record.getIp()); // 终端IP + wxPayOrderP.setAuth_code(record.getAuthCode()); + wxPayOrderP.setTime_start(Utility.getDataFormatStringYYYYMMDDHHmmss(currentDate)); + Date futureDate = new Date(); + futureDate.setTime(currentDate.getTime() + 15 * 60 * 1000); + wxPayOrderP.setTime_expire(Utility.getDataFormatStringYYYYMMDDHHmmss(futureDate)); // 15分钟后结束 + Map payOrderMap = BeanUtils.toStringMap(wxPayOrderP); + wxPayOrderP.setSign(WxPayment.createSign(payOrderMap, payAccount.getApiKey())); + return wxPayOrderP; + } + + private PayAdapterResult getWxMicroPayOrderPResult(Map returnMap,WxPayOrder record,WxPayAccount payAccount) { + String return_code = returnMap.get("return_code"); + String result_code = returnMap.get("result_code"); + PayAdapterResult pr = null; + if ("SUCCESS".equalsIgnoreCase(return_code)) { + if ("SUCCESS".equals(result_code)) { + String openId = returnMap.get("openid"); + String isSubscribe = returnMap.get("is_subscribe"); + String transactionId = returnMap.get("transaction_id"); + record.setTransactionId(transactionId); + record.setUpdateTime(new Date()); + pr = new PayAdapterResult(true, "success", returnMap,transactionId); + } else { + String err_code = returnMap.get("err_code"); + String errMsg = returnMap.get("err_code_des"); + if (errMsg.length() <= 0) { + errMsg = returnMap.get("return_msg"); + } + record.setFailReason(errMsg); + record.setUpdateTime(new Date()); + pr = new PayAdapterResult(false, errMsg, returnMap,null); + } + } else { + String errMsg = returnMap.get("return_msg"); + record.setFailReason(errMsg); + record.setUpdateTime(new Date()); + pr = new PayAdapterResult(false, errMsg, returnMap,null); + } + return pr; + } + + + private WxMicroPayOrderSP generateWxMicroPayOrderSP(WxPayAccount payAccount, WxComposeOrder composeOrder, String productName,WxPayOrder record, EnumPayShare isShare, + WxAppinfo appInfo, Date currentDate,String bUserPhone) throws Exception { + String noncestr = Utility.generate32UUID(); + WxMicroPayOrderSP wxPayOrderSP = new WxMicroPayOrderSP(); + wxPayOrderSP.setAppid(appInfo.getParentAppId()); + wxPayOrderSP.setMch_id(payAccount.getMchId()); + wxPayOrderSP.setSub_appid(appInfo.getAppId()); + wxPayOrderSP.setSub_mch_id(payAccount.getSubMchId()); + wxPayOrderSP.setDevice_info(bUserPhone); + wxPayOrderSP.setNonce_str(noncestr); + wxPayOrderSP.setBody(productName); + wxPayOrderSP.setOut_trade_no(record.getPayOrderNo()); + wxPayOrderSP.setTotal_fee(record.getPayAmount()); + wxPayOrderSP.setSpbill_create_ip(record.getIp()); + wxPayOrderSP.setAuth_code(record.getAuthCode()); + wxPayOrderSP.setTime_start(Utility.getDataFormatStringYYYYMMDDHHmmss(currentDate)); + Date futureDate = new Date(); + futureDate.setTime(currentDate.getTime() + 15 * 60 * 1000); + wxPayOrderSP.setTime_expire(Utility.getDataFormatStringYYYYMMDDHHmmss(futureDate)); // 15分钟后结束 + wxPayOrderSP.setSign_type("HMAC-SHA256"); + wxPayOrderSP.setProfit_sharing(null); + if (isShare == EnumPayShare.YES) { + wxPayOrderSP.setProfit_sharing("Y"); + } + Map payOrderMap = BeanUtils.toStringMap(wxPayOrderSP); + wxPayOrderSP.setSign(WxPayment.createSignHMAC(payOrderMap, payAccount.getApiKey())); + return wxPayOrderSP; + } + + private PayAdapterResult getWxMicroPayOrderSPResutl(Map returnMap,WxPayOrder record,WxPayAccount payAccount) { + PayAdapterResult pr = null; + String return_code = returnMap.get("return_code"); + String result_code = returnMap.get("result_code"); + if ("SUCCESS".equalsIgnoreCase(return_code)) { + if ("SUCCESS".equals(result_code)) { + String openId = returnMap.get("sub_openid"); + String isSubscribe = returnMap.get("sub_is_subscribe"); + String transactionId = returnMap.get("transaction_id"); + record.setTransactionId(transactionId); + record.setUpdateTime(new Date()); + pr = new PayAdapterResult(true, "success", returnMap,transactionId); + } else { + String err_code = returnMap.get("err_code"); + String errMsg = returnMap.get("err_code_des"); + if (errMsg.length() <= 0) { + errMsg = returnMap.get("return_msg"); + } + record.setFailReason(errMsg); + record.setUpdateTime(new Date()); + pr = new PayAdapterResult(false, errMsg, returnMap,null); + } + } else { + String errMsg = returnMap.get("return_msg"); + record.setFailReason(errMsg); + record.setUpdateTime(new Date()); + pr = new PayAdapterResult(false, errMsg, returnMap,null); + } + return pr; + } + + + @Override + public PayAdapterResult pay(WxPayAccount payAccount, WxPayOrder record, WxComposeOrder composeOrder,String productName, EnumPayShare isShare, + WxAppinfo appInfo, Date currentDate, PayExtraParam params) throws Exception { + if (payAccount.getType() == EnumPayMode.MCH.getCode()) { + // 扫码支付 普通商户模式 + String bAppId = (String) params.getValue("bAppId"); + if (StringUtils.isBlank(bAppId)) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"bAppId 不能为空"); + } + String bUserPhone = (String) params.getValue("bUserPhone"); + if (StringUtils.isBlank(bUserPhone)) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"bUserPhone 不能为空"); + } + + WxMicroPayOrderP wxPayOrderP = generateWxMicroPayOrderP(payAccount, composeOrder,productName,record, isShare, appInfo, currentDate, bAppId, bUserPhone); + String response = WxPay.micropay(BeanUtils.toStringMap(wxPayOrderP)); + log.info("pay order, wechat micropay, " + wxPayOrderP.toString() + ", response: " + response.toString()); + Map returnMap = WxPayment.xmlToMap(response); + returnMap.put("payOrderId", record.getPayOrderNo()); + returnMap.put("orderId", String.valueOf(composeOrder.getMainOrderId())); + return getWxMicroPayOrderPResult(returnMap, record, payAccount); + } else { + // 统一下单 // 服务商模式 + String bUserPhone = (String) params.getValue("bUserPhone"); + if (StringUtils.isBlank(bUserPhone)) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"bUserPhone 不能为空"); + } + WxMicroPayOrderSP wxPayOrderSP = generateWxMicroPayOrderSP(payAccount, composeOrder,productName,record, isShare, appInfo, currentDate, bUserPhone); + String response = WxPay.micropay(BeanUtils.toStringMap(wxPayOrderSP)); + log.info("pay order, wechat micropay, " + wxPayOrderSP.toString() + ", response: " + response.toString()); + Map returnMap = WxPayment.xmlToMap(response); + returnMap.put("payOrderId", record.getPayOrderNo()); + returnMap.put("orderId", String.valueOf(composeOrder.getMainOrderId())); + return getWxMicroPayOrderSPResutl(returnMap, record, payAccount); + } + } + + + @Autowired + WxCUserMapper wxCUserMapper; + @Autowired + WxCUserService wxCUserService; + @Autowired + WxCUserBasicInfoMapper wxCUserBasicInfoMapper; + @Autowired + WxMallMapper wxMallMapper; + + @Override + public CreateUser getCUserAfterPay(Object result,WxAppinfo appInfo) throws Exception { + // add c_user, 收银台支付和券支付可能不是同一个人 + WxCUser userQ = new WxCUser(); + Map returnMap = (Map) result; + String openId = returnMap.get("sub_openid"); + //String isSubscribe = returnMap.get("sub_is_subscribe"); + userQ.setOpenId(openId); + userQ.setAppId(appInfo.getAppId()); + userQ.updateTenantInfo(appInfo); + WxCUser user1 = wxCUserMapper.findByOpenId(userQ); + if (user1 == null) { + return null; + }else { + return new CreateUser(user1.getId(),user1.getUserId()); + } + } + + @Override + public PayQueryAdapterResult queryPayStatus(WxPayOrder oldRecord, WxAppinfo appInfo, + WxPayAccount payAccount) throws Exception { + //return super.queryPayStatus(oldRecord,appInfo, payAccount); + return null; + } + + @Override + public int queryPayStatus(PayQueryAdapterResult statusObject, String orderOutNo) throws Exception { + //return super.queryPayStatus(statusObject, orderOutNo); + return 0; + } + + @Override + public int queryPayStatusCode(WxPayOrder oldRecord, WxAppinfo appInfo, WxPayAccount payAccount) + throws Exception { + //return super.queryPayStatusCode(oldRecord, appInfo, payAccount); + return 0; + } + + @Override + public PayAdapterResult payOrderClose(WxAppinfo appInfo, WxPayOrder record,WxPayAccount payAccount) throws Exception { + //return super.closeOrder(appInfo, record, payAccount); + return null; + } + + @Override + public PayAdapterResult payOrderReverse(WxAppinfo appInfo, WxPayOrder record, WxPayAccount payAccount) + throws Exception { + //return super.payOrderReverse(appInfo, record, payAccount); + return null; + } + + @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); + return null; + } + + @Override + public PayAdapterResult noCreatePay(WxPayOrder record, WxComposeOrder composeOrder, List childOrders) { + throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR); + } + + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/WxRefundAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/v2/WxRefundAdapterService.java similarity index 99% rename from mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/WxRefundAdapterService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/v2/WxRefundAdapterService.java index 9458ac013..1f87ec534 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/WxRefundAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/v2/WxRefundAdapterService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.refund.wx; +package com.iformall.service.pay.service.refund.wx.v2; import java.util.List; import java.util.Map; diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/v3/WxRefundV3AdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/v3/WxRefundV3AdapterService.java new file mode 100644 index 000000000..fdcf82252 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/v3/WxRefundV3AdapterService.java @@ -0,0 +1,685 @@ +package com.iformall.service.pay.service.refund.wx.v3; + +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +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.JSONObject; +import com.iformall.common.ErrorCode; +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxPayAccount; +import com.iformall.domain.po.WxPayOrder; +import com.iformall.domain.po.WxRefundOrder; +import com.iformall.enums.EnumPayMode; +import com.iformall.enums.EnumPayType; +import com.iformall.enums.EnumPayWay; +import com.iformall.enums.EnumRefundStatus; +import com.iformall.exception.MallinkException; +import com.iformall.mapper.WxAppinfoMapper; +import com.iformall.mapper.WxPayAccountMapper; +import com.iformall.mapper.WxPayOrderMapper; +import com.iformall.mapper.WxRefundOrderMapper; +import com.iformall.pay.WxPay; +import com.iformall.pay.WxPayment; +import com.iformall.pay.WxRefundOrderP; +import com.iformall.pay.WxRefundOrderSP; +import com.iformall.service.pay.service.refund.RefundPayAdapterService; +import com.iformall.service.pay.service.refund.entity.RefundAdapterResult; +import com.iformall.service.pay.service.refund.entity.RefundNotifyAdapterResult; +import com.iformall.utils.BeanUtils; +import com.iformall.utils.CipherUtil; +import com.iformall.utils.Utility; +import com.iformall.utils.XmlUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class WxRefundV3AdapterService implements RefundPayAdapterService{ + + JSONObject errorRefundReqMap = JSON.parseObject("{\n" + + " \"SYSTEMERROR\": {\n" + + " \"detail\": \"接口返回错误\",\n" + + " \"reason\": \"系统超时等\",\n" + + " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + + " },\n" + + " \"BIZERR_NEED_RETRY\": {\n" + + " \"detail\": \"退款业务流程错误,需要商户触发重试来解决\",\n" + + " \"reason\": \"并发情况下,业务被拒绝,商户重试即可解决\",\n" + + " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + + " },\n" + + " \"TRADE_OVERDUE\": {\n" + + " \"detail\": \"订单已经超过退款期限\",\n" + + " \"reason\": \"订单已经超过可退款的最大期限(支付后一年内可退款)\\t\",\n" + + " \"resolution\": \"请选择其他方式自行退款\"\n" + + " },\n" + + " \"ERROR\": {\n" + + " \"detail\": \"业务错误\",\n" + + " \"reason\": \"申请退款业务发生错误\",\n" + + " \"resolution\": \"该错误都会返回具体的错误原因,请根据实际返回做相应处理。\"\n" + + " },\n" + + " \"USER_ACCOUNT_ABNORMAL\": {\n" + + " \"detail\": \"退款请求失败\",\n" + + " \"reason\": \"用户帐号注销\",\n" + + " \"resolution\": \"此状态代表退款申请失败,商户可自行处理退款。\"\n" + + " },\n" + + " \"INVALID_REQ_TOO_MUCH\": {\n" + + " \"detail\": \"无效请求过多\",\n" + + " \"reason\": \"连续错误请求数过多被系统短暂屏蔽\\t\",\n" + + " \"resolution\": \"请检查业务是否正常,确认业务正常后请在1分钟后再来重试\"\n" + + " },\n" + + " \"NOTENOUGH\": {\n" + + " \"detail\": \"余额不足\",\n" + + " \"reason\": \"商户可用退款余额不足\",\n" + + " \"resolution\": \"此状态代表退款申请失败,商户可根据具体的错误提示做相应的处理。\"\n" + + " },\n" + + " \"INVALID_TRANSACTIONID\": {\n" + + " \"detail\": \"无效transaction_id\",\n" + + " \"reason\": \"请求参数未按指引进行填写\",\n" + + " \"resolution\": \"请求参数错误,检查原交易号是否存在或发起支付交易接口返回失败\"\n" + + " },\n" + + " \"PARAM_ERROR\": {\n" + + " \"detail\": \"参数错误\",\n" + + " \"reason\": \"请求参数未按指引进行填写\",\n" + + " \"resolution\": \"请求参数错误,请重新检查再调用退款申请\"\n" + + " },\n" + + " \"APPID_NOT_EXIST\": {\n" + + " \"detail\": \"APPID不存在\",\n" + + " \"reason\": \"参数中缺少APPID\",\n" + + " \"resolution\": \"请检查APPID是否正确\"\n" + + " },\n" + + " \"MCHID_NOT_EXIST\": {\n" + + " \"detail\": \"MCHID不存在\",\n" + + " \"reason\": \"参数中缺少MCHID\",\n" + + " \"resolution\": \"请检查MCHID是否正确\"\n" + + " },\n" + + " \"REQUIRE_POST_METHOD\": {\n" + + " \"detail\": \"请使用post方法\",\n" + + " \"reason\": \"未使用post传递参数\",\n" + + " \"resolution\": \"请检查请求参数是否通过post方法提交\"\n" + + " },\n" + + " \"SIGNERROR\": {\n" + + " \"detail\": \"签名错误\",\n" + + " \"reason\": \"参数签名结果不正确\",\n" + + " \"resolution\": \"请检查签名参数和方法是否都符合签名算法要求\"\n" + + " },\n" + + " \"XML_FORMAT_ERROR\": {\n" + + " \"detail\": \"XML格式错误\",\n" + + " \"reason\": \"XML格式错误\",\n" + + " \"resolution\": \"请检查XML参数格式是否正确\"\n" + + " },\n" + + " \"FREQUENCY_LIMITED\": {\n" + + " \"detail\": \"频率限制\",\n" + + " \"reason\": \"2个月之前的订单申请退款有频率限制\",\n" + + " \"resolution\": \"该笔退款未受理,请降低频率后重试\"\n" + + " }\n" + + "}"); + + JSONObject errorRefundQueryMap = JSON.parseObject("{\n" + + " \"SYSTEMERROR\": {\n" + + " \"detail\": \"接口返回错误\",\n" + + " \"reason\": \"系统超时等\",\n" + + " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + + " },\n" + + " \"BIZERR_NEED_RETRY\": {\n" + + " \"detail\": \"退款业务流程错误,需要商户触发重试来解决\",\n" + + " \"reason\": \"并发情况下,业务被拒绝,商户重试即可解决\",\n" + + " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + + " },\n" + + " \"TRADE_OVERDUE\": {\n" + + " \"detail\": \"订单已经超过退款期限\",\n" + + " \"reason\": \"订单已经超过可退款的最大期限(支付后一年内可退款)\\t\",\n" + + " \"resolution\": \"请选择其他方式自行退款\"\n" + + " },\n" + + " \"ERROR\": {\n" + + " \"detail\": \"业务错误\",\n" + + " \"reason\": \"申请退款业务发生错误\",\n" + + " \"resolution\": \"该错误都会返回具体的错误原因,请根据实际返回做相应处理。\"\n" + + " },\n" + + " \"USER_ACCOUNT_ABNORMAL\": {\n" + + " \"detail\": \"退款请求失败\",\n" + + " \"reason\": \"用户帐号注销\",\n" + + " \"resolution\": \"此状态代表退款申请失败,商户可自行处理退款。\"\n" + + " },\n" + + " \"INVALID_REQ_TOO_MUCH\": {\n" + + " \"detail\": \"无效请求过多\",\n" + + " \"reason\": \"连续错误请求数过多被系统短暂屏蔽\\t\",\n" + + " \"resolution\": \"请检查业务是否正常,确认业务正常后请在1分钟后再来重试\"\n" + + " },\n" + + " \"NOTENOUGH\": {\n" + + " \"detail\": \"余额不足\",\n" + + " \"reason\": \"商户可用退款余额不足\",\n" + + " \"resolution\": \"此状态代表退款申请失败,商户可根据具体的错误提示做相应的处理。\"\n" + + " },\n" + + " \"INVALID_TRANSACTIONID\": {\n" + + " \"detail\": \"无效transaction_id\",\n" + + " \"reason\": \"请求参数未按指引进行填写\",\n" + + " \"resolution\": \"请求参数错误,检查原交易号是否存在或发起支付交易接口返回失败\"\n" + + " },\n" + + " \"PARAM_ERROR\": {\n" + + " \"detail\": \"参数错误\",\n" + + " \"reason\": \"请求参数未按指引进行填写\",\n" + + " \"resolution\": \"请求参数错误,请重新检查再调用退款申请\"\n" + + " },\n" + + " \"APPID_NOT_EXIST\": {\n" + + " \"detail\": \"APPID不存在\",\n" + + " \"reason\": \"参数中缺少APPID\",\n" + + " \"resolution\": \"请检查APPID是否正确\"\n" + + " },\n" + + " \"MCHID_NOT_EXIST\": {\n" + + " \"detail\": \"MCHID不存在\",\n" + + " \"reason\": \"参数中缺少MCHID\",\n" + + " \"resolution\": \"请检查MCHID是否正确\"\n" + + " },\n" + + " \"REQUIRE_POST_METHOD\": {\n" + + " \"detail\": \"请使用post方法\",\n" + + " \"reason\": \"未使用post传递参数\",\n" + + " \"resolution\": \"请检查请求参数是否通过post方法提交\"\n" + + " },\n" + + " \"SIGNERROR\": {\n" + + " \"detail\": \"签名错误\",\n" + + " \"reason\": \"参数签名结果不正确\",\n" + + " \"resolution\": \"请检查签名参数和方法是否都符合签名算法要求\"\n" + + " },\n" + + " \"XML_FORMAT_ERROR\": {\n" + + " \"detail\": \"XML格式错误\",\n" + + " \"reason\": \"XML格式错误\",\n" + + " \"resolution\": \"请检查XML参数格式是否正确\"\n" + + " },\n" + + " \"FREQUENCY_LIMITED\": {\n" + + " \"detail\": \"频率限制\",\n" + + " \"reason\": \"2个月之前的订单申请退款有频率限制\",\n" + + " \"resolution\": \"该笔退款未受理,请降低频率后重试\"\n" + + " }\n" + + "}"); + + private WxRefundOrderP generateWxRefundOrderP(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,EnumPayType payType) { + String noncestr = Utility.generate32UUID(); + WxRefundOrderP wxRefundOrderP = new WxRefundOrderP(); + wxRefundOrderP.setAppid(appInfo.getAppId()); + wxRefundOrderP.setMch_id(payAccount.getMchId()); + wxRefundOrderP.setNonce_str(noncestr); + // 微信内部订单号 + if (record.getTransactionId() != null) + wxRefundOrderP.setTransaction_id(record.getTransactionId()); + // 支付订单号 + wxRefundOrderP.setOut_trade_no(payOrder.getPayOrderNo()); + // 退款支付订单号 + wxRefundOrderP.setOut_refund_no(String.valueOf(record.getId())); + wxRefundOrderP.setTotal_fee(record.getTotalFee()); + wxRefundOrderP.setRefund_fee(record.getRefundFee()); + if(null != payType) { + if (payType == EnumPayType.PAY_B_REFUND) { + wxRefundOrderP.setRefund_desc("B端商户退款"); + } else if (payType == EnumPayType.PAY_ADMIN_REFUND) { + wxRefundOrderP.setRefund_desc("管理端商户退款"); + } else if (payType == EnumPayType.PAY_AUTO_REFUND) { + wxRefundOrderP.setRefund_desc("超期自动退款"); + } else { + wxRefundOrderP.setRefund_desc("用户自己退款"); + } + } + wxRefundOrderP.setNotify_url(payAccount.getRefundNotifyUrl()); + return wxRefundOrderP; + } + + private RefundAdapterResult getReusltFromp(String response,WxRefundOrder record,WxPayOrder payOrder) throws MallinkException{ + Map returnMap = WxPayment.xmlToMap(response); + String result_no = returnMap.get("result_code"); + String refund_id = returnMap.get("refund_id"); + // 设置 微信退款订单号 + record.setRefundId(refund_id); + record.setRefundVendor(payOrder.getPayVendor()); + if ("SUCCESS".equals(result_no)) { + log.info("微信退款订单申请成功: " + returnMap.toString()); + try { + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_REQ_SUCCESS.getCode(),"退款订单申请成功",returnMap); + } catch (Exception e) { + log.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); + } + } else { + String errDesc = returnMap.get("err_code_des"); + if (errDesc.equalsIgnoreCase("订单已全额退款")) { + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_REQ_SUCCESS.getCode(),"退款订单申请成功",returnMap); + } + log.error("微信退款订单申请失败: " + response); + String errMsg = ""; + JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); + if (errObj != null) { + errMsg = errObj.toJSONString(); + record.setFailReason(errMsg); + } else { + errMsg = returnMap.get("return_msg"); + record.setFailReason(errMsg); + } + if (errDesc.equalsIgnoreCase("超期订单不允许退款")) { + // 更新券状态 + throw new MallinkException(ErrorCode.REFUND_NOT_ALLOW); + } + return new RefundAdapterResult(false, EnumRefundStatus.REFUND_REQ_FAIL.getCode(), errMsg, returnMap); + } + } + + + private WxRefundOrderSP generateWxRefundOrderSP(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,EnumPayType payType) { + String noncestr = Utility.generate32UUID(); + WxRefundOrderSP wxRefundOrderSP = new WxRefundOrderSP(); + wxRefundOrderSP.setAppid(appInfo.getParentAppId()); + wxRefundOrderSP.setSub_appid(appInfo.getAppId()); + wxRefundOrderSP.setMch_id(payAccount.getMchId()); + wxRefundOrderSP.setSub_mch_id(payAccount.getSubMchId()); + wxRefundOrderSP.setNonce_str(noncestr); + // 微信内部订单号 + if (record.getTransactionId() != null) + wxRefundOrderSP.setTransaction_id(record.getTransactionId()); + // 支付订单号 + wxRefundOrderSP.setOut_trade_no(payOrder.getPayOrderNo()); + // 退款支付订单号 + wxRefundOrderSP.setOut_refund_no(String.valueOf(record.getId())); + wxRefundOrderSP.setTotal_fee(record.getTotalFee()); + wxRefundOrderSP.setRefund_fee(record.getRefundFee()); + if(null != payType) { + if (payType == EnumPayType.PAY_B_REFUND) { + wxRefundOrderSP.setRefund_desc("B端商户退款"); + } else if (payType == EnumPayType.PAY_ADMIN_REFUND) { + wxRefundOrderSP.setRefund_desc("管理端商户退款"); + } else if (payType == EnumPayType.PAY_AUTO_REFUND) { + wxRefundOrderSP.setRefund_desc("超期自动退款"); + } else { + wxRefundOrderSP.setRefund_desc("用户自己退款"); + } + } + wxRefundOrderSP.setNotify_url(payAccount.getRefundNotifyUrl()); + wxRefundOrderSP.setSign_type("HMAC-SHA256"); + return wxRefundOrderSP; + } + + private RefundAdapterResult getResultFromSp(String response,WxRefundOrder record,WxPayOrder payOrder) { + Map returnMap = WxPayment.xmlToMap(response); + String result_no = returnMap.get("result_code"); + String refund_id = returnMap.get("refund_id"); + // 设置 微信退款订单号 + record.setRefundId(refund_id); + record.setRefundVendor(payOrder.getPayVendor()); + if ("SUCCESS".equals(result_no)) { + log.info("微信退款订单申请成功: " + returnMap.toString()); + try { + return new RefundAdapterResult(true, EnumRefundStatus.REFUND_REQ_SUCCESS.getCode(), "退款订单申请成功", returnMap); + } catch (Exception e) { + log.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "订单状态更新失败"); + } + } else { + // 特殊处理 + String errDesc = returnMap.get("err_code_des"); + if (errDesc.equalsIgnoreCase("订单已全额退款")) { + return new RefundAdapterResult(true, EnumRefundStatus.REFUND_REQ_SUCCESS.getCode(), "退款订单申请成功", returnMap); + } + log.error("微信退款订单申请失败: " + response); + String errMsg = ""; + JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); + if (errObj != null) { + errMsg = errObj.toJSONString(); + record.setFailReason(errMsg); + } else { + errMsg = returnMap.get("err_code_des"); + record.setFailReason(errMsg); + } + if (errDesc.equalsIgnoreCase("超期订单不允许退款")) { + // 更新券状态 + throw new MallinkException(ErrorCode.REFUND_NOT_ALLOW); + } + return new RefundAdapterResult(false,EnumRefundStatus.REFUND_REQ_FAIL.getCode(),errMsg,returnMap); + } + } + + @Override + public RefundAdapterResult refund(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,EnumPayType payType) { + if (StringUtils.isBlank(payAccount.getApiKey())) { + log.error("支付密钥为空"); + throw new MallinkException(ErrorCode.API_KEY_NOT_FOUND.getCode(), "支付密钥为空,请联系商城管理员"); + } + if (StringUtils.isBlank(payAccount.getCertPath())) { + log.error("证书路径为空"); + throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书路径为空,请联系商城管理员"); + } + if (!Utility.isFileExist(payAccount.getCertPath())) { + log.error("证书文件不存在"); + throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书文件不存在,请联系商城管理员"); + } + + // 实际支付 + // 向微信提交退款申请 + if (payAccount.getType() == EnumPayMode.MCH.getCode()) { + // 普通商户模式 + WxRefundOrderP wxRefundOrderP = generateWxRefundOrderP(payAccount, appInfo, record, payOrder, payType); + + Map signMap = null; + try { + signMap = BeanUtils.toStringMap(wxRefundOrderP); + } catch (Exception e) { + log.error("退款命令生辰: " + e.getMessage()); + throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常"); + } + + String signAgent = WxPayment.createSign(signMap, payAccount.getApiKey()); + signMap.put("sign", signAgent); + String response = null; + try { + response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId()); + } catch (Exception e) { + log.error("退款异常: " + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); + } + log.info("微信退款订单:" + wxRefundOrderP.toString() + ", response: " + response.toString()); + return getReusltFromp(response, record, payOrder); + } else { + // 服务商模式 + WxRefundOrderSP wxRefundOrderSP = generateWxRefundOrderSP(payAccount, appInfo, record, payOrder, payType); + + Map signMap = null; + try { + signMap = BeanUtils.toStringMap(wxRefundOrderSP); + } catch (Exception e) { + log.error("退款命令生成: " + e.getMessage()); + throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常"); + } + + String signAgent = WxPayment.createSignHMAC(signMap, payAccount.getApiKey()); + signMap.put("sign", signAgent); + String response = null; + try { + response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId()); + } catch (Exception e) { + log.error("退款异常: " + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); + } + log.info("微信退款订单:" + wxRefundOrderSP.toString() + ", response: " + response.toString()); + return getResultFromSp(response, record, payOrder); + } + } + + @Override + public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record) { + if (payAccount.getType() == EnumPayMode.MCH.getCode()) { + Map paramMap = WxPayment.buildWeappRefundQueryMap( + appInfo.getAppId(), payAccount.getMchId(), + record.getTransactionId(), record.getPayOrderNo(), String.valueOf(record.getId()), + record.getRefundId(), payAccount.getApiKey()); + String response = WxPay.orderRefundQuery(paramMap); + log.info("微信退款订单:" + record.toString() + ", response: " + response.toString()); + Map returnMap = WxPayment.xmlToMap(response); + String return_code = returnMap.get("return_code"); + if("SUCCESS".equals(return_code)){ + String result_code = returnMap.get("result_code"); + if("SUCCESS".equals(result_code)){ + String refund_status_0 = returnMap.get("refund_status_0"); + if("SUCCESS".equals(refund_status_0)){ + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_SUCCESS.getCode(),"退款成功",returnMap); + }else if("REFUNDCLOSE".equals(refund_status_0)){ + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_FAIL.getCode(),"退款关闭,指商户发起退款失败的情况",returnMap); + }else if("PROCESSING".equals(refund_status_0)){ + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_REQ_SUCCESS.getCode(),"退款中",returnMap); + }else if("CHANGE".equals(refund_status_0)){ + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_FAIL.getCode(), + "退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败。",returnMap); + }else{ + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),"查询状态异常 非法状态"); + } + }else{ + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),"查询状态异常 "+returnMap.get("err_code_des")); + } + }else{ + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),"查询状态异常 "+returnMap.get("return_msg")); + } + +// String result_no = returnMap.get("result_code"); +// if ("SUCCESS".equals(result_no)) { +// String refund_id = returnMap.get("refund_id"); +// return new RefundAdapterResult(true,0,"退款",returnMap); +// } else { +// String errMsg = ""; +// JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); +// if (errObj != null) { +// errMsg = errObj.toJSONString(); +// } else { +// errMsg = returnMap.get("return_msg"); +// } +// return new RefundAdapterResult(false,ErrorCode.REFUND_ORDER_ERROR.getCode(),errMsg,returnMap); +// } + } else { + Map paramMap = WxPayment.buildSWeappRefundQueryMap( + appInfo.getParentAppId(), appInfo.getAppId(), payAccount.getMchId(), payAccount.getSubMchId(), + record.getTransactionId(), record.getPayOrderNo(), String.valueOf(record.getId()), record.getRefundId(), payAccount.getApiKey()); + String response = WxPay.orderRefundQuery(paramMap); + log.info("微信退款订单:" + record.toString() + ", response: " + response.toString()); + Map returnMap = WxPayment.xmlToMap(response); + String return_code = returnMap.get("return_code"); + if("SUCCESS".equals(return_code)){ + String result_code = returnMap.get("result_code"); + if("SUCCESS".equals(result_code)){ + String refund_status_0 = returnMap.get("refund_status_0"); + if("SUCCESS".equals(refund_status_0)){ + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_SUCCESS.getCode(),"退款成功",returnMap); + }else if("REFUNDCLOSE".equals(refund_status_0)){ + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_FAIL.getCode(),"退款关闭,指商户发起退款失败的情况",returnMap); + }else if("PROCESSING".equals(refund_status_0)){ + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_REQ_SUCCESS.getCode(),"退款中",returnMap); + }else if("CHANGE".equals(refund_status_0)){ + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_FAIL.getCode(),"退款异常",returnMap); + }else{ + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),"查询状态异常 非法状态"); + } + }else{ + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),"查询状态异常 "+returnMap.get("err_code_des")); + } + }else{ + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),"查询状态异常 "+returnMap.get("return_msg")); + } + +// String result_no = returnMap.get("result_code"); +// if ("SUCCESS".equals(result_no)) { +// String refund_id = returnMap.get("refund_id"); +// return new RefundAdapterResult(true,0,"退款",returnMap); +// } else { +// String errMsg = ""; +// JSONObject errObj = errorRefundQueryMap.getJSONObject(result_no); +// if (errObj != null) { +// errMsg = errObj.toJSONString(); +// } else { +// errMsg = returnMap.get("return_msg"); +// } +// return new RefundAdapterResult(false,ErrorCode.REFUND_ORDER_ERROR.getCode(),errMsg,returnMap); +// } + } + } + + @Autowired + WxAppinfoMapper wxAppinfoMapper; + @Autowired + WxPayAccountMapper wxPayAccountMapper; + @Autowired + WxPayOrderMapper wxPayOrderMapper; + @Autowired + WxRefundOrderMapper wxRefundOrderMapper; + + + private RefundNotifyAdapterResult notifyErrorResult(String msg) { + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "FAIL"); + resultMap.put("return_msg", msg); + return new RefundNotifyAdapterResult(false,ErrorCode.REFUND_ORDER_ERROR.getCode(),msg,XmlUtil.getRequestXml(resultMap)); + } + + private RefundNotifyAdapterResult notifySuccessResult(String transactionId,String refundId,WxRefundOrder refundOrder) { + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "SUCCESS"); + resultMap.put("return_msg", "OK"); + return new RefundNotifyAdapterResult(transactionId, refundId,refundOrder,XmlUtil.getRequestXml(resultMap)); + } + + + @Override + public RefundNotifyAdapterResult notify(Map paramMap, EnumPayWay payWay) { + // how to get wechatAppId, wechatMchId, partnerKey + String appId = paramMap.get("appid"); + String subAppId = paramMap.get("sub_appid"); + String mchId = paramMap.get("mch_id"); + String subMchId = paramMap.get("sub_mch_id"); + if (StringUtils.isBlank(subAppId) && StringUtils.isBlank(subMchId)) { + // 普通商户号 + WxAppinfo appinfo = wxAppinfoMapper.findByAppId(appId); + if (appinfo == null) { + log.error("未找到appid信息:" + appId); + throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); + } + WxPayAccount payAccount = wxPayAccountMapper.selectById(appinfo.getPayId()); + if (payAccount == null) { + log.error("未找到mch_id信息:" + mchId); + throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND); + } + if (!mchId.equalsIgnoreCase(payAccount.getMchId())) { + log.error("mch_id不对应:" + mchId + ",account:" + payAccount.getMchId()); + throw new MallinkException(ErrorCode.MCH_INFO_NOT_EQUAL); + } + String partnerKey = payAccount.getApiKey(); + try { + if (payWay.getType() == EnumPayWay.EnumPayWayType.WX_MINIPAY) { + if (!"SUCCESS".equals(paramMap.get("return_code"))) { + log.warn("notify refund, wxpay status not success, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("订单状态码非SUCCESS"); + } + + // 解密req_info + String req_info = CipherUtil.decryptReqInfo(paramMap.get("req_info"), partnerKey); + Map reqMap = WxPayment.xmlToMap(req_info); + + String payOrderNo = reqMap.get("out_trade_no"); + Long payOrderId = Long.valueOf(payOrderNo); + WxPayOrder payOrder = wxPayOrderMapper.selectById(payOrderId,payAccount.getTenantId()); + if (payOrder == null) { + log.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("支付订单不存在"); + } + // 验证支付金额 + if (!reqMap.get("total_fee").equals(payOrder.getPayAmount().toString())) { + log.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("支付订单总金额不一致"); + } + String refundIdStr = reqMap.get("out_refund_no"); + Long refundOrderId = Long.valueOf(refundIdStr); + WxRefundOrder refundOrder = wxRefundOrderMapper.selectById(refundOrderId); + if (refundOrder == null) { + log.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("退款订单不存在"); + } + // 验证支付金额 + if (!reqMap.get("total_fee").equals(refundOrder.getTotalFee().toString())) { + log.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("订单总金额不一致"); + } + // 验证退款金额 + if (!reqMap.get("refund_fee").equals(refundOrder.getRefundFee().toString())) { + log.warn("notify refund, wxpay check refund_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("退款总金额不一致"); + } + + // 处理支付成功 + //handleRefundSuccess(refundOrder, reqMap.get("transaction_id"), reqMap.get("refund_id")); + log.info("notify refund, wxpay checksign success, paramMap:{}, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifySuccessResult(reqMap.get("transaction_id"), reqMap.get("refund_id"), refundOrder); + } + } catch (RuntimeException e) { + log.warn("notify refund paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage()); + } catch (Exception e) { + log.warn("notify refund, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage()); + } + } else { + // 服务号回调 + WxAppinfo appinfo = wxAppinfoMapper.findByAppId(subAppId); + if (appinfo == null) { + log.error("未找到appid信息:" + appId); + throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); + } + WxPayAccount payAccount = wxPayAccountMapper.selectById(appinfo.getPayId()); + if (payAccount == null) { + log.error("未找到mch_id信息:" + mchId); + throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND); + } + if (!mchId.equalsIgnoreCase(payAccount.getMchId())) { + log.error("mch_id不对应:" + mchId + ",account:" + payAccount.getMchId()); + throw new MallinkException(ErrorCode.MCH_INFO_NOT_EQUAL); + } + String partnerKey = payAccount.getApiKey(); + try { + if (payWay.getType() == EnumPayWay.EnumPayWayType.WX_MINIPAY) { + if (!"SUCCESS".equals(paramMap.get("return_code"))) { + log.warn("notify order, wxpay status not success, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("订单状态码非SUCCESS"); + } + + // 解密req_info + String req_info = CipherUtil.decryptReqInfo(paramMap.get("req_info"), partnerKey); + log.info(req_info); + Map reqMap = WxPayment.xmlToMap(req_info); + + String payOrderNo = reqMap.get("out_trade_no"); + if (payOrderNo == null) { + return notifySuccessResult(reqMap.get("transaction_id"), reqMap.get("refund_id"), null); + } + Long payOrderId = Long.valueOf(payOrderNo); + WxPayOrder payOrder = wxPayOrderMapper.selectById(payOrderId,payAccount.getTenantId()); + if (payOrder == null) { + log.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("支付订单不存在"); + } + // 验证支付金额 + if (!reqMap.get("total_fee").equals(payOrder.getPayAmount().toString())) { + log.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("支付订单总金额不一致"); + } + String refundIdStr = reqMap.get("out_refund_no"); + Long refundOrderId = Long.valueOf(refundIdStr); + WxRefundOrder refundOrder = wxRefundOrderMapper.selectById(refundOrderId); + if (refundOrder == null) { + log.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("退款订单不存在"); + } + // 验证支付金额 + if (!reqMap.get("total_fee").equals(refundOrder.getTotalFee().toString())) { + log.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("订单总金额不一致"); + } + // 验证退款金额 + if (!reqMap.get("refund_fee").equals(refundOrder.getRefundFee().toString())) { + log.warn("notify refund, wxpay check refund_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("退款总金额不一致"); + } + + log.info("notify refund, wxpay checksign success, paramMap:{}, paramMap: " + reqMap.toString() + ", payWay:" + payWay.toString()); + return notifySuccessResult(reqMap.get("transaction_id"), reqMap.get("refund_id"), refundOrder); + } + } catch (RuntimeException e) { + log.warn("notify refund, wepay checksign error, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); + } catch (Exception e) { + log.warn("notify refund, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage()); + } + } + + return notifyErrorResult("FAILED"); + } + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/share/wx/WxPayShareService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/share/wx/v2/WxPayShareService.java similarity index 99% rename from mallinkService/src/main/java/com/iformall/service/pay/service/share/wx/WxPayShareService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/share/wx/v2/WxPayShareService.java index b521e9da6..b23926da4 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/share/wx/WxPayShareService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/share/wx/v2/WxPayShareService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.share.wx; +package com.iformall.service.pay.service.share.wx.v2; import java.text.ParseException; import java.util.*; diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/share/wx/v3/WxPayShareV3Service.java b/mallinkService/src/main/java/com/iformall/service/pay/service/share/wx/v3/WxPayShareV3Service.java new file mode 100644 index 000000000..9a5a61f04 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/share/wx/v3/WxPayShareV3Service.java @@ -0,0 +1,602 @@ +package com.iformall.service.pay.service.share.wx.v3; + +import java.text.ParseException; +import java.util.*; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.iformall.common.IdWorker; +import com.iformall.domain.dto.WxSharingOrderDto; +import com.iformall.domain.po.*; +import com.iformall.domain.po.base.TenantEntity; +import com.iformall.douyin.pay.enums.MerchantImportStatus; +import com.iformall.enums.*; +import com.iformall.mapper.*; +import com.iformall.service.pay.service.pay.douyin.miniApp.EnumTtPayChannel; +import net.sf.saxon.trans.Err; +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.iformall.common.ErrorCode; +import com.iformall.common.ResultData; +import com.iformall.exception.MallinkException; +import com.iformall.pay.WxPayment; +import com.iformall.pay.WxProfitSharing; +import com.iformall.pay.WxProfitSharingFinishP; +import com.iformall.pay.WxProfitSharingP; +import com.iformall.pay.WxProfitSharingQueryP; +import com.iformall.pay.WxProfitSharingReceiverP; +import com.iformall.service.order.util.OrderHelper; +import com.iformall.service.pay.service.share.PayShareAdapterService; +import com.iformall.service.pay.service.share.PayShareBaseAdapterService; +import com.iformall.service.pay.service.share.entity.ShareAccountResult; +import com.iformall.service.pay.service.share.entity.PayShareCalculateAmount; +import com.iformall.service.pay.service.share.entity.PayShareQueryResult; +import com.iformall.service.pay.service.share.entity.PayShareResult; +import com.iformall.service.pay.service.share.entity.ShareNotifyAdapterResult; +import com.iformall.utils.BeanUtils; +import com.iformall.utils.Utility; +import com.iformall.utils.XmlUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class WxPayShareV3Service extends PayShareBaseAdapterService{ + + @Autowired + WxProfitSharingOrderMapper wxProfitSharingOrderMapper; + + final JSONObject statusMap = JSON.parseObject( + "{\"ACCEPTED\":3," + + "\"PROCESSING\": 4," + + "\"FINISHED\": 5," + + "\"CLOSED\": 6}"); + + + @Override + public Integer getSubsidyType() { + return EnumMerchantSubsidyType.WECHAT.getCode(); + } + + @Override + public Integer getProfitSharingType() { + return EnumProfitSharingType.PROFIT_SHARING_TYPE_WECHAT.getCode(); + } + + @Override + public Integer getSharingOrderInitialStatus() { + return EnumProfitSharingOrderStatus.PROFIT_SHARING_READY.getCode(); + } + + @Override + public PayShareCalculateAmount calculateAmount(Integer payAmount,Integer officialCommissionRate, WxPayAccount payAccount) { + int mallCharge = OrderHelper.getMallCharge(payAmount, payAccount); + Integer realRateAmount = OrderHelper.getRealRateAmount(payAmount, payAccount); + return new PayShareCalculateAmount(payAmount,mallCharge,realRateAmount,0); + } + + @Override + public PayShareResult noReciverShare(WxAppinfo appInfo,WxPayAccount payAccount,WxProfitSharingOrder record,String transcationId,Integer amount) { + + WxProfitSharingFinishP psFCmd = new WxProfitSharingFinishP(); + psFCmd.setMch_id(payAccount.getMchId()); + psFCmd.setSub_mch_id(payAccount.getSubMchId()); + psFCmd.setAppid(appInfo.getParentAppId()); + psFCmd.setNonce_str(Utility.generate32UUID()); + psFCmd.setTransaction_id(transcationId); + psFCmd.setOut_order_no(record.getId().toString()); + //psFCmd.setAmount(amount); + psFCmd.setDescription("分账已完结"); + psFCmd.setSign_type("HMAC-SHA256"); + + String response; + try { + psFCmd.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(psFCmd), payAccount.getApiKey())); + log.info("request:" + psFCmd.toString()); + response = WxProfitSharing.finishOrder(BeanUtils.toStringMap(psFCmd), payAccount.getCertPath(), payAccount.getMchId()); + } catch (Exception e) { + log.error("wx noreciver share error:",e); + return new PayShareResult(false, EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode(),ErrorCode.PROFIT_SHARING_REQUEST_FAILED.getMessage()+":"+e.getMessage(), null,null); + } + + log.info("response: " + response); + Map returnMap = WxPayment.xmlToMap(response); + String return_code = returnMap.get("return_code"); + + if (!"SUCCESS".equals(return_code)) { + return new PayShareResult(false, EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode(),returnMap.get("return_msg"), null,null); + } + if (!WxPayment.verifyNotifyHMAC(returnMap,payAccount.getApiKey())){ + return new PayShareResult(false, EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode(),ErrorCode.PROFIT_SHARING_RETURN_INVALID.getMessage(), null,null); + } + String result_code = returnMap.get("result_code"); + if (!"SUCCESS".equals(result_code)) { + return new PayShareResult(false, EnumProfitSharingOrderStatus.PROFIT_SHARING_APPLY_FAILED.getCode(),returnMap.get("err_code_des"), null,null); + } + + return new PayShareResult(true, null,"success", returnMap,returnMap.get("order_id")); + } + + @Override + public PayShareResult haveReciversShare(WxAppinfo appInfo,WxPayAccount payAccount,WxProfitSharingOrder record,String transcationId,JSONArray receivers,EnumProfitSharingOrderType shareType ) throws MallinkException { + //分账提交 + WxProfitSharingP psCmd = new WxProfitSharingP(); + psCmd.setMch_id(payAccount.getMchId()); + psCmd.setSub_mch_id(payAccount.getSubMchId()); + psCmd.setAppid(appInfo.getParentAppId()); + psCmd.setSub_appid(appInfo.getAppId()); + psCmd.setNonce_str(Utility.generate32UUID()); + psCmd.setTransaction_id(transcationId); + psCmd.setOut_order_no(record.getId().toString()); + psCmd.setSign_type("HMAC-SHA256"); + psCmd.setReceivers(receivers.toJSONString()); + + String response; + try { + psCmd.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(psCmd), payAccount.getApiKey())); + log.info("request:" + psCmd.toString()); + if(shareType.getCode().intValue()==EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE.getCode().intValue()) { + response = WxProfitSharing.pushOrder(BeanUtils.toStringMap(psCmd), payAccount.getCertPath(), payAccount.getMchId()); + } else if(shareType.getCode().intValue()==EnumProfitSharingOrderType.PROFIT_SHARING_MULTI.getCode().intValue()) { + response = WxProfitSharing.pushMultiOrder(BeanUtils.toStringMap(psCmd), payAccount.getCertPath(), payAccount.getMchId()); + } else { + throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR); + } + } catch (Exception e) { + log.error("wx recivers share error:",e); + return new PayShareResult(false, EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode(), ErrorCode.PROFIT_SHARING_REQUEST_FAILED.getMessage()+":"+e.getMessage(), null, null); + } + + log.info("response: " + response); + Map returnMap = WxPayment.xmlToMap(response); + String return_code = returnMap.get("return_code"); + + if (!"SUCCESS".equals(return_code)) { + return new PayShareResult(false, EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode(), returnMap.get("return_msg"), null, null); + } + + if (!WxPayment.verifyNotifyHMAC(returnMap,payAccount.getApiKey())){ + return new PayShareResult(false, EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode(), ErrorCode.PROFIT_SHARING_RETURN_INVALID.getMessage(), null, null); + } + + String result_code = returnMap.get("result_code"); + if (!"SUCCESS".equals(result_code)) { + return new PayShareResult(false, EnumProfitSharingOrderStatus.PROFIT_SHARING_APPLY_FAILED.getCode(), returnMap.get("err_code_des"), null, null); + } + + return new PayShareResult(true, null, "success",returnMap, returnMap.get("order_id")); + } + + @Override + public PayShareQueryResult shareQuery(WxAppinfo appInfo, WxPayAccount payAccount, WxProfitSharingOrder record) throws MallinkException { + WxProfitSharingQueryP wxProfitSharingQueryP = new WxProfitSharingQueryP();; + wxProfitSharingQueryP.setMch_id(payAccount.getMchId()); + wxProfitSharingQueryP.setSub_mch_id(payAccount.getSubMchId()); + wxProfitSharingQueryP.setNonce_str(Utility.generate32UUID()); + wxProfitSharingQueryP.setTransaction_id(record.getTransactionId()); + wxProfitSharingQueryP.setOut_order_no(record.getId().toString()); + wxProfitSharingQueryP.setSign_type("HMAC-SHA256"); + String response; + try { + wxProfitSharingQueryP.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(wxProfitSharingQueryP),payAccount.getApiKey())); + response = WxProfitSharing.queryOrder(BeanUtils.toStringMap(wxProfitSharingQueryP), payAccount.getCertPath(), payAccount.getMchId()); + }catch (Exception e){ + throw new MallinkException(ErrorCode.PROFIT_SHARING_QUERY_REQUEST_FAILED.getCode(), ErrorCode.PROFIT_SHARING_QUERY_REQUEST_FAILED.getMessage()+e.getMessage()); + } + Map returnMap = WxPayment.xmlToMap(response); + String return_code = returnMap.get("return_code"); + if (!"SUCCESS".equals(return_code)) { + throw new MallinkException(ErrorCode.PROFIT_SHARING_QUERY_REQUEST_FAILED.getCode(), returnMap.get("return_msg")); + } + + if (!WxPayment.verifyNotifyHMAC(returnMap,payAccount.getApiKey())){ + throw new MallinkException(ErrorCode.PROFIT_SHARING_QUERY_RETURN_INVALID); + } + + String result_code = returnMap.get("result_code"); + if (!"SUCCESS".equals(result_code)) { + throw new MallinkException(ErrorCode.PROFIT_SHARING_QUERY_APPLY_FAILED.getCode(), returnMap.get("err_code_des")); + } + + String out_order_no = returnMap.get("out_order_no"); + if (StringUtils.isBlank(out_order_no) || !out_order_no.equals(record.getId().toString())){ + throw new MallinkException(ErrorCode.PROFIT_SHARING_QUERY_RETURN_INVALID.getCode(),"out_order_no:["+out_order_no+"] WxProfitSharingOrder:["+record.getId()+"]"); + } + + Integer code = (Integer) statusMap.get(returnMap.get("status")); + return new PayShareQueryResult(true, code, "success",returnMap, returnMap.get("receivers")); + } + + + @Autowired + WxAppinfoMapper wxAppinfoMapper; + @Autowired + WxPayAccountMapper wxPayAccountMapper; + @Autowired + WxPayOrderMapper wxPayOrderMapper; + + private ShareNotifyAdapterResult getErrorResult(String msg) { + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "FAIL"); + resultMap.put("return_msg", msg); + return new ShareNotifyAdapterResult(false,ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR.getCode(),msg,XmlUtil.getRequestXml(resultMap)); + } + + private ShareNotifyAdapterResult getSuccessResult(WxPayOrder payOrder, String transcationId){ + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "SUCCESS"); + resultMap.put("return_msg", "OK"); + return new ShareNotifyAdapterResult(transcationId, payOrder, XmlUtil.getRequestXml(resultMap)); + } + + @Override + public ShareNotifyAdapterResult notify(Map paramMap,EnumPayWay payWay) { + // how to get wechatAppId, wechatMchId, partnerKey + String appId = paramMap.get("appid"); + String subAppId = paramMap.get("sub_appid"); + String mchId = paramMap.get("mch_id"); + String subMchId = paramMap.get("sub_mch_id"); + WxAppinfo appinfo = null; + boolean isNormal = true; + if (StringUtils.isBlank(subAppId) && StringUtils.isBlank(subMchId)) { + // 普通商户号 + appinfo = wxAppinfoMapper.findByAppId(appId); + if (appinfo == null) { + log.error("appid not found: " + appId); + throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); + } + isNormal = true; + } else { + // 服务号 现在用hmac-sha256 + appinfo = wxAppinfoMapper.findByAppId(subAppId); + if (appinfo == null) { + log.error("subappid not found: " + subAppId); + throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); + } + isNormal = false; + } + + WxPayAccount payAccount = wxPayAccountMapper.selectById(appinfo.getPayId()); + if (payAccount == null) { + throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND); + } + String partnerKey = payAccount.getApiKey(); + try { + if (payWay == EnumPayWay.PAY_WAY_WECHAT) { + boolean signVerified = false; + if (isNormal) { + // 普通商户号支付 + signVerified = WxPayment.verifyNotify(paramMap, partnerKey); + if (!signVerified) { + log.warn("notify order, wxpay checksign error, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + throw new MallinkException(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR); + } + } else { + // 服务号 现在用hmac-sha256 + signVerified = WxPayment.verifyNotifyHMAC(paramMap, partnerKey); + if (!signVerified) { + log.warn("notify order, wxpay checksign error, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + throw new MallinkException(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR); + } + } + + if (!"SUCCESS".equals(paramMap.get("return_code"))) { + log.warn("notify order, wxpay status not success, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return getErrorResult("订单状态码非SUCCESS"); + } + + String payOrderNo = paramMap.get("out_trade_no"); + String timEndStr = paramMap.get("time_end"); + Long payOrderId = Long.valueOf(payOrderNo); + WxPayOrder payOrder = wxPayOrderMapper.selectById(payOrderId,payAccount.getTenantId()); + if (payOrder == null) { + log.warn("notify order, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return getErrorResult("订单不存在"); + } + // 验证支付金额 + if (!paramMap.get("total_fee").equals(payOrder.getPayAmount().toString())) { + log.warn("notify order, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return getErrorResult("订单总金额不一致"); + } + + Date timeEnd = null; + + try { + timeEnd = Utility.getDateFromString(timEndStr); + } catch (ParseException e) { + log.error("解析timeEnd失败"); + timeEnd = new Date(); + } + payOrder.setPayTimeEnd(timeEnd); + + log.info("notify order, wxpay checksign success, paramMap:{}, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return getSuccessResult(payOrder, paramMap.get("transaction_id")); + } + } catch (RuntimeException e) { + log.warn("notify order, checksign error, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); + throw new MallinkException(ErrorCode.PAY_ORDER_ERROR); + } + + return getErrorResult("FAILED"); + } + + @Override + public ShareAccountResult createShareAccount(WxAppinfo appInfo,WxPayAccount payAccount,WxProfitSharingReceiver receiver) { + WxProfitSharingReceiverP wxProfitSharingReceiverP = new WxProfitSharingReceiverP(); + if (StringUtils.isNotBlank(appInfo.getParentAppId())) { + wxProfitSharingReceiverP.setAppid(appInfo.getParentAppId()); + wxProfitSharingReceiverP.setMch_id(payAccount.getMchId()); + wxProfitSharingReceiverP.setSub_appid(appInfo.getAppId()); + wxProfitSharingReceiverP.setSub_mch_id(payAccount.getSubMchId()); + } else { + wxProfitSharingReceiverP.setAppid(appInfo.getAppId()); + wxProfitSharingReceiverP.setMch_id(payAccount.getMchId()); + } + wxProfitSharingReceiverP.setNonce_str(Utility.generate32UUID()); + wxProfitSharingReceiverP.setSign_type("HMAC-SHA256"); + + + JSONObject receiverJSON = new JSONObject(); + receiverJSON.put("type", EnumProfitSharingReceiverType.getEnum(receiver.getReceiverType()).getMessage()); + receiverJSON.put("account", receiver.getReceiverAccount()); + receiverJSON.put("name", receiver.getTrueName()); + + wxProfitSharingReceiverP.setReceiver(receiverJSON.toJSONString()); + String response; + try { + wxProfitSharingReceiverP.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(wxProfitSharingReceiverP), payAccount.getApiKey())); + response = WxProfitSharing.addReceiver(BeanUtils.toStringMap(wxProfitSharingReceiverP)); + log.info(response); + } catch (Exception e) { + log.error(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getMessage() + e.getMessage()); + return new ShareAccountResult(false, ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getCode(), e.getMessage(), null); + } + Map returnMap = WxPayment.xmlToMap(response); + String return_code = returnMap.get("return_code"); + if (!"SUCCESS".equals(return_code)) { + log.error(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getMessage() + returnMap.get("return_msg")+":"+JSON.toJSONString(returnMap)); + return new ShareAccountResult(false, ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getCode(), returnMap.get("return_msg"), null); + } + + String result_code = returnMap.get("result_code"); + if (!"SUCCESS".equals(result_code)) { + log.error(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getMessage() + returnMap.get("err_code_des")+":"+JSON.toJSONString(returnMap)); + return new ShareAccountResult(false, ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getCode(), returnMap.get("err_code_des"), null); + } + + if (!WxPayment.verifyNotifyHMAC(returnMap, payAccount.getApiKey())) { + log.error(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getMessage() + "verifyNotifyHMAC"+":"+JSON.toJSONString(returnMap)); + return new ShareAccountResult(false, ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getCode(), ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getMessage(), null); + } + + return new ShareAccountResult(true, null, "success", returnMap); + } + + @Autowired + WxProfitSharingReceiverMapper wxProfitSharingReceiverMapper; + + @Override + public ShareAccountResult deleteShareAccount(WxAppinfo appInfo, WxPayAccount payAccount, + WxProfitSharingReceiver receiver) { + //删除分账账户从微信服务器 + WxProfitSharingReceiverP wxProfitSharingReceiverP = new WxProfitSharingReceiverP(); + if (StringUtils.isNotBlank(appInfo.getParentAppId())) { + wxProfitSharingReceiverP.setAppid(appInfo.getParentAppId()); + wxProfitSharingReceiverP.setMch_id(payAccount.getMchId()); + wxProfitSharingReceiverP.setSub_appid(appInfo.getAppId()); + wxProfitSharingReceiverP.setSub_mch_id(payAccount.getSubMchId()); + } else { + wxProfitSharingReceiverP.setAppid(appInfo.getAppId()); + wxProfitSharingReceiverP.setMch_id(payAccount.getMchId()); + } + wxProfitSharingReceiverP.setNonce_str(Utility.generate32UUID()); + wxProfitSharingReceiverP.setSign_type("HMAC-SHA256"); + + JSONObject receiverJSON = new JSONObject(); + receiverJSON.put("type", EnumProfitSharingReceiverType.getEnum(receiver.getReceiverType()).getMessage()); + receiverJSON.put("account", receiver.getReceiverAccount()); + + wxProfitSharingReceiverP.setReceiver(receiverJSON.toJSONString()); + String response; + try { + wxProfitSharingReceiverP.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(wxProfitSharingReceiverP), payAccount.getApiKey())); + response = WxProfitSharing.delReceiver(BeanUtils.toStringMap(wxProfitSharingReceiverP)); + } catch (Exception e) { + log.error(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getMessage() + e.getMessage()); + return new ShareAccountResult(false, ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getCode(), e.getMessage(), null); + } + Map returnMap = WxPayment.xmlToMap(response); + String return_code = returnMap.get("return_code"); + if (!"SUCCESS".equals(return_code)) { + log.error(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getMessage() + returnMap.get("return_msg")+":"+JSON.toJSONString(returnMap)); + return new ShareAccountResult(false, ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getCode(), returnMap.get("return_msg"), null); + } + + String result_code = returnMap.get("result_code"); + if (!"SUCCESS".equals(result_code)) { + + if (returnMap.get("err_code").contains("USER_NOT_EXIST")) { + receiver.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_INVALID.getCode()); + receiver.setUpdateTime(new Date()); + wxProfitSharingReceiverMapper.updateById(receiver); + } + log.error(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getMessage() + returnMap.get("err_code_des")+":"+JSON.toJSONString(returnMap)); + return new ShareAccountResult(false, ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getCode(), returnMap.get("err_code_des"), null); + } + + if (!WxPayment.verifyNotifyHMAC(returnMap, payAccount.getApiKey())) { + log.error(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getMessage()+":"+JSON.toJSONString(returnMap)); + return new ShareAccountResult(false, ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getCode(), "verifyNotifyHMAC", null); + } + + return new ShareAccountResult(true, null, "success", returnMap); + } + + @Override + public int getOfficialCommission(WxOrder o, WxPayAccount payAccount) { + return 0; + } + + @Override + public ResultData handerSharingOrder(WxPayOrder payOrder, WxProfitSharingOrder sharingOrder) { + return new ResultData(ErrorCode.SYS_PARAMETER_TYPE_ERROR.getCode(),"微信分账无需处理"); + } + + @Override + public WxProfitSharingOrder createSharingOrder(WxSharingOrderDto sharingOrderDto, Integer mchType,Integer share) { + if(EnumPayMchType.DIRECT.getCode().equals(mchType)){ + throw new MallinkException(ErrorCode.SYS_PARAMETER_TYPE_ERROR.getCode(),"微信直连模式待开发"); + } + if(EnumYesOrNo.NO.getCode().equals(share)){ + throw new MallinkException(ErrorCode.SYS_PARAMETER_TYPE_ERROR.getCode(),"微信不分账"); + } + //是否已创建分账订单 + WxProfitSharingOrder record = new WxProfitSharingOrder(); + record.updateTenantInfo(sharingOrderDto); + record.setOrderId(sharingOrderDto.getOrderId()); + record = wxProfitSharingOrderMapper.selectOne(new QueryWrapper(record)); + if (record == null) { + //创建分账订单 + Date currentDate = new Date(); + record = new WxProfitSharingOrder(); + final IdWorker idworker = IdWorker.get(); + record.setId(idworker.nextId()); + record.updateTenantInfo(sharingOrderDto); + record.setTransactionId(sharingOrderDto.getTransactionId()); + record.setOrderId(sharingOrderDto.getOrderId()); + record.setPayAmount(sharingOrderDto.getPayAmount()); + record.setMerchantId(sharingOrderDto.getMerchantId()); + record.setSharingStatus(this.getSharingOrderInitialStatus()); + record.setCreateTime(currentDate); + record.setUpdateTime(currentDate); + record.setPayTimeStart(sharingOrderDto.getPayTimeStart()); + record.setPayTimeEnd(sharingOrderDto.getPayTimeEnd()); + record.setType(sharingOrderDto.getType()); + wxProfitSharingOrderMapper.insert(record); + } + + List psReceiverList = getReceiverList(sharingOrderDto, sharingOrderDto.getMerchantId(), null); + + if (psReceiverList != null && psReceiverList.size() > 50) { + throw new MallinkException(ErrorCode.PROFIT_SHARING_RECEIVER_INVALID); + } + + if (psReceiverList == null || psReceiverList.size() == 0) { //没有分账账户, + throw new MallinkException(ErrorCode.PROFIT_SHARING_RECEIVER_UNKNOWN); + } + + if (psReceiverList.size() > 1 &&//计算分账账户合法性 + psReceiverList.stream().filter(r->(r.getParameter() == null)).count() > 0) { + throw new MallinkException(ErrorCode.PROFIT_SHARING_RECEIVER_INVALID); + } + + //计算分账金额合法性 + psReceiverList.stream().forEach(r-> + { + if (r.getParameter() == null){ + r.setSharingAmount(sharingOrderDto.getShareAmount()); + r.setRateAmount(sharingOrderDto.getRateAmount()); + r.setRealRateAmount(sharingOrderDto.getRealRateAmount()); + r.setCommissionAmount(sharingOrderDto.getCommissionAmount()); + } else { + r.setSharingAmount(sharingOrderDto.getShareAmount()*Integer.valueOf(r.getParameter())/10000); + } + }); + if (psReceiverList.stream().mapToInt(r->r.getSharingAmount()).sum() > sharingOrderDto.getShareAmount()){ + throw new MallinkException(ErrorCode.PROFIT_SHARING_RECEIVER_UNKNOWN); + } + + // 添加分账接收方 + JSONArray receivers = new JSONArray(); + psReceiverList.stream().forEach(receiver->{ + JSONObject jo = new JSONObject(); + jo.put("type",this.getShareAccount(receiver.getReceiverType()).getMessage()); + jo.put("account",receiver.getReceiverAccount()); + jo.put("amount", receiver.getSharingAmount()); + jo.put("rateAmount", receiver.getRateAmount()); + jo.put("realRateAmount", receiver.getRateAmount()); + jo.put("commissionAmount", receiver.getCommissionAmount()); + //jo.put("description",receiver.getReceiverComments()); //改为存ID, + jo.put("description",receiver.getId().toString()); //为重试做准备 + receivers.add(jo); + }); + + record.setReceivers(receivers.toJSONString()); + wxProfitSharingOrderMapper.updateById(record); + + return record; + } + + @Override + public List getReceiverList(TenantEntity tenantEntity, Long merchantId, Integer ttPayWay) { + WxProfitSharingReceiver psReceiverQ = new WxProfitSharingReceiver(); + psReceiverQ.updateTenantInfo(tenantEntity); + psReceiverQ.setMerchantId(merchantId); + psReceiverQ.setSharingType(getProfitSharingType()); + psReceiverQ.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_VALID.getCode()); + psReceiverQ.setPlat(EnumAppPlat.WX.getCode()); + List psReceiverList = wxProfitSharingReceiverMapper.findList(psReceiverQ); + if (null == psReceiverList || psReceiverList.size() == 0) { + throw new MallinkException(ErrorCode.PROFIT_SHARING_RECEIVER_INVALID.getCode(),"该商户未设置分账账号."); + }else { + for (WxProfitSharingReceiver receiver:psReceiverList) { + if (EnumProfitSharingReceiverType.PROFIT_SHARING_RECEIVER_PERSONAL_WECHATID.getCode().intValue() + == receiver.getReceiverType().intValue()) { + throw new MallinkException(ErrorCode.PROFIT_SHARING_RECEIVER_INVALID.getCode(),"该商户收款账号存在个人微信号方式,微信已停止支持,请重新设置."); + } + } + } + return psReceiverList; + } + + private static String queryOrderShareAmount(String mchId,String transcationId,String apiKey) { + WxProfitSharingP psCmd = new WxProfitSharingP(); + psCmd.setMch_id(mchId);//服务商商户id + psCmd.setNonce_str(Utility.generate32UUID()); + psCmd.setTransaction_id(transcationId); + psCmd.setSign_type("HMAC-SHA256"); + + try { + psCmd.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(psCmd), apiKey)); + return WxProfitSharing.queryOrderShareAmount(BeanUtils.toStringMap(psCmd)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + +// public static void main(String[] args) { +// System.out.println(queryOrderShareAmount("1511925291","4200001516202205010431149938","XHZfpVA0NzoXgLEjsujctUTcyj8Zur2C")); +// //System.out.println(test("1511925291", "1604439800", "wxed2f44705544b892", "4200001455202205127949391954", "XHZfpVA0NzoXgLEjsujctUTcyj8Zur2C", "684670745960046592", "D:\\apiclient_cert.p12")); +// } +// +// private static String test(String mchId,String subMchId,String parentAppId,String transcationId,String apiKey,String orderNo,String certPaht) { +// WxProfitSharingFinishP psFCmd = new WxProfitSharingFinishP(); +// psFCmd.setMch_id(mchId); +// psFCmd.setSub_mch_id(subMchId); +// psFCmd.setAppid(parentAppId); +// psFCmd.setNonce_str(Utility.generate32UUID()); +// psFCmd.setTransaction_id(transcationId); +// psFCmd.setOut_order_no(orderNo); +// //psFCmd.setAmount(amount); +// psFCmd.setDescription("分账已完结"); +// psFCmd.setSign_type("HMAC-SHA256"); +// +// String response; +// try { +// psFCmd.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(psFCmd), apiKey)); +// log.info("request:" + psFCmd.toString()); +// response = WxProfitSharing.finishOrder(BeanUtils.toStringMap(psFCmd), certPaht, mchId); +// return response; +// } catch (Exception e) { +// e.printStackTrace(); +// } +// return null; +// +// } + +}