Browse Source

:new: #3327【微信支付】增加平台收付通(注销申请)相关接口

zhuangzibin 7 months ago
parent
commit
5821710e07

+ 24 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/AccountCancelApplicationsMediaResult.java

@@ -0,0 +1,24 @@
+package com.github.binarywang.wxpay.bean.ecommerce;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 图片上传API
+ * <pre>
+ *   https://pay.weixin.qq.com/docs/partner/apis/ecommerce-cancel/media/upload-media.html
+ * </pre>
+ */
+@Data
+@NoArgsConstructor
+public class AccountCancelApplicationsMediaResult implements Serializable {
+
+  /**
+   * 微信返回的媒体文件标识ID。
+   */
+  @SerializedName(value = "media_id")
+  private String mediaId;
+}

+ 64 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/AccountCancelApplicationsRequest.java

@@ -0,0 +1,64 @@
+package com.github.binarywang.wxpay.bean.ecommerce;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 提交注销申请单
+ * <pre>
+ *   https://pay.weixin.qq.com/docs/partner/apis/ecommerce-cancel/cancel-applications/create-cancel-application.html
+ * </pre>
+ */
+@Data
+@NoArgsConstructor
+public class AccountCancelApplicationsRequest implements Serializable {
+
+  /**
+   * 【申请注销的二级商户号】 电商平台二级商户号,由微信支付生成并下发
+   */
+  @SerializedName(value = "sub_mchid")
+  private String subMchid;
+
+  /**
+   * 【商户注销申请单号】 商户注销申请单号,由商户自定义生成,要求在服务商维度下是唯一的,必须仅包含大小写字母与数字
+   */
+  @SerializedName(value = "out_apply_no")
+  private String outApplyNo;
+
+  /**
+   * 【注销申请材料】 注销申请材料,详见文档:注销申请材料
+   */
+  @SerializedName(value = "application_info")
+  private List<CancelApplicationInfo> applicationInfo;
+
+  @Data
+  @Builder
+  @AllArgsConstructor
+  @NoArgsConstructor
+  public static class CancelApplicationInfo implements Serializable {
+
+    /**
+     *【注销申请材料类型】 注销申请材料类型,详见文档:注销申请材料
+     * 可选取值:
+     * SP_MERCHANT_APPLICATION: 此枚举值已废弃,请使用新字段 SP_CANCEL_ACCOUNT_APPLICATION 以及新版本材料
+     * SUB_MERCHANT_APPLICATION: 此枚举值已废弃,请使用新字段 SUB_CANCEL_ACCOUNT_APPLICATION 以及新版本材料
+     * MISSING_OFFICIAL_SEAL_LETTER: 此材料已废弃,无需上传
+     * SP_CANCEL_ACCOUNT_APPLICATION: 电商服务商注销电商子申请书,请下载模板打印纸质版、填写盖章后拍照。模板文档详见:微信支付商户号注销申请书-服务商(纸质版)
+     * SUB_CANCEL_ACCOUNT_APPLICATION: 电商服务商子商户注销申请书,详见文档:微信支付商户号注销申请书-电商平台子商户适用(纸质版)
+     */
+    @SerializedName("application_type")
+    private String applicationType;
+
+    /**
+     * 【注销申请材料照片ID】 注销申请材料照片ID,请填写通过上传图片接口预先上传图片生成好的media_id
+     */
+    @SerializedName("application_media_id")
+    private String applicationMediaId;
+  }
+}

+ 52 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/AccountCancelApplicationsResult.java

@@ -0,0 +1,52 @@
+package com.github.binarywang.wxpay.bean.ecommerce;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 提交注销申请单
+ * <pre>
+ *   https://pay.weixin.qq.com/docs/partner/apis/ecommerce-cancel/cancel-applications/create-cancel-application.html
+ * </pre>
+ */
+@Data
+@NoArgsConstructor
+public class AccountCancelApplicationsResult implements Serializable {
+
+  /**
+   * 【商户注销申请单号】 商户注销申请单号,原样返回请求参数里的内容
+   */
+  @SerializedName(value = "out_apply_no")
+  private String outApplyNo;
+
+  /**
+   * 【二级商户号】 二级商户号
+   */
+  @SerializedName(value = "sub_mchid")
+  private String subMchid;
+
+  /**
+   * 【驳回原因】 受理失败原因
+   */
+  @SerializedName(value = "reject_reason")
+  private String rejectReason;
+
+  /**
+   * 【注销状态】 注销状态
+   * 可选取值:
+   * REVIEWING: 审核中
+   * REJECTED: 审核驳回,驳回原因详见reject_reason
+   * CANCEL_SUCCESS: 注销成功
+   */
+  @SerializedName(value = "cancel_state")
+  private String cancelState;
+
+  /**
+   * 【最后更新时间】 最后更新时间。遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。
+   */
+  @SerializedName(value = "update_time")
+  private String updateTime;
+}

