diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java index fc0b97d7bb..221e0fa623 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java @@ -29,16 +29,16 @@ public String toString() { /** *
-   * 字段名:商家批次单号
-   * 变量名:out_batch_no
+   * 字段名:商户转账单号
+   * 变量名:out_bill_no
    * 是否必填:是
    * 类型:string[5,32]
    * 描述:
-   *  商户系统内部的商家批次单号,在商户系统内部唯一。需要电子回单的批次单号
+   *  商户系统内部的商户转账单号,在商户系统内部唯一。兼容旧字段out_batch_no
    *  示例值:plfk2020042013
    * 
*/ - @SerializedName(value = "out_batch_no") + @SerializedName(value = "out_bill_no", alternate = {"out_batch_no"}) private String outBatchNo; /** @@ -58,17 +58,18 @@ public String toString() { /** *
    * 字段名:电子回单状态
-   * 变量名:signature_status
+   * 变量名:state
    * 是否必填:否
    * 类型:string[1,10]
    * 描述:
    *  枚举值:
    *     ACCEPTED:已受理,电子签章已受理成功
    *     FINISHED:已完成。电子签章已处理完成
+   *     兼容旧字段signature_status
    *     示例值:ACCEPTED
    * 
*/ - @SerializedName(value = "signature_status") + @SerializedName(value = "state", alternate = {"signature_status"}) private String signatureStatus; /** diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java index 1995ac1656..cf605474fd 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java @@ -9,7 +9,7 @@ /** * 转账电子回单申请受理API *
- * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_1.shtml
+ * 文档地址:https://pay.weixin.qq.com/doc/v3/merchant/4012716452
  * 
* * @author xiaoqiang @@ -21,15 +21,15 @@ public class ReceiptBillRequest implements Serializable { private static final long serialVersionUID = 1L; /** *
-   * 字段名:商家批次单号
-   * 变量名:out_batch_no
+   * 字段名:商户转账单号
+   * 变量名:out_bill_no
    * 是否必填:是
    * 类型:string[5, 32]
    * 描述:
-   *  body商户系统内部的商家批次单号,在商户系统内部唯一。需要电子回单的批次单号
+   *  body商户系统内部的商户转账单号,在商户系统内部唯一。兼容旧字段out_batch_no
    *  示例值:plfk2020042013
    * 
*/ - @SerializedName(value = "out_batch_no") + @SerializedName(value = "out_bill_no", alternate = {"out_batch_no"}) private String outBatchNo; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/merchanttransfer/ElectronicBillApplyRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/merchanttransfer/ElectronicBillApplyRequest.java index 363c0e357e..4d2ed6183e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/merchanttransfer/ElectronicBillApplyRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/merchanttransfer/ElectronicBillApplyRequest.java @@ -24,15 +24,15 @@ public class ElectronicBillApplyRequest implements Serializable { private static final long serialVersionUID = -2121536206019844928L; /** *
-   * 字段名:商家批次单号
-   * 变量名:out_batch_no
+   * 字段名:商户转账单号
+   * 变量名:out_bill_no
    * 是否必填:是
    * 类型:string[5,32]
    * 描述:
-   *  body商户系统内部的商家批次单号,在商户系统内部唯一。需要电子回单的批次单号
+   *  body商户系统内部的商户转账单号,在商户系统内部唯一。兼容旧字段out_batch_no
    * 示例值:plfk2020042013
    * 
*/ - @SerializedName("out_batch_no") + @SerializedName(value = "out_bill_no", alternate = {"out_batch_no"}) private String outBatchNo; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/merchanttransfer/ElectronicBillResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/merchanttransfer/ElectronicBillResult.java index aaff96ad43..1c5094bbbb 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/merchanttransfer/ElectronicBillResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/merchanttransfer/ElectronicBillResult.java @@ -24,16 +24,16 @@ public class ElectronicBillResult implements Serializable { private static final long serialVersionUID = 7528245102572829190L; /** *
-   * 字段名:商家批次单号
-   * 变量名:out_batch_no
+   * 字段名:商户转账单号
+   * 变量名:out_bill_no
    * 是否必填:是
    * 类型:string[5,32]
    * 描述:
-   *  body商户系统内部的商家批次单号,在商户系统内部唯一。需要电子回单的批次单号
+   *  body商户系统内部的商户转账单号,在商户系统内部唯一。兼容旧字段out_batch_no
    * 示例值:plfk2020042013
    * 
*/ - @SerializedName("out_batch_no") + @SerializedName(value = "out_bill_no", alternate = {"out_batch_no"}) private String outBatchNo; /** @@ -53,17 +53,18 @@ public class ElectronicBillResult implements Serializable { /** *
    * 字段名:电子回单状态
-   * 变量名:signature_status
+   * 变量名:state
    * 是否必填:否
    * 类型:string[1,10]
    * 描述:
    *  枚举值:
    * ACCEPTED:已受理,电子签章已受理成功
    * FINISHED:已完成。电子签章已处理完成
+   *  兼容旧字段signature_status
    * 示例值:ACCEPTED
    * 
*/ - @SerializedName("signature_status") + @SerializedName(value = "state", alternate = {"signature_status"}) private String signatureStatus; /** diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantTransferService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantTransferService.java index 585a96e763..3b6c19cc9c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantTransferService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantTransferService.java @@ -91,8 +91,8 @@ public interface MerchantTransferService { * 转账电子回单申请受理API *

* 适用对象:直连商户 - * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_7.shtml - * 请求URL:https://api.mch.weixin.qq.com/v3/transfer/bill-receipt + * 文档详见: https://pay.weixin.qq.com/doc/v3/merchant/4012716452 + * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/elecsign/out-bill-no * 请求方式:POST * 接口限频: 单个商户 20QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。 * @@ -106,15 +106,15 @@ public interface MerchantTransferService { * 查询转账电子回单API *

* 适用对象:直连商户 - * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_8.shtml - * 请求URL:https://api.mch.weixin.qq.com/v3/transfer/bill-receipt/{out_batch_no} + * 文档详见: https://pay.weixin.qq.com/doc/v3/merchant/4012716436 + * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/elecsign/out-bill-no/{out_bill_no} * 请求方式:GET * - * @param outBatchNo the out batch no + * @param outBillNo 商户转账单号 * @return electronic bill result * @throws WxPayException the wx pay exception */ - ElectronicBillResult queryElectronicBill(String outBatchNo) throws WxPayException; + ElectronicBillResult queryElectronicBill(String outBillNo) throws WxPayException; /** * 转账明细电子回单受理API diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/PartnerTransferService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/PartnerTransferService.java index b7397605ac..cea20e86f0 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/PartnerTransferService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/PartnerTransferService.java @@ -99,11 +99,11 @@ public interface PartnerTransferService { * 转账电子回单申请受理API * 接口说明 * 适用对象:直连商户 服务商 - * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_1.shtml - * 请求URL:https://api.mch.weixin.qq.com/v3/transfer/bill-receipt + * 文档详见: https://pay.weixin.qq.com/doc/v3/merchant/4012716452 + * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/elecsign/out-bill-no * 请求方式:POST * - * @param request 商家批次单号 + * @param request 商户转账单号 * @return 返回数据 fund balance result * @throws WxPayException the wx pay exception */ @@ -114,15 +114,15 @@ public interface PartnerTransferService { * 查询转账电子回单API * 接口说明 * 适用对象:直连商户 服务商 - * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_2.shtml - * 请求URL:https://api.mch.weixin.qq.com/v3/transfer/bill-receipt/{out_batch_no} + * 文档详见: https://pay.weixin.qq.com/doc/v3/merchant/4012716436 + * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/elecsign/out-bill-no/{out_bill_no} * 请求方式:GET * - * @param outBatchNo 商家批次单号 + * @param outBillNo 商户转账单号 * @return 返回数据 fund balance result * @throws WxPayException the wx pay exception */ - BillReceiptResult queryBillReceipt(String outBatchNo) throws WxPayException; + BillReceiptResult queryBillReceipt(String outBillNo) throws WxPayException; /** * 转账明细电子回单受理API diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantTransferServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantTransferServiceImpl.java index 8974ca7e2b..df4b36fdb9 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantTransferServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantTransferServiceImpl.java @@ -92,14 +92,15 @@ public DetailsQueryResult queryMerchantDetails(MerchantDetailsQueryRequest reque @Override public ElectronicBillResult applyElectronicBill(ElectronicBillApplyRequest request) throws WxPayException { - String url = String.format("%s/v3/transfer/bill-receipt", this.wxPayService.getPayBaseUrl()); + String url = String.format("%s/v3/fund-app/mch-transfer/elecsign/out-bill-no", this.wxPayService.getPayBaseUrl()); String response = wxPayService.postV3(url, GSON.toJson(request)); return GSON.fromJson(response, ElectronicBillResult.class); } @Override - public ElectronicBillResult queryElectronicBill(String outBatchNo) throws WxPayException { - String url = String.format("%s/v3/transfer/bill-receipt/%s", this.wxPayService.getPayBaseUrl(), outBatchNo); + public ElectronicBillResult queryElectronicBill(String outBillNo) throws WxPayException { + String url = String.format("%s/v3/fund-app/mch-transfer/elecsign/out-bill-no/%s", + this.wxPayService.getPayBaseUrl(), outBillNo); String response = wxPayService.getV3(url); return GSON.fromJson(response, ElectronicBillResult.class); } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerTransferServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerTransferServiceImpl.java index d5ee9dfebb..0fe6ac860d 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerTransferServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerTransferServiceImpl.java @@ -186,17 +186,17 @@ public BatchDetailsResult queryBatchDetailByMch(String outBatchNo, String outDet * 转账电子回单申请受理API * 接口说明 * 适用对象:直连商户 服务商 - * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_1.shtml - * 请求URL:https://api.mch.weixin.qq.com/v3/transfer/bill-receipt + * 文档详见: https://pay.weixin.qq.com/doc/v3/merchant/4012716452 + * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/elecsign/out-bill-no * 请求方式:POST * - * @param request 商家批次单号 + * @param request 商户转账单号 * @return 返回数据 fund balance result * @throws WxPayException the wx pay exception */ @Override public BillReceiptResult receiptBill(ReceiptBillRequest request) throws WxPayException { - String url = String.format("%s/v3/transfer/bill-receipt", this.payService.getPayBaseUrl()); + String url = String.format("%s/v3/fund-app/mch-transfer/elecsign/out-bill-no", this.payService.getPayBaseUrl()); String response = this.payService.postV3(url, GSON.toJson(request)); return GSON.fromJson(response, BillReceiptResult.class); } @@ -206,17 +206,18 @@ public BillReceiptResult receiptBill(ReceiptBillRequest request) throws WxPayExc * 查询转账电子回单API * 接口说明 * 适用对象:直连商户 服务商 - * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_2.shtml - * 请求URL:https://api.mch.weixin.qq.com/v3/transfer/bill-receipt/{out_batch_no} + * 文档详见: https://pay.weixin.qq.com/doc/v3/merchant/4012716436 + * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/elecsign/out-bill-no/{out_bill_no} * 请求方式:GET * - * @param outBatchNo 商家批次单号 + * @param outBillNo 商户转账单号 * @return 返回数据 fund balance result * @throws WxPayException the wx pay exception */ @Override - public BillReceiptResult queryBillReceipt(String outBatchNo) throws WxPayException { - String url = String.format("%s/v3/transfer/bill-receipt/%s", this.payService.getPayBaseUrl(), outBatchNo); + public BillReceiptResult queryBillReceipt(String outBillNo) throws WxPayException { + String url = String.format("%s/v3/fund-app/mch-transfer/elecsign/out-bill-no/%s", + this.payService.getPayBaseUrl(), outBillNo); String response = this.payService.getV3(url); return GSON.fromJson(response, BillReceiptResult.class); } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferReceiptApiCompatibilityTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferReceiptApiCompatibilityTest.java new file mode 100644 index 0000000000..2fbb56fded --- /dev/null +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferReceiptApiCompatibilityTest.java @@ -0,0 +1,135 @@ +package com.github.binarywang.wxpay.service.impl; + +import com.github.binarywang.wxpay.bean.marketing.transfer.BillReceiptResult; +import com.github.binarywang.wxpay.bean.marketing.transfer.ReceiptBillRequest; +import com.github.binarywang.wxpay.bean.merchanttransfer.ElectronicBillApplyRequest; +import com.github.binarywang.wxpay.bean.merchanttransfer.ElectronicBillResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.google.gson.Gson; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +@Test +public class TransferReceiptApiCompatibilityTest { + + private static final String BASE_URL = "https://api.mch.weixin.qq.com"; + + /** + * 验证直连商户电子回单接口已切换到新版fund-app路径。 + */ + public void shouldUseNewMerchantTransferElecsignApiPath() throws WxPayException { + RequestCaptureHandler handler = new RequestCaptureHandler(); + WxPayService wxPayService = handler.createWxPayService(); + MerchantTransferServiceImpl merchantTransferService = new MerchantTransferServiceImpl(wxPayService); + + merchantTransferService.applyElectronicBill(new ElectronicBillApplyRequest().setOutBatchNo("plfk2020042013")); + Assert.assertEquals(handler.lastPostUrl, BASE_URL + "/v3/fund-app/mch-transfer/elecsign/out-bill-no"); + Assert.assertTrue(handler.lastPostBody.contains("\"out_bill_no\"")); + Assert.assertFalse(handler.lastPostBody.contains("\"out_batch_no\"")); + + merchantTransferService.queryElectronicBill("plfk2020042013"); + Assert.assertEquals(handler.lastGetUrl, BASE_URL + "/v3/fund-app/mch-transfer/elecsign/out-bill-no/plfk2020042013"); + } + + /** + * 验证服务商电子回单接口已切换到新版fund-app路径。 + */ + public void shouldUseNewPartnerTransferElecsignApiPath() throws WxPayException { + RequestCaptureHandler handler = new RequestCaptureHandler(); + WxPayService wxPayService = handler.createWxPayService(); + PartnerTransferServiceImpl partnerTransferService = new PartnerTransferServiceImpl(wxPayService); + + ReceiptBillRequest request = new ReceiptBillRequest(); + request.setOutBatchNo("plfk2020042013"); + partnerTransferService.receiptBill(request); + Assert.assertEquals(handler.lastPostUrl, BASE_URL + "/v3/fund-app/mch-transfer/elecsign/out-bill-no"); + Assert.assertTrue(handler.lastPostBody.contains("\"out_bill_no\"")); + Assert.assertFalse(handler.lastPostBody.contains("\"out_batch_no\"")); + + partnerTransferService.queryBillReceipt("plfk2020042013"); + Assert.assertEquals(handler.lastGetUrl, BASE_URL + "/v3/fund-app/mch-transfer/elecsign/out-bill-no/plfk2020042013"); + } + + /** + * 验证新版字段名能够正确反序列化到现有结果对象。 + */ + public void shouldDeserializeNewResponseFieldNames() { + Gson gson = new Gson(); + BillReceiptResult billReceiptResult = + gson.fromJson("{\"out_bill_no\":\"plfk2020042013\",\"state\":\"FINISHED\"}", BillReceiptResult.class); + Assert.assertEquals(billReceiptResult.getOutBatchNo(), "plfk2020042013"); + Assert.assertEquals(billReceiptResult.getSignatureStatus(), "FINISHED"); + + ElectronicBillResult electronicBillResult = + gson.fromJson("{\"out_bill_no\":\"plfk2020042013\",\"state\":\"FINISHED\"}", ElectronicBillResult.class); + Assert.assertEquals(electronicBillResult.getOutBatchNo(), "plfk2020042013"); + Assert.assertEquals(electronicBillResult.getSignatureStatus(), "FINISHED"); + } + + /** + * 通过动态代理拦截WxPayService请求并记录URL/请求体,便于断言接口路径和参数。 + */ + private static class RequestCaptureHandler implements InvocationHandler { + private String lastPostUrl; + private String lastPostBody; + private String lastGetUrl; + + private WxPayService createWxPayService() { + return (WxPayService) Proxy.newProxyInstance( + WxPayService.class.getClassLoader(), + new Class[]{WxPayService.class}, + this + ); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) { + if ("getPayBaseUrl".equals(method.getName())) { + return BASE_URL; + } + if ("postV3".equals(method.getName())) { + this.lastPostUrl = (String) args[0]; + this.lastPostBody = (String) args[1]; + return "{}"; + } + if ("getV3".equals(method.getName())) { + this.lastGetUrl = (String) args[0]; + return "{}"; + } + if ("toString".equals(method.getName())) { + return "MockWxPayService"; + } + Class returnType = method.getReturnType(); + if (boolean.class.equals(returnType)) { + return false; + } + if (int.class.equals(returnType)) { + return 0; + } + if (long.class.equals(returnType)) { + return 0L; + } + if (double.class.equals(returnType)) { + return 0D; + } + if (float.class.equals(returnType)) { + return 0F; + } + if (short.class.equals(returnType)) { + return (short) 0; + } + if (byte.class.equals(returnType)) { + return (byte) 0; + } + if (char.class.equals(returnType)) { + return (char) 0; + } + return null; + } + } +}