From cffd17399ba790644f11f1fb4961d250a39b23de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BD=98=E5=AE=89?= Date: Thu, 18 Nov 2021 11:17:54 +0800 Subject: [PATCH] =?UTF-8?q?:new:=20#2397=E3=80=90=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E3=80=91=E5=B8=90=E5=8F=B7ID=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E6=80=A7=E5=85=A8=E9=9D=A2=E5=8D=87=E7=BA=A7=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=8E=A5=E5=8F=A3=E6=94=B9=E9=80=A0=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BB=A3=E5=BC=80=E5=8F=91=E5=BA=94=E7=94=A8?= =?UTF-8?q?external=5Fuserid=E8=BD=AC=E6=8D=A2=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cp/api/WxCpExternalContactService.java | 91 +++++++++++++++++++ .../impl/WxCpExternalContactServiceImpl.java | 45 ++++++++- .../bean/external/WxCpExternalUserIdList.java | 53 +++++++++++ .../external/WxCpNewExternalUserIdList.java | 47 ++++++++++ .../weixin/cp/constant/WxCpApiPathConsts.java | 4 + 5 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpExternalUserIdList.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpNewExternalUserIdList.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 40e7741a9..ef3cc2a3a 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 @@ -168,6 +168,97 @@ public interface WxCpExternalContactService { */ String unionidToExternalUserid(@NotNull String unionid,String openid) throws WxErrorException; + /** + * 代开发应用external_userid转换 + *
+   *
+   * 文档地址:https://work.weixin.qq.com/api/doc/90001/90143/95195
+   *
+   * 企业同时安装服务商第三方应用以及授权代开发自建应用的时,服务商可使用该接口将代开发应用获取到的外部联系人id跟第三方应用的id进行关联,
+   * 该接口可将代开发自建应用获取到的external_userid转换为服务商第三方应用的external_userid。
+   *
+   * 权限说明:
+   *
+   * 该企业授权了该服务商第三方应用,且授权的第三方应用具备“企业客户权限->客户基础信息”权限
+   * 该客户的跟进人必须在应用的可见范围之内
+   * 应用需具备“企业客户权限->客户基础信息”权限
+   * 
+ * + * @param externalUserid 代开发自建应用获取到的外部联系人ID + * @return 该服务商第三方应用下的企业的外部联系人ID + * @throws WxErrorException . + */ + String toServiceExternalUserid(@NotNull String externalUserid) throws WxErrorException; + + /** + * 企业客户微信unionid的升级 - unionid查询external_userid + *
+   *
+   * 文档地址:https://open.work.weixin.qq.com/api/doc/35863#4.2%20unionid%E6%9F%A5%E8%AF%A2external_userid
+   *
+   * 当微信用户在微信中使用第三方应用的小程序或公众号时,第三方可将获取到的unionid与openid,调用此接口转换为企业客户external_userid。
+   * 该接口调用频次有限,每个服务商每小时仅可调用1万次,仅用于微信用户主动使用第三方应用的场景来调用,服务商切不可滥用。
+   * 同时建议服务商的小程序路径或公众号页面链接带上corpid参数,如此可明确地转换出该企业对应的external_userid,以获得更好的性能。
+   *
+   * 权限说明:
+   *
+   * 该企业授权了该服务商第三方应用
+   * 调用频率最大为10000次/小时
+   * unionid和openid的主体需与服务商的主体一致
+   * openid与unionid必须是在同一个小程序或同一个公众号获取到的
+   * 
+ * + * @param unionid 微信客户的unionid + * @param openid 微信客户的openid + * @param corpid 需要换取的企业corpid,不填则拉取所有企业 + * @return 该服务商第三方应用下的企业的外部联系人ID + * @throws WxErrorException . + */ + WxCpExternalUserIdList unionidToExternalUserid3rd(@NotNull String unionid, @NotNull String openid, String corpid) throws WxErrorException; + + /** + * 转换external_userid + *
+   *
+   * 文档地址:https://open.work.weixin.qq.com/api/doc/35863#转换external_userid
+   *
+   * 对于历史已授权的企业,在2022年3月1号之前,所有接口与回调返回的external_userid仍然为旧的external_userid,
+   * 从2022年3月1号0点开始,所有输入与返回的external_userid字段,将启用升级后的external_userid。
+   * 所以服务商需要在此之前完成历史数据的迁移整改
+   *
+   * 权限说明:
+   *
+   * 该企业授权了该服务商第三方应用
+   * external_userid对应的跟进人需要在应用可见范围内
+   * 
+ * + * @param externalUserIdList 微信客户的unionid + * @return List 新外部联系人id + * @throws WxErrorException . + */ + WxCpNewExternalUserIdList getNewExternalUserId(String[] externalUserIdList) throws WxErrorException; + + /** + * 设置迁移完成 + *
+   *
+   * 文档地址:https://open.work.weixin.qq.com/api/doc/35863#转换external_userid
+   *
+   * 企业授权确认之后,且服务商完成了新旧external_userid的迁移,即可主动将该企业设置为“迁移完成”,
+   * 设置之后,从该企业获取到的将是新的external_userid。注意,该接口需要使用provider_access_token来调用,
+   * 对于有多个应用的服务商,可逐个应用进行external_userid的转换,最后再使用provider_access_token调用该接口完成设置。
+   *
+   * 权限说明:
+   *
+   * 该企业授权了该服务商第三方应用
+   * 
+ * + * @param corpid 企业corpid + * @return wx cp base resp + * @throws WxErrorException . + */ + WxCpBaseResp finishExternalUserIdMigration(@NotNull String corpid) throws WxErrorException; + /** * 客户群opengid转换 *
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 d9426a834..6cf6172a8 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
@@ -25,7 +25,7 @@ import java.util.List;
 import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*;
 
 /**
- * @author 曹祖鹏 & yuanqixun
+ * @author 曹祖鹏 & yuanqixun & Mr.Pan
  */
 @RequiredArgsConstructor
 public class WxCpExternalContactServiceImpl implements WxCpExternalContactService {
@@ -135,6 +135,49 @@ public class WxCpExternalContactServiceImpl implements WxCpExternalContactServic
     return tmpJson.get("external_userid").getAsString();
   }
 
