From bf1def00c21eeebeb55da6c6c9c6dd870fece205 Mon Sep 17 00:00:00 2001 From: pengg Date: Tue, 23 Mar 2021 15:20:50 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E5=8D=87=E7=BA=A7XStream=E7=89=88?= =?UTF-8?q?=E6=9C=AC=EF=BC=8C20201.3.13=E6=97=A5XStream=E5=AE=98=E6=96=B9?= =?UTF-8?q?=E5=8F=91=E5=B8=83=E5=AE=89=E5=85=A8=E6=9B=B4=E6=96=B0=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=85=B1=E8=AE=A111=E4=B8=AA?= =?UTF-8?q?=E9=AB=98=E5=8D=B1=E5=92=8C=E4=B8=A5=E9=87=8D=E6=BC=8F=E6=B4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 18e2b5cfa..41bc13859 100644 --- a/pom.xml +++ b/pom.xml @@ -175,7 +175,7 @@ com.thoughtworks.xstream xstream - 1.4.15 + 1.4.16 com.google.guava From 05520cbcbebe27df4fca9ba5d4673725195d7e9a Mon Sep 17 00:00:00 2001 From: pengg Date: Mon, 21 Jun 2021 11:28:46 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=AC=A2=E8=BF=8E=E8=AF=AD=E4=B8=8D=E6=94=AF=E6=8C=81=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E7=B1=BB=E5=9E=8B=E7=9A=84=E6=AC=A2=E8=BF=8E=E8=AF=AD?= =?UTF-8?q?=20#2155=20=E5=90=8C=E6=97=B6=E4=BF=AE=E6=94=B9=E6=AC=A2?= =?UTF-8?q?=E8=BF=8E=E8=AF=AD=E7=BB=93=E6=9E=84=E4=B8=8D=E6=AD=A3=E7=A1=AE?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cp/bean/external/WxCpWelcomeMsg.java | 12 +-- .../cp/bean/external/msg/Attachment.java | 76 +++++++++++++++++++ .../weixin/cp/bean/external/msg/Video.java | 19 +++++ .../weixin/cp/constant/WxCpConsts.java | 20 +++++ .../WxCpExternalContactServiceImplTest.java | 17 +++++ 5 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/msg/Attachment.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/msg/Video.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpWelcomeMsg.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpWelcomeMsg.java index ce744b9f2..ade49684c 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpWelcomeMsg.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpWelcomeMsg.java @@ -2,13 +2,11 @@ import com.google.gson.annotations.SerializedName; import lombok.*; -import me.chanjar.weixin.cp.bean.external.msg.Image; -import me.chanjar.weixin.cp.bean.external.msg.Link; -import me.chanjar.weixin.cp.bean.external.msg.MiniProgram; -import me.chanjar.weixin.cp.bean.external.msg.Text; +import me.chanjar.weixin.cp.bean.external.msg.*; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; import java.io.Serializable; +import java.util.List; /** * 新客户欢迎语. @@ -28,11 +26,7 @@ public class WxCpWelcomeMsg implements Serializable { private Text text; - private Image image; - - private Link link; - - private MiniProgram miniprogram; + private List attachments; public String toJson() { return WxCpGsonBuilder.create().toJson(this); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/msg/Attachment.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/msg/Attachment.java new file mode 100644 index 000000000..0c64b9bf6 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/msg/Attachment.java @@ -0,0 +1,76 @@ +package me.chanjar.weixin.cp.bean.external.msg; + +import com.google.gson.annotations.SerializedName; +import me.chanjar.weixin.cp.constant.WxCpConsts; + +import java.io.Serializable; + +public class Attachment implements Serializable { + private static final long serialVersionUID = -8078748379570640198L; + + @SerializedName("msgtype") + private String msgType; + + private Image image; + + private Link link; + + private MiniProgram miniprogram; + + private Video video; + + @Override + public String toString() { + return "Attachment{" + + "msgType='" + msgType + '\'' + + ", image=" + image + + ", link=" + link + + ", miniprogram=" + miniprogram + + ", video=" + video + + '}'; + } + + private String getMsgType() { + return msgType; + } + + private void setMsgType(String msgType) { + this.msgType = msgType; + } + + public Image getImage() { + return image; + } + + public void setImage(Image image) { + this.image = image; + this.msgType = WxCpConsts.WelcomeMsgType.IMAGE; + } + + public Link getLink() { + return link; + } + + public void setLink(Link link) { + this.link = link; + this.msgType = WxCpConsts.WelcomeMsgType.LINK; + } + + public MiniProgram getMiniprogram() { + return miniprogram; + } + + public void setMiniprogram(MiniProgram miniprogram) { + this.miniprogram = miniprogram; + this.msgType = WxCpConsts.WelcomeMsgType.MINIPROGRAM; + } + + public Video getVideo() { + return video; + } + + public void setVideo(Video video) { + this.video = video; + this.msgType = WxCpConsts.WelcomeMsgType.VIDEO; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/msg/Video.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/msg/Video.java new file mode 100644 index 000000000..237fb75cf --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/msg/Video.java @@ -0,0 +1,19 @@ +package me.chanjar.weixin.cp.bean.external.msg; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 视频消息 + * + * @author pg + * @date 2021-6-21 + */ +@Data +public class Video implements Serializable { + private static final long serialVersionUID = -6048642921382867138L; + @SerializedName("media_id") + private String mediaId; +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java index 4a41fa8f7..69db78efb 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java @@ -334,4 +334,24 @@ public static class WorkBenchType { * */ public static final String WEBVIEW = "webview"; } + + @UtilityClass + public static class WelcomeMsgType { + /** + * 图片消息. + */ + public static final String IMAGE = "image"; + /** + * 图文消息. + */ + public static final String LINK = "link"; + /** + * 视频消息. + */ + public static final String VIDEO = "video"; + /** + * 小程序消息. + */ + public static final String MINIPROGRAM = "miniprogram"; + } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java index 29089d478..4b6221d17 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java @@ -8,6 +8,9 @@ import me.chanjar.weixin.cp.bean.WxCpBaseResp; import me.chanjar.weixin.cp.bean.external.*; import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo; +import me.chanjar.weixin.cp.bean.external.msg.Attachment; +import me.chanjar.weixin.cp.bean.external.msg.Image; +import me.chanjar.weixin.cp.bean.external.msg.Video; import org.apache.commons.lang3.time.DateFormatUtils; import org.testng.annotations.Guice; import org.testng.annotations.Test; @@ -214,8 +217,22 @@ public void testAddMsgTemplate() { @Test public void testSendWelcomeMsg() throws WxErrorException { + Image image = new Image(); + image.setMediaId("123123"); + Attachment attachment = new Attachment(); + attachment.setImage(image); + + Video video = new Video(); + video.setMediaId("video_media_id"); + Attachment attachment2 = new Attachment(); + attachment2.setVideo(video); + + List attachments = new ArrayList<>(); + attachments.add(attachment); + attachments.add(attachment2); this.wxCpService.getExternalContactService().sendWelcomeMsg(WxCpWelcomeMsg.builder() .welcomeCode("abc") + .attachments(attachments) .build()); } From dc3f8550276ad99bbfb6162425f0d71fd6cb33f8 Mon Sep 17 00:00:00 2001 From: pengg Date: Mon, 21 Jun 2021 17:06:01 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E8=81=94=E7=B3=BB=E6=8E=A5=E5=8F=A3=E7=BC=BA?= =?UTF-8?q?=E5=B0=91=20#2150?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cp/api/WxCpExternalContactService.java | 105 ++++++++++++++++++ .../impl/WxCpExternalContactServiceImpl.java | 52 +++++++++ ...WxCpUserExternalGroupChatTransferResp.java | 51 +++++++++ .../external/WxCpUserTransferCustomerReq.java | 49 ++++++++ .../WxCpUserTransferCustomerResp.java | 60 ++++++++++ .../external/WxCpUserTransferResultResp.java | 92 +++++++++++++++ .../weixin/cp/constant/WxCpApiPathConsts.java | 6 + .../WxCpExternalContactServiceImplTest.java | 52 ++++++++- 8 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatTransferResp.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferCustomerReq.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferCustomerResp.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferResultResp.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java index 231e0bfa3..86a85a545 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java @@ -6,6 +6,7 @@ import me.chanjar.weixin.cp.bean.external.*; import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactBatchInfo; import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo; +import org.jetbrains.annotations.NotNull; import java.util.Date; import java.util.List; @@ -225,9 +226,85 @@ WxCpExternalContactBatchInfo getContactDetailBatch(String userId, String cursor, * @param takeOverUserid the take over userid * @return wx cp base resp * @throws WxErrorException the wx error exception + * @deprecated 此后续将不再更新维护,建议使用 {@link #transferCustomer(WxCpUserTransferCustomerReq)} */ + @Deprecated WxCpBaseResp transferExternalContact(String externalUserid, String handOverUserid, String takeOverUserid) throws WxErrorException; + /** + * 企业可通过此接口,转接在职成员的客户给其他成员。 + * + * external_userid必须是handover_userid的客户(即配置了客户联系功能的成员所添加的联系人)。 + * 在职成员的每位客户最多被分配2次。客户被转接成功后,将有90个自然日的服务关系保护期,保护期内的客户无法再次被分配。 + * + * 权限说明: + * * 企业需要使用“客户联系”secret或配置到“可调用应用”列表中的自建应用secret所获取的accesstoken来调用(accesstoken如何获取?)。 + * 第三方应用需拥有“企业客户权限->客户联系->在职继承”权限 + * 接替成员必须在此第三方应用或自建应用的可见范围内。 + * 接替成员需要配置了客户联系功能。 + * 接替成员需要在企业微信激活且已经过实名认证。 + * + * @param req 转接在职成员的客户给其他成员请求实体 + * @return wx cp base resp + * @throws WxErrorException the wx error exception + */ + WxCpUserTransferCustomerResp transferCustomer(WxCpUserTransferCustomerReq req) throws WxErrorException; + + /** + * 企业和第三方可通过此接口查询在职成员的客户转接情况。 + * + * 权限说明: + * + * 企业需要使用“客户联系”secret或配置到“可调用应用”列表中的自建应用secret所获取的accesstoken来调用(accesstoken如何获取?)。 + * 第三方应用需拥有“企业客户权限->客户联系->在职继承”权限 + * 接替成员必须在此第三方应用或自建应用的可见范围内。 + * + * @param handOverUserid 原添加成员的userid + * @param takeOverUserid 接替成员的userid + * @param cursor 分页查询的cursor,每个分页返回的数据不会超过1000条;不填或为空表示获取第一个分页; + * @return 客户转接接口实体 + * @throws WxErrorException the wx error exception + */ + WxCpUserTransferResultResp trnsferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor) throws WxErrorException; + + /** + * 企业可通过此接口,分配离职成员的客户给其他成员。 + * + * handover_userid必须是已离职用户。 + * external_userid必须是handover_userid的客户(即配置了客户联系功能的成员所添加的联系人)。 + * 在职成员的每位客户最多被分配2次。客户被转接成功后,将有90个自然日的服务关系保护期,保护期内的客户无法再次被分配。 + * + * 权限说明: + * + * 企业需要使用“客户联系”secret或配置到“可调用应用”列表中的自建应用secret所获取的accesstoken来调用(accesstoken如何获取?)。 + * 第三方应用需拥有“企业客户权限->客户联系->离职分配”权限 + * 接替成员必须在此第三方应用或自建应用的可见范围内。 + * 接替成员需要配置了客户联系功能。 + * 接替成员需要在企业微信激活且已经过实名认证。 + * + * @param req 转接在职成员的客户给其他成员请求实体 + * @return wx cp base resp + * @throws WxErrorException the wx error exception + */ + WxCpUserTransferCustomerResp resignedTransferCustomer(WxCpUserTransferCustomerReq req) throws WxErrorException; + + /** + * 企业和第三方可通过此接口查询离职成员的客户分配情况。 + * + * 权限说明: + * + * 企业需要使用“客户联系”secret或配置到“可调用应用”列表中的自建应用secret所获取的accesstoken来调用(accesstoken如何获取?)。 + * 第三方应用需拥有“企业客户权限->客户联系->在职继承”权限 + * 接替成员必须在此第三方应用或自建应用的可见范围内。 + * + * @param handOverUserid 原添加成员的userid + * @param takeOverUserid 接替成员的userid + * @param cursor 分页查询的cursor,每个分页返回的数据不会超过1000条;不填或为空表示获取第一个分页; + * @return 客户转接接口实体 + * @throws WxErrorException the wx error exception + */ + WxCpUserTransferResultResp resignedTrnsferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor) throws WxErrorException; + /** *
    * 该接口用于获取配置过客户群管理的客户群列表。