+ 37 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java

@@ -6,6 +6,8 @@ import com.github.binarywang.wxpay.bean.ecommerce.enums.SpAccountTypeEnum;
 import com.github.binarywang.wxpay.bean.ecommerce.enums.TradeTypeEnum;
 import com.github.binarywang.wxpay.exception.WxPayException;
 
+import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 
 /**
@@ -535,4 +537,39 @@ public interface EcommerceService {
    */
   SubsidiesCancelResult subsidiesCancel(SubsidiesCancelRequest subsidiesCancelRequest) throws WxPayException;
 
+  /**
+   * <pre>
+   * 提交注销申请单
+   * 文档地址: https://pay.weixin.qq.com/docs/partner/apis/ecommerce-cancel/cancel-applications/create-cancel-application.html
+   * </pre>
+   *
+   * @param accountCancelApplicationsRequest 提交注销申请单
+   * @return 返回数据 return AccountCancelApplicationsResult
+   * @throws WxPayException the wx pay exception
+   */
+  AccountCancelApplicationsResult createdAccountCancelApplication(AccountCancelApplicationsRequest accountCancelApplicationsRequest) throws WxPayException;
+
+  /**
+   * <pre>
+   * 查询注销单状态
+   * 文档地址: https://pay.weixin.qq.com/docs/partner/apis/ecommerce-cancel/cancel-applications/get-cancel-application.html
+   * </pre>
+   *
+   * @param outApplyNo 注销申请单号
+   * @return 返回数据 return AccountCancelApplicationsResult
+   * @throws WxPayException the wx pay exception
+   */
+  AccountCancelApplicationsResult getAccountCancelApplication(String outApplyNo) throws WxPayException;
+
+  /**
+   * <pre>
+   * 注销单资料图片上传
+   * 文档地址: https://pay.weixin.qq.com/docs/partner/apis/ecommerce-cancel/media/upload-media.html
+   * </pre>
+   *
+   * @param imageFile 图片
+   * @return 返回数据 return AccountCancelApplicationsResult
+   * @throws WxPayException the wx pay exception
+   */
+  AccountCancelApplicationsMediaResult uploadMediaAccountCancelApplication(File imageFile) throws WxPayException, IOException;;
 }

+ 35 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java

@@ -7,22 +7,27 @@ import com.github.binarywang.wxpay.bean.ecommerce.enums.TradeTypeEnum;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.EcommerceService;
 import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.v3.WechatPayUploadHttpPost;
 import com.github.binarywang.wxpay.v3.util.AesUtils;
 import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
 import com.google.common.base.CaseFormat;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import lombok.RequiredArgsConstructor;
+import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.lang3.StringUtils;
 
 import java.beans.BeanInfo;
 import java.beans.IntrospectionException;
 import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.net.URI;
 import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.text.DateFormat;
@@ -395,6 +400,36 @@ public class EcommerceServiceImpl implements EcommerceService {
     String response = this.payService.postV3(url, GSON.toJson(subsidiesCancelRequest));
     return GSON.fromJson(response, SubsidiesCancelResult.class);
   }