+  @Override
+  public String toServiceExternalUserid(@NotNull String externalUserid) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("external_userid", externalUserid);
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(TO_SERVICE_EXTERNAL_USERID);
+    String responseContent = this.mainService.post(url, json.toString());
+    JsonObject tmpJson = GsonParser.parse(responseContent);
+    return tmpJson.get("external_userid").getAsString();
+  }
+
+  @Override
+  public WxCpExternalUserIdList unionidToExternalUserid3rd(@NotNull String unionid, @NotNull String openid, String corpid) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("unionid", unionid);
+    json.addProperty("openid", openid);
+    if(StringUtils.isNotEmpty(corpid)){
+      json.addProperty("corpid",corpid);
+    }
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(UNIONID_TO_EXTERNAL_USERID_3RD);
+    String responseContent = this.mainService.post(url, json.toString());
+    return WxCpExternalUserIdList.fromJson(responseContent);
+  }
+
+  @Override
+  public WxCpNewExternalUserIdList getNewExternalUserId(String[] externalUserIdList) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    if (ArrayUtils.isNotEmpty(externalUserIdList)) {
+      json.add("external_userid_list", new Gson().toJsonTree(externalUserIdList).getAsJsonArray());
+    }
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_NEW_EXTERNAL_USERID);
+    String responseContent = this.mainService.post(url, json.toString());
+    return WxCpNewExternalUserIdList.fromJson(responseContent);
+  }
+
+  @Override
+  public WxCpBaseResp finishExternalUserIdMigration(@NotNull String corpid) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("corpid", corpid);
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(FINISH_EXTERNAL_USERID_MIGRATION);
+    String responseContent = this.mainService.post(url, json.toString());
+    return WxCpBaseResp.fromJson(responseContent);
+  }
+
   @Override
   public String opengidToChatid(@NotNull String opengid) throws WxErrorException {
     JsonObject json = new JsonObject();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpExternalUserIdList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpExternalUserIdList.java
new file mode 100644
index 000000000..5de738c74
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpExternalUserIdList.java
@@ -0,0 +1,53 @@
+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;
+
+/**
+ * 企业客户微信unionid的升级 - 企业客户external_userid列表
+ *
+ * @author Mr.Pan
+ * @date 2021/11/18
+ */
+@Getter
+@Setter
+public class WxCpExternalUserIdList extends WxCpBaseResp {
+
+  @SerializedName("external_userid_info")
+  private List externalUserIdInfo;
+
+  @Getter
+  @Setter
+  public static class ExternalUserIdInfo implements Serializable {
+    private static final long serialVersionUID = 8846290993790709261L;
+
+    /**
+     * 所属企业id
+     */
+    @SerializedName("corpid")
+    private String corpId;
+
+    /**
+     * 外部联系人id
+     */
+    @SerializedName("external_userid")
+    private String externalUserId;
+
+    /**
+     * 新外部联系人id
+     */
+    @SerializedName("new_external_userid")
+    private String newExternalUserId;
+
+  }
+
+  public static WxCpExternalUserIdList fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpExternalUserIdList.class);
+  }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpNewExternalUserIdList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpNewExternalUserIdList.java
new file mode 100644
index 000000000..4bc68f957
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpNewExternalUserIdList.java
@@ -0,0 +1,47 @@
+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;
+
+/**
+ * 企业客户微信unionid的升级 - 企业客户external_userid列表
+ *
+ * @author Mr.Pan
+ * @date 2021/11/18
+ */
+@Getter
+@Setter
+public class WxCpNewExternalUserIdList extends WxCpBaseResp {
+
+  @SerializedName("items")
+  private List items;
+
+  @Getter
+  @Setter
+  public static class NewExternalUserIdInfo implements Serializable {
+    private static final long serialVersionUID = 8846290993790709261L;
+
+    /**
+     * 外部联系人id
+     */
+    @SerializedName("external_userid")
+    private String externalUserId;
+
+    /**
+     * 新外部联系人id
+     */
+    @SerializedName("new_external_userid")
+    private String newExternalUserId;
+
+  }
+
+  public static WxCpNewExternalUserIdList fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpNewExternalUserIdList.class);
+  }
+}
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 71eadb63a..710f7f6a7 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
@@ -182,6 +182,10 @@ public interface WxCpApiPathConsts {
     String GET_CONTACT_DETAIL = "/cgi-bin/externalcontact/get?external_userid=";
     String CONVERT_TO_OPENID = "/cgi-bin/externalcontact/convert_to_openid";
     String UNIONID_TO_EXTERNAL_USERID = "/cgi-bin/externalcontact/unionid_to_external_userid";
+    String UNIONID_TO_EXTERNAL_USERID_3RD = "/cgi-bin/service/externalcontact/unionid_to_external_userid_3rd";
+    String GET_NEW_EXTERNAL_USERID = "/cgi-bin/service/externalcontact/get_new_external_userid";
+    String TO_SERVICE_EXTERNAL_USERID = "/cgi-bin/externalcontact/to_service_external_userid";
+    String FINISH_EXTERNAL_USERID_MIGRATION = "/cgi-bin/externalcontact/finish_external_userid_migration";
     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=";