@@ -260,6 +337,32 @@ WxCpExternalContactBatchInfo getContactDetailBatch(String userId, String cursor,
    */
   WxCpUserExternalGroupChatInfo getGroupChat(String chatId) throws WxErrorException;
 
+  /**
+   *
+   * 企业可通过此接口,将已离职成员为群主的群,分配给另一个客服成员。
+   *
+   * 
+   * 注意::
+   *
+   * 群主离职了的客户群,才可继承
+   * 继承给的新群主,必须是配置了客户联系功能的成员
+   * 继承给的新群主,必须有设置实名
+   * 继承给的新群主,必须有激活企业微信
+   * 同一个人的群,限制每天最多分配300个给新群主
+   *
+   * 权限说明:
+   *
+   * 企业需要使用“客户联系”secret或配置到“可调用应用”列表中的自建应用secret所获取的accesstoken来调用(accesstoken如何获取?)。
+   * 第三方应用需拥有“企业客户权限->客户联系->分配离职成员的客户群”权限
+   * 对于第三方/自建应用,群主必须在应用的可见范围。
+   * 
+   * @param chatIds 需要转群主的客户群ID列表。取值范围: 1 ~ 100
+   * @param newOwner  新群主ID
+   * @return 分配结果,主要是分配失败的群列表
+   * @throws WxErrorException  the wx error exception
+   */
+  WxCpUserExternalGroupChatTransferResp transferGroupChat(String[] chatIds, String newOwner)  throws WxErrorException;
+
   /**
    * 
    * 企业可通过此接口获取成员联系客户的数据,包括发起申请数、新增客户数、聊天数、发送消息数和删除/拉黑成员的客户数等指标。
@@ -397,4 +500,6 @@ WxCpExternalContactBatchInfo getContactDetailBatch(String userId, String cursor,
    * @throws WxErrorException the wx error exception
    */
   WxCpBaseResp markTag(String userid, String externalUserid, String[] addTag, String[] removeTag) throws WxErrorException;
+
+
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
index 19e7cdfe7..0a8c26ad7 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
@@ -7,6 +7,7 @@
 import me.chanjar.weixin.common.error.WxCpErrorMsgEnum;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxRuntimeException;
+import me.chanjar.weixin.common.util.BeanUtils;
 import me.chanjar.weixin.cp.api.WxCpExternalContactService;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.WxCpBaseResp;
@@ -15,6 +16,7 @@
 import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Collections;
 import java.util.Date;
@@ -176,6 +178,44 @@ public WxCpBaseResp transferExternalContact(String externalUserid, String handOv
     return WxCpBaseResp.fromJson(result);
   }
 
+  @Override
+  public WxCpUserTransferCustomerResp transferCustomer(WxCpUserTransferCustomerReq req) throws WxErrorException {
+    BeanUtils.checkRequiredFields(req);
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(TRANSFER_CUSTOMER);
+    final String result = this.mainService.post(url, req.toJson());
+    return WxCpUserTransferCustomerResp.fromJson(result);
+  }
+
+  @Override
+  public WxCpUserTransferResultResp trnsferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("cursor", cursor);
+    json.addProperty("handover_userid", handOverUserid);
+    json.addProperty("takeover_userid", takeOverUserid);
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(TRANSFER_RESULT);
+    final String result = this.mainService.post(url, json.toString());
+    return WxCpUserTransferResultResp.fromJson(result);
+  }
+
+  @Override
+  public WxCpUserTransferCustomerResp resignedTransferCustomer(WxCpUserTransferCustomerReq req) throws WxErrorException {
+    BeanUtils.checkRequiredFields(req);
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(RESIGNED_TRANSFER_CUSTOMER);
+    final String result = this.mainService.post(url, req.toJson());
+    return WxCpUserTransferCustomerResp.fromJson(result);
+  }
+
+  @Override
+  public WxCpUserTransferResultResp resignedTrnsferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("cursor", cursor);
+    json.addProperty("handover_userid", handOverUserid);
+    json.addProperty("takeover_userid", takeOverUserid);
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(RESIGNED_TRANSFER_RESULT);
+    final String result = this.mainService.post(url, json.toString());
+    return WxCpUserTransferResultResp.fromJson(result);
+  }
+
   @Override
   public WxCpUserExternalGroupChatList listGroupChat(Integer pageIndex, Integer pageSize, int status, String[] userIds, String[] partyIds) throws WxErrorException {
     JsonObject json = new JsonObject();
@@ -206,6 +246,18 @@ public WxCpUserExternalGroupChatInfo getGroupChat(String chatId) throws WxErrorE
     return WxCpUserExternalGroupChatInfo.fromJson(result);
   }
 