+
+  @Override
+  public AccountCancelApplicationsResult createdAccountCancelApplication(AccountCancelApplicationsRequest accountCancelApplicationsRequest) throws WxPayException {
+    String url = String.format("%s/v3/ecommerce/account/cancel-applications", this.payService.getPayBaseUrl());
+    String response = this.payService.postV3(url, GSON.toJson(accountCancelApplicationsRequest));
+    return GSON.fromJson(response, AccountCancelApplicationsResult.class);
+  }
+
+  @Override
+  public AccountCancelApplicationsResult getAccountCancelApplication(String outApplyNo) throws WxPayException {
+    String url = String.format("%s/v3/ecommerce/account/cancel-applications/out-apply-no/%s", this.payService.getPayBaseUrl(), outApplyNo);
+    String result = this.payService.getV3(url);
+    return GSON.fromJson(result, AccountCancelApplicationsResult.class);
+  }
+
+  @Override
+  public AccountCancelApplicationsMediaResult uploadMediaAccountCancelApplication(File imageFile) throws WxPayException, IOException {
+    String url = String.format("%s/v3/ecommerce/account/cancel-applications/media", this.payService.getPayBaseUrl());
+    try (FileInputStream s1 = new FileInputStream(imageFile)) {
+      String sha256 = DigestUtils.sha256Hex(s1);
+      try (InputStream s2 = new FileInputStream(imageFile)) {
+        WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(URI.create(url))
+          .withImage(imageFile.getName(), sha256, s2)
+          .buildEcommerceAccount();
+        String result = this.payService.postV3(url, request);
+        return GSON.fromJson(result, AccountCancelApplicationsMediaResult.class);
+      }
+    }
+  }
+
   /**
    * 校验通知签名
    *

+ 28 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/WechatPayUploadHttpPost.java

@@ -72,5 +72,33 @@ public class WechatPayUploadHttpPost extends HttpPost {
 
       return request;
     }
+
+    /**
+     * 平台收付通(注销申请)-图片上传-图片上传
+     * https://pay.weixin.qq.com/docs/partner/apis/ecommerce-cancel/media/upload-media.html
+     * @return WechatPayUploadHttpPost
+     */
+    public WechatPayUploadHttpPost buildEcommerceAccount() {
+      if (fileName == null || fileSha256 == null || fileInputStream == null) {
+        throw new IllegalArgumentException("缺少待上传图片文件信息");
+      }
+
+      if (uri == null) {
+        throw new IllegalArgumentException("缺少上传图片接口URL");
+      }
+
+      String meta = String.format("{\"file_name\":\"%s\",\"file_digest\":\"%s\"}", fileName, fileSha256);
+      WechatPayUploadHttpPost request = new WechatPayUploadHttpPost(uri, meta);
+
+      MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
+      entityBuilder.setMode(HttpMultipartMode.RFC6532)
+        .addBinaryBody("file", fileInputStream, fileContentType, fileName)
+        .addTextBody("meta", meta, ContentType.APPLICATION_JSON);
+
+      request.setEntity(entityBuilder.build());
+      request.addHeader("Accept", ContentType.APPLICATION_JSON.toString());
+
+      return request;
+    }
   }
 }

+ 29 - 7
weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImplTest.java

@@ -1,12 +1,7 @@
 package com.github.binarywang.wxpay.service.impl;
+import com.google.common.collect.Lists;
 
-import com.github.binarywang.wxpay.bean.ecommerce.CombineTransactionsRequest;
-import com.github.binarywang.wxpay.bean.ecommerce.PartnerTransactionsQueryRequest;
-import com.github.binarywang.wxpay.bean.ecommerce.PartnerTransactionsResult;
-import com.github.binarywang.wxpay.bean.ecommerce.ProfitSharingReceiverRequest;
-import com.github.binarywang.wxpay.bean.ecommerce.ProfitSharingReceiverResult;
-import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
-import com.github.binarywang.wxpay.bean.ecommerce.TransactionsResult;
+import com.github.binarywang.wxpay.bean.ecommerce.*;
 import com.github.binarywang.wxpay.bean.ecommerce.enums.SpAccountTypeEnum;
 import com.github.binarywang.wxpay.bean.ecommerce.enums.TradeTypeEnum;
 import com.github.binarywang.wxpay.exception.WxPayException;
@@ -19,6 +14,8 @@ import me.chanjar.weixin.common.util.RandomUtils;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
+import java.io.File;
+import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 
@@ -151,4 +148,29 @@ public class EcommerceServiceImplTest {
     String date = "";
     wxPayService.getEcommerceService().subDayEndBalance(subMchid, date);
   }
+
+  @Test
+  public void testCreatedAccountCancelApplication() throws WxPayException {
+    AccountCancelApplicationsRequest request = new AccountCancelApplicationsRequest();
+    request.setSubMchid("");
+    request.setOutApplyNo("");
+    request.setApplicationInfo(Lists.newArrayList());
+
+    AccountCancelApplicationsResult result = wxPayService.getEcommerceService().createdAccountCancelApplication(request);
+    log.info("请求参数:{} 响应结果:{}", request, result);
+  }
+
+  @Test
+  public void testGetAccountCancelApplication() throws WxPayException {
+    String request = "申请单号";
+    AccountCancelApplicationsResult result = wxPayService.getEcommerceService().getAccountCancelApplication(request);
+    log.info("请求参数:{} 响应结果:{}", request, result);
+  }
+
+  @Test
+  public void testUploadMediaAccountCancelApplication() throws WxPayException, IOException {
+    AccountCancelApplicationsMediaResult result = wxPayService.getEcommerceService()
+      .uploadMediaAccountCancelApplication(new File("src\\test\\resources\\mm.jpeg"));
+    log.info("响应结果:{}", result);
+  }
 }