+  @Override
+  public WxCpUserExternalGroupChatTransferResp transferGroupChat(String[] chatIds, String newOwner) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    if (ArrayUtils.isNotEmpty(chatIds)) {
+      json.add("chat_id_list", new Gson().toJsonTree(chatIds).getAsJsonArray());
+    }
+    json.addProperty("new_owner", newOwner);
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GROUP_CHAT_TRANSFER);
+    final String result = this.mainService.post(url, json.toString());
+    return WxCpUserExternalGroupChatTransferResp.fromJson(result);
+  }
+
   @Override
   public WxCpUserExternalUserBehaviorStatistic getUserBehaviorStatistic(Date startTime, Date endTime, String[] userIds, String[] partyIds) throws WxErrorException {
     JsonObject json = new JsonObject();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatTransferResp.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatTransferResp.java
new file mode 100644
index 000000000..ff6fb8237
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatTransferResp.java
@@ -0,0 +1,51 @@
+package me.chanjar.weixin.cp.bean.external;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Getter;
+import lombok.Setter;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.util.List;
+
+/**
+ * 分配离职成员的客户群结果
+ * @author pg
+ * @date 2021年6月21日
+ */
+@Getter
+@Setter
+public class WxCpUserExternalGroupChatTransferResp extends WxCpBaseResp {
+  private static final long serialVersionUID = -943124579487821819L;
+  /**
+   * 没有成功继承的群列表
+   */
+  @SerializedName("failed_chat_list")
+  private List failedChatList;
+
+  public static WxCpUserExternalGroupChatTransferResp fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalGroupChatTransferResp.class);
+  }
+
+  public String toJson() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+
+  @Getter
+  @Setter
+  public static class GroupChatFailedTransfer extends WxCpBaseResp  {
+    private static final long serialVersionUID = -5836775099634587239L;
+    /**
+     * 没能成功继承的群ID
+     */
+    private String chatId;
+
+    public static WxCpUserExternalGroupChatTransferResp.GroupChatFailedTransfer fromJson(String json) {
+      return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalGroupChatTransferResp.GroupChatFailedTransfer.class);
+    }
+
+    public String toJson() {
+      return WxCpGsonBuilder.create().toJson(this);
+    }
+  }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferCustomerReq.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferCustomerReq.java
new file mode 100644
index 000000000..e8b8142cc
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferCustomerReq.java
@@ -0,0 +1,49 @@
+package me.chanjar.weixin.cp.bean.external;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Getter;
+import lombok.Setter;
+import me.chanjar.weixin.common.annotation.Required;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 转接在职成员的客户给其他成员,请求对象
+ *
+ * @author pg
+ * @date 2021年6月21日
+ */
+@Getter
+@Setter
+public class WxCpUserTransferCustomerReq implements Serializable {
+  private static final long serialVersionUID = -309819538677411801L;
+  /**
+   * 原跟进成员的userid
+   */
+  @SerializedName("handover_userid")
+  @Required
+  private String handOverUserid;
+  /**
+   * 接替成员的userid
+   */
+  @SerializedName("takeover_userid")
+  @Required
+  private String takeOverUserid;
+  /**
+   * 客户的external_userid列表,每次最多分配100个客户
+   */
+  @SerializedName("external_userid")
+  @Required
+  private List externalUserid;
+  /**
+   * 转移成功后发给客户的消息,最多200个字符,不填则使用默认文案
+   */
+  @SerializedName("transfer_success_msg")
+  private String transferMsg;
+
+  public String toJson() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferCustomerResp.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferCustomerResp.java
new file mode 100644
index 000000000..27d1c0ad4
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferCustomerResp.java
@@ -0,0 +1,60 @@
+package me.chanjar.weixin.cp.bean.external;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Getter;
+import lombok.Setter;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 转接在职成员的客户给其他成员,返回对象
+ *
+ * @author pg
+ * @date 2021年6月21日
+ */
+@Getter
+@Setter
+public class WxCpUserTransferCustomerResp extends WxCpBaseResp {
+  private static final long serialVersionUID = -8030598756503590089L;
+  /**
+   * 客户转移结果列表
+   */
+  private List customer;
+
+  public static WxCpUserTransferCustomerResp fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpUserTransferCustomerResp.class);
+  }
+
+  public String toJson() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+
+  /**
+   * 转接客户结果实体
+   */
+  @Getter
+  @Setter
+  public static class TransferCustomer implements Serializable {
+    private static final long serialVersionUID = 8720554208727083338L;
+    /**
+     * 客户的external_userid
+     */
+    @SerializedName("external_userid")
+    private String externalUserid;
+    /**
+     * 对此客户进行分配的结果, 0表示成功发起接替,待24小时后自动接替,并不代表最终接替成功
+     */
+    private Integer errcode;
+
+    public static WxCpUserTransferCustomerResp.TransferCustomer fromJson(String json) {
+      return WxCpGsonBuilder.create().fromJson(json, WxCpUserTransferCustomerResp.TransferCustomer.class);
+    }
+
+    public String toJson() {
+      return WxCpGsonBuilder.create().toJson(this);
+    }
+  }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferResultResp.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferResultResp.java
new file mode 100644
index 000000000..e1b8cc459
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserTransferResultResp.java
@@ -0,0 +1,92 @@
+package me.chanjar.weixin.cp.bean.external;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Getter;
+import lombok.Setter;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 在职成员的客户转接情况
+ * @author pg
+ * @date 2021年6月21日
+ */
+@Getter
+@Setter
+public class WxCpUserTransferResultResp extends WxCpBaseResp {
+  private static final long serialVersionUID = 6897979567174991786L;
+  @SerializedName("next_cursor")
+  private String nextCursor;
+
+  public static WxCpUserTransferResultResp fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpUserTransferResultResp.class);
+  }
+
+  public String toJson() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+
+  /**
+   * 客户转接结果实体
+   */
+  @Getter
+  @Setter
+  public static class TransferResult implements Serializable {
+    private static final long serialVersionUID = 2847784363733118393L;
+
+    /**
+     * 客户的external_userid
+     */
+    @SerializedName("external_userid")
+    private String externalUserid;
+    /**
+     * 接替状态, 1-接替完毕 2-等待接替 3-客户拒绝 4-接替成员客户达到上限 5-无接替记录
+     */
+    private STATUS status;
+    /**
+     * 接替客户的时间,如果是等待接替状态,则为未来的自动接替时间
+     */
+    @SerializedName("takeover_time")
+    private Long takeOverTime;
+
+    public static WxCpUserTransferResultResp.TransferResult fromJson(String json) {
+      return WxCpGsonBuilder.create().fromJson(json, WxCpUserTransferResultResp.TransferResult.class);
+    }
+
+    public String toJson() {
+      return WxCpGsonBuilder.create().toJson(this);
+    }
+  }
+
+  public enum STATUS {
+
+    /**
+     * 接替完毕
+     */
+    @SerializedName("1")
+    COMPLETE,
+
+    /**
+     * 等待接替
+     */
+    @SerializedName("2")
+    WAITING,
+    /**
+     * 客户拒绝
+     */
+    @SerializedName("3")
+    REFUSED,
+    /**
+     * 接替成员客户达到上限
+     */
+    @SerializedName("4")
+    LIMIT,
+    /**
+     * 无接替记录
+     */
+    @SerializedName("5")
+    NORECORD
+  }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
index bc96269ea..35aee76f7 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
@@ -179,9 +179,15 @@ interface ExternalContact {
     String UPDATE_REMARK = "/cgi-bin/externalcontact/remark";
     String LIST_EXTERNAL_CONTACT = "/cgi-bin/externalcontact/list?userid=";
     String LIST_UNASSIGNED_CONTACT = "/cgi-bin/externalcontact/get_unassigned_list";
+    @Deprecated
     String TRANSFER_UNASSIGNED_CONTACT = "/cgi-bin/externalcontact/transfer";
+    String TRANSFER_CUSTOMER = "/cgi-bin/externalcontact/transfer_customer";
+    String TRANSFER_RESULT = "/cgi-bin/externalcontact/transfer_result";
+    String RESIGNED_TRANSFER_CUSTOMER = "/cgi-bin/externalcontact/resigned/transfer_customer";
+    String RESIGNED_TRANSFER_RESULT = "/cgi-bin/externalcontact/resigned/transfer_result";
     String GROUP_CHAT_LIST = "/cgi-bin/externalcontact/groupchat/list";
     String GROUP_CHAT_INFO = "/cgi-bin/externalcontact/groupchat/get";
+    String GROUP_CHAT_TRANSFER = "/cgi-bin/externalcontact/groupchat/transfer";
     String LIST_USER_BEHAVIOR_DATA = "/cgi-bin/externalcontact/get_user_behavior_data";
     String LIST_GROUP_CHAT_DATA = "/cgi-bin/externalcontact/groupchat/statistic";
     String ADD_MSG_TEMPLATE = "/cgi-bin/externalcontact/add_msg_template";
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
index 4b6221d17..2ce5526f2 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
@@ -16,6 +16,7 @@
 import org.testng.annotations.Test;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
@@ -196,13 +197,62 @@ public void testTransferExternalContact() {
   }
 
   @Test
-  public void testListGroupChat() {
+  public void testTransferCustomer() throws WxErrorException {
+    WxCpUserTransferCustomerReq req = new WxCpUserTransferCustomerReq();
+    req.setExternalUserid(Collections.emptyList());
+    req.setHandOverUserid("123");
+    req.setTakeOverUserid("234");
+    WxCpBaseResp result = this.wxCpService.getExternalContactService().transferCustomer(req);
+
+    System.out.println(result);
+    assertNotNull(result);
+  }
+
+  @Test
+  public void testTrnsferResult() throws WxErrorException {
+    WxCpUserTransferResultResp result = this.wxCpService.getExternalContactService().trnsferResult("123", "234", "");
+    System.out.println(result);
+    assertNotNull(result);
+  }
+
+  @Test
+  public void testresignedTransferCustomer() throws WxErrorException {
+    WxCpUserTransferCustomerReq req = new WxCpUserTransferCustomerReq();
+    req.setExternalUserid(Collections.emptyList());
+    req.setHandOverUserid("123");
+    req.setTakeOverUserid("234");
+    WxCpBaseResp result = this.wxCpService.getExternalContactService().resignedTransferCustomer(req);
+
+    System.out.println(result);
+    assertNotNull(result);
+  }
+
+  @Test
+  public void testresignedTrnsferResult() throws WxErrorException {
+    WxCpUserTransferResultResp result = this.wxCpService.getExternalContactService().resignedTrnsferResult("123", "234", "");
+    System.out.println(result);
+    assertNotNull(result);
+  }
+
+  @Test
+  public void testListGroupChat() throws WxErrorException {
+    WxCpUserExternalGroupChatList result = this.wxCpService.getExternalContactService().listGroupChat(0, 100 ,0,new String[1],new String[1]);
+    System.out.println(result);
+    assertNotNull(result);
   }
 
   @Test
   public void testGetGroupChat() {
   }
 
+  @Test
+  public void testTransferGroupChat() throws WxErrorException {
+    String[] str = {"wri1_QEAAATfnZl_VJ4hlQda0e4Mgf1A"};
+    WxCpUserExternalGroupChatTransferResp result = this.wxCpService.getExternalContactService().transferGroupChat(str, "123");
+    System.out.println(result);
+    assertNotNull(result);
+  }
+
   @Test
   public void testGetUserBehaviorStatistic() {
   }

From f23271e9e08594b86dbac43e77a2c5475307b6ab Mon Sep 17 00:00:00 2001
From: pengg 
Date: Tue, 22 Jun 2021 10:14:31 +0800
Subject: [PATCH 04/10] =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1?=
 =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=95=86=E6=A8=A1=E5=BC=8F=E7=BC=BA=E5=B0=91?=
 =?UTF-8?q?=E5=A4=96=E9=83=A8=E8=81=94=E7=B3=BB=E4=BA=BAopenid=E8=BD=AC?=
 =?UTF-8?q?=E6=8D=A2=20#2147?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weixin/cp/api/WxCpExternalContactService.java     |  8 ++++++++
 .../cp/api/impl/WxCpExternalContactServiceImpl.java   | 11 +++++++++++
 .../chanjar/weixin/cp/constant/WxCpApiPathConsts.java |  1 +
 3 files changed, 20 insertions(+)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
index 86a85a545..1dcf83eb0 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
@@ -135,6 +135,14 @@ public interface WxCpExternalContactService {
    */
   WxCpExternalContactInfo getContactDetail(String userId) throws WxErrorException;
 
+  /**
+   * 企业和服务商可通过此接口,将微信外部联系人的userid转为微信openid,用于调用支付相关接口。暂不支持企业微信外部联系人(ExternalUserid为wo开头)的userid转openid。
+   * @param externalUserid 微信外部联系人的userid
+   * @return 该企业的外部联系人openid
+   * @throws WxErrorException .
+   */
+  String convertToOpenid(String externalUserid) throws WxErrorException;
+
   /**
    * 批量获取客户详情.
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
index 0a8c26ad7..6a75ef4a2 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
@@ -8,6 +8,7 @@
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.BeanUtils;
+import me.chanjar.weixin.common.util.json.GsonParser;
 import me.chanjar.weixin.cp.api.WxCpExternalContactService;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.WxCpBaseResp;
@@ -108,6 +109,16 @@ public WxCpExternalContactInfo getContactDetail(String userId) throws WxErrorExc
     return WxCpExternalContactInfo.fromJson(responseContent);
   }
 
+  @Override
+  public String convertToOpenid(@NotNull String externalUserId) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("external_userid", externalUserId);
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(CONVERT_TO_OPENID);
+    String responseContent = this.mainService.post(url, json.toString());
+    JsonObject tmpJson = GsonParser.parse(responseContent);
+    return tmpJson.get("openid").getAsString();
+  }
+
   @Override
   public WxCpExternalContactBatchInfo getContactDetailBatch(String userId,
                                                             String cursor,
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
index 35aee76f7..c60a1bddb 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
@@ -175,6 +175,7 @@ interface ExternalContact {
     String CLOSE_TEMP_CHAT = "/cgi-bin/externalcontact/close_temp_chat";
     String GET_FOLLOW_USER_LIST = "/cgi-bin/externalcontact/get_follow_user_list";
     String GET_CONTACT_DETAIL = "/cgi-bin/externalcontact/get?external_userid=";
+    String CONVERT_TO_OPENID = "/cgi-bin/externalcontact/convert_to_openid";
     String GET_CONTACT_DETAIL_BATCH = "/cgi-bin/externalcontact/batch/get_by_user?";
     String UPDATE_REMARK = "/cgi-bin/externalcontact/remark";
     String LIST_EXTERNAL_CONTACT = "/cgi-bin/externalcontact/list?userid=";

From 3d3ad017bc3dd2118989efc5a4f6caca5e56817c Mon Sep 17 00:00:00 2001
From: pengg 
Date: Tue, 22 Jun 2021 10:51:37 +0800
Subject: [PATCH 05/10] =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1?=
 =?UTF-8?q?=E5=AE=A2=E6=88=B7=E8=81=94=E7=B3=BB=E6=8E=A5=E5=8F=A3=E7=BC=BA?=
 =?UTF-8?q?=E5=B0=91=20#2150=20=E6=9C=89=E4=B8=A4=E4=B8=AA=E5=8D=95?=
 =?UTF-8?q?=E8=AF=8D=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../me/chanjar/weixin/cp/api/WxCpExternalContactService.java  | 4 ++--
 .../weixin/cp/api/impl/WxCpExternalContactServiceImpl.java    | 4 ++--
 .../cp/api/impl/WxCpExternalContactServiceImplTest.java       | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
index 1dcf83eb0..cd65ad377 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
@@ -273,7 +273,7 @@ WxCpExternalContactBatchInfo getContactDetailBatch(String userId, String cursor,
    * @return 客户转接接口实体
    * @throws WxErrorException the wx error exception
    */
-  WxCpUserTransferResultResp trnsferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor)  throws WxErrorException;
+  WxCpUserTransferResultResp transferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor)  throws WxErrorException;
 
   /**
    * 企业可通过此接口,分配离职成员的客户给其他成员。
@@ -311,7 +311,7 @@ WxCpExternalContactBatchInfo getContactDetailBatch(String userId, String cursor,
    * @return 客户转接接口实体
    * @throws WxErrorException the wx error exception
    */
-  WxCpUserTransferResultResp resignedTrnsferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor)  throws WxErrorException;
+  WxCpUserTransferResultResp resignedTransferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor)  throws WxErrorException;
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
index 6a75ef4a2..8065d2198 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
@@ -198,7 +198,7 @@ public WxCpUserTransferCustomerResp transferCustomer(WxCpUserTransferCustomerReq
   }
 
   @Override
-  public WxCpUserTransferResultResp trnsferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor) throws WxErrorException {
+  public WxCpUserTransferResultResp transferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor) throws WxErrorException {
     JsonObject json = new JsonObject();
     json.addProperty("cursor", cursor);
     json.addProperty("handover_userid", handOverUserid);
@@ -217,7 +217,7 @@ public WxCpUserTransferCustomerResp resignedTransferCustomer(WxCpUserTransferCus
   }
 
   @Override
-  public WxCpUserTransferResultResp resignedTrnsferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor) throws WxErrorException {
+  public WxCpUserTransferResultResp resignedTransferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor) throws WxErrorException {
     JsonObject json = new JsonObject();
     json.addProperty("cursor", cursor);
     json.addProperty("handover_userid", handOverUserid);
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
index 2ce5526f2..8869a6a02 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
@@ -210,7 +210,7 @@ public void testTransferCustomer() throws WxErrorException {
 
   @Test
   public void testTrnsferResult() throws WxErrorException {
-    WxCpUserTransferResultResp result = this.wxCpService.getExternalContactService().trnsferResult("123", "234", "");
+    WxCpUserTransferResultResp result = this.wxCpService.getExternalContactService().transferResult("123", "234", "");
     System.out.println(result);
     assertNotNull(result);
   }
@@ -229,7 +229,7 @@ public void testresignedTransferCustomer() throws WxErrorException {
 
   @Test
   public void testresignedTrnsferResult() throws WxErrorException {
-    WxCpUserTransferResultResp result = this.wxCpService.getExternalContactService().resignedTrnsferResult("123", "234", "");
+    WxCpUserTransferResultResp result = this.wxCpService.getExternalContactService().resignedTransferResult("123", "234", "");
     System.out.println(result);
     assertNotNull(result);
   }

From 11ee52f6e381f10aced9b3c5ca80f4c03ad46482 Mon Sep 17 00:00:00 2001
From: pengg 
Date: Tue, 22 Jun 2021 13:42:56 +0800
Subject: [PATCH 06/10] =?UTF-8?q?=E4=BA=92=E8=81=94=E4=BC=81=E4=B8=9A?=
 =?UTF-8?q?=E7=9A=84=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81=E6=8E=A5=E5=8F=A3?=
 =?UTF-8?q?=E8=BF=94=E5=9B=9E=E5=AD=97=E6=AE=B5=E7=B1=BB=E5=9E=8B=E5=92=8C?=
 =?UTF-8?q?=E5=AE=98=E7=BD=91api=E4=B8=8D=E4=B8=80=E8=87=B4=20#2148?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weixin/cp/api/WxCpMessageService.java     |  7 ++--
 .../cp/api/impl/WxCpMessageServiceImpl.java   |  9 ++---
 .../WxCpLinkedCorpMessageSendResult.java      | 36 +++++++++++++++++++
 3 files changed, 41 insertions(+), 11 deletions(-)
 create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessageSendResult.java

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageService.java
index fae0a6a0d..1b66d00c0 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageService.java
@@ -1,10 +1,7 @@
 package me.chanjar.weixin.cp.api;
 
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.cp.bean.message.WxCpLinkedCorpMessage;
-import me.chanjar.weixin.cp.bean.message.WxCpMessage;
-import me.chanjar.weixin.cp.bean.message.WxCpMessageSendResult;
-import me.chanjar.weixin.cp.bean.message.WxCpMessageSendStatistics;
+import me.chanjar.weixin.cp.bean.message.*;
 
 /**
  * 消息推送接口.
@@ -52,5 +49,5 @@ public interface WxCpMessageService {
    * @return the wx cp message send result
    * @throws WxErrorException the wx error exception
    */
-  WxCpMessageSendResult sendLinkedCorpMessage(WxCpLinkedCorpMessage message) throws WxErrorException;
+  WxCpLinkedCorpMessageSendResult sendLinkedCorpMessage(WxCpLinkedCorpMessage message) throws WxErrorException;
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImpl.java
index 07824c218..9be2f60df 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImpl.java
@@ -5,10 +5,7 @@
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.api.WxCpMessageService;
 import me.chanjar.weixin.cp.api.WxCpService;
-import me.chanjar.weixin.cp.bean.message.WxCpLinkedCorpMessage;
-import me.chanjar.weixin.cp.bean.message.WxCpMessage;
-import me.chanjar.weixin.cp.bean.message.WxCpMessageSendResult;
-import me.chanjar.weixin.cp.bean.message.WxCpMessageSendStatistics;
+import me.chanjar.weixin.cp.bean.message.*;
 import me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Message;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
@@ -40,13 +37,13 @@ public WxCpMessageSendStatistics getStatistics(int timeType) throws WxErrorExcep
   }
 
   @Override
-  public WxCpMessageSendResult sendLinkedCorpMessage(WxCpLinkedCorpMessage message) throws WxErrorException {
+  public WxCpLinkedCorpMessageSendResult sendLinkedCorpMessage(WxCpLinkedCorpMessage message) throws WxErrorException {
     Integer agentId = message.getAgentId();
     if (null == agentId) {
       message.setAgentId(this.cpService.getWxCpConfigStorage().getAgentId());
     }
 
-    return WxCpMessageSendResult.fromJson(this.cpService.post(this.cpService.getWxCpConfigStorage()
+    return WxCpLinkedCorpMessageSendResult.fromJson(this.cpService.post(this.cpService.getWxCpConfigStorage()
       .getApiUrl(Message.LINKEDCORP_MESSAGE_SEND), message.toJson()));
   }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessageSendResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessageSendResult.java
new file mode 100644
index 000000000..32ca3bd9c
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessageSendResult.java
@@ -0,0 +1,36 @@
+package me.chanjar.weixin.cp.bean.message;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Getter;
+import lombok.Setter;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * 互联企业的消息推送接口返回实体
+ *
+ * @author pg
+ * @date 2021年6月22日
+ */
+@Setter
+@Getter
+public class WxCpLinkedCorpMessageSendResult extends WxCpBaseResp {
+  private static final long serialVersionUID = 3990693822996824333L;
+
+  @SerializedName("invaliduser")
+  private String[] invaliduser;
+  @SerializedName("invalidparty")
+  private String[] invalidparty;
+  @SerializedName("invalidtag")
+  private String[] invalidtag;
+
+  @Override
+  public String toString() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+
+  public static WxCpLinkedCorpMessageSendResult fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpLinkedCorpMessageSendResult.class);
+  }
+
+}

From bf266b821b7ff832c9064086173af3680e43e740 Mon Sep 17 00:00:00 2001
From: pengg 
Date: Wed, 23 Jun 2021 16:09:26 +0800
Subject: [PATCH 07/10] =?UTF-8?q?=E4=BA=92=E8=81=94=E4=BC=81=E4=B8=9A?=
 =?UTF-8?q?=E7=9A=84=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81=E6=8E=A5=E5=8F=A3?=
 =?UTF-8?q?=E8=BF=94=E5=9B=9E=E5=AD=97=E6=AE=B5=E7=B1=BB=E5=9E=8B=E5=92=8C?=
 =?UTF-8?q?=E5=AE=98=E7=BD=91api=E4=B8=8D=E4=B8=80=E8=87=B4=20#2148?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../cp/bean/message/WxCpLinkedCorpMessageSendResult.java  | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessageSendResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessageSendResult.java
index 32ca3bd9c..2955df54c 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessageSendResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpLinkedCorpMessageSendResult.java
@@ -18,11 +18,13 @@ public class WxCpLinkedCorpMessageSendResult extends WxCpBaseResp {
   private static final long serialVersionUID = 3990693822996824333L;
 
   @SerializedName("invaliduser")
-  private String[] invaliduser;
+  private String[] invalidUser;
+
   @SerializedName("invalidparty")
-  private String[] invalidparty;
+  private String[] invalidParty;
+
   @SerializedName("invalidtag")
-  private String[] invalidtag;
+  private String[] invalidTag;
 
   @Override
   public String toString() {

From 37959e05bc7ab0517929ea3327f3bb0a072cdb89 Mon Sep 17 00:00:00 2001
From: pengg 
Date: Fri, 25 Jun 2021 15:31:25 +0800
Subject: [PATCH 08/10] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=88=86=E8=B4=A6?=
 =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=B1=BB=E5=A2=9E=E5=8A=A0v3=E6=8E=A5?=
 =?UTF-8?q?=E5=8F=A3=20#2120?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../ProfitSharingReceiver.java                | 144 +++++++++++++++
 .../profitsharingV3/ProfitSharingRequest.java |  77 ++++++++
 .../profitsharingV3/ProfitSharingResult.java  | 172 ++++++++++++++++++
 .../ProfitSharingReturnRequest.java           |  82 +++++++++
 .../ProfitSharingReturnResult.java            | 141 ++++++++++++++
 .../ProfitSharingUnfreezeRequest.java         |  54 ++++++
 .../ProfitSharingUnfreezeResult.java          | 162 +++++++++++++++++
 .../ProfitSharingUnsplitResult.java           |  39 ++++
 .../wxpay/service/ProfitSharingV3Service.java | 164 +++++++++++++++++
 .../wxpay/service/WxPayService.java           |   9 +
 .../service/impl/BaseWxPayServiceImpl.java    |   6 +
 .../impl/ProfitSharingV3ServiceImpl.java      |  85 +++++++++
 12 files changed, 1135 insertions(+)
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReceiver.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingRequest.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingResult.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReturnRequest.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReturnResult.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnfreezeRequest.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnfreezeResult.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnsplitResult.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/ProfitSharingV3Service.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/ProfitSharingV3ServiceImpl.java

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReceiver.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReceiver.java
new file mode 100644
index 000000000..cbdeeba28
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReceiver.java
@@ -0,0 +1,144 @@
+package com.github.binarywang.wxpay.bean.profitsharingV3;
+
+import com.github.binarywang.wxpay.v3.SpecEncrypt;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *
+ * 微信V3接口 分账接收方实体
+ * @author pg
+ * @date 2021-6-25
+ *
+ */
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProfitSharingReceiver implements Serializable {
+  private static final long serialVersionUID = -4391888575149767840L;
+
+  /**
+   * 
+   * 字段名:应用ID
+   * 是否必填:是
+   * 描述:微信分配的商户appid
+   * 
+ */ + @SerializedName("appid") + private String appid; + + /** + *
+   * 字段名:分账接收方类型
+   * 是否必填:是
+   * 描述:
+   * 1、MERCHANT_ID:商户号
+   * 2、PERSONAL_OPENID:个人openid(由父商户APPID转换得到)
+   * 
+ */ + @SerializedName("type") + private String type; + + /** + *
+   * 字段名:分账接收方帐号
+   * 是否必填:是
+   * 描述:
+   * 1、分账接收方类型为MERCHANT_ID时,分账接收方账号为商户号
+   * 2、分账接收方类型为PERSONAL_OPENID时,分账接收方账号为个人openid
+   * 
+ */ + @SerializedName("account") + private String account; + + /** + *
+   * 字段名:分账个人接收方姓名
+   * 是否必填:否
+   * 描述:
+   * 可选项,在接收方类型为个人的时可选填,若有值,会检查与 name 是否实名匹配,不匹配会拒绝分账请求
+   * 1、分账接收方类型是PERSONAL_OPENID,是个人姓名的密文(选传,传则校验) 此字段的加密方法详见:敏感信息加密说明
+   * 2、使用微信支付平台证书中的公钥
+   * 3、使用RSAES-OAEP算法进行加密
+   * 4、将请求中HTTP头部的Wechatpay-Serial设置为证书序列号
+   * 
+ */ + @SerializedName("name") + @SpecEncrypt + private String name; + + /** + *
+   * 字段名:与分账方的关系类型
+   * 是否必填:是
+   * 描述:子商户与接收方的关系。 本字段值为枚举:
+   * STORE:门店
+   * STAFF:员工
+   * STORE_OWNER:店主
+   * PARTNER:合作伙伴
+   * HEADQUARTER:总部
+   * BRAND:品牌方
+   * DISTRIBUTOR:分销商
+   * USER:用户
+   * SUPPLIER: 供应商
+   * CUSTOM:自定义
+   * 
+ */ + @SerializedName("relation_type") + private String relationType; + + /** + *
+   * 字段名:自定义的分账关系
+   * 是否必填:是
+   * 描述:子商户与接收方具体的关系,本字段最多10个字。
+   * 当字段relationType的值为CUSTOM时,本字段必填;
+   * 当字段relationType的值不为CUSTOM时,本字段无需填写。
+   * 
+ */ + @SerializedName("custom_relation") + private String customRelation; + + /** + *
+   * 字段名:分账描述
+   * 是否必填:是
+   * 描述: 分账的原因描述,分账账单中需要体现
+   * 
+ */ + private String description; + /** + *
+   * 字段名:分账金额
+   * 是否必填:是
+   * 描述: 分账金额,单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额
+   * 
+ */ + private Long amount; + + /** + * 此构造函数用于分账接口 + * + * @param type MERCHANT_ID:商户ID + * PERSONAL_WECHATID:个人微信号PERSONAL_OPENID:个人openid(由父商户APPID转换得到)PERSONAL_SUB_OPENID: 个人sub_openid(由子商户APPID转换得到) + * @param account 类型是MERCHANT_ID时,是商户ID + * 类型是PERSONAL_WECHATID时,是个人微信号 + * 类型是PERSONAL_OPENID时,是个人openid + * 类型是PERSONAL_SUB_OPENID时,是个人sub_openid + * @param amount 分账金额,单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额 + * @param description 分账的原因描述,分账账单中需要体现 + */ + public ProfitSharingReceiver(String type, String account, Long amount, String description) { + this.type = type; + this.account = account; + this.amount = amount; + this.description = description; + } + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingRequest.java new file mode 100644 index 000000000..78122bfbf --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingRequest.java @@ -0,0 +1,77 @@ +package com.github.binarywang.wxpay.bean.profitsharingV3; + +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; + +/** + * 微信V3接口 + * 请求分账API请求实体 + * + * @author pg + * @date 2021-6-24 + */ +@Data +@Builder(builderMethodName = "newBuilder") +@NoArgsConstructor +@AllArgsConstructor +public class ProfitSharingRequest implements Serializable { + private static final long serialVersionUID = 3644929701624280800L; + + /** + *
+   * 字段名:应用ID
+   * 是否必填:是
+   * 描述:微信分配的商户appid
+   * 
+ */ + @SerializedName("appid") + private String appid; + + /** + *
+   * 字段名:微信订单号
+   * 是否必填:是
+   * 描述:微信支付订单号
+   * 
+ */ + @SerializedName("transaction_id") + private String transactionId; + + /** + *
+   * 字段名:商户分账单号
+   * 是否必填:是
+   * 描述:商户系统内部的分账单号,在商户系统内部唯一,同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@
+   * 
+ */ + @SerializedName("out_order_no") + private String outOrderNo; + + /** + *
+   * 字段名:分账接收方列表
+   * 是否必填:是
+   * 描述:分账接收方列表,可以设置出资商户作为分账接受方,最多可有50个分账接收方
+   * 
+ */ + @SerializedName("receivers") + private List receivers; + + /** + *
+   * 字段名:是否解冻剩余未分资金
+   * 是否必填:是
+   * 描述:
+   * 1、如果为true,该笔订单剩余未分账的金额会解冻回分账方商户;
+   * 2、如果为false,该笔订单剩余未分账的金额不会解冻回分账方商户,可以对该笔订单再次进行分账。
+   * 
+ */ + @SerializedName("unfreeze_unsplit") + private boolean unfreezeUnsplit; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingResult.java new file mode 100644 index 000000000..6e0626f65 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingResult.java @@ -0,0 +1,172 @@ +package com.github.binarywang.wxpay.bean.profitsharingV3; + + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 微信V3接口 + * 请求分账API返回的分账结果实体 + * + * @author pg + * @date 2021-6-24 + */ +@Data +public class ProfitSharingResult implements Serializable { + private static final long serialVersionUID = -6201692412535987502L; + + /** + *
+   * 字段名:微信订单号
+   * 是否必填:是
+   * 描述:微信支付订单号
+   * 
+ */ + @SerializedName("transaction_id") + private String transactionId; + + /** + *
+   * 字段名:商户分账单号
+   * 是否必填:是
+   * 描述:商户系统内部的分账单号,在商户系统内部唯一,同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@
+   * 
+ */ + @SerializedName("out_order_no") + private String outOrderNo; + + /** + *
+   * 字段名:微信分账单号,
+   * 是否必填:是
+   * 描述:微信系统返回的唯一标识.
+   * 
+ */ + @SerializedName("order_id") + private String orderId; + + /** + *
+   * 字段名:分账单状态
+   * 是否必填:是
+   * 描述:分账单状态(每个接收方的分账结果请查看receivers中的result字段):
+   * 1、PROCESSING:处理中
+   * 2、FINISHED:分账完成.
+   * 
+ */ + @SerializedName("state") + private String state; + + /** + * 分账接收方列表 + */ + @SerializedName("receivers") + private List receivers; + + @Data + public static class Receiver implements Serializable { + private static final long serialVersionUID = 4240983048700956806L; + + /** + *
+     * 字段名:分账接收方类型
+     * 是否必填:是
+     * 描述:
+     * 1、MERCHANT_ID:商户号
+     * 2、PERSONAL_OPENID:个人openid(由父商户APPID转换得到)
+     * 
+ */ + @SerializedName("type") + private String type; + + /** + *
+     * 字段名:分账接收方帐号
+     * 是否必填:是
+     * 描述:
+     * 1、分账接收方类型为MERCHANT_ID时,分账接收方账号为商户号
+     * 2、分账接收方类型为PERSONAL_OPENID时,分账接收方账号为个人openid
+     * 
+ */ + @SerializedName("account") + private String account; + + /** + *
+     * 字段名:分账金额
+     * 是否必填:是
+     * 描述: 分账金额,单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额
+     * 
+ */ + @SerializedName("amount") + private Long amount; + + /** + *
+     * 字段名:分账描述
+     * 是否必填:是
+     * 描述: 分账的原因描述,分账账单中需要体现
+     * 
+ */ + @SerializedName("description") + private String description; + + /** + *
+     * 字段名:分账结果
+     * 是否必填:是
+     * 描述:
+     * 1、PENDING:待分账
+     * 2、SUCCESS:分账成功
+     * 3、CLOSED:已关闭
+     * 
+ */ + @SerializedName("result") + private String result; + + /** + *
+     * 字段名:分账失败原因
+     * 是否必填:是
+     * 描述:包含以下枚举值:
+     * 1、ACCOUNT_ABNORMAL : 分账接收账户异常
+     * 2、NO_RELATION : 分账关系已解除
+     * 3、RECEIVER_HIGH_RISK : 高风险接收方
+     * 4、RECEIVER_REAL_NAME_NOT_VERIFIED : 接收方未实名
+     * 5、NO_AUTH : 分账权限已解除
+     * 
+ */ + @SerializedName("fail_reason") + private String failReason; + + /** + *
+     * 字段名:分账创建时间
+     * 是否必填:是
+     * 描述:遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,
+     * YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,
+     * HH:mm:ss.sss表示时分秒毫秒,
+     * TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+     * 例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+     * 
+ */ + @SerializedName("create_time") + private String createTime; + /** + *
+     * 字段名:分账完成时间
+     * 是否必填:是
+     * 描述:遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,
+     * YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,
+     * HH:mm:ss.sss表示时分秒毫秒,
+     * TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+     * 例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+     * 
+ */ + @SerializedName("finish_time") + private String finishTime; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReturnRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReturnRequest.java new file mode 100644 index 000000000..31e26775f --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReturnRequest.java @@ -0,0 +1,82 @@ +package com.github.binarywang.wxpay.bean.profitsharingV3; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 微信V3接口 + * 请求分账回退API请求实体 + * + * @author pg + * @date 2021-6-25 + */ +@Data +@Builder(builderMethodName = "newBuilder") +@NoArgsConstructor +@AllArgsConstructor +public class ProfitSharingReturnRequest implements Serializable { + private static final long serialVersionUID = -2175582517588397426L; + + /** + *
+   * 字段名:微信分账单号
+   * 是否必填:是
+   * 描述:微信分账单号,微信系统返回的唯一标识。
+   * 
+ */ + @SerializedName("order_id") + private String orderId; + + /** + *
+   * 字段名:商户分账单号
+   * 是否必填:是
+   * 描述:商户系统内部的分账单号,在商户系统内部唯一,同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@
+   * 
+ */ + @SerializedName("out_order_no") + private String outOrderNo; + + /** + *
+   * 字段名:商户回退单号
+   * 是否必填:是
+   * 描述:此回退单号是商户在自己后台生成的一个新的回退单号,在商户后台唯一
+   * 
+ */ + @SerializedName("out_return_no") + private String outReturnNo; + + /** + *
+   * 字段名:回退商户号
+   * 是否必填:是
+   * 描述:分账回退的出资商户,只能对原分账请求中成功分给商户接收方进行回退
+   * 
+ */ + @SerializedName("return_mchid") + private String returnMchid; + + /** + *
+   * 字段名:回退金额
+   * 是否必填:是
+   * 描述:需要从分账接收方回退的金额,单位为分,只能为整数,不能超过原始分账单分出给该接收方的金额
+   * 
+ */ + private Long amount; + + /** + *
+   * 字段名:回退描述
+   * 是否必填:是
+   * 描述: 分账回退的原因描述
+   * 
+ */ + private String description; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReturnResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReturnResult.java new file mode 100644 index 000000000..6e08a9a41 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingReturnResult.java @@ -0,0 +1,141 @@ +package com.github.binarywang.wxpay.bean.profitsharingV3; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 微信V3接口 + * 请求分账回退API返回实体 + * + * @author pg + * @date 2021-6-25 + */ +@Data +public class ProfitSharingReturnResult implements Serializable { + private static final long serialVersionUID = -2175582517588397426L; + + /** + *
+   * 字段名:微信分账单号
+   * 是否必填:是
+   * 描述:微信分账单号,微信系统返回的唯一标识。
+   * 
+ */ + @SerializedName("order_id") + private String orderId; + + /** + *
+   * 字段名:商户分账单号
+   * 是否必填:是
+   * 描述:商户系统内部的分账单号,在商户系统内部唯一,同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@
+   * 
+ */ + @SerializedName("out_order_no") + private String outOrderNo; + + /** + *
+   * 字段名:商户回退单号
+   * 是否必填:是
+   * 描述:此回退单号是商户在自己后台生成的一个新的回退单号,在商户后台唯一
+   * 
+ */ + @SerializedName("out_return_no") + private String outReturnNo; + + /** + *
+   * 字段名:微信回退单号
+   * 是否必填:是
+   * 描述:微信分账回退单号,微信系统返回的唯一标识
+   * 
+ */ + @SerializedName("return_id") + private String returnId; + + /** + *
+   * 字段名:回退商户号
+   * 是否必填:是
+   * 描述:分账回退的出资商户,只能对原分账请求中成功分给商户接收方进行回退
+   * 
+ */ + @SerializedName("return_mchid") + private String returnMchid; + + /** + *
+   * 字段名:回退金额
+   * 是否必填:是
+   * 描述:需要从分账接收方回退的金额,单位为分,只能为整数,不能超过原始分账单分出给该接收方的金额
+   * 
+ */ + private Long amount; + + /** + *
+   * 字段名:回退描述
+   * 是否必填:是
+   * 描述: 分账回退的原因描述
+   * 
+ */ + private String description; + + /** + *
+   * 字段名:分账结果
+   * 是否必填:是
+   * 描述:
+   * 如果请求返回为处理中,则商户可以通过调用回退结果查询接口获取请求的最终处理结果。
+   * 如果查询到回退结果在处理中,请勿变更商户回退单号,使用相同的参数再次发起分账回退,否则会出现资金风险。
+   * 在处理中状态的回退单如果5天没有成功,会因为超时被设置为已失败。
+   * PROCESSING:处理中
+   * SUCCESS:已成功
+   * FAILED:已失败
+   * 
+ */ + @SerializedName("result") + private String result; + + /** + *
+   * 字段名:失败原因
+   * 是否必填:是
+   * 描述:失败原因。包含以下枚举值:
+   * ACCOUNT_ABNORMAL : 分账接收方账户异常
+   * TIME_OUT_CLOSED : 超时关单
+   * 
+ */ + @SerializedName("fail_reason") + private String failReason; + + /** + *
+   * 字段名:分账回退创建时间
+   * 是否必填:是
+   * 描述:遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,
+   * YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,
+   * HH:mm:ss.sss表示时分秒毫秒,
+   * TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+   * 例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+   * 
+ */ + @SerializedName("create_time") + private String createTime; + /** + *
+   * 字段名:分账回退完成时间
+   * 是否必填:是
+   * 描述:遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,
+   * YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,
+   * HH:mm:ss.sss表示时分秒毫秒,
+   * TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+   * 例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+   * 
+ */ + @SerializedName("finish_time") + private String finishTime; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnfreezeRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnfreezeRequest.java new file mode 100644 index 000000000..c79b9b638 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnfreezeRequest.java @@ -0,0 +1,54 @@ +package com.github.binarywang.wxpay.bean.profitsharingV3; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 微信V3接口 + * 解冻剩余资金API请求实体 + * + * @author pg + * @date 2021-6-25 + */ +@Data +@Builder(builderMethodName = "newBuilder") +@NoArgsConstructor +@AllArgsConstructor +public class ProfitSharingUnfreezeRequest implements Serializable { + private static final long serialVersionUID = 6835471990040104843L; + + /** + *
+   * 字段名:微信订单号
+   * 是否必填:是
+   * 描述:微信支付订单号
+   * 
+ */ + @SerializedName("transaction_id") + private String transactionId; + + /** + *
+   * 字段名:商户分账单号
+   * 是否必填:是
+   * 描述:商户系统内部的分账单号,在商户系统内部唯一,同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@
+   * 
+ */ + @SerializedName("out_order_no") + private String outOrderNo; + + /** + *
+   * 字段名:分账描述
+   * 是否必填:是
+   * 描述: 分账的原因描述,分账账单中需要体现
+   * 
+ */ + @SerializedName("description") + private String description; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnfreezeResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnfreezeResult.java new file mode 100644 index 000000000..0e67eee4c --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnfreezeResult.java @@ -0,0 +1,162 @@ +package com.github.binarywang.wxpay.bean.profitsharingV3; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 微信V3接口 + * 解冻剩余资金API返回实体 + * + * @author pg + * @date 2021-6-25 + */ +@Data +public class ProfitSharingUnfreezeResult implements Serializable { + private static final long serialVersionUID = 5053171678880645337L; + + /** + *
+   * 字段名:微信订单号
+   * 是否必填:是
+   * 描述:微信支付订单号
+   * 
+ */ + @SerializedName("transaction_id") + private String transactionId; + + /** + *
+   * 字段名:商户分账单号
+   * 是否必填:是
+   * 描述:商户系统内部的分账单号,在商户系统内部唯一,同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@
+   * 
+ */ + @SerializedName("out_order_no") + private String outOrderNo; + + /** + *
+   * 字段名:微信分账单号
+   * 是否必填:是
+   * 描述:微信分账单号,微信系统返回的唯一标识。
+   * 
+ */ + @SerializedName("order_id") + private String orderId; + + + /** + *
+   * 字段名:分账单状态
+   * 是否必填:是
+   * 描述:分账单状态(每个接收方的分账结果请查看receivers中的result字段),枚举值:
+   * 1、PROCESSING:处理中
+   * 2、FINISHED:分账完成
+   * 
+ */ + @SerializedName("state") + private String state; + + @Data + public static class Receiver implements Serializable { + private static final long serialVersionUID = 4240983048700956806L; + /** + *
+     * 字段名:分账接收方类型
+     * 是否必填:是
+     * 描述:
+     * 1、MERCHANT_ID:商户号
+     * 2、PERSONAL_OPENID:个人openid(由父商户APPID转换得到)
+     * 
+ */ + @SerializedName("type") + private String type; + + /** + *
+     * 字段名:分账接收方帐号
+     * 是否必填:是
+     * 描述:
+     * 1、分账接收方类型为MERCHANT_ID时,分账接收方账号为商户号
+     * 2、分账接收方类型为PERSONAL_OPENID时,分账接收方账号为个人openid
+     * 
+ */ + @SerializedName("account") + private String account; + + /** + *
+     * 字段名:分账金额
+     * 是否必填:是
+     * 描述: 分账金额,单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额
+     * 
+ */ + @SerializedName("amount") + private Long amount; + + /** + *
+     * 字段名:分账描述
+     * 是否必填:是
+     * 描述: 分账的原因描述,分账账单中需要体现
+     * 
+ */ + @SerializedName("description") + private String description; + + /** + *
+     * 字段名:分账结果
+     * 是否必填:是
+     * 描述:
+     * 1、PENDING:待分账
+     * 2、SUCCESS:分账成功
+     * 3、CLOSED:已关闭
+     * 
+ */ + @SerializedName("result") + private String result; + + /** + *
+     * 字段名:分账失败原因
+     * 是否必填:是
+     * 描述:枚举值:
+     * 1、PENDING:待分账
+     * 2、SUCCESS:分账成功
+     * 3、CLOSED:已关闭
+     * 
+ */ + @SerializedName("fail_reason") + private String failReason; + + /** + *
+     * 字段名:分账创建时间
+     * 是否必填:是
+     * 描述:遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,
+     * YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,
+     * HH:mm:ss.sss表示时分秒毫秒,
+     * TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+     * 例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+     * 
+ */ + @SerializedName("create_time") + private String createTime; + /** + *
+     * 字段名:分账完成时间
+     * 是否必填:是
+     * 描述:遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE,
+     * YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,
+     * HH:mm:ss.sss表示时分秒毫秒,
+     * TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+     * 例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
+     * 
+ */ + @SerializedName("finish_time") + private String finishTime; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnsplitResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnsplitResult.java new file mode 100644 index 000000000..2cec40d2b --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharingV3/ProfitSharingUnsplitResult.java @@ -0,0 +1,39 @@ +package com.github.binarywang.wxpay.bean.profitsharingV3; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 微信V3接口 + * 查询剩余待分金额API返回实体 + * + * @author pg + * @date 2021-6-25 + */ +@Data +public class ProfitSharingUnsplitResult implements Serializable { + + private static final long serialVersionUID = -7025255772409082288L; + /** + *
+   * 字段名:微信订单号
+   * 是否必填:是
+   * 描述:微信支付订单号
+   * 
+ */ + @SerializedName("transaction_id") + private String transactionId; + + /** + *
+   * 字段名:订单剩余待分金额
+   * 是否必填:是
+   * 描述:订单剩余待分金额,整数,单元为分
+   * 
+ */ + @SerializedName("unsplit_amount") + private String unsplitAmount; + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/ProfitSharingV3Service.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/ProfitSharingV3Service.java new file mode 100644 index 000000000..fcb87063a --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/ProfitSharingV3Service.java @@ -0,0 +1,164 @@ +package com.github.binarywang.wxpay.service; + +import com.github.binarywang.wxpay.bean.profitsharingV3.*; +import com.github.binarywang.wxpay.exception.WxPayException; + +/** + * 微信支付V3-资金应用-分账 + * + * @author pg 2021-6-23 + * @date 2021-6-23 + */ +public interface ProfitSharingV3Service { + /** + *
+   * 请求分账API
+   *
+   * 微信订单支付成功后,商户发起分账请求,将结算后的资金分到分账接收方
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_1.shtml
+   * 接口链接: https://api.mch.weixin.qq.com/v3/profitsharing/orders
+   *
+   * 注意:
+   * 对同一笔订单最多能发起20次分账请求,每次请求最多分给50个接收方
+   * 此接口采用异步处理模式,即在接收到商户请求后,优先受理请求再异步处理,最终的分账结果可以通过查询分账接口获取
+   * 
+ * + * @param request {@link ProfitSharingRequest} 针对某一笔支付订单的分账方法 + * @return {@link ProfitSharingResult} 微信返回的分账结果 + * @throws WxPayException the wx pay exception + * @see 微信文档 + */ + ProfitSharingResult profitSharing(ProfitSharingRequest request) throws WxPayException; + + /** + *
+   * 查询分账结果API
+   *
+   * 发起分账请求后,可调用此接口查询分账结果
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_2.shtml
+   * 接口链接:https://api.mch.weixin.qq.com/v3/profitsharing/orders/{out_order_no}
+   *
+   * 注意:
+   * • 发起解冻剩余资金请求后,可调用此接口查询解冻剩余资金的结果
+   * 
+ * + * @param outOrderNo 商户系统内部的分账单号,在商户系统内部唯一,同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@ 。 + * @param transactionId 微信支付订单号 + * @return {@link ProfitSharingResult} 微信返回的分账结果 + * @throws WxPayException the wx pay exception + * @see 微信文档 + */ + ProfitSharingResult getProfitSharingResult(String outOrderNo, String transactionId) throws WxPayException; + + /** + *
+   * 请求分账回退API
+   *
+   * 如果订单已经分账,在退款时,可以先调此接口,将已分账的资金从分账接收方的账户回退给分账方,再发起退款
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_3.shtml
+   * 接口链接: https://api.mch.weixin.qq.com/v3/profitsharing/return-orders
+   *
+   * 注意:
+   * • 分账回退以原分账单为依据,支持多次回退,申请回退总金额不能超过原分账单分给该接收方的金额
+   * • 此接口采用同步处理模式,即在接收到商户请求后,会实时返回处理结果
+   * • 对同一笔分账单最多能发起20次分账回退请求
+   * • 退款和分账回退没有耦合,分账回退可以先于退款请求,也可以后于退款请求
+   * • 此功能需要接收方在商户平台-交易中心-分账-分账接收设置下,开启同意分账回退后,才能使用
+   * 
+ * + * @param request {@link ProfitSharingReturnRequest} 针对某一笔支付订单的分账方法 + * @return {@link ProfitSharingReturnResult} 微信返回的分账回退结果 + * @throws WxPayException the wx pay exception + * @see 微信文档 + */ + ProfitSharingReturnResult profitSharingReturn(ProfitSharingReturnRequest request) throws WxPayException; + + /** + *
+   * 查询分账回退结果API
+   *
+   * 商户需要核实回退结果,可调用此接口查询回退结果
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_4.shtml
+   * 接口链接:https://api.mch.weixin.qq.com/v3/profitsharing/return-orders/{out_return_no}
+   *
+   * 注意:
+   * • 如果分账回退接口返回状态为处理中,可调用此接口查询回退结果
+   * 
+ * + * @param outOrderNo 原发起分账请求时使用的商户系统内部的分账单号 + * @param outReturnNo 调用回退接口提供的商户系统内部的回退单号 + * @return {@link ProfitSharingReturnResult} 微信返回的分账回退结果 + * @throws WxPayException the wx pay exception + * @see 微信文档 + */ + ProfitSharingReturnResult getProfitSharingReturnResult(String outOrderNo, String outReturnNo) throws WxPayException; + + /** + *
+   * 解冻剩余资金API
+   *
+   * 不需要进行分账的订单,可直接调用本接口将订单的金额全部解冻给特约商户
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_5.shtml
+   * 接口链接: https://api.mch.weixin.qq.com/v3/profitsharing/orders/unfreeze
+   *
+   * 注意:
+   * • 调用分账接口后,需要解冻剩余资金时,调用本接口将剩余的分账金额全部解冻给特约商户
+   * • 此接口采用异步处理模式,即在接收到商户请求后,优先受理请求再异步处理,最终的分账结果可以通过查询分账接口获取
+   * 
+ * + * @param request 解冻剩余资金请求实体 {@link ProfitSharingUnfreezeRequest} + * @return {@link ProfitSharingReturnResult} 微信返回的解冻剩余资金结果 + * @throws WxPayException the wx pay exception + * @see 微信文档 + */ + ProfitSharingUnfreezeResult profitSharingUnfreeze(ProfitSharingUnfreezeRequest request) throws WxPayException; + + /** + *
+   * 查询剩余待分金额API
+   *
+   * 可调用此接口查询订单剩余待分金额
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_6.shtml
+   * 接口链接: https://api.mch.weixin.qq.com/v3/profitsharing/transactions/{transaction_id}/amounts
+   * 
+ * + * @param transactionId 微信订单号,微信支付订单号 + * @return {@link ProfitSharingUnsplitResult} 微信返回的订单剩余待分金额结果 + * @throws WxPayException the wx pay exception + * @see 微信文档 + */ + ProfitSharingUnsplitResult getProfitSharingUnsplitAmount(String transactionId) throws WxPayException; + + /** + *
+   * 添加分账接收方API
+   *
+   * 商户发起添加分账接收方请求,建立分账接收方列表。后续可通过发起分账请求,将分账方商户结算后的资金,分到该分账接收方
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_8.shtml
+   * 接口链接: https://api.mch.weixin.qq.com/v3/profitsharing/receivers/add
+   * 
+ * + * @param receiver 分账接收方实体 {@link ProfitSharingReceiver} + * @return {@link ProfitSharingReceiver} 微信返回的分账接收方结果 + * @throws WxPayException the wx pay exception + * @see 微信文档 + */ + ProfitSharingReceiver addProfitSharingReceiver(ProfitSharingReceiver receiver) throws WxPayException; + + /** + *
+   * 删除分账接收方API
+   *
+   * 商户发起删除分账接收方请求。删除后,不支持将分账方商户结算后的资金,分到该分账接收方
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_9.shtml
+   * 接口链接: https://api.mch.weixin.qq.com/v3/profitsharing/receivers/delete
+   * 
+ * + * @param receiver 分账接收方实体 {@link ProfitSharingReceiver} + * @return {@link ProfitSharingReceiver} 微信返回的删除的分账接收方结果 + * @throws WxPayException the wx pay exception + * @see 微信文档 + */ + ProfitSharingReceiver deleteProfitSharingReceiver(ProfitSharingReceiver receiver) throws WxPayException; + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index 563cf1c52..9b418bcea 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -189,11 +189,20 @@ public interface WxPayService { /** * 获取分账服务类. + *

+ * V3接口 {@link WxPayService#getProfitSharingV3Service()} + *

* * @return the ent pay service */ ProfitSharingService getProfitSharingService(); + /** + * 获取V3分账服务类. + * + * @return the ent pay service + */ + ProfitSharingV3Service getProfitSharingV3Service(); /** * 获取支付分服务类. diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java index a369369f1..d39e22e7d 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java @@ -64,6 +64,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { private EntPayService entPayService = new EntPayServiceImpl(this); private final ProfitSharingService profitSharingService = new ProfitSharingServiceImpl(this); + private final ProfitSharingV3Service profitSharingV3Service = new ProfitSharingV3ServiceImpl(this); private final RedpackService redpackService = new RedpackServiceImpl(this); private final PayScoreService payScoreService = new PayScoreServiceImpl(this); private final EcommerceService ecommerceService = new EcommerceServiceImpl(this); @@ -85,6 +86,11 @@ public ProfitSharingService getProfitSharingService() { return profitSharingService; } + @Override + public ProfitSharingV3Service getProfitSharingV3Service() { + return profitSharingV3Service; + } + @Override public PayScoreService getPayScoreService() { return payScoreService; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/ProfitSharingV3ServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/ProfitSharingV3ServiceImpl.java new file mode 100644 index 000000000..539836de1 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/ProfitSharingV3ServiceImpl.java @@ -0,0 +1,85 @@ +package com.github.binarywang.wxpay.service.impl; + +import com.github.binarywang.wxpay.bean.profitsharingV3.*; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.ProfitSharingV3Service; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * 微信支付V3-资金应用-分账Service + * + * @author pg 2021-6-23 + * @version 1.0 + */ +@Slf4j +@RequiredArgsConstructor +public class ProfitSharingV3ServiceImpl implements ProfitSharingV3Service { + private static final Gson GSON = new GsonBuilder().create(); + private final WxPayService payService; + + @Override + public ProfitSharingResult profitSharing(ProfitSharingRequest request) throws WxPayException { + String url = String.format("%s/v3/profitsharing/orders", this.payService.getPayBaseUrl()); + RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate()); + String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request)); + return GSON.fromJson(result, ProfitSharingResult.class); + } + + @Override + public ProfitSharingResult getProfitSharingResult(String outOrderNo, String transactionId) throws WxPayException { + String url = String.format("%s/v3/profitsharing/orders/%s?transaction_id=%s", this.payService.getPayBaseUrl(), outOrderNo, transactionId); + String result = this.payService.getV3(url); + return GSON.fromJson(result, ProfitSharingResult.class); + } + + @Override + public ProfitSharingReturnResult profitSharingReturn(ProfitSharingReturnRequest request) throws WxPayException { + String url = String.format("%s/v3/profitsharing/return-orders", this.payService.getPayBaseUrl()); + RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate()); + String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request)); + return GSON.fromJson(result, ProfitSharingReturnResult.class); + } + + @Override + public ProfitSharingReturnResult getProfitSharingReturnResult(String outOrderNo, String outReturnNo) throws WxPayException { + String url = String.format("%s/v3/profitsharing/return-orders/%s?out_order_no=%s", this.payService.getPayBaseUrl(), outReturnNo, outOrderNo); + String result = this.payService.getV3(url); + return GSON.fromJson(result, ProfitSharingReturnResult.class); + } + + @Override + public ProfitSharingUnfreezeResult profitSharingUnfreeze(ProfitSharingUnfreezeRequest request) throws WxPayException { + String url = String.format("%s/v3/profitsharing/orders/unfreeze", this.payService.getPayBaseUrl()); + RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate()); + String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request)); + return GSON.fromJson(result, ProfitSharingUnfreezeResult.class); + } + + @Override + public ProfitSharingUnsplitResult getProfitSharingUnsplitAmount(String transactionId) throws WxPayException { + String url = String.format("%s/v3/profitsharing/transactions/%s/amounts", this.payService.getPayBaseUrl(), transactionId); + String result = this.payService.getV3(url); + return GSON.fromJson(result, ProfitSharingUnsplitResult.class); + } + + @Override + public ProfitSharingReceiver addProfitSharingReceiver(ProfitSharingReceiver request) throws WxPayException { + String url = String.format("%s/v3/profitsharing/receivers/add", this.payService.getPayBaseUrl()); + RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate()); + String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request)); + return GSON.fromJson(result, ProfitSharingReceiver.class); + } + + @Override + public ProfitSharingReceiver deleteProfitSharingReceiver(ProfitSharingReceiver request) throws WxPayException { + String url = String.format("%s/v3/profitsharing/receivers/delete", this.payService.getPayBaseUrl()); + RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate()); + String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request)); + return GSON.fromJson(result, ProfitSharingReceiver.class); + } +} From 56f79c07b268b7d1613784f7f8232ab15e8f289e Mon Sep 17 00:00:00 2001 From: pengg Date: Mon, 28 Jun 2021 17:15:46 +0800 Subject: [PATCH 09/10] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=95=86=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E4=B8=8B=E8=BF=9B=E4=BB=B6=E5=A2=9E=E5=8A=A0=E5=B0=8F?= =?UTF-8?q?=E5=BE=AE=E5=95=86=E6=88=B7=E7=B1=BB=E5=9E=8B=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20#2114?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WxPayApplyment4SubCreateRequest.java | 174 ++++++++++++++++++ .../applyment/enums/MicroBizTypeEnum.java | 20 ++ .../bean/applyment/enums/SubjectTypeEnum.java | 4 + 3 files changed, 198 insertions(+) create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/enums/MicroBizTypeEnum.java diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/WxPayApplyment4SubCreateRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/WxPayApplyment4SubCreateRequest.java index 8fa1aa0ca..bf84d17b0 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/WxPayApplyment4SubCreateRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/WxPayApplyment4SubCreateRequest.java @@ -177,6 +177,11 @@ public static class SubjectInfo implements Serializable { @SpecEncrypt private UboInfo uboInfo; + /** + * 小微辅助证明材料(subjectType为小微商户时必填) + */ + @SerializedName("micro_biz_info") + private MicroBizInfo microBizInfo; @Data @Builder @@ -468,6 +473,175 @@ public static class UboInfo implements Serializable { private String idPeriodEnd; } + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Accessors(chain = true) + public static class MicroBizInfo implements Serializable{ + private static final long serialVersionUID = -5679477993681265764L; + /** + * 小微经营类型 + */ + @SerializedName("micro_biz_type") + private MicroBizTypeEnum microBizType; + + /** + * 门店场所---经营类型为“门店场所”时填写 + */ + @SerializedName("micro_store_info") + private MicroStoreInfo microStoreInfo; + + /** + * 经营类型为“流动经营/便民服务”时填写 + */ + @SerializedName("micro_mobile_info") + private MicroMobileInfo microMobileInfo; + + /** + * 经营类型为“线上商品/服务交易”时填写 + */ + @SerializedName("micro_online_info") + private MicroOnlineInfo microOnlineInfo; + + /** + * 门店场所 + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Accessors(chain = true) + public static class MicroStoreInfo implements Serializable{ + private static final long serialVersionUID = 5277440587305558389L; + /** + * 门店名称 + */ + @SerializedName("micro_name") + private String microName; + /** + * 门店省市编码 填写门店省市编码,只能由数字组成,详细参见《微信支付提供的省市对照表》 + * @see 下载微信支付提供的省市对照表 + */ + @SerializedName("micro_address_code") + private String microAddressCode; + /** + * 门店地址(填写店铺详细地址,具体区/县及街道门牌号或大厦楼层) + */ + @SerializedName("micro_address") + private String microAddress; + /** + * 门店门头照片 + * + * 1、提交门店门口照片,要求招牌清晰可见 + * 2、可上传1张图片,请填写通过《图片上传API》预先上传图片生成好的MediaID + * + * + * @see 图片上传API + */ + @SerializedName("store_entrance_pic") + private String storeEntrancePic; + /** + * 店内环境照片 + * + * 1、提交店内环境照片 + * 2、可上传1张图片,请填写通过《图片上传API》预先上传图片生成好的MediaID + * + * + * @see 图片上传API + */ + @SerializedName("micro_indoor_copy") + private String microIndoorCopy; + /** + * 门店经度 + */ + @SerializedName("store_longitude") + private String storeLongitude; + /** + * 门店纬度 + */ + @SerializedName("store_latitude") + private String storeLatitude; + } + + /** + * 流动经营/便民服务 + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Accessors(chain = true) + public static class MicroMobileInfo implements Serializable{ + private static final long serialVersionUID = -1308090894511066935L; + /** + * 经营/服务名称 + */ + @SerializedName("micro_mobile_name") + private String microMobileName; + /** + * 经营/服务所在地省市 + */ + @SerializedName("micro_mobile_city") + private String microMobileCity; + /** + * 经营/服务所在地(不含省市) 填写“无" + */ + @SerializedName("micro_mobile_address") + private String microMobileAddress; + /** + * 经营/服务现场照片 + * + * 1、提交经营/服务现场照片 + * 2、可上传多张图片,请填写通过《图片上传API》预先上传图片生成好的MediaID + * + * @see 图片上传API + */ + @SerializedName("micro_mobile_pics") + private String micro_mobile_pics; + } + + /** + * 线上商品/服务交易 + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Accessors(chain = true) + public static class MicroOnlineInfo implements Serializable{ + private static final long serialVersionUID = 9029168841403055743L; + /** + * 线上店铺名称 + */ + @SerializedName("micro_online_store") + private String microOnlineStore; + /** + * 电商平台名称 + */ + @SerializedName("micro_ec_name") + private String microEcName; + /** + * 店铺二维码 + * + * 1、店铺二维码或店铺链接二选一必填 + * 2、可上传多张图片,请填写通过《图片上传API》预先上传图片生成好的MediaID + * + * @see 图片上传API + */ + @SerializedName("micro_qrcode") + private String microQrcode; + /** + * 店铺二维码 + * + * 1、店铺二维码或店铺链接二选一必填 + * 2、请填写店铺主页链接,需符合网站规范 + * + */ + @SerializedName("micro_link") + private String microLink; + } + } } /** diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/enums/MicroBizTypeEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/enums/MicroBizTypeEnum.java new file mode 100644 index 000000000..100f83268 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/enums/MicroBizTypeEnum.java @@ -0,0 +1,20 @@ +package com.github.binarywang.wxpay.bean.applyment.enums; + +/** + * 小微经营类型 + */ +public enum MicroBizTypeEnum { + /** + * 门店场所 + */ + MICRO_TYPE_STORE, + /** + * 流动经营/便民服务 + */ + MICRO_TYPE_MOBILE, + /** + * 线上商品/服务交易 + */ + MICRO_TYPE_ONLINE, + ; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/enums/SubjectTypeEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/enums/SubjectTypeEnum.java index 7845c052c..4a6c9d29e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/enums/SubjectTypeEnum.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyment/enums/SubjectTypeEnum.java @@ -25,6 +25,10 @@ public enum SubjectTypeEnum { * (其他组织):不属于企业、政府/事业单位的组织机构(如社会团体、民办非企业、基金会),要求机构已办理组织机构代码证。 */ SUBJECT_TYPE_OTHERS, + /** + * (小微):无营业执照、免办理工商注册登记的实体商户 + */ + SUBJECT_TYPE_MICRO, ; } From 92320d438ea90ca450477e59d75b59fb0c84309b Mon Sep 17 00:00:00 2001 From: pengg Date: Tue, 29 Jun 2021 10:00:13 +0800 Subject: [PATCH 10/10] =?UTF-8?q?[=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1]?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E7=94=B5=E5=AD=90=E5=8F=91=E7=A5=A8=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1=E5=AE=98=E6=96=B9=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8E=A5=E5=8F=A3=20#2178?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cp/api/WxCpExternalContactService.java | 19 +++++++++++++++++++ .../impl/WxCpExternalContactServiceImpl.java | 18 ++++++++++++++++++ .../WxCpUserExternalGroupChatList.java | 4 ++++ .../WxCpExternalContactServiceImplTest.java | 7 +++++++ 4 files changed, 48 insertions(+) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java index cd65ad377..184ce8ef9 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java @@ -321,6 +321,7 @@ WxCpExternalContactBatchInfo getContactDetailBatch(String userId, String cursor, * 微信文档:https://work.weixin.qq.com/api/doc/90000/90135/92119 *
* + * @deprecated 请使用 {@link WxCpExternalContactService#listGroupChat(Integer, String, int, String[])} * @param pageIndex the page index * @param pageSize the page size * @param status the status @@ -329,8 +330,26 @@ WxCpExternalContactBatchInfo getContactDetailBatch(String userId, String cursor, * @return the wx cp user external group chat list * @throws WxErrorException the wx error exception */ + @Deprecated WxCpUserExternalGroupChatList listGroupChat(Integer pageIndex, Integer pageSize, int status, String[] userIds, String[] partyIds) throws WxErrorException; + /** + *
+   * 该接口用于获取配置过客户群管理的客户群列表。
+   * 企业需要使用“客户联系”secret或配置到“可调用应用”列表中的自建应用secret所获取的accesstoken来调用(accesstoken如何获取?)。
+   * 暂不支持第三方调用。
+   * 微信文档:https://work.weixin.qq.com/api/doc/90000/90135/92119
+   * 
+ * + * @param limit 分页,预期请求的数据量,取值范围 1 ~ 1000 + * @param cursor 用于分页查询的游标,字符串类型,由上一次调用返回,首次调用不填 + * @param status 客户群跟进状态过滤。0 - 所有列表(即不过滤) 1 - 离职待继承 2 - 离职继承中 3 - 离职继承完成 默认为0 + * @param userIds 群主过滤。如果不填,表示获取应用可见范围内全部群主的数据(但是不建议这么用,如果可见范围人数超过1000人,为了防止数据包过大,会报错 81017);用户ID列表。最多100个 + * @return the wx cp user external group chat list + * @throws WxErrorException the wx error exception + */ + WxCpUserExternalGroupChatList listGroupChat(Integer limit, String cursor, int status, String[] userIds) throws WxErrorException; + /** *
    * 通过客户群ID,获取详情。包括群名、群成员列表、群成员入群时间、入群方式。(客户群是由具有客户群使用权限的成员创建的外部群)
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
index 8065d2198..ffaf556ef 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
@@ -248,6 +248,24 @@ public WxCpUserExternalGroupChatList listGroupChat(Integer pageIndex, Integer pa
     return WxCpUserExternalGroupChatList.fromJson(result);
   }
 
+  @Override
+  public WxCpUserExternalGroupChatList listGroupChat(Integer limit, String cursor, int status, String[] userIds) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("cursor", cursor == null ? "" : cursor);
+    json.addProperty("limit", limit == null ? 100 : limit);
+    json.addProperty("status_filter", status);
+    if (ArrayUtils.isNotEmpty(userIds)) {
+      JsonObject ownerFilter = new JsonObject();
+      if (ArrayUtils.isNotEmpty(userIds)) {
+        ownerFilter.add("userid_list", new Gson().toJsonTree(userIds).getAsJsonArray());
+      }
+      json.add("owner_filter", ownerFilter);
+    }
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GROUP_CHAT_LIST);
+    final String result = this.mainService.post(url, json.toString());
+    return WxCpUserExternalGroupChatList.fromJson(result);
+  }
+
   @Override
   public WxCpUserExternalGroupChatInfo getGroupChat(String chatId) throws WxErrorException {
     JsonObject json = new JsonObject();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatList.java
index 07ac8f69d..a9a9e6b48 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatList.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatList.java
@@ -16,10 +16,14 @@
 @Getter
 @Setter
 public class WxCpUserExternalGroupChatList extends WxCpBaseResp {
+  private static final long serialVersionUID = 1907272035492110236L;
 
   @SerializedName("group_chat_list")
   private List groupChatList;
 
+  @SerializedName("next_cursor")
+  private String nextCursor;
+
   @Getter
   @Setter
   public static class ChatStatus implements Serializable {
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
index 8869a6a02..accd8f270 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
@@ -241,6 +241,13 @@ public void testListGroupChat() throws WxErrorException {
     assertNotNull(result);
   }
 
+  @Test
+  public void testListGroupChatV3() throws WxErrorException {
+    WxCpUserExternalGroupChatList result = this.wxCpService.getExternalContactService().listGroupChat(100, "" ,0,new String[1]);
+    System.out.println(result);
+    assertNotNull(result);
+  }
+
   @Test
   public void testGetGroupChat() {
   }