From f14b88cbc5882d909d2703d17b57e557352dfe0d Mon Sep 17 00:00:00 2001 From: sxc <13250172040> Date: Fri, 14 May 2021 13:47:43 +0800 Subject: [PATCH 01/17] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9=E8=AF=9D?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=EF=BC=88=E5=8E=9F=E5=AF=BC=E8=B4=AD=EF=BC=89?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=BB=93=E6=9E=9C=20=E5=9D=87=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/WxMpGuideBuyerService.java | 157 ++++++++++++ .../mp/api/WxMpGuideMassedJobService.java | 100 ++++++++ .../mp/api/WxMpGuideMaterialService.java | 153 +++++++++++ .../weixin/mp/api/WxMpGuideService.java | 242 +++++++++++++++++- .../weixin/mp/api/WxMpGuideTagService.java | 204 +++++++++++++++ .../me/chanjar/weixin/mp/api/WxMpService.java | 60 ++++- .../mp/api/impl/BaseWxMpServiceImpl.java | 16 +- .../api/impl/WxMpGuideBuyerServiceImpl.java | 118 +++++++++ .../impl/WxMpGuideMassedJobServiceImpl.java | 80 ++++++ .../impl/WxMpGuideMaterialServiceImpl.java | 96 +++++++ .../mp/api/impl/WxMpGuideServiceImpl.java | 141 +++++++++- .../mp/api/impl/WxMpGuideTagServiceImpl.java | 160 ++++++++++++ .../mp/bean/guide/WxMpAddGuideAutoReply.java | 44 ++++ .../mp/bean/guide/WxMpAddGuideBuyerInfo.java | 42 +++ .../mp/bean/guide/WxMpGuideAcctConfig.java | 33 +++ .../mp/bean/guide/WxMpGuideAutoReply.java | 48 ++++ .../mp/bean/guide/WxMpGuideBuyerInfo.java | 55 ++++ .../mp/bean/guide/WxMpGuideBuyerInfoList.java | 33 +++ .../mp/bean/guide/WxMpGuideBuyerRelation.java | 59 +++++ .../mp/bean/guide/WxMpGuideBuyerResp.java | 46 ++++ .../bean/guide/WxMpGuideCardMaterialInfo.java | 64 +++++ .../weixin/mp/bean/guide/WxMpGuideConfig.java | 40 +++ .../mp/bean/guide/WxMpGuideFastReply.java | 40 +++ .../weixin/mp/bean/guide/WxMpGuideGroup.java | 52 ++++ .../mp/bean/guide/WxMpGuideGroupInfo.java | 66 +++++ .../mp/bean/guide/WxMpGuideGroupInfoList.java | 34 +++ .../bean/guide/WxMpGuideImgMaterialInfo.java | 33 +++ .../guide/WxMpGuideImgMaterialInfoList.java | 35 +++ .../weixin/mp/bean/guide/WxMpGuideMassed.java | 41 +++ .../bean/guide/WxMpGuideMassedBuyerInfo.java | 41 +++ .../mp/bean/guide/WxMpGuideMassedInfo.java | 102 ++++++++ .../mp/bean/guide/WxMpGuideMaterialInfo.java | 66 +++++ .../weixin/mp/bean/guide/WxMpGuideMsg.java | 78 ++++++ .../mp/bean/guide/WxMpGuideMsgList.java | 35 +++ .../mp/bean/guide/WxMpGuideOffLineReply.java | 42 +++ .../bean/guide/WxMpGuideSensitiveWords.java | 40 +++ .../mp/bean/guide/WxMpGuideTagInfo.java | 42 +++ .../bean/guide/WxMpGuideWordMaterialInfo.java | 39 +++ .../guide/WxMpGuideWordMaterialInfoList.java | 34 +++ .../chanjar/weixin/mp/enums/WxMpApiUrl.java | 207 ++++++++++++++- .../impl/WxMpGuideBuyerServiceImplTest.java | 94 +++++++ .../WxMpGuideMassedJobServiceImplTest.java | 66 +++++ .../WxMpGuideMaterialServiceImplTest.java | 87 +++++++ .../mp/api/impl/WxMpGuideServiceImplTest.java | 109 +++++++- .../api/impl/WxMpGuideTagServiceImplTest.java | 115 +++++++++ 45 files changed, 3462 insertions(+), 27 deletions(-) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideBuyerService.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideMassedJobService.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideMaterialService.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideTagService.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideBuyerServiceImpl.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMassedJobServiceImpl.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMaterialServiceImpl.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpAddGuideAutoReply.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpAddGuideBuyerInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideAcctConfig.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideAutoReply.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerInfoList.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerRelation.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerResp.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideCardMaterialInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideConfig.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideFastReply.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroup.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroupInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroupInfoList.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideImgMaterialInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideImgMaterialInfoList.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassed.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassedBuyerInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassedInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMaterialInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMsg.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMsgList.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideOffLineReply.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideSensitiveWords.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideTagInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideWordMaterialInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideWordMaterialInfoList.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideBuyerServiceImplTest.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMassedJobServiceImplTest.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMaterialServiceImplTest.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImplTest.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideBuyerService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideBuyerService.java new file mode 100644 index 0000000000..5d3c21407f --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideBuyerService.java @@ -0,0 +1,157 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.guide.*; + +import java.util.List; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ +public interface WxMpGuideBuyerService { + /** + * 为顾问分配客户(批量) + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/addguidebuyerrelation?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/buyer-account/shopping-guide.addGuideBuyerRelation.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param infos 客户列表 + * @return 客户列表添加结果 + * @throws WxErrorException . + */ + List addGuideBuyerRelation(String account, String openid, List infos) throws WxErrorException; + + /** + * 为顾问分配客户(单个) + * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param userOpenid 用户openid + * @param nickname 用户昵称 + * @throws WxErrorException . + */ + void addGuideBuyerRelation(String account, String openid, String userOpenid, String nickname) throws WxErrorException; + + /** + * 为顾问移除客户(批量) + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/delguidebuyerrelation?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/buyer-account/shopping-guide.delGuideBuyerRelation.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param buyerOpenIds 客户openid列表,不超过200 + * @return 客户列表移除结果 + */ + List delGuideBuyerRelation(String account, String openid, List buyerOpenIds) throws WxErrorException; + + /** + * 为顾问移除客户(单个) + * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param userOpenid 用户openid + * @throws WxErrorException . + */ + void delGuideBuyerRelation(String account, String openid, String userOpenid) throws WxErrorException; + + /** + * 获取顾问的客户列表 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidebuyerrelationlist?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/buyer-account/shopping-guide.getGuideBuyerRelationList.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param page 分页页数,从0开始,用于组内顾问分页获取 + * @param num 每页数量 + * @return 顾问的客户列表 + * @throws WxErrorException . + */ + WxMpGuideBuyerInfoList getGuideBuyerRelationList(String account, String openid, int page, int num) throws WxErrorException; + + /** + * 为客户更换顾问(批量) + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/rebindguideacctforbuyer?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/buyer-account/shopping-guide.rebindGuideAcctForBuyer.html
+   * 
+ * + * @param oldAccount 原顾问微信号(old_guide_account和new_guide_account配套使用) + * @param oldOpenid 原顾问openid或者unionid(old_guide_openid和new_guide_openid配套使用) + * @param account 新顾问微信号(new_guide_account和new_guide_openid二选一) + * @param openid 新顾问openid或者unionid(new_guide_account和new_guide_openid二选一) + * @param buyerOpenIds 客户列表,不超过200 + * @return 客户列表换绑结果 + * @throws WxErrorException . + */ + List rebindGuideAcctForBuyer(String oldAccount, String oldOpenid, String account, String openid, List buyerOpenIds) throws WxErrorException; + + /** + * 为客户更换顾问(单个) + * + * @param oldAccount 原顾问微信号(old_guide_account和new_guide_account配套使用) + * @param oldOpenid 原顾问openid或者unionid(old_guide_openid和new_guide_openid配套使用) + * @param account 新顾问微信号(new_guide_account和new_guide_openid二选一) + * @param openid 新顾问openid或者unionid(new_guide_account和new_guide_openid二选一) + * @param userOpenid 用户openid + * @throws WxErrorException 。 + */ + void rebindGuideAcctForBuyer(String oldAccount, String oldOpenid, String account, String openid, String userOpenid) throws WxErrorException; + + /** + * 修改客户昵称 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/updateguidebuyerrelation?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/buyer-account/shopping-guide.updateGuideBuyerRelation.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param userOpenid 客户openid + * @param nickname 客户昵称 + * @throws WxErrorException . + */ + void updateGuideBuyerRelation(String account, String openid, String userOpenid, String nickname) throws WxErrorException; + + /** + * 查询客户所属顾问 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidebuyerrelationbybuyer?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/buyer-account/shopping-guide.getGuideBuyerRelationByBuyer.html
+   * 
+ * + * @param openid 客户openid + * @return 客户顾问关系信息 + * @throws WxErrorException . + */ + WxMpGuideBuyerRelation getGuideBuyerRelationByBuyer(String openid) throws WxErrorException; + + /** + * 查询指定顾问和客户的关系 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidebuyerrelation?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/buyer-account/shopping-guide.getGuideBuyerRelation.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param userOpenid 客户openid + * @return 客户信息 + * @throws WxErrorException . + */ + WxMpGuideBuyerInfo getGuideBuyerRelation(String account, String openid, String userOpenid) throws WxErrorException; +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideMassedJobService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideMassedJobService.java new file mode 100644 index 0000000000..2414615807 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideMassedJobService.java @@ -0,0 +1,100 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideMassed; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideMassedInfo; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideMaterialInfo; + +import java.util.List; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ +public interface WxMpGuideMassedJobService { + + /** + * 添加群发任务 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/addguidemassendjob?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/task-account/shopping-guide.addGuideMassendJob.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param taskName 群发任务名称,不超过16字 + * @param taskRemark 群发任务备注,不超过100字 + * @param pushTime 任务下发给顾问的时间, 秒级时间戳, 范围为当前时间开始到最近一个月内 + * @param userOpenIds 客户openid列表 + * @param materialInfos 不超过3个素材 + * @return 群发任务id与客户openid列表 + * @throws WxErrorException 。 + */ + WxMpGuideMassed addGuideMassedJob(String account, String openid, String taskName, String taskRemark, Long pushTime, List userOpenIds, List materialInfos) throws WxErrorException; + + /** + * 获取群发任务列表 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidemassendjoblist?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/task-account/shopping-guide.getGuideMassendJobList.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param taskStatus 获取指定状态的任务(为空则表示拉取所有状态的任务) + * @param offset 偏移位置(从什么位置开始拉取) + * @param limit 条数(默认50) + * @return 群发任务列表 + * @throws WxErrorException 。 + */ + List getGuideMassedJobList(String account, String openid, List taskStatus, Integer offset, Integer limit) throws WxErrorException; + + /** + * 获取指定群发任务信息 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidemassendjob?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/task-account/shopping-guide.getGuideMassendJob.html
+   * 
+ * + * @param taskId 任务ID + * @return 群发任务信息 + * @throws WxErrorException 。 + */ + WxMpGuideMassedInfo getGuideMassedJob(String taskId) throws WxErrorException; + + /** + * 修改群发任务 + * 无法修改已经执行的任务,返回参数错误 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/updateguidemassendjob?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/task-account/shopping-guide.updateGuideMassendJob.html
+   * 
+ * + * @param taskId 任务ID + * @param taskName 群发任务名称,不超过16字 + * @param taskRemark 群发任务备注,不超过100字 + * @param pushTime 下发时间, 秒级时间戳, 范围为当前时间开始到最近一个月内 + * @param userOpenIds 客户openid列表 + * @param materialInfos 不超过3个素材 + * @throws WxErrorException 。 + */ + void updateGuideMassedJob(String taskId, String taskName, String taskRemark, Long pushTime, List userOpenIds, List materialInfos) throws WxErrorException; + + /** + * 取消群发任务 + * 取消给顾问分配的群发任务, 已执行的任务无法取消。 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/cancelguidemassendjob?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/task-account/shopping-guide.cancelGuideMassendJob.html
+   * 
+ * + * @param taskId 任务ID + * @throws WxErrorException . + */ + void cancelGuideMassedJob(String taskId) throws WxErrorException; +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideMaterialService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideMaterialService.java new file mode 100644 index 0000000000..70fd5f8007 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideMaterialService.java @@ -0,0 +1,153 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideCardMaterialInfo; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideImgMaterialInfoList; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideWordMaterialInfoList; + +import java.util.List; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ +public interface WxMpGuideMaterialService { + + /** + * 添加小程序卡片素材 + *

+ * 踩坑记录(2021/5/12):该方法只支持临时素材mediaid + * + *

+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/setguidecardmaterial?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/model-account/shopping-guide.setGuideCardMaterial.html
+   * 
+ * + * @param mediaId 图片素材,只能用《素材管理获取media_id》(注意:只支持临时素材的media_id) + * @param type 操作类型,填0,表示服务号素材 + * @param title 小程序卡片名字 + * @param path 小程序路径 + * @param appId 小程序的appid + * @throws WxErrorException . + */ + void setGuideCardMaterial(String mediaId, int type, String title, String path, String appId) throws WxErrorException; + + /** + * 查询小程序卡片素材 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidecardmaterial?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/model-account/shopping-guide.getGuideCardMaterial.html
+   * 
+ * + * @param type 操作类型,填0,表示服务号素材 + * @return 小程序卡片素材信息列表 + * @throws WxErrorException . + */ + List getGuideCardMaterial(int type) throws WxErrorException; + + /** + * 删除小程序卡片素材 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/delguidecardmaterial?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/model-account/shopping-guide.delGuideCardMaterial.html
+   * 
+ * + * @param type 操作类型,填0,表示服务号素材 + * @param title 小程序卡片名字 + * @param path 小程序路径 + * @param appId 小程序的appid + * @throws WxErrorException . + */ + void delGuideCardMaterial(int type, String title, String path, String appId) throws WxErrorException; + + /** + * 添加图片素材 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/setguideimagematerial?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/model-account/shopping-guide.setGuideImageMaterial.html
+   * 
+ * + * @param mediaId 图片素材,只能用《素材管理获取media_id》(注意:只支持临时素材的media_id) + * @param type 操作类型,填0,表示服务号素材 + * @throws WxErrorException . + */ + void setGuideImageMaterial(String mediaId, int type) throws WxErrorException; + + /** + * 查询图片素材 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguideimagematerial?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/model-account/shopping-guide.getGuideImageMaterial.html
+   * 
+ * + * @param type 操作类型,填0,表示服务号素材 + * @param start 分页查询,起始位置 + * @param num 分页查询,查询个数 + * @return 图片素材列表 + * @throws WxErrorException . + */ + WxMpGuideImgMaterialInfoList getGuideImageMaterial(int type, int start, int num) throws WxErrorException; + + /** + * 删除图片素材 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/delguideimagematerial?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/model-account/shopping-guide.delGuideImageMaterial.html
+   * 
+ * + * @param type 操作类型,填0,表示服务号素材 + * @param picUrl 图片素材内容 + * @throws WxErrorException . + */ + void delGuideImageMaterial(int type, String picUrl) throws WxErrorException; + + /** + * 添加文字素材 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/setguidewordmaterial?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/model-account/shopping-guide.setGuideWordMaterial.html
+   * 
+ * + * @param type 操作类型,填0,表示服务号素材 + * @param word 文字素材内容 + * @throws WxErrorException . + */ + void setGuideWordMaterial(int type, String word) throws WxErrorException; + + /** + * 查询文字素材 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidewordmaterial?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/model-account/shopping-guide.getGuideWordMaterial.html
+   * 
+ * + * @param type 操作类型,填0,表示服务号素材 + * @param start 分页查询,起始位置 + * @param num 分页查询,查询个数 + * @return 文字素材列表 + * @throws WxErrorException 。 + */ + WxMpGuideWordMaterialInfoList getGuideWordMaterial(int type, int start, int num) throws WxErrorException; + + /** + * 删除文字素材 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/delguidewordmaterial?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/model-account/shopping-guide.delGuideWordMaterial.html
+   * 
+ * + * @param type 操作类型,填0,表示服务号素材 + * @param word 文字素材内容 + * @throws WxErrorException . + */ + void delGuideWordMaterial(int type, String word) throws WxErrorException; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideService.java index e1427dbb67..e91cfc1dc4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideService.java @@ -1,8 +1,9 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.bean.guide.WxMpGuideInfo; -import me.chanjar.weixin.mp.bean.guide.WxMpGuideList; +import me.chanjar.weixin.mp.bean.guide.*; + +import java.util.List; /** * 微信导购助手(现在叫对话能力)接口. @@ -11,6 +12,7 @@ * @date 2020 -10-06 */ public interface WxMpGuideService { + /** * 为服务号添加顾问 *
@@ -93,4 +95,240 @@ public interface WxMpGuideService {
    * @throws WxErrorException .
    */
   WxMpGuideList listGuide(int page, int num) throws WxErrorException;
+
+  /**
+   * 生成顾问二维码
+   * 

+ * 生成顾问二维码后,微信用户扫码直接跳转公众号首页。分为两种情况: + * 1.微信用户已经关注公众号,扫码后绑定该顾问。 + * 2.微信用户未关注公众号,扫码后 3 分钟内关注该公众号,则绑定该顾问 + * + *

+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/guidecreateqrcode?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.guideCreateQrCode.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param qrcodeInfo 额外参数,用于事件推送 + * @return 二维码下载链接 + * @throws WxErrorException . + */ + String createGuideQrCode(String account, String openid, String qrcodeInfo) throws WxErrorException; + + /** + * 获取顾问聊天记录 + *

+ * 支持拉取该顾问近 30 天的聊天记录。begin_time 与 end_time 同时非0情况下,该参数才会生效,否则为默认值。 + * + *

+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidebuyerchatrecord?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.getGuideBuyerChatRecord.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param clientOpenid 客户openid 若不填,则拉取该顾问所有客户的聊天记录。若填写,则拉取顾问与某一个客户的聊天记录 + * @param beginTime 消息的起始UNIX时间戳,如果不填,默认当前时间的前30天(仅支持30天范围内的查询) + * @param endTime 消息的截止UNIX时间戳,如果不填,默认当前时间。 + * @param page 分页页数,从0开始 + * @param num 每页数量 + * @return 顾问聊天记录列表 + */ + WxMpGuideMsgList getGuideChatRecord(String account, String openid, String clientOpenid, Long beginTime, Long endTime, int page, int num) throws WxErrorException; + + /** + * 设置快捷回复与关注自动回复 + *

+ * 快捷回复:指顾问在对话详情页,可快速选择的回复内容。 + * 注意:1.快捷回复只允许全部删除 2.快捷回复的添加删除需要指定顾问的guide_account和guide_openid二选一 + *

+ * 关注自动回复:是指客户通过扫顾问码、扫顾问分组码、微信广告三种方式主动关注公众号并绑定顾问, + * 顾问会下发的自动回复,即顾问欢迎语。最多可下发两条消息,支持文字、图片或小程序素材,可更新、删除,设置好后先后下发。 + * 不指定 guide_account 和 guide_openid 时,可设置所有顾问默认的关注自动回复。 + * 对单个顾问来说,如果指定 guide_account 和 guide_openid 设置了自动回复,则下发它,否则下发所有顾问默认的关注自动回复 + * 注意:自动回复每次设置会覆盖原有的,自动回复只允许出现两条 + *

+ * 特别注意:删除需要传递 guideAutoReply:{"msgtype":"1"} + * 删除目前只支持两条全部删除 2021/5/8 + *

+ * 自动回复格式: + * String content: 新客户关注自动回复内容,图片填mediaid,获取方式同图片素材,小程序卡片填下面请求demo中字段的json格式 + * int msgtype: 1表示文字,2表示图片,3表示小程序卡片 + * 例如:JsonObject:{"content": "abc","msgtype":"1"} + * + *

+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/setguideconfig?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.setGuideConfig.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param isDelete 操作类型,false表示添加 true表示删除 + * @param guideFastReplyList 快捷回复列表 + * @param guideAutoReply 第一条新客户关注自动回复 + * @param guideAutoReplyPlus 第二条新客户关注自动回复 + * @throws WxErrorException . + */ + void setGuideConfig(String account, String openid, boolean isDelete, List guideFastReplyList, WxMpAddGuideAutoReply guideAutoReply, WxMpAddGuideAutoReply guideAutoReplyPlus) throws WxErrorException; + + /** + * 获取快捷回复与关注自动回复 + * 如果要获取服务号维度的新客户关注自动回复,不填guide_account与guide_openid即可 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguideconfig?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.getGuideConfig.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一,若同时请求,默认为guide_account) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @return 顾问的 快捷回复,关注顾问自动回复 + */ + WxMpGuideConfig getGuideConfig(String account, String openid) throws WxErrorException; + + /** + * 为服务号设置敏感词与离线自动回复 + * 顾问在小程序离线状态时,客户发消息会收到设置的离线自动回复,最多支持 300 字。 顾问在小程序内发消息,如果触发敏感词将无法发出。 + *

+ * 注意:添加模式 black_keyword字段传递null将删除全部敏感词 + * black_keyword字段有值将对敏感词进行追加而不是全量更新覆盖 (实际测试与官方文档有冲突) + * + *

+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/setguideacctconfig?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.setGuideAcctConfig.html
+   * 
+ * + * @param isDelete 操作类型,false表示添加 true表示删除 + * @param blackKeyword 敏感词,每次全量更新覆盖原来数据(如果不设置就不传black_keyword字段) + * @param guideAutoReply 离线自动回复(如果不设置就不传guide_auto_reply字段) + * @throws WxErrorException . + */ + void setGuideAcctConfig(boolean isDelete, List blackKeyword, String guideAutoReply) throws WxErrorException; + + /** + * 获取离线自动回复与敏感词 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguideacctconfig?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.getGuideAcctConfig.html
+   * 
+ * + * @return 离线自动回复与敏感词 + * @throws WxErrorException . + */ + WxMpGuideAcctConfig getGuideAcctConfig() throws WxErrorException; + + /** + * 允许微信用户复制小程序页面路径 + * 请求成功后,该微信号用户可在微信上复制对应小程序的任意页面path,有效期为60天。若需要添加小程序卡片素材时的path,可以用这个方式获取。 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/pushshowwxapathmenu?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.pushShowWxaPathMenu.html
+   * 
+ * + * @param appId 小程序appid,暂时只支持小程序,不支持小游戏 + * @param userName 关注该公众号的微信号 + * @throws WxErrorException . + */ + void pushShowWxaPathMenu(String appId, String userName) throws WxErrorException; + + /** + * 新建顾问分组 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/newguidegroup?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.newGuideGroup.html
+   * 
+ * + * @param groupName 顾问分组名称 + * @return 顾问分组唯一id + * @throws WxErrorException . + */ + Long newGuideGroup(String groupName) throws WxErrorException; + + /** + * 获取服务号下所有顾问分组的列表 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidegrouplist?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.getGuideGroupList.html
+   * 
+ * + * @return 顾问分组列表 + * @throws WxErrorException . + */ + List getGuideGroupList() throws WxErrorException; + + /** + * 获取指定顾问分组内顾问信息 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getgroupinfo?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.getGroupInfo.html
+   * 
+ * + * @param groupId 顾问群组id + * @param page 分页页数,从0开始,用于组内顾问分页获取 + * @param num 每页数量 + * @return 顾问分组内顾问信息 + * @throws WxErrorException . + */ + WxMpGuideGroupInfoList getGroupInfo(long groupId, int page, int num) throws WxErrorException; + + /** + * 分组内添加顾问 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/addguide2guidegroup?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.addGuide2GuideGroup.html
+   * 
+ * + * @param groupId 顾问分组id + * @param account 顾问微信号 + * @throws WxErrorException . + */ + void addGuide2GuideGroup(long groupId, String account) throws WxErrorException; + + /** + * 分组内删除顾问 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/delguide2guidegroup?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.delGuide2GuideGroup.html
+   * 
+ * + * @param groupId 顾问分组id + * @param account 顾问微信号 + * @throws WxErrorException . + */ + void delGuide2GuideGroup(long groupId, String account) throws WxErrorException; + + /** + * 获取顾问所在分组 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getgroupbyguide?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.getGroupByGuide.html
+   * 
+ * + * @param account 顾问微信号 + * @return 顾问分组id列表 + * @throws WxErrorException . + */ + List getGroupByGuide(String account) throws WxErrorException; + + /** + * 删除指定顾问分组 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/delguidegroup?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide-account/shopping-guide.delGuideGroup.html
+   * 
+ * + * @param groupId 顾问分组id + * @throws WxErrorException . + */ + void delGuideGroup(long groupId) throws WxErrorException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideTagService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideTagService.java new file mode 100644 index 0000000000..554815b701 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideTagService.java @@ -0,0 +1,204 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideBuyerResp; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideTagInfo; + +import java.util.List; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ +public interface WxMpGuideTagService { + + /** + * 新建标签类型 + * 最多 4 类标签类型,50 个可选值,所有的标签可选值不能有相等重复的值。 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/newguidetagoption?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/tag-account/shopping-guide.newGuideTagOption.html
+   * 
+ * + * @param tagName 标签类型的名字 + * @param values 标签可选值列表,可选值不能为空值,所有的标签可选值不能有相等重复的值 + * @throws WxErrorException 。 + */ + void newGuideTagOption(String tagName, List values) throws WxErrorException; + + /** + * 删除指定标签类型 + * 此操作会更新所有相关客户的标签信息,存在延迟。 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/delguidetagoption?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/tag-account/shopping-guide.delguidetagoption.html
+   * 
+ * + * @param tagName 标签类型的名字 + * @throws WxErrorException 。 + */ + void delGuideTagOption(String tagName) throws WxErrorException; + + /** + * 为标签添加可选值 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/addguidetagoption?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/tag-account/shopping-guide.addGuideTagOption.html
+   * 
+ * + * @param tagName 标签类型的名字 + * @param values 标签可选值列表,可选值不能为空值,所有的标签可选值不能有相等重复的值 + * @throws WxErrorException 。 + */ + void addGuideTagOption(String tagName, List values) throws WxErrorException; + + /** + * 获取标签和可选值 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidetagoption?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/tag-account/shopping-guide.getGuideTagOption.html
+   * 
+ * + * @return 标签信息列表 + */ + List getGuideTagOption() throws WxErrorException; + + /** + * 为客户设置标签(批量) + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/addguidebuyertag?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/tag-account/shopping-guide.addGuideBuyerTag.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param value 标签的可选值,该值必须在标签的可选值集合中 + * @param userOpenIds 客户列表,不超过200 + * @return 客户列表添加结果 + * @throws WxErrorException . + */ + List addGuideBuyerTag(String account, String openid, String value, List userOpenIds) throws WxErrorException; + + /** + * 为客户设置标签(单个) + * + * @param account 顾问微信号(guide_account和guide_openid二选一) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param value 标签的可选值,该值必须在标签的可选值集合中 + * @param userOpenid 用户openid + * @throws WxErrorException . + */ + void addGuideBuyerTag(String account, String openid, String value, String userOpenid) throws WxErrorException; + + /** + * 查询客户标签 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidebuyertag?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/tag-account/shopping-guide.getGuideBuyerTag.html
+   * 
+ *

+ * 踩坑记录(2021/5/12):这里不只是返回标签值 + * 如果该客户设置了自定义信息也会同样返回在标签数组的末尾 + * 未设置则只返回客户标签列表 + * 为此坑我添加一个参数是否排除客户自定义信息 + * + * @param account 顾问微信号(guide_account和guide_openid二选一) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param userOpenid 用户openid + * @param isExclude 是否排除客户自定义信息 + * @return 标签值列表 + * @throws WxErrorException 。 + */ + List getGuideBuyerTag(String account, String openid, String userOpenid, Boolean isExclude) throws WxErrorException; + + /** + * 根据标签值筛选客户 + * + *

+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/queryguidebuyerbytag?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/tag-account/shopping-guide.queryGuideBuyerByTag.html
+   * 
+ *

+ * 踩坑记录(2021/5/12): 不传递pushCount参数会返回-1 + * 传递0查询所有 (推荐传递0) + * 当pushCount > 0 该条件查询逻辑有问题 + * 目前发现:传递1可以查询出可发次数为4次的用户,而传递4是查询不出来的。 + *

+ * 注意:该查询是查询所有条件均符合的 例如:查询A标签的客户 假如客户标签为A,B两个 将无法查询到该客户 + * + * @param account 顾问微信号(guide_account和guide_openid二选一) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param pushCount 本月还可主动发消息次数 (建议传递0查询) + * @param value 标签值集合,该值必须在标签可选值集合中 + * @return 客户openid集合 + * @throws WxErrorException 。 + */ + List queryGuideBuyerByTag(String account, String openid, Integer pushCount, List value) throws WxErrorException; + + /** + * 删除客户标签(批量) + * + *

+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/delguidebuyertag?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/tag-account/shopping-guide.delGuideBuyerTag.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param value 标签的可选值,该值必须在标签的可选值集合中 + * @param userOpenIds 客户列表,不超过200 + * @return 客户列表处理结果 + * @throws WxErrorException。 + */ + List delGuideBuyerTag(String account, String openid, String value, List userOpenIds) throws WxErrorException; + + /** + * 删除客户标签(单个) + * + * @param account 顾问微信号(guide_account和guide_openid二选一) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param value 标签的可选值,该值必须在标签的可选值集合中 + * @param userOpenid 用户openid + * @throws WxErrorException . + */ + void delGuideBuyerTag(String account, String openid, String value, String userOpenid) throws WxErrorException; + + /** + * 设置自定义客户信息 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/addguidebuyerdisplaytag?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/tag-account/shopping-guide.addGuideBuyerDisplayTag.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param userOpenid 用户openid + * @param msgList 自定义客户信息,全量更新,调用时传所有信息 + * @throws WxErrorException . + */ + void addGuideBuyerDisplayTag(String account, String openid, String userOpenid, List msgList) throws WxErrorException; + + /** + * 获取自定义客户信息 + * + *
+   * 请求地址: POST https://api.weixin.qq.com/cgi-bin/guide/getguidebuyerdisplaytag?access_token=ACCESS_TOKEN
+   * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/tag-account/shopping-guide.getGuideBuyerDisplayTag.html
+   * 
+ * + * @param account 顾问微信号(guide_account和guide_openid二选一) + * @param openid 顾问openid或者unionid(guide_account和guide_openid二选一) + * @param userOpenid 用户openid + * @return 自定义客户信息列表 + * @throws WxErrorException 。 + */ + List getGuideBuyerDisplayTag(String account, String openid, String userOpenid) throws WxErrorException; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index eff7ed63af..4e8cb96987 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -1,13 +1,13 @@ package me.chanjar.weixin.mp.api; import com.google.gson.JsonObject; -import me.chanjar.weixin.common.service.WxImgProcService; -import me.chanjar.weixin.common.service.WxOcrService; import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.bean.WxNetCheckResult; import me.chanjar.weixin.common.enums.TicketType; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.service.WxImgProcService; import me.chanjar.weixin.common.service.WxOAuth2Service; +import me.chanjar.weixin.common.service.WxOcrService; import me.chanjar.weixin.common.service.WxService; import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; @@ -720,4 +720,60 @@ public interface WxMpService extends WxService { * @param guideService the guide service */ void setGuideService(WxMpGuideService guideService); + + /** + * Gets guideBuyer service. + * + * @return the guideBuyer service + */ + WxMpGuideBuyerService getGuideBuyerService(); + + /** + * Sets guideBuyer service. + * + * @param guideBuyerService the guideBuyer service + */ + void setGuideBuyerService(WxMpGuideBuyerService guideBuyerService); + + /** + * Gets guideTag service. + * + * @return the guide service + */ + WxMpGuideTagService getGuideTagService(); + + /** + * Sets guideTag service. + * + * @param guideTagService the guideTag service + */ + void setGuideTagService(WxMpGuideTagService guideTagService); + + /** + * Gets guideMaterial service. + * + * @return the guideMaterial service + */ + WxMpGuideMaterialService getGuideMaterialService(); + + /** + * Sets guideMaterial service. + * + * @param guideMaterialService the guideMaterial service + */ + void setGuideMaterialService(WxMpGuideMaterialService guideMaterialService); + + /** + * Gets guideMassedJob service. + * + * @return the guideMassedJob service + */ + WxMpGuideMassedJobService getGuideMassedJobService(); + + /** + * Sets guide service. + * + * @param guideMassedJobService the guide service + */ + void setGuideMassedJobService(WxMpGuideMassedJobService guideMassedJobService); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java index fc0aceade6..d340c6dc4d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java @@ -8,8 +8,6 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.common.service.WxImgProcService; -import me.chanjar.weixin.common.service.WxOcrService; import me.chanjar.weixin.common.bean.ToJson; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.WxJsapiSignature; @@ -19,7 +17,9 @@ import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.error.WxRuntimeException; +import me.chanjar.weixin.common.service.WxImgProcService; import me.chanjar.weixin.common.service.WxOAuth2Service; +import me.chanjar.weixin.common.service.WxOcrService; import me.chanjar.weixin.common.session.StandardSessionManager; import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.DataUtils; @@ -124,6 +124,18 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH @Getter @Setter private WxMpGuideService guideService = new WxMpGuideServiceImpl(this); + @Getter + @Setter + private WxMpGuideBuyerService guideBuyerService = new WxMpGuideBuyerServiceImpl(this); + @Getter + @Setter + private WxMpGuideTagService guideTagService = new WxMpGuideTagServiceImpl(this); + @Getter + @Setter + private WxMpGuideMassedJobService guideMassedJobService = new WxMpGuideMassedJobServiceImpl(this); + @Getter + @Setter + private WxMpGuideMaterialService guideMaterialService = new WxMpGuideMaterialServiceImpl(this); @Getter @Setter diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideBuyerServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideBuyerServiceImpl.java new file mode 100644 index 0000000000..94c07ad4db --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideBuyerServiceImpl.java @@ -0,0 +1,118 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.gson.reflect.TypeToken; +import lombok.AllArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.common.util.json.GsonParser; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.api.WxMpGuideBuyerService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.guide.*; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ +@AllArgsConstructor +public class WxMpGuideBuyerServiceImpl implements WxMpGuideBuyerService { + private static final String ACCOUNT = "guide_account"; + private static final String OPENID = "guide_openid"; + private final WxMpService mpService; + + @Override + public List addGuideBuyerRelation(String account, String openid, List infos) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("buyer_list", infos); + + String json = this.mpService.post(WxMpApiUrl.Guide.ADD_GUIDE_BUYER_RELATION, body); + return WxGsonBuilder.create().fromJson(GsonParser.parse(json).getAsJsonArray("buyer_resp"), + new TypeToken>() { + }.getType()); + } + + @Override + public void addGuideBuyerRelation(String account, String openid, String userOpenid, String nickname) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.ADD_GUIDE_BUYER_RELATION, + GsonHelper.buildJsonObject(ACCOUNT, account, OPENID, openid, "openid", userOpenid, "buyer_nickname", nickname)); + } + + @Override + public List delGuideBuyerRelation(String account, String openid, List buyerOpenIds) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("openid_list", buyerOpenIds); + + String json = this.mpService.post(WxMpApiUrl.Guide.DEL_GUIDE_BUYER_RELATION, body); + return WxGsonBuilder.create().fromJson(GsonParser.parse(json).getAsJsonArray("buyer_resp"), + new TypeToken>() { + }.getType()); + } + + @Override + public void delGuideBuyerRelation(String account, String openid, String userOpenid) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.DEL_GUIDE_BUYER_RELATION, + GsonHelper.buildJsonObject(ACCOUNT, account, OPENID, openid, "openid", userOpenid)); + } + + @Override + public WxMpGuideBuyerInfoList getGuideBuyerRelationList(String account, String openid, int page, int num) throws WxErrorException { + return WxMpGuideBuyerInfoList.fromJson(this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_BUYER_RELATION_LIST, + GsonHelper.buildJsonObject(ACCOUNT, account, OPENID, openid, "page", page, "num", num))); + } + + @Override + public List rebindGuideAcctForBuyer(String oldAccount, String oldOpenid, String account, String openid, List buyerOpenIds) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put("old_guide_account", oldAccount); + body.put("old_guide_openid", oldOpenid); + body.put("new_guide_account", account); + body.put("new_guide_openid", openid); + body.put("openid_list", buyerOpenIds); + + String json = this.mpService.post(WxMpApiUrl.Guide.REBIND_GUIDE_ACCT_FOR_BUYER, body); + return WxGsonBuilder.create().fromJson(GsonParser.parse(json).getAsJsonArray("buyer_resp"), + new TypeToken>() { + }.getType()); + } + + @Override + public void rebindGuideAcctForBuyer(String oldAccount, String oldOpenid, String account, String openid, String userOpenid) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put("old_guide_account", oldAccount); + body.put("old_guide_openid", oldOpenid); + body.put("new_guide_account", account); + body.put("new_guide_openid", openid); + body.put("openid", userOpenid); + + this.mpService.post(WxMpApiUrl.Guide.REBIND_GUIDE_ACCT_FOR_BUYER, body); + } + + @Override + public void updateGuideBuyerRelation(String account, String openid, String userOpenid, String nickname) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.UPDATE_GUIDE_BUYER_RELATION, + GsonHelper.buildJsonObject(ACCOUNT, account, OPENID, openid, + "openid", userOpenid, "buyer_nickname", nickname)); + } + + @Override + public WxMpGuideBuyerRelation getGuideBuyerRelationByBuyer(String openid) throws WxErrorException { + return WxMpGuideBuyerRelation.fromJson(this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_BUYER_RELATION_BY_BUYER, + GsonHelper.buildJsonObject("openid", openid))); + } + + @Override + public WxMpGuideBuyerInfo getGuideBuyerRelation(String account, String openid, String userOpenid) throws WxErrorException { + return WxMpGuideBuyerInfo.fromJson(this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_BUYER_RELATION, + GsonHelper.buildJsonObject(ACCOUNT, account, OPENID, openid, + "openid", userOpenid))); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMassedJobServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMassedJobServiceImpl.java new file mode 100644 index 0000000000..9bc7881b6d --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMassedJobServiceImpl.java @@ -0,0 +1,80 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.gson.reflect.TypeToken; +import lombok.AllArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.common.util.json.GsonParser; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.api.WxMpGuideMassedJobService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideMassed; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideMassedInfo; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideMaterialInfo; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ +@AllArgsConstructor +public class WxMpGuideMassedJobServiceImpl implements WxMpGuideMassedJobService { + private static final String ACCOUNT = "guide_account"; + private static final String OPENID = "guide_openid"; + private final WxMpService mpService; + + @Override + public WxMpGuideMassed addGuideMassedJob(String account, String openid, String taskName, String taskRemark, Long pushTime, List userOpenIds, List materialInfos) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("task_name", taskName); + body.put("task_remark", taskRemark); + body.put("push_time", pushTime); + body.put("openid", userOpenIds); + body.put("material", materialInfos); + String returnString = this.mpService.post(WxMpApiUrl.Guide.ADD_GUIDE_MASSED_JOB, body); + return WxMpGuideMassed.fromJson(GsonParser.parse(returnString).getAsJsonArray("task_result").get(0)); + } + + @Override + public List getGuideMassedJobList(String account, String openid, List taskStatus, Integer offset, Integer limit) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("task_status", taskStatus); + body.put("offset", offset); + body.put("limit", limit); + String returnString = this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_MASSED_JOB_LIST, body); + return WxGsonBuilder.create().fromJson(GsonParser.parse(returnString).getAsJsonArray("list"), + new TypeToken>() { + }.getType()); + } + + @Override + public WxMpGuideMassedInfo getGuideMassedJob(String taskId) throws WxErrorException { + String returnString = this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_MASSED_JOB, GsonHelper.buildJsonObject("task_id", taskId)); + return WxMpGuideMassedInfo.fromJson(GsonParser.parse(returnString).get("job")); + } + + @Override + public void updateGuideMassedJob(String taskId, String taskName, String taskRemark, Long pushTime, List userOpenIds, List materialInfos) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put("task_id", taskId); + body.put("task_name", taskName); + body.put("task_remark", taskRemark); + body.put("push_time", pushTime); + body.put("openid", userOpenIds); + body.put("material", materialInfos); + this.mpService.post(WxMpApiUrl.Guide.UPDATE_GUIDE_MASSED_JOB, body); + } + + @Override + public void cancelGuideMassedJob(String taskId) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.CANCEL_GUIDE_MASSED_JOB, GsonHelper.buildJsonObject("task_id", taskId)); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMaterialServiceImpl.java new file mode 100644 index 0000000000..0584d82460 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMaterialServiceImpl.java @@ -0,0 +1,96 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.gson.reflect.TypeToken; +import lombok.AllArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.common.util.json.GsonParser; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.api.WxMpGuideMaterialService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideCardMaterialInfo; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideImgMaterialInfoList; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideWordMaterialInfoList; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ +@AllArgsConstructor +public class WxMpGuideMaterialServiceImpl implements WxMpGuideMaterialService { + private static final String ACCOUNT = "guide_account"; + private static final String OPENID = "guide_openid"; + private final WxMpService mpService; + + @Override + public void setGuideCardMaterial(String mediaId, int type, String title, String path, String appId) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put("type", type); + body.put("media_id", mediaId); + body.put("title", title); + body.put("path", path); + body.put("appid", appId); + this.mpService.post(WxMpApiUrl.Guide.SET_GUIDE_CARD_MATERIAL, body); + } + + @Override + public List getGuideCardMaterial(int type) throws WxErrorException { + String returnString = this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_CARD_MATERIAL, GsonHelper.buildJsonObject("type", type)); + return WxGsonBuilder.create().fromJson(GsonParser.parse(returnString).getAsJsonArray("card_list"), + new TypeToken>() { + }.getType()); + } + + @Override + public void delGuideCardMaterial(int type, String title, String path, String appId) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put("type", type); + body.put("title", title); + body.put("path", path); + body.put("appid", appId); + this.mpService.post(WxMpApiUrl.Guide.DEL_GUIDE_CARD_MATERIAL, body); + } + + @Override + public void setGuideImageMaterial(String mediaId, int type) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.SET_GUIDE_IMAGE_MATERIAL, + GsonHelper.buildJsonObject("media_id", mediaId, "type", type)); + } + + @Override + public WxMpGuideImgMaterialInfoList getGuideImageMaterial(int type, int start, int num) throws WxErrorException { + String returnString = this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_IMAGE_MATERIAL, + GsonHelper.buildJsonObject("type", type, "start", start, "num", num)); + return WxMpGuideImgMaterialInfoList.fromJson(returnString); + } + + @Override + public void delGuideImageMaterial(int type, String picUrl) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.DEL_GUIDE_IMAGE_MATERIAL, + GsonHelper.buildJsonObject("type", type, "picurl", picUrl)); + } + + @Override + public void setGuideWordMaterial(int type, String word) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.SET_GUIDE_WORD_MATERIAL, + GsonHelper.buildJsonObject("type", type, "word", word)); + } + + @Override + public WxMpGuideWordMaterialInfoList getGuideWordMaterial(int type, int start, int num) throws WxErrorException { + String returnString = this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_WORD_MATERIAL, + GsonHelper.buildJsonObject("type", type, "start", start, "num", num)); + return WxMpGuideWordMaterialInfoList.fromJson(returnString); + } + + @Override + public void delGuideWordMaterial(int type, String word) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.DEL_GUIDE_WORD_MATERIAL, + GsonHelper.buildJsonObject("type", type, "word", word)); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java index 51513fbfe7..3fb47d0971 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java @@ -1,14 +1,22 @@ package me.chanjar.weixin.mp.api.impl; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; import lombok.AllArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.common.util.json.GsonParser; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.api.WxMpGuideService; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.guide.WxMpGuideInfo; -import me.chanjar.weixin.mp.bean.guide.WxMpGuideList; +import me.chanjar.weixin.mp.bean.guide.*; import me.chanjar.weixin.mp.enums.WxMpApiUrl; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + /** * . * @@ -63,4 +71,133 @@ public WxMpGuideList listGuide(int page, int num) throws WxErrorException { return WxMpGuideList.fromJson(this.mpService.post(WxMpApiUrl.Guide.LIST_GUIDE, GsonHelper.buildJsonObject("page", page, "num", num))); } + + @Override + public String createGuideQrCode(String account, String openid, String qrcodeInfo) throws WxErrorException { + String json = this.mpService.post(WxMpApiUrl.Guide.CREATE_QR_CODE, + GsonHelper.buildJsonObject(ACCOUNT, account, OPENID, openid, "qrcode_info", qrcodeInfo)); + return GsonParser.parse(json).get("qrcode_url").toString().replaceAll("\"",""); + } + + @Override + public WxMpGuideMsgList getGuideChatRecord(String account, String openid, String clientOpenid, Long beginTime, Long endTime, int page, int num) throws WxErrorException { + return WxMpGuideMsgList.fromJson(this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_CHAT_RECORD, + GsonHelper.buildJsonObject(ACCOUNT, account, OPENID, openid, + "begin_time", beginTime, + "end_time", endTime, + "page", page, + "num", num) + )); + } + + @Override + public void setGuideConfig(String account, String openid, boolean isDelete, List guideFastReplyList, WxMpAddGuideAutoReply guideAutoReply,WxMpAddGuideAutoReply guideAutoReplyPlus) throws WxErrorException { + JsonArray jsonArray = null; + if (guideFastReplyList != null) { + jsonArray = new JsonArray(); + for (String it : guideFastReplyList) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("content", it); + jsonArray.add(jsonObject); + } + } + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("is_delete", isDelete); + body.put("guide_fast_reply_list", jsonArray); + body.put("guide_auto_reply", guideAutoReply); + body.put("guide_auto_reply_plus", guideAutoReplyPlus); + + this.mpService.post(WxMpApiUrl.Guide.SET_GUIDE_CONFIG,body); + } + + @Override + public WxMpGuideConfig getGuideConfig(String account, String openid) throws WxErrorException { + return WxMpGuideConfig.fromJson(this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_CONFIG, + GsonHelper.buildJsonObject(ACCOUNT, account, OPENID, openid))); + } + + @Override + public void setGuideAcctConfig(boolean isDelete, List blackKeyWord, String guideAutoReply) throws WxErrorException { + JsonObject jsonObject1 = null; + if (blackKeyWord != null && blackKeyWord.size() > 0) { + jsonObject1 = new JsonObject(); + JsonArray jsonArray = new JsonArray(); + blackKeyWord.forEach(jsonArray::add); + jsonObject1.add("values", jsonArray); + } + + JsonObject jsonObject2 = null; + if (guideAutoReply != null) { + jsonObject2 = new JsonObject(); + jsonObject2.addProperty("content", guideAutoReply); + } + + this.mpService.post(WxMpApiUrl.Guide.SET_GUIDE_ACCT_CONFIG, + GsonHelper.buildJsonObject( + "is_delete", isDelete, + "black_keyword", jsonObject1, + "guide_auto_reply", jsonObject2)); + } + + @Override + public WxMpGuideAcctConfig getGuideAcctConfig() throws WxErrorException { + return WxMpGuideAcctConfig.fromJson(this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_ACCT_CONFIG, new JsonObject())); + } + + @Override + public void pushShowWxaPathMenu(String appId, String userName) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.PUSH_SHOW_WX_PATH_MENU, + GsonHelper.buildJsonObject("wxa_appid", appId, "wx_username", userName)); + } + + @Override + public Long newGuideGroup(String groupName) throws WxErrorException { + String json = this.mpService.post(WxMpApiUrl.Guide.NEW_GUIDE_GROUP, + GsonHelper.buildJsonObject("group_name", groupName)); + return Long.valueOf(GsonParser.parse(json).get("group_id").toString()); + } + + @Override + public List getGuideGroupList() throws WxErrorException { + String json = this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_GROUP_LIST, new JsonObject()); + return WxGsonBuilder.create().fromJson(GsonParser.parse(json).getAsJsonArray("group_list"), + new TypeToken>() { + }.getType()); + } + + @Override + public WxMpGuideGroupInfoList getGroupInfo(long groupId, int page, int num) throws WxErrorException { + return WxMpGuideGroupInfoList.fromJson(this.mpService.post(WxMpApiUrl.Guide.GET_GROUP_GUIDE_INFO, + GsonHelper.buildJsonObject("group_id", groupId, "page", page, "num", num) + )); + } + + @Override + public void addGuide2GuideGroup(long groupId, String account) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.ADD_GROUP_GUIDE, + GsonHelper.buildJsonObject("group_id", groupId, ACCOUNT, account)); + } + + @Override + public void delGuide2GuideGroup(long groupId, String account) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.DEL_GROUP_GUIDE, + GsonHelper.buildJsonObject("group_id", groupId, ACCOUNT, account)); + } + + @Override + public List getGroupByGuide(String account) throws WxErrorException { + String json = this.mpService.post(WxMpApiUrl.Guide.GET_GROUP_ON_GUIDE, + GsonHelper.buildJsonObject(ACCOUNT, account)); + return WxGsonBuilder.create().fromJson(GsonParser.parse(json).getAsJsonArray("group_id_list"), + new TypeToken>() { + }.getType()); + } + + @Override + public void delGuideGroup(long groupId) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.DEL_GROUP, + GsonHelper.buildJsonObject("group_id", groupId)); + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java new file mode 100644 index 0000000000..1bde21e9b2 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java @@ -0,0 +1,160 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import lombok.AllArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.common.util.json.GsonParser; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.api.WxMpGuideTagService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideBuyerResp; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideTagInfo; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ + +@AllArgsConstructor +public class WxMpGuideTagServiceImpl implements WxMpGuideTagService { + private static final String ACCOUNT = "guide_account"; + private static final String OPENID = "guide_openid"; + private final WxMpService mpService; + + @Override + public void newGuideTagOption(String tagName, List values) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put("tag_name", tagName); + body.put("tag_values", values); + this.mpService.post(WxMpApiUrl.Guide.NEW_GUIDE_TAG_OPTION, body); + } + + @Override + public void delGuideTagOption(String tagName) throws WxErrorException { + this.mpService.post(WxMpApiUrl.Guide.DEL_GUIDE_TAG_OPTION, GsonHelper.buildJsonObject("tag_name", tagName)); + } + + @Override + public void addGuideTagOption(String tagName, List values) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put("tag_name", tagName); + body.put("tag_values", values); + this.mpService.post(WxMpApiUrl.Guide.ADD_GUIDE_TAG_OPTION, body); + } + + @Override + public List getGuideTagOption() throws WxErrorException { + String returnString = this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_TAG_OPTION, new JsonObject()); + List infoList = WxGsonBuilder.create().fromJson(GsonParser.parse(returnString).getAsJsonArray("options"), + new TypeToken>() { + }.getType()); + return infoList.stream().filter(it -> !it.getTagName().equals("")).collect(Collectors.toList()); + } + + @Override + public List addGuideBuyerTag(String account, String openid, String value, List userOpenIds) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("tag_value", value); + body.put("openid_list", userOpenIds); + String returnString = this.mpService.post(WxMpApiUrl.Guide.ADD_GUIDE_BUYER_TAG, body); + return WxGsonBuilder.create().fromJson(GsonParser.parse(returnString).getAsJsonArray("buyer_resp"), + new TypeToken>() { + }.getType()); + } + + @Override + public void addGuideBuyerTag(String account, String openid, String value, String userOpenid) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("tag_value", value); + body.put("openid", userOpenid); + this.mpService.post(WxMpApiUrl.Guide.ADD_GUIDE_BUYER_TAG, body); + } + + @Override + public List getGuideBuyerTag(String account, String openid, String userOpenid, Boolean isExclude) throws WxErrorException { + String returnString = this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_BUYER_TAG, + GsonHelper.buildJsonObject(ACCOUNT, account, OPENID, openid, + "openid", userOpenid)); + List list = WxGsonBuilder.create().fromJson(GsonParser.parse(returnString).getAsJsonArray("tag_values"), + new TypeToken>() { + }.getType()); + if (isExclude) { + if (list.size() > 0) { + if (list.get(list.size() - 1).contains("\n")) { + list.remove(list.size() - 1); + } + } + } + return list; + } + + @Override + public List queryGuideBuyerByTag(String account, String openid, Integer pushCount, List value) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("push_count", pushCount); + body.put("tag_value", value); + String returnString = this.mpService.post(WxMpApiUrl.Guide.QUERY_GUIDE_BUYER_BY_TAG, body); + return WxGsonBuilder.create().fromJson(GsonParser.parse(returnString).getAsJsonArray("openid_list"), + new TypeToken>() { + }.getType()); + } + + @Override + public List delGuideBuyerTag(String account, String openid, String value, List userOpenIds) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("tag_value", value); + body.put("openid_list", userOpenIds); + String returnString = this.mpService.post(WxMpApiUrl.Guide.DEL_GUIDE_BUYER_TAG, body); + return WxGsonBuilder.create().fromJson(GsonParser.parse(returnString).getAsJsonArray("buyer_resp"), + new TypeToken>() { + }.getType()); + } + + @Override + public void delGuideBuyerTag(String account, String openid, String value, String userOpenid) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("tag_value", value); + body.put("openid", userOpenid); + this.mpService.post(WxMpApiUrl.Guide.DEL_GUIDE_BUYER_TAG, body); + } + + @Override + public void addGuideBuyerDisplayTag(String account, String openid, String userOpenid, List msgList) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("openid", userOpenid); + body.put("display_tag_list", msgList); + this.mpService.post(WxMpApiUrl.Guide.ADD_GUIDE_BUYER_DISPLAY_TAG, body); + } + + @Override + public List getGuideBuyerDisplayTag(String account, String openid, String userOpenid) throws WxErrorException { + Map body = new LinkedHashMap<>(); + body.put(ACCOUNT, account); + body.put(OPENID, openid); + body.put("openid", userOpenid); + String returnString = this.mpService.post(WxMpApiUrl.Guide.GET_GUIDE_BUYER_DISPLAY_TAG, body); + return WxGsonBuilder.create().fromJson(GsonParser.parse(returnString).getAsJsonArray("display_tag_list"), + new TypeToken>() { + }.getType()); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpAddGuideAutoReply.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpAddGuideAutoReply.java new file mode 100644 index 0000000000..87ad3cb3fc --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpAddGuideAutoReply.java @@ -0,0 +1,44 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Builder; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 关注顾问自动回复(欢迎语)添加实体 + * + * @author 广州跨界-宋心成 + * @date 2021/5/8/008 + */ +@Data +@Builder +public class WxMpAddGuideAutoReply implements ToJson, Serializable { + private static final long serialVersionUID = -3364721434924095836L; + + /** + * 新客户关注自动回复内容 + */ + @SerializedName("content") + private String content; + + /** + * 新客户关注自动回复内容类型 + * 1表示文字,2表示图片,3表示小程序卡片 + */ + @SerializedName("msgtype") + private Integer msgType; + + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpAddGuideAutoReply fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpAddGuideAutoReply.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpAddGuideBuyerInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpAddGuideBuyerInfo.java new file mode 100644 index 0000000000..caac651070 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpAddGuideBuyerInfo.java @@ -0,0 +1,42 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Builder; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 客户信息dto + * @author 广州跨界-宋心成 + * @date 2021/5/11/011 + */ + +@Data +@Builder +public class WxMpAddGuideBuyerInfo implements ToJson, Serializable { + private static final long serialVersionUID = -1703303970552268691L; + + /** + * 客户的openId + */ + @SerializedName("openid") + private String openid; + + /** + * 客户的名称 + */ + @SerializedName("buyer_nickname") + private String nickname; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpAddGuideBuyerInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpAddGuideBuyerInfo.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideAcctConfig.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideAcctConfig.java new file mode 100644 index 0000000000..fcd817a981 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideAcctConfig.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 离线自动回复与敏感词 + * @author 广州跨界-宋心成 + * @date 2021/5/8/008 + */ +@Data +public class WxMpGuideAcctConfig implements Serializable { + private static final long serialVersionUID = -5941249630655543648L; + + /** + * 敏感词 + */ + @SerializedName("black_keyword") + private WxMpGuideSensitiveWords guideSensitiveWords; + + /** + * 离线自动回复内容 + */ + @SerializedName("guide_auto_reply") + private WxMpGuideOffLineReply guideOffLineReply; + + public static WxMpGuideAcctConfig fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideAcctConfig.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideAutoReply.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideAutoReply.java new file mode 100644 index 0000000000..b0ea06a46d --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideAutoReply.java @@ -0,0 +1,48 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 关注顾问自动回复(欢迎语) + * + * @author 广州跨界-宋心成 + * @date 2021/5/8/008 + */ +@Data +public class WxMpGuideAutoReply implements ToJson, Serializable { + + private static final long serialVersionUID = -3584275317132197695L; + + /** + * 新客户关注自动回复内容 + */ + @SerializedName("content") + private String content; + + /** + * 新客户关注自动回复内容类型 + * 1表示文字,2表示图片,3表示小程序卡片 + */ + @SerializedName("msgtype") + private Integer msgType; + + /** + * 修改时间 + */ + @SerializedName("updatetime") + private Long updateTime; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideAutoReply fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideAutoReply.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerInfo.java new file mode 100644 index 0000000000..a692c7d15e --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerInfo.java @@ -0,0 +1,55 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 客户信息 + * + * @author 广州跨界-宋心成 + * @date 2021/5/10/010 + */ + +@Data +@Builder +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class WxMpGuideBuyerInfo implements ToJson, Serializable { + private static final long serialVersionUID = -8076715937378141119L; + + /** + * 客户的openId + */ + @SerializedName("openid") + private String openid; + + /** + * 客户的名称 + */ + @SerializedName("buyer_nickname") + private String nickname; + + /** + * 创建时间戳 + */ + @SerializedName("create_time") + private Long createTime; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideBuyerInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideBuyerInfo.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerInfoList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerInfoList.java new file mode 100644 index 0000000000..530a7810c5 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerInfoList.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 顾问的客户列表 + * @author 广州跨界-宋心成 + * @date 2021/5/11/011 + */ +@Data +public class WxMpGuideBuyerInfoList implements Serializable { + private static final long serialVersionUID = 9094928050460133322L; + + /** + * 客户总数量 + */ + @SerializedName("total_num") + private Integer totalNum; + + /** + * 客户列表 + */ + private List list; + + public static WxMpGuideBuyerInfoList fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideBuyerInfoList.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerRelation.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerRelation.java new file mode 100644 index 0000000000..f4609937a8 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerRelation.java @@ -0,0 +1,59 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 客户顾问关系 + * + * @author 广州跨界-宋心成 + * @date 2021/5/11/011 + */ + +@Data +public class WxMpGuideBuyerRelation implements ToJson, Serializable { + private static final long serialVersionUID = 1531261524650705552L; + + /** + * 顾问的微信帐号 + */ + @SerializedName("guide_account") + private String guideAccount; + + /** + * 顾问的openid或者unionid + */ + @SerializedName("guide_openid") + private String guideOpenid; + + /** + * 客户的openId + */ + @SerializedName("openid") + private String openid; + + /** + * 客户的名称 + */ + @SerializedName("buyer_nickname") + private String nickname; + + /** + * 创建时间戳 + */ + @SerializedName("create_time") + private Long createTime; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideBuyerRelation fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideBuyerRelation.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerResp.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerResp.java new file mode 100644 index 0000000000..f0707ebd7a --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideBuyerResp.java @@ -0,0 +1,46 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 批量操作客户是否成功返回信息 + * @author 广州跨界-宋心成 + * @date 2021/5/10/010 + */ + +@Data +public class WxMpGuideBuyerResp implements ToJson, Serializable { + private static final long serialVersionUID = -5628199106867822424L; + + /** + * 错误码 + */ + @SerializedName("errcode") + private Integer errCode; + + /** + * 错误信息 + */ + @SerializedName("errmsg") + private String errMsg; + + /** + * 客户openid + */ + @SerializedName("openid") + private String openid; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideBuyerResp fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideBuyerResp.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideCardMaterialInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideCardMaterialInfo.java new file mode 100644 index 0000000000..7c83432de4 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideCardMaterialInfo.java @@ -0,0 +1,64 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 小程序素材信息 + * + * @author 广州跨界-宋心成 + * @date 2021/5/12/012 + */ +@Data +public class WxMpGuideCardMaterialInfo implements ToJson, Serializable { + private static final long serialVersionUID = -3165724834271407258L; + + /** + * 卡片名字 + */ + @SerializedName("title") + private String title; + + /** + * 小程序appid + */ + @SerializedName("appid") + private String appId; + + /** + * 路径 + */ + @SerializedName("path") + private String path; + + /** + * 图片链接 + */ + @SerializedName("picurl") + private String picUrl; + + /** + * 图片id + */ + @SerializedName("master_id") + private Long masterId; + + /** + * 图片id + */ + @SerializedName("slave_id") + private Long slaveId; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideCardMaterialInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideCardMaterialInfo.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideConfig.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideConfig.java new file mode 100644 index 0000000000..9ddaf7318f --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideConfig.java @@ -0,0 +1,40 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 获取快捷回复,关注顾问自动回复返回类 + * @author 广州跨界-宋心成 + * @date 2021/5/8/008 + */ +@Data +public class WxMpGuideConfig implements Serializable { + private static final long serialVersionUID = -343579331927473027L; + + /** + * 快捷回复列表 + */ + @SerializedName("guide_fast_reply_list") + private List guideFastReplyList; + + /** + * 第一条关注顾问自动回复(欢迎语) + */ + @SerializedName("guide_auto_reply") + private WxMpGuideAutoReply guideAutoReply; + + /** + * 第二条关注顾问自动回复(欢迎语) + */ + @SerializedName("guide_auto_reply_plus") + private WxMpGuideAutoReply guideAutoReplyPlus; + + public static WxMpGuideConfig fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideConfig.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideFastReply.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideFastReply.java new file mode 100644 index 0000000000..116ed91c70 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideFastReply.java @@ -0,0 +1,40 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 顾问快捷回复 + * + * @author 广州跨界-宋心成 + * @date 2021/5/8/008 + */ +@Data +public class WxMpGuideFastReply implements ToJson, Serializable { + private static final long serialVersionUID = -3316181204068248972L; + + /** + * 快捷回复内容 + */ + @SerializedName("content") + private String content; + + /** + * 修改时间 + */ + @SerializedName("updatetime") + private Long updateTime; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideFastReply fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideFastReply.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroup.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroup.java new file mode 100644 index 0000000000..f37677ea79 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroup.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 顾问分组信息 + * + * @author 广州跨界-宋心成 + * @date 2021/5/8/008 + */ +@Data +public class WxMpGuideGroup implements ToJson, Serializable { + private static final long serialVersionUID = 6235142804489175294L; + + /** + * 顾问分组id + */ + @SerializedName("id") + private Long id; + + /** + * 顾问分组名称 + */ + @SerializedName("name") + private String name; + + /** + * 创建时间戳 + */ + @SerializedName("create_time") + private Long createTime; + + /** + * 更新时间戳 + */ + @SerializedName("update_time") + private Long updateTime; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideGroup fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideGroup.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroupInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroupInfo.java new file mode 100644 index 0000000000..4173ad35d2 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroupInfo.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 分组顾问信息. + * + * @author 广州跨界-宋心成 + * @date 2021/5/8/008 + */ +@Data +@Builder +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class WxMpGuideGroupInfo implements ToJson, Serializable { + private static final long serialVersionUID = -4927568853154487513L; + + /** + * 顾问的微信帐号 + */ + @SerializedName("guide_account") + private String account; + + /** + * 顾问的openid或者unionid + */ + @SerializedName("guide_openid") + private String openid; + + /** + * 顾问昵称 + */ + @SerializedName("guide_nickname") + private String nickName; + + /** + * 顾问头像 + */ + @SerializedName("guide_headimgurl") + private String headImgUrl; + + /** + * 创建时间戳 + */ + @SerializedName("create_time") + private Long createTime; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideGroupInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideGroupInfo.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroupInfoList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroupInfoList.java new file mode 100644 index 0000000000..63e18b80d7 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideGroupInfoList.java @@ -0,0 +1,34 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 顾问分组内顾问信息 + * @author 广州跨界-宋心成 + * @date 2021/5/8/008 + */ +@Data +public class WxMpGuideGroupInfoList implements Serializable { + private static final long serialVersionUID = 7037631524066068497L; + + /** + * 分组顾问总数量 + */ + @SerializedName("total_num") + private Integer totalNum; + + /** + * 分组顾问列表 + */ + @SerializedName("guide_list") + private List list; + + public static WxMpGuideGroupInfoList fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideGroupInfoList.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideImgMaterialInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideImgMaterialInfo.java new file mode 100644 index 0000000000..854d6ab8ac --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideImgMaterialInfo.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 图片素材信息 + * @author 广州跨界-宋心成 + * @date 2021/5/12/012 + */ +@Data +public class WxMpGuideImgMaterialInfo implements ToJson, Serializable { + private static final long serialVersionUID = 9165977127399850455L; + + /** + * 图片链接 + */ + @SerializedName("picurl") + private String picUrl; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideImgMaterialInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideImgMaterialInfo.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideImgMaterialInfoList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideImgMaterialInfoList.java new file mode 100644 index 0000000000..f87900191d --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideImgMaterialInfoList.java @@ -0,0 +1,35 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 图片素材列表 + * + * @author 广州跨界-宋心成 + * @date 2021/5/12/012 + */ +@Data +public class WxMpGuideImgMaterialInfoList implements Serializable { + private static final long serialVersionUID = 8876840664010690223L; + + /** + * 图片素材总数 + */ + @SerializedName("total_num") + private Integer totalNum; + + /** + * 图片素材列表 + */ + @SerializedName("model_list") + private List list; + + public static WxMpGuideImgMaterialInfoList fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideImgMaterialInfoList.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassed.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassed.java new file mode 100644 index 0000000000..258793ccad --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassed.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.JsonElement; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 添加群发任务返回值 + * + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ +@Data +public class WxMpGuideMassed implements ToJson, Serializable { + private static final long serialVersionUID = 7049976499427665050L; + + @SerializedName("task_id") + private Long taskId; + + @SerializedName("openid") + private List list; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideMassed fromJson(T json) { + if (json instanceof String) { + return WxGsonBuilder.create().fromJson((String) json, WxMpGuideMassed.class); + } else if (json instanceof JsonElement) { + return WxGsonBuilder.create().fromJson((JsonElement) json, WxMpGuideMassed.class); + } + return null; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassedBuyerInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassedBuyerInfo.java new file mode 100644 index 0000000000..58f6345f33 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassedBuyerInfo.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 下方客户状态信息 + * + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ + +@Data +public class WxMpGuideMassedBuyerInfo implements ToJson, Serializable { + private static final long serialVersionUID = -7433816414896345471L; + + /** + * 客户openid + */ + @SerializedName("openid") + private String openid; + + /** + * 消息发送状态(1.未发送 2.发送成功 3.未关注公众号 4.没有quota(没有发送机会) 5.系统错误) + */ + @SerializedName("send_status") + private int sendStatus; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideMassedBuyerInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideMassedBuyerInfo.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassedInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassedInfo.java new file mode 100644 index 0000000000..ddce7d6b73 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMassedInfo.java @@ -0,0 +1,102 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.JsonElement; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 群发任务信息 + * + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ + +@Data +public class WxMpGuideMassedInfo implements ToJson, Serializable { + private static final long serialVersionUID = -6120573244255111822L; + + /** + * 任务id + */ + @SerializedName("task_id") + private String taskId; + + /** + * 顾问openid + */ + @SerializedName("guide_openid") + private String openid; + + /** + * 任务创建时间 + */ + @SerializedName("create_time") + private Long createTime; + + /** + * 任务最后修改时间 + */ + @SerializedName("update_time") + private Long updateTime; + + /** + * 任务下发时间 + */ + @SerializedName("push_time") + private Long pushTime; + + /** + * 任务完成时间 + */ + @SerializedName("finish_time") + private Long finishTime; + + /** + * 任务名称 + */ + @SerializedName("task_name") + private String taskName; + + /** + * 任务备注 + */ + @SerializedName("task_remark") + private String taskRemark; + + /** + * 任务状态(1.任务未执行 2.已执行 3.执行完成 4.任务取消) + */ + @SerializedName("task_status") + private int taskStatus; + + /** + * 素材 + */ + @SerializedName("material") + private List material; + + /** + * 客户列表 + */ + @SerializedName("buyer_info") + private List buyerInfos; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideMassedInfo fromJson(T json) { + if (json instanceof String) { + return WxGsonBuilder.create().fromJson((String) json, WxMpGuideMassedInfo.class); + } else if (json instanceof JsonElement) { + return WxGsonBuilder.create().fromJson((JsonElement) json, WxMpGuideMassedInfo.class); + } + return null; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMaterialInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMaterialInfo.java new file mode 100644 index 0000000000..e7426fcc9c --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMaterialInfo.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Builder; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 素材信息 + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ + +@Data +@Builder +public class WxMpGuideMaterialInfo implements ToJson, Serializable { + private static final long serialVersionUID = -6201520701655588983L; + + /** + * 素材类型,1.文本,3.图片,49.小程序卡片 + */ + @SerializedName("type") + private int type; + + /** + * 图片类型素材或者卡片类型素材的封面,只能用《素材管理获取media_id》(注意目前只能用临时素材的media_id) + */ + @SerializedName("media_id") + private String mediaId; + + /** + * 小程序卡片标题,最多35字 + */ + @SerializedName("title") + private String title; + + /** + * 小程序卡片路径 + */ + @SerializedName("path") + private String path; + + /** + * 小程序卡片appid,需要关联到公众号 + */ + @SerializedName("appid") + private String appId; + + /** + * 文本类型素材的内容,不超过300字节 + */ + @SerializedName("word") + private String word; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideMaterialInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideMaterialInfo.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMsg.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMsg.java new file mode 100644 index 0000000000..37e1246579 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMsg.java @@ -0,0 +1,78 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 顾问聊天记录 + * @author 广州跨界-宋心成 + * @date 2021/5/7/007 + */ +@Data +@Builder +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class WxMpGuideMsg implements ToJson, Serializable { + private static final long serialVersionUID = -5175162334221904778L; + + /** + * 顾问的微信帐号 + */ + @SerializedName("guide_account") + private String account; + + /** + * 顾问的openid或者unionid + */ + @SerializedName("guide_openid") + private String openid; + + /** + * 聊天记录生成时间 + */ + @SerializedName("create_time") + private Long createTime; + + /** + * 聊天内容 + */ + @SerializedName("content") + private String content; + + /** + * 聊天记录类型 + * + * 1 文字类型 + * 3 图片类型 + * 49 小程序卡片类型 + */ + @SerializedName("content_type") + private Integer contentType; + + /** + * 消息指向 + * + * 1 顾问发送消息给客户 + * 2 客户发送消息给顾问 + */ + @SerializedName("direction") + private Integer direction; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideMsg fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideMsg.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMsgList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMsgList.java new file mode 100644 index 0000000000..04e58b0c3d --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideMsgList.java @@ -0,0 +1,35 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 顾问聊天记录列表 + * @author 广州跨界-宋心成 + * @date 2021/5/7/007 + */ + +@Data +public class WxMpGuideMsgList implements Serializable { + private static final long serialVersionUID = -4041549590019624417L; + + /** + * 顾问聊天记录总数量 + */ + @SerializedName("total_num") + private Integer totalNum; + + /** + * 顾问聊天记录列表 + */ + @SerializedName("msg_list") + private List msgList; + + public static WxMpGuideMsgList fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideMsgList.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideOffLineReply.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideOffLineReply.java new file mode 100644 index 0000000000..37ea15937f --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideOffLineReply.java @@ -0,0 +1,42 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 离线自动回复 + * + * @author 广州跨界-宋心成 + * @date 2021/5/8/008 + */ +@Data +@Builder +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class WxMpGuideOffLineReply implements ToJson, Serializable { + private static final long serialVersionUID = 1337376246361830706L; + + /** + * 离线自动回复内容 + */ + @SerializedName("content") + private String content; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideOffLineReply fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideOffLineReply.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideSensitiveWords.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideSensitiveWords.java new file mode 100644 index 0000000000..3346def2b0 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideSensitiveWords.java @@ -0,0 +1,40 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 顾问敏感词 + * + * @author 广州跨界-宋心成 + * @date 2021/5/8/008 + */ + +@Data +public class WxMpGuideSensitiveWords implements ToJson, Serializable { + private static final long serialVersionUID = 1546603590395563048L; + + /** + * 敏感词数组 + */ + @SerializedName("values") + private String[] values; + /** + * 修改时间 + */ + @SerializedName("updatetime") + private Long updateTime; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideSensitiveWords fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideSensitiveWords.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideTagInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideTagInfo.java new file mode 100644 index 0000000000..2d39ebcba3 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideTagInfo.java @@ -0,0 +1,42 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 标签信息 + * + * @author 广州跨界-宋心成 + * @date 2021/5/11/011 + */ + +@Data +public class WxMpGuideTagInfo implements ToJson, Serializable { + private static final long serialVersionUID = 2086445319422158695L; + + /** + * 标签类型名称 + */ + @SerializedName("tag_name") + private String tagName; + + /** + * 标签值 + */ + @SerializedName("tag_values") + private List values; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideTagInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideTagInfo.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideWordMaterialInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideWordMaterialInfo.java new file mode 100644 index 0000000000..213615d547 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideWordMaterialInfo.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** 文字素材信息 + * @author 广州跨界-宋心成 + * @date 2021/5/12/012 + */ + +@Data +public class WxMpGuideWordMaterialInfo implements ToJson, Serializable { + private static final long serialVersionUID = -1370377663251409658L; + + /** + * 文字内容 + */ + @SerializedName("word") + private String word; + + /** + * 创建时间戳 + */ + @SerializedName("create_time") + private Long createTime; + + @Override + public String toJson() { + return WxGsonBuilder.create().toJson(this); + } + + public static WxMpGuideWordMaterialInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideWordMaterialInfo.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideWordMaterialInfoList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideWordMaterialInfoList.java new file mode 100644 index 0000000000..52ee16adad --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/guide/WxMpGuideWordMaterialInfoList.java @@ -0,0 +1,34 @@ +package me.chanjar.weixin.mp.bean.guide; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 文字素材信息列表 + * @author 广州跨界-宋心成 + * @date 2021/5/12/012 + */ +@Data +public class WxMpGuideWordMaterialInfoList implements Serializable { + private static final long serialVersionUID = 6891519244712898267L; + + /** + * 文字素材总数 + */ + @SerializedName("total_num") + private Integer totalNum; + + /** + * 文字素材列表 + */ + @SerializedName("word_list") + private List list; + + public static WxMpGuideWordMaterialInfoList fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpGuideWordMaterialInfoList.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java index b6a08b25ac..0facd7cbb0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java @@ -2,8 +2,8 @@ import lombok.AllArgsConstructor; import lombok.Getter; -import me.chanjar.weixin.mp.config.WxMpHostConfig; import me.chanjar.weixin.mp.config.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpHostConfig; import static me.chanjar.weixin.mp.config.WxMpHostConfig.*; @@ -290,27 +290,27 @@ enum SubscribeMsg implements WxMpApiUrl { /** * 获取模板标题下的关键词列表. */ - GET_PUB_TEMPLATE_TITLE_LIST_URL (API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/getpubtemplatetitles"), + GET_PUB_TEMPLATE_TITLE_LIST_URL(API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/getpubtemplatetitles"), /** * 获取模板标题下的关键词列表. */ - GET_PUB_TEMPLATE_KEY_WORDS_BY_ID_URL (API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/getpubtemplatekeywords"), + GET_PUB_TEMPLATE_KEY_WORDS_BY_ID_URL(API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/getpubtemplatekeywords"), /** * 组合模板并添加至帐号下的个人模板库. */ - TEMPLATE_ADD_URL(API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/addtemplate"), + TEMPLATE_ADD_URL(API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/addtemplate"), /** * 获取当前帐号下的个人模板列表. */ - TEMPLATE_LIST_URL(API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/gettemplate"), + TEMPLATE_LIST_URL(API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/gettemplate"), /** * 删除帐号下的某个模板. */ - TEMPLATE_DEL_URL(API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/deltemplate"), + TEMPLATE_DEL_URL(API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/deltemplate"), /** * 获取小程序账号的类目 */ - GET_CATEGORY_URL (API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/getcategory"), + GET_CATEGORY_URL(API_DEFAULT_HOST_URL, "/wxaapi/newtmpl/getcategory"), UNIFORM_MSG_SEND_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/wxopen/template/uniform_send"), ACTIVITY_ID_CREATE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/wxopen/activityid/create"), UPDATABLE_MSG_SEND_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/wxopen/updatablemsg/send"); @@ -1133,22 +1133,22 @@ enum Invoice implements WxMpApiUrl { /** * 报销方查询报销发票信息 */ - GET_INVOICE_INFO(API_DEFAULT_HOST_URL,"/card/invoice/reimburse/getinvoiceinfo"), + GET_INVOICE_INFO(API_DEFAULT_HOST_URL, "/card/invoice/reimburse/getinvoiceinfo"), /** * 报销方批量查询报销发票信息 */ - GET_INVOICE_BATCH(API_DEFAULT_HOST_URL,"/card/invoice/reimburse/getinvoicebatch"), + GET_INVOICE_BATCH(API_DEFAULT_HOST_URL, "/card/invoice/reimburse/getinvoicebatch"), /** * 报销方更新发票状态 */ - UPDATE_INVOICE_STATUS(API_DEFAULT_HOST_URL,"/card/invoice/reimburse/updateinvoicestatus"), + UPDATE_INVOICE_STATUS(API_DEFAULT_HOST_URL, "/card/invoice/reimburse/updateinvoicestatus"), /** * 报销方批量更新发票状态 */ - UPDATE_STATUS_BATCH(API_DEFAULT_HOST_URL,"/card/invoice/reimburse/updatestatusbatch"), + UPDATE_STATUS_BATCH(API_DEFAULT_HOST_URL, "/card/invoice/reimburse/updatestatusbatch"), ; private final String prefix; private final String path; @@ -1180,7 +1180,190 @@ enum Guide implements WxMpApiUrl { /** * 获取服务号顾问列表 */ - LIST_GUIDE(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguideacctlist"); + LIST_GUIDE(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguideacctlist"), + /** + * 生成顾问二维码 + */ + CREATE_QR_CODE(API_DEFAULT_HOST_URL, "/cgi-bin/guide/guidecreateqrcode"), + /** + * 获取顾问聊天记录 + */ + GET_GUIDE_CHAT_RECORD(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidebuyerchatrecord"), + /** + * 设置快捷回复与关注自动回复 + */ + SET_GUIDE_CONFIG(API_DEFAULT_HOST_URL, "/cgi-bin/guide/setguideconfig"), + /** + * 获取快捷回复与关注自动回复 + */ + GET_GUIDE_CONFIG(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguideconfig"), + /** + * 为服务号设置敏感词与离线自动回复 + */ + SET_GUIDE_ACCT_CONFIG(API_DEFAULT_HOST_URL, "/cgi-bin/guide/setguideacctconfig"), + /** + * 获取服务号敏感词与离线自动回复 + */ + GET_GUIDE_ACCT_CONFIG(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguideacctconfig"), + /** + * 允许微信用户复制小程序页面路径 + */ + PUSH_SHOW_WX_PATH_MENU(API_DEFAULT_HOST_URL, "/cgi-bin/guide/pushshowwxapathmenu"), + /** + * 新建顾问分组 + */ + NEW_GUIDE_GROUP(API_DEFAULT_HOST_URL, "/cgi-bin/guide/newguidegroup"), + /** + * 获取服务号下所有顾问分组的列表 + */ + GET_GUIDE_GROUP_LIST(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidegrouplist"), + /** + * 获取指定顾问分组内顾问信息 + */ + GET_GROUP_GUIDE_INFO(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getgroupinfo"), + /** + * 分组内添加顾问 + */ + ADD_GROUP_GUIDE(API_DEFAULT_HOST_URL, "/cgi-bin/guide/addguide2guidegroup"), + /** + * 分组内删除顾问 + */ + DEL_GROUP_GUIDE(API_DEFAULT_HOST_URL, "/cgi-bin/guide/delguide2guidegroup"), + /** + * 获取顾问所在分组 + */ + GET_GROUP_ON_GUIDE(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getgroupbyguide"), + /** + * 删除指定顾问分组 + */ + DEL_GROUP(API_DEFAULT_HOST_URL, "/cgi-bin/guide/delguidegroup"), + /** + * 为顾问分配客户 + */ + ADD_GUIDE_BUYER_RELATION(API_DEFAULT_HOST_URL, "/cgi-bin/guide/addguidebuyerrelation"), + /** + * 为顾问移除客户 + */ + DEL_GUIDE_BUYER_RELATION(API_DEFAULT_HOST_URL, "/cgi-bin/guide/delguidebuyerrelation"), + /** + * 获取顾问的客户列表 + */ + GET_GUIDE_BUYER_RELATION_LIST(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidebuyerrelationlist"), + /** + * 为客户更换顾问 + */ + REBIND_GUIDE_ACCT_FOR_BUYER(API_DEFAULT_HOST_URL, "/cgi-bin/guide/rebindguideacctforbuyer"), + /** + * 修改客户昵称 + */ + UPDATE_GUIDE_BUYER_RELATION(API_DEFAULT_HOST_URL, "/cgi-bin/guide/updateguidebuyerrelation"), + /** + * 查询客户所属顾问 + */ + GET_GUIDE_BUYER_RELATION_BY_BUYER(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidebuyerrelationbybuyer"), + /** + * 查询指定顾问和客户的关系 + */ + GET_GUIDE_BUYER_RELATION(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidebuyerrelation"), + /** + * 新建标签类型 + */ + NEW_GUIDE_TAG_OPTION(API_DEFAULT_HOST_URL, "/cgi-bin/guide/newguidetagoption"), + /** + * 删除标签类型 + */ + DEL_GUIDE_TAG_OPTION(API_DEFAULT_HOST_URL, "/cgi-bin/guide/delguidetagoption"), + /** + * 为标签添加可选值 + */ + ADD_GUIDE_TAG_OPTION(API_DEFAULT_HOST_URL, "/cgi-bin/guide/addguidetagoption"), + /** + * 获取标签和可选值 + */ + GET_GUIDE_TAG_OPTION(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidetagoption"), + /** + * 为客户设置标签 + */ + ADD_GUIDE_BUYER_TAG(API_DEFAULT_HOST_URL, "/cgi-bin/guide/addguidebuyertag"), + /** + * 查询客户标签 + */ + GET_GUIDE_BUYER_TAG(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidebuyertag"), + /** + * 根据标签值筛选客户 + */ + QUERY_GUIDE_BUYER_BY_TAG(API_DEFAULT_HOST_URL, "/cgi-bin/guide/queryguidebuyerbytag"), + /** + * 删除客户标签 + */ + DEL_GUIDE_BUYER_TAG(API_DEFAULT_HOST_URL, "/cgi-bin/guide/delguidebuyertag"), + /** + * 设置自定义客户信息 + */ + ADD_GUIDE_BUYER_DISPLAY_TAG(API_DEFAULT_HOST_URL, "/cgi-bin/guide/addguidebuyerdisplaytag"), + /** + * 获取自定义客户信息 + */ + GET_GUIDE_BUYER_DISPLAY_TAG(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidebuyerdisplaytag"), + /** + * 添加小程序卡片素材 + */ + SET_GUIDE_CARD_MATERIAL(API_DEFAULT_HOST_URL, "/cgi-bin/guide/setguidecardmaterial"), + /** + * 查询小程序卡片素材 + */ + GET_GUIDE_CARD_MATERIAL(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidecardmaterial"), + /** + * 删除小程序卡片素材 + */ + DEL_GUIDE_CARD_MATERIAL(API_DEFAULT_HOST_URL, "/cgi-bin/guide/delguidecardmaterial"), + /** + * 添加图片素材 + */ + SET_GUIDE_IMAGE_MATERIAL(API_DEFAULT_HOST_URL, "/cgi-bin/guide/setguideimagematerial"), + /** + * 查询图片素材 + */ + GET_GUIDE_IMAGE_MATERIAL(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguideimagematerial"), + /** + * 删除图片素材 + */ + DEL_GUIDE_IMAGE_MATERIAL(API_DEFAULT_HOST_URL, "/cgi-bin/guide/delguideimagematerial"), + /** + * 添加文字素材 + */ + SET_GUIDE_WORD_MATERIAL(API_DEFAULT_HOST_URL, "/cgi-bin/guide/setguidewordmaterial"), + /** + * 查询文字素材 + */ + GET_GUIDE_WORD_MATERIAL(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidewordmaterial"), + /** + * 删除文字素材 + */ + DEL_GUIDE_WORD_MATERIAL(API_DEFAULT_HOST_URL, "/cgi-bin/guide/delguidewordmaterial"), + /** + * 添加群发任务 + */ + ADD_GUIDE_MASSED_JOB(API_DEFAULT_HOST_URL, "/cgi-bin/guide/addguidemassendjob"), + /** + * 获取群发任务列表 + */ + GET_GUIDE_MASSED_JOB_LIST(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidemassendjoblist"), + /** + * 获取指定群发任务信息 + */ + GET_GUIDE_MASSED_JOB(API_DEFAULT_HOST_URL, "/cgi-bin/guide/getguidemassendjob"), + /** + * 修改群发任务 + */ + UPDATE_GUIDE_MASSED_JOB(API_DEFAULT_HOST_URL, "/cgi-bin/guide/updateguidemassendjob"), + /** + * 取消群发任务 + */ + CANCEL_GUIDE_MASSED_JOB(API_DEFAULT_HOST_URL, "/cgi-bin/guide/cancelguidemassendjob"), + ; + + private final String prefix; private final String path; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideBuyerServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideBuyerServiceImplTest.java new file mode 100644 index 0000000000..6fd3dda3f0 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideBuyerServiceImplTest.java @@ -0,0 +1,94 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.test.ApiTestModule; +import me.chanjar.weixin.mp.bean.guide.*; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ + +@Guice(modules = ApiTestModule.class) +public class WxMpGuideBuyerServiceImplTest { + @Inject + protected WxMpService wxService; + + /** + * 顾问微信号 guide_account + */ + private static final String ACCOUNT = "sxc_Warm"; + + @Test + public void testAddGuideBuyerRelation() throws WxErrorException { + List list = new ArrayList<>(); + list.add(WxMpAddGuideBuyerInfo.builder().nickname("小执花").openid("oqlk8v0uTJgRnn5eEskNruD4-bc8").build()); + List wxMpGuideBuyerResps = this.wxService.getGuideBuyerService().addGuideBuyerRelation(ACCOUNT, null, list); + assertThat(wxMpGuideBuyerResps).isNotNull(); + } + + @Test + public void testAddGuideBuyerRelationOnce() throws WxErrorException { + this.wxService.getGuideBuyerService().addGuideBuyerRelation(ACCOUNT, null, "oqlk8v0uTJgRnn5eEskNruD4-bc8", "小执花"); + } + + @Test + public void testDelGuideBuyerRelation() throws WxErrorException { + List list = new ArrayList<>(); + list.add("oqlk8v0uTJgRnn5eEskNruD4-bc8"); + List wxMpGuideBuyerResps = this.wxService.getGuideBuyerService().delGuideBuyerRelation(ACCOUNT, null, list); + assertThat(wxMpGuideBuyerResps).isNotNull(); + } + + @Test + public void testDelGuideBuyerRelationOnce() throws WxErrorException { + this.wxService.getGuideBuyerService().delGuideBuyerRelation(ACCOUNT, null, "oqlk8v0uTJgRnn5eEskNruD4-bc8"); + } + + @Test + public void testGetGuideBuyerRelationList() throws WxErrorException { + WxMpGuideBuyerInfoList list = this.wxService.getGuideBuyerService().getGuideBuyerRelationList(ACCOUNT, null, 0, 10); + assertThat(list).isNotNull(); + } + + @Test + public void testRebindGuideAcctForBuyer() throws WxErrorException { + List list = new ArrayList<>(); + list.add("oqlk8v0uTJgRnn5eEskNruD4-bc8"); + list.add("oqlk8vybPMWapMwOfFTFVYqWpGM0"); + List enemytriplekill = this.wxService.getGuideBuyerService().rebindGuideAcctForBuyer(ACCOUNT, null, "enemytriplekill", null, list); + assertThat(enemytriplekill).isNotNull(); + } + + @Test + public void testRebindGuideAcctForBuyerOnce() throws WxErrorException { + this.wxService.getGuideBuyerService().rebindGuideAcctForBuyer(ACCOUNT, null, "enemytriplekill", null, "oqlk8v0uTJgRnn5eEskNruD4-bc8"); + } + + @Test + public void testUpdateGuideBuyerRelation() throws WxErrorException { + this.wxService.getGuideBuyerService().updateGuideBuyerRelation(ACCOUNT, null, "oqlk8v0uTJgRnn5eEskNruD4-bc8", "微信文档有坑"); + } + + @Test + public void testGetGuideBuyerRelationByBuyer() throws WxErrorException { + WxMpGuideBuyerRelation guideBuyerRelationByBuyer = this.wxService.getGuideBuyerService().getGuideBuyerRelationByBuyer("oqlk8v0uTJgRnn5eEskNruD4-bc8"); + assertThat(guideBuyerRelationByBuyer).isNotNull(); + } + + @Test + public void testGetGuideBuyerRelation() throws WxErrorException { + WxMpGuideBuyerInfo guideBuyerRelation = this.wxService.getGuideBuyerService().getGuideBuyerRelation(ACCOUNT, null, "oqlk8v0uTJgRnn5eEskNruD4-bc8"); + assertThat(guideBuyerRelation).isNotNull(); + } + +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMassedJobServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMassedJobServiceImplTest.java new file mode 100644 index 0000000000..20621a34d4 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMassedJobServiceImplTest.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.test.ApiTestModule; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideMassed; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideMassedInfo; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideMaterialInfo; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ + +@Guice(modules = ApiTestModule.class) +public class WxMpGuideMassedJobServiceImplTest { + @Inject + protected WxMpService wxService; + + /** + * 顾问微信号 guide_account + */ + private static final String ACCOUNT = "sxc_Warm"; + + @Test + public void testAddGuideMassedJob() throws WxErrorException { + List userOpenId = new ArrayList<>(); + userOpenId.add("oqlk8v0uTJgRnn5eEskNruD4-bc8"); + List list = new ArrayList<>(); + list.add(WxMpGuideMaterialInfo.builder().type(1).word("文字素材测试").build()); + list.add(WxMpGuideMaterialInfo.builder().type(3).mediaId("qDrCfXeDorLgy83d8h6VzVip9s6omPXF_2ILuoke1j0sY4bSFVaA8lkGzUaznU9e").build()); //图片素材 + list.add(WxMpGuideMaterialInfo.builder().type(49).mediaId("qDrCfXeDorLgy83d8h6VzVip9s6omPXF_2ILuoke1j0sY4bSFVaA8lkGzUaznU9e").title("小程序标题").path("pages/login-type/index.html").appId("wx4f793c04fd3be5a8").build()); //图片素材 + WxMpGuideMassed wxMpGuideMassed = this.wxService.getGuideMassedJobService().addGuideMassedJob(ACCOUNT, null, "群发任务", "群发任务备注", System.currentTimeMillis() / 1000, userOpenId, list); + assertThat(wxMpGuideMassed).isNotNull(); + } + + @Test + public void testGetGuideMassedJobList() throws WxErrorException { + List guideMassedJobList = this.wxService.getGuideMassedJobService().getGuideMassedJobList(ACCOUNT, null, null, null, null); + assertThat(guideMassedJobList).isNotNull(); + } + + @Test + public void testGetGuideMassedJob() throws WxErrorException { + WxMpGuideMassedInfo guideMassedJob = this.wxService.getGuideMassedJobService().getGuideMassedJob("1867407932930228228"); + assertThat(guideMassedJob).isNotNull(); + } + + @Test + public void testUpdateGuideMassedJob() throws WxErrorException { + this.wxService.getGuideMassedJobService().updateGuideMassedJob("1867407932930228228", "修改群发任务", null, null, null, null); + } + + @Test + public void testCancelGuideMassedJob() throws WxErrorException { + this.wxService.getGuideMassedJobService().cancelGuideMassedJob("1867407932930228228"); + } +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMaterialServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMaterialServiceImplTest.java new file mode 100644 index 0000000000..f1ffe8f9ff --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideMaterialServiceImplTest.java @@ -0,0 +1,87 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.test.ApiTestModule; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideCardMaterialInfo; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideImgMaterialInfoList; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideWordMaterialInfoList; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.io.File; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ + +@Guice(modules = ApiTestModule.class) +public class WxMpGuideMaterialServiceImplTest { + @Inject + protected WxMpService wxService; + + /** + * 图片路径 + */ + private static final String IMG_URL = "C:\\Users\\Administrator\\Desktop\\imgText.png"; + + + @Test + public void testSetGuideCardMaterial() throws WxErrorException { + WxMediaUploadResult wxMediaUploadResult = this.wxService.getMaterialService() + .mediaUpload(WxConsts.MediaFileType.IMAGE, new File(IMG_URL)); + this.wxService.getGuideMaterialService().setGuideCardMaterial(wxMediaUploadResult.getMediaId(), 0, "小程序素材标题", "pages/login-type/index.html", "wx4f793c04fd3be5a8"); + } + + @Test + public void testGetGuideCardMaterial() throws WxErrorException { + List guideCardMaterial = this.wxService.getGuideMaterialService().getGuideCardMaterial(0); + assertThat(guideCardMaterial).isNotNull(); + } + + @Test + public void testDelGuideCardMaterial() throws WxErrorException { + this.wxService.getGuideMaterialService().delGuideCardMaterial(0, "小程序素材标题", "pages/login-type/index.html", "wx4f793c04fd3be5a8"); + } + + @Test + public void testSetGuideImageMaterial() throws WxErrorException { + WxMediaUploadResult wxMediaUploadResult = this.wxService.getMaterialService() + .mediaUpload(WxConsts.MediaFileType.IMAGE, new File(IMG_URL)); + this.wxService.getGuideMaterialService().setGuideImageMaterial(wxMediaUploadResult.getMediaId(), 0); + } + + @Test + public void testGetGuideImageMaterial() throws WxErrorException { + WxMpGuideImgMaterialInfoList guideImageMaterial = this.wxService.getGuideMaterialService().getGuideImageMaterial(0, 0, 20); + assertThat(guideImageMaterial).isNotNull(); + } + + @Test + public void testDelGuideImageMaterial() throws WxErrorException { + this.wxService.getGuideMaterialService().delGuideImageMaterial(0, "http://mmbiz.qpic.cn/mmbiz_png/63bwCoCgX0neicbffKiaL4vqXAUChYwE1VO0ZG5b6SW3Shv7kR1ia46b3gS8zf78piaR7vk7I6MRqbVzibJVJoNtkEg/0"); + } + + @Test + public void testSetGuideWordMaterial() throws WxErrorException { + this.wxService.getGuideMaterialService().setGuideWordMaterial(0, "文字素材测试"); + } + + @Test + public void testGetGuideWordMaterial() throws WxErrorException { + WxMpGuideWordMaterialInfoList guideWordMaterial = this.wxService.getGuideMaterialService().getGuideWordMaterial(0, 0, 20); + assertThat(guideWordMaterial).isNotNull(); + } + + @Test + public void testDelGuideWordMaterial() throws WxErrorException { + this.wxService.getGuideMaterialService().delGuideWordMaterial(0, "文字素材测试"); + } +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImplTest.java index 5742191f91..13ec80c168 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImplTest.java @@ -4,11 +4,13 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.test.ApiTestModule; -import me.chanjar.weixin.mp.bean.guide.WxMpGuideInfo; -import me.chanjar.weixin.mp.bean.guide.WxMpGuideList; +import me.chanjar.weixin.mp.bean.guide.*; import org.testng.annotations.Guice; import org.testng.annotations.Test; +import java.util.ArrayList; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -22,30 +24,35 @@ public class WxMpGuideServiceImplTest { @Inject protected WxMpService wxService; + /** + * 顾问微信号 guide_account + */ + private static final String ACCOUNT = "sxc_Warm"; + @Test public void testAddGuide() throws WxErrorException { - this.wxService.getGuideService().addGuide("wx1java", "", null, null); + this.wxService.getGuideService().addGuide(ACCOUNT, "", null, null); } @Test public void testAddGuide_another() throws WxErrorException { - this.wxService.getGuideService().addGuide(WxMpGuideInfo.builder().account("wx1java").build()); + this.wxService.getGuideService().addGuide(WxMpGuideInfo.builder().account(ACCOUNT).build()); } @Test public void testGetGuide() throws WxErrorException { - final WxMpGuideInfo guideInfo = this.wxService.getGuideService().getGuide("wx1java", null); + final WxMpGuideInfo guideInfo = this.wxService.getGuideService().getGuide(ACCOUNT, null); assertThat(guideInfo).isNotNull(); } @Test public void testUpdateGuide() throws WxErrorException { - this.wxService.getGuideService().updateGuide(WxMpGuideInfo.builder().account("wx1java").nickName("我是谁").build()); + this.wxService.getGuideService().updateGuide(WxMpGuideInfo.builder().account(ACCOUNT).nickName("我是谁").build()); } @Test public void testDelGuide() throws WxErrorException { - this.wxService.getGuideService().delGuide("wx1java", null); + this.wxService.getGuideService().delGuide(ACCOUNT, null); } @Test @@ -53,4 +60,92 @@ public void testListGuide() throws WxErrorException { final WxMpGuideList guideList = this.wxService.getGuideService().listGuide(0, 10); assertThat(guideList).isNotNull(); } + + @Test + public void testCreateGuideQrCode() throws WxErrorException { + String guideQrCode = this.wxService.getGuideService().createGuideQrCode(ACCOUNT, null, null); + assertThat(guideQrCode).isNotNull(); + } + + @Test + public void testGetGuideChatRecord() throws WxErrorException { + final WxMpGuideMsgList guideChatRecord = this.wxService.getGuideService().getGuideChatRecord(ACCOUNT, null, null, null, null, 0, 10); + assertThat(guideChatRecord).isNotNull(); + } + + @Test + public void testSetGuideConfig() throws WxErrorException { + List list = new ArrayList<>(); + list.add("自动回复设置" + ACCOUNT); + list.add("自动回复设置" + ACCOUNT); + + this.wxService.getGuideService().setGuideConfig(null, null, true, list, + WxMpAddGuideAutoReply.builder().content("欢迎测试1").msgType(1).build(), + WxMpAddGuideAutoReply.builder().content("欢迎测试2").msgType(1).build()); + } + + @Test + public void testGetGuideConfig() throws WxErrorException { + final WxMpGuideConfig guideConfig = this.wxService.getGuideService().getGuideConfig(ACCOUNT, null); + assertThat(guideConfig).isNotNull(); + } + + @Test + public void testSetGuideAcctConfig() throws WxErrorException { + List list = new ArrayList<>(); + list.add("敏感词1"); + list.add("敏感词2"); + this.wxService.getGuideService().setGuideAcctConfig(false, list, "离线自动回复"); + } + + @Test + public void testGetGuideAcctConfig() throws WxErrorException { + final WxMpGuideAcctConfig guideAcctConfig = this.wxService.getGuideService().getGuideAcctConfig(); + assertThat(guideAcctConfig).isNotNull(); + } + + @Test + public void testPushShowWxaPathMenu() throws WxErrorException { + this.wxService.getGuideService().pushShowWxaPathMenu("wx4f793c04fd3be5a8", ACCOUNT); + } + + @Test + public void testNewGuideGroup() throws WxErrorException { + Long id = this.wxService.getGuideService().newGuideGroup("顾问分组名称"); + assertThat(id).isNotNull(); + } + + @Test + public void testGetGuideGroup() throws WxErrorException { + List guideGroupList = this.wxService.getGuideService().getGuideGroupList(); + assertThat(guideGroupList).isNotNull(); + } + + @Test + public void testGetGroupInfo() throws WxErrorException { + WxMpGuideGroupInfoList groupInfo = this.wxService.getGuideService().getGroupInfo(1860131524965138433L, 0, 10); + assertThat(groupInfo).isNotNull(); + } + + @Test + public void testAddGuide2GuideGroup() throws WxErrorException { + this.wxService.getGuideService().addGuide2GuideGroup(1860131524965138433L, ACCOUNT); + } + + @Test + public void testDelGuide2GuideGroup() throws WxErrorException { + this.wxService.getGuideService().delGuide2GuideGroup(1860131524965138433L, ACCOUNT); + } + + @Test + public void testGetGroupByGuide() throws WxErrorException { + List groupByGuide = this.wxService.getGuideService().getGroupByGuide(ACCOUNT); + assertThat(groupByGuide).isNotNull(); + } + + @Test + public void testDelGuideGroup() throws WxErrorException { + this.wxService.getGuideService().delGuideGroup(1860131524965138433L); + } } + diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImplTest.java new file mode 100644 index 0000000000..6ba2fae1ff --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImplTest.java @@ -0,0 +1,115 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.test.ApiTestModule; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideBuyerResp; +import me.chanjar.weixin.mp.bean.guide.WxMpGuideTagInfo; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author 广州跨界-宋心成 + * @date 2021/5/13/013 + */ + +@Guice(modules = ApiTestModule.class) +public class WxMpGuideTagServiceImplTest { + @Inject + protected WxMpService wxService; + + /** + * 顾问微信号 guide_account + */ + private static final String ACCOUNT = "sxc_Warm"; + + @Test + public void testNewGuideTagOption() throws WxErrorException { + List list = new ArrayList<>(); + list.add("分类一"); + list.add("分类二"); + list.add("分类三"); + this.wxService.getGuideTagService().newGuideTagOption("A组", list); + } + + @Test + public void testDelGuideTagOption() throws WxErrorException { + this.wxService.getGuideTagService().delGuideTagOption("A组"); + } + + @Test + public void testAddGuideTagOption() throws WxErrorException { + List list = new ArrayList<>(); + list.add("分类四"); + this.wxService.getGuideTagService().addGuideTagOption("A组", list); + } + + @Test + public void testGetGuideTagOption() throws WxErrorException { + List guideTagOption = this.wxService.getGuideTagService().getGuideTagOption(); + assertThat(guideTagOption).isNotNull(); + } + + @Test + public void testAddGuideBuyerTag() throws WxErrorException { + List list = new ArrayList<>(); + list.add("oqlk8v0uTJgRnn5eEskNruD4-bc8"); + list.add("oqlk8vybPMWapMwOfFTFVYqWpGM0"); + List wxMpGuideBuyerResps = this.wxService.getGuideTagService().addGuideBuyerTag(ACCOUNT, null, "分类一", list); + assertThat(wxMpGuideBuyerResps).isNotNull(); + } + + @Test + public void testAddGuideBuyerTagOnce() throws WxErrorException { + this.wxService.getGuideTagService().addGuideBuyerTag(ACCOUNT, null, "分类二", "oqlk8v0uTJgRnn5eEskNruD4-bc8"); + } + + @Test + public void testGetGuideBuyerTag() throws WxErrorException { + List guideBuyerTag = this.wxService.getGuideTagService().getGuideBuyerTag(ACCOUNT, null, "oqlk8v0uTJgRnn5eEskNruD4-bc8", true); + assertThat(guideBuyerTag).isNotNull(); + } + + @Test + public void testQueryGuideBuyerByTag() throws WxErrorException { + List list = new ArrayList<>(); + list.add("分类一"); + List list1 = this.wxService.getGuideTagService().queryGuideBuyerByTag(ACCOUNT, null, 0, list); + assertThat(list1).isNotNull(); + } + + @Test + public void testdelGuideBuyerTag() throws WxErrorException { + List list = new ArrayList<>(); + list.add("oqlk8v0uTJgRnn5eEskNruD4-bc8"); + list.add("oqlk8vybPMWapMwOfFTFVYqWpGM0"); + List respList = this.wxService.getGuideTagService().delGuideBuyerTag(ACCOUNT, null, "分类一", list); + assertThat(respList).isNotNull(); + } + + @Test + public void testDelGuideBuyerTagOnce() throws WxErrorException { + this.wxService.getGuideTagService().delGuideBuyerTag(ACCOUNT, null, "分类一", "oqlk8v0uTJgRnn5eEskNruD4-bc8"); + } + + @Test + public void testAddGuideBuyerDisplayTag() throws WxErrorException { + List list = new ArrayList<>(); + list.add("自定义信息1"); + list.add("自定义信息2"); + this.wxService.getGuideTagService().addGuideBuyerDisplayTag(ACCOUNT, null, "oqlk8v0uTJgRnn5eEskNruD4-bc8", list); + } + + @Test + public void testGetGuideBuyerDisplayTag() throws WxErrorException { + List list = this.wxService.getGuideTagService().getGuideBuyerDisplayTag(ACCOUNT, null, "oqlk8v0uTJgRnn5eEskNruD4-bc8"); + assertThat(list).isNotNull(); + } + +} From aec9387e2fcf11dfce17a6dab21e9c7f9c3b2b29 Mon Sep 17 00:00:00 2001 From: zpf <178668028@qq.com> Date: Mon, 17 May 2021 10:45:59 +0800 Subject: [PATCH 02/17] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=85=AC=E4=BC=97?= =?UTF-8?q?=E5=8F=B7=E3=80=81=E5=B0=8F=E7=A8=8B=E5=BA=8F=E3=80=81=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1=E7=9A=84access=20token=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=88=B7=E6=96=B0=E9=80=BB=E8=BE=91=EF=BC=8C=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E9=81=BF=E5=85=8D=E5=BD=93=E4=BD=BF=E7=94=A8secrete?= =?UTF-8?q?=E8=AF=AF=E8=B0=83=E7=94=A8=E7=AC=AC=E4=B8=89=E6=96=B9=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E4=B8=93=E5=B1=9E=E6=8E=A5=E5=8F=A3=E7=9A=84=E6=83=85?= =?UTF-8?q?=E5=86=B5=E4=B8=8B=E5=87=BA=E7=8E=B0=E5=BE=AA=E7=8E=AF=E9=80=92?= =?UTF-8?q?=E5=BD=92=E8=B0=83=E7=94=A8=E7=94=9A=E8=87=B3=E8=A2=AB=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E9=99=90=E5=88=B6qps=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cp/api/impl/BaseWxCpServiceImpl.java | 10 ++- .../weixin/cp/api/WxCpBusyRetryTest.java | 2 +- .../cp/api/impl/BaseWxCpServiceImplTest.java | 70 ++++++++++++++++- .../miniapp/api/impl/BaseWxMaServiceImpl.java | 10 ++- .../miniapp/api/impl/WxMaServiceImplTest.java | 40 ++++++++++ .../mp/api/impl/BaseWxMpServiceImpl.java | 10 ++- .../weixin/mp/api/WxMpBusyRetryTest.java | 10 +-- .../mp/api/impl/BaseWxMpServiceImplTest.java | 76 ++++++++++++++++--- 8 files changed, 200 insertions(+), 28 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java index 65ba5dce51..8c70178213 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java @@ -241,7 +241,7 @@ public T execute(RequestExecutor executor, String uri, E data) thro int retryTimes = 0; do { try { - return this.executeInternal(executor, uri, data); + return this.executeInternal(executor, uri, data, false); } catch (WxErrorException e) { if (retryTimes + 1 > this.maxRetryTimes) { log.warn("重试达到最大次数【{}】", this.maxRetryTimes); @@ -271,7 +271,7 @@ public T execute(RequestExecutor executor, String uri, E data) thro throw new WxRuntimeException("微信服务端异常,超出重试次数"); } - protected T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + protected T executeInternal(RequestExecutor executor, String uri, E data, boolean doNotAutoRefresh) throws WxErrorException { E dataForLog = DataUtils.handleDataWithSecret(data); if (uri.contains("access_token=")) { @@ -291,9 +291,11 @@ protected T executeInternal(RequestExecutor executor, String uri, E if (WxConsts.ACCESS_TOKEN_ERROR_CODES.contains(error.getErrorCode())) { // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token this.configStorage.expireAccessToken(); - if (this.getWxCpConfigStorage().autoRefreshToken()) { + if (this.getWxCpConfigStorage().autoRefreshToken() && !doNotAutoRefresh) { log.warn("即将重新获取新的access_token,错误代码:{},错误信息:{}", error.getErrorCode(), error.getErrorMsg()); - return this.execute(executor, uri, data); + //下一次不再自动重试 + //当小程序误调用第三方平台专属接口时,第三方无法使用小程序的access token,如果可以继续自动获取token会导致无限循环重试,直到栈溢出 + return this.executeInternal(executor, uri, data, true); } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java index b8a72add12..34d4065dcf 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java @@ -22,7 +22,7 @@ public Object[][] getService() { @Override public synchronized T executeInternal( - RequestExecutor executor, String uri, E data) + RequestExecutor executor, String uri, E data, boolean doNotAutoRefresh) throws WxErrorException { log.info("Executed"); throw new WxErrorException("something"); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java index 22cee8f405..739470a2d7 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java @@ -1,13 +1,26 @@ package me.chanjar.weixin.cp.api.impl; import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.error.WxMpErrorMsgEnum; +import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.cp.api.ApiTestModule; import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl; +import org.mockito.Mockito; +import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; +import java.io.IOException; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicInteger; + import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; /** *
@@ -35,6 +48,61 @@ public void testJsCode2Session() throws WxErrorException {
 
   @Test
   public void testGetProviderToken() throws WxErrorException {
-    assertThat(this.wxService.getProviderToken("111","123")).isNotNull();
+    assertThat(this.wxService.getProviderToken("111", "123")).isNotNull();
+  }
+
+
+  @Test
+  public void testExecuteAutoRefreshToken() throws WxErrorException, IOException {
+    //测试access token获取时的重试机制
+    WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl();
+    BaseWxCpServiceImpl service = new BaseWxCpServiceImpl() {
+      @Override
+      public Object getRequestHttpClient() {
+        return null;
+      }
+
+      @Override
+      public Object getRequestHttpProxy() {
+        return null;
+      }
+
+      @Override
+      public HttpType getRequestType() {
+        return null;
+      }
+
+      @Override
+      public String getAccessToken(boolean forceRefresh) throws WxErrorException {
+        return "模拟一个过期的access token:" + System.currentTimeMillis();
+      }
+
+      @Override
+      public void initHttp() {
+
+      }
+
+      @Override
+      public WxCpConfigStorage getWxCpConfigStorage() {
+        return config;
+      }
+    };
+    config.setAgentId(1);
+    service.setWxCpConfigStorage(config);
+    RequestExecutor re = mock(RequestExecutor.class);
+
+    AtomicInteger counter = new AtomicInteger();
+    Mockito.when(re.execute(Mockito.anyString(), Mockito.any(), Mockito.any())).thenAnswer(invocation -> {
+      counter.incrementAndGet();
+      WxError error = WxError.builder().errorCode(WxMpErrorMsgEnum.CODE_40001.getCode()).errorMsg(WxMpErrorMsgEnum.CODE_40001.getMsg()).build();
+      throw new WxErrorException(error);
+    });
+    try {
+      Object execute = service.execute(re, "http://baidu.com", new HashMap<>());
+      Assert.assertTrue(false, "代码应该不会执行到这里");
+    } catch (WxErrorException e) {
+      Assert.assertEquals(WxMpErrorMsgEnum.CODE_40001.getCode(), e.getError().getErrorCode());
+      Assert.assertEquals(2, counter.get());
+    }
   }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
index 7d0d96da95..241d0b37f1 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
@@ -207,7 +207,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
     int retryTimes = 0;
     do {
       try {
-        return this.executeInternal(executor, uri, data);
+        return this.executeInternal(executor, uri, data, false);
       } catch (WxErrorException e) {
         if (retryTimes + 1 > this.maxRetryTimes) {
           log.warn("重试达到最大次数【{}】", maxRetryTimes);
@@ -238,7 +238,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
     throw new WxRuntimeException("微信服务端异常,超出重试次数");
   }
 
-  private  T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
+  private  T executeInternal(RequestExecutor executor, String uri, E data, boolean doNotAutoRefreshToken) throws WxErrorException {
     E dataForLog = DataUtils.handleDataWithSecret(data);
 
     if (uri.contains("access_token=")) {
@@ -271,9 +271,11 @@ private  T executeInternal(RequestExecutor executor, String uri, E d
         } finally {
           lock.unlock();
         }
-        if (this.getWxMaConfig().autoRefreshToken()) {
+        if (this.getWxMaConfig().autoRefreshToken() && !doNotAutoRefreshToken) {
           log.warn("即将重新获取新的access_token,错误代码:{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
-          return this.execute(executor, uri, data);
+          //下一次不再自动重试
+          //当小程序误调用第三方平台专属接口时,第三方无法使用小程序的access token,如果可以继续自动获取token会导致无限循环重试,直到栈溢出
+          return this.executeInternal(executor, uri, data, true);
         }
       }
 
diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java
index 4e0a886f74..73343d8e4e 100644
--- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java
+++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java
@@ -2,14 +2,25 @@
 
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
 import cn.binarywang.wx.miniapp.test.ApiTestModule;
 import com.google.inject.Inject;
+import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxMpErrorMsgEnum;
+import me.chanjar.weixin.common.util.http.RequestExecutor;
 import org.apache.commons.lang3.StringUtils;
+import org.mockito.Mockito;
+import org.testng.Assert;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
 import static org.testng.Assert.assertNotEquals;
 import static org.testng.Assert.assertTrue;
 
@@ -101,6 +112,35 @@ public void testGet() {
   public void testExecute() {
   }
 
+  @Test
+  public void testExecuteAutoRefreshToken() throws WxErrorException, IOException {
+    //测试access token获取时的重试机制
+    WxMaServiceImpl service = new WxMaServiceImpl() {
+      @Override
+      public String getAccessToken(boolean forceRefresh) throws WxErrorException {
+        return "模拟一个过期的access token:" + System.currentTimeMillis();
+      }
+    };
+    WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
+    config.setAppid("1");
+    service.setWxMaConfig(config);
+    RequestExecutor re = mock(RequestExecutor.class);
+
+    AtomicInteger counter = new AtomicInteger();
+    Mockito.when(re.execute(Mockito.anyString(), Mockito.any(), Mockito.any())).thenAnswer(invocation -> {
+      counter.incrementAndGet();
+      WxError error = WxError.builder().errorCode(WxMpErrorMsgEnum.CODE_40001.getCode()).errorMsg(WxMpErrorMsgEnum.CODE_40001.getMsg()).build();
+      throw new WxErrorException(error);
+    });
+    try {
+      Object execute = service.execute(re, "http://baidu.com", new HashMap<>());
+      Assert.assertTrue(false, "代码应该不会执行到这里");
+    } catch (WxErrorException e) {
+      Assert.assertEquals(WxMpErrorMsgEnum.CODE_40001.getCode(), e.getError().getErrorCode());
+      Assert.assertEquals(2, counter.get());
+    }
+  }
+
   @Test
   public void testGetWxMaConfig() {
   }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
index d340c6dc4d..828921b1ea 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
@@ -341,7 +341,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
     int retryTimes = 0;
     do {
       try {
-        return this.executeInternal(executor, uri, data);
+        return this.executeInternal(executor, uri, data, false);
       } catch (WxErrorException e) {
         WxError error = e.getError();
         // -1 系统繁忙, 1000ms后重试
@@ -370,7 +370,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
     throw new WxRuntimeException("微信服务端异常,超出重试次数");
   }
 
-  protected  T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
+  protected  T executeInternal(RequestExecutor executor, String uri, E data, boolean doNotAutoRefresh) throws WxErrorException {
     E dataForLog = DataUtils.handleDataWithSecret(data);
 
     if (uri.contains("access_token=")) {
@@ -399,9 +399,11 @@ protected  T executeInternal(RequestExecutor executor, String uri, E
         } finally {
           lock.unlock();
         }
-        if (this.getWxMpConfigStorage().autoRefreshToken()) {
+        if (this.getWxMpConfigStorage().autoRefreshToken() && !doNotAutoRefresh) {
           log.warn("即将重新获取新的access_token,错误代码:{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
-          return this.execute(executor, uri, data);
+          //下一次不再自动重试
+          //当小程序误调用第三方平台专属接口时,第三方无法使用小程序的access token,如果可以继续自动获取token会导致无限循环重试,直到栈溢出
+          return this.executeInternal(executor, uri, data, true);
         }
       }
 
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java
index 938eb5c032..6e29d0c649 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java
@@ -1,12 +1,12 @@
 package me.chanjar.weixin.mp.api;
 
 import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpClientImpl;
-import org.testng.annotations.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -23,7 +23,7 @@ public Object[][] getService() {
 
       @Override
       public synchronized  T executeInternal(
-        RequestExecutor executor, String uri, E data)
+        RequestExecutor executor, String uri, E data, boolean doNotAutoRefresh)
         throws WxErrorException {
         log.info("Executed");
         throw new WxErrorException("something");
@@ -37,7 +37,7 @@ public synchronized  T executeInternal(
 
   @Test(dataProvider = "getService", expectedExceptions = RuntimeException.class)
   public void testRetry(WxMpService service) throws WxErrorException {
-    service.execute(null, (String)null, null);
+    service.execute(null, (String) null, null);
   }
 
   @Test(dataProvider = "getService")
@@ -48,7 +48,7 @@ public void testRetryInThreadPool(final WxMpService service) throws InterruptedE
       try {
         System.out.println("=====================");
         System.out.println(Thread.currentThread().getName() + ": testRetry");
-        service.execute(null, (String)null, null);
+        service.execute(null, (String) null, null);
       } catch (WxErrorException e) {
         throw new WxRuntimeException(e);
       } catch (RuntimeException e) {
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java
index 1bb8922271..c4b57ff13c 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java
@@ -2,27 +2,35 @@
 
 import com.google.common.collect.Sets;
 import com.google.inject.Inject;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.bean.WxJsapiSignature;
 import me.chanjar.weixin.common.bean.WxNetCheckResult;
+import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxMpErrorMsgEnum;
+import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.test.ApiTestModule;
+import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
 import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder;
+import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
+import java.io.IOException;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.testng.Assert.*;
 
 /**
  * 
@@ -93,7 +101,7 @@ public void refreshAccessTokenDuplicatelyTest() throws InterruptedException {
 
     final int threadNumber = 10;
     ExecutorService executorService = Executors.newFixedThreadPool(threadNumber);
-    for ( int i = 0; i < threadNumber; i++ ) {
+    for (int i = 0; i < threadNumber; i++) {
       executorService.submit(r);
     }
     executorService.shutdown();
@@ -190,7 +198,57 @@ public void testTestPost() {
   }
 
   @Test
-  public void testExecute() {
+  public void testExecute() throws WxErrorException, IOException {
+
+  }
+
+  @Test
+  public void testExecuteAutoRefreshToken() throws WxErrorException, IOException {
+    //测试access token获取时的重试机制
+    BaseWxMpServiceImpl service = new BaseWxMpServiceImpl() {
+      @Override
+      public String getAccessToken(boolean forceRefresh) throws WxErrorException {
+        return "模拟一个过期的access token:" + System.currentTimeMillis();
+      }
+
+      @Override
+      public void initHttp() {
+
+      }
+
+      @Override
+      public Object getRequestHttpClient() {
+        return null;
+      }
+
+      @Override
+      public Object getRequestHttpProxy() {
+        return null;
+      }
+
+      @Override
+      public HttpType getRequestType() {
+        return null;
+      }
+    };
+    WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl();
+    config.setAppId("1");
+    service.setWxMpConfigStorage(config);
+    RequestExecutor re = mock(RequestExecutor.class);
+
+    AtomicInteger counter = new AtomicInteger();
+    Mockito.when(re.execute(Mockito.anyString(), Mockito.any(), Mockito.any())).thenAnswer(invocation -> {
+      counter.incrementAndGet();
+      WxError error = WxError.builder().errorCode(WxMpErrorMsgEnum.CODE_40001.getCode()).errorMsg(WxMpErrorMsgEnum.CODE_40001.getMsg()).build();
+      throw new WxErrorException(error);
+    });
+    try {
+      Object execute = service.execute(re, "http://baidu.com", new HashMap<>());
+      Assert.assertTrue(false, "代码应该不会执行到这里");
+    } catch (WxErrorException e) {
+      Assert.assertEquals(WxMpErrorMsgEnum.CODE_40001.getCode(), e.getError().getErrorCode());
+      Assert.assertEquals(2, counter.get());
+    }
   }
 
   @Test

From edc935a9ffbf6a99d73c607b345ef6583725535e Mon Sep 17 00:00:00 2001
From: zpf <178668028@qq.com>
Date: Fri, 21 May 2021 15:33:35 +0800
Subject: [PATCH 03/17] =?UTF-8?q?1.=E4=BF=AE=E5=A4=8D=E5=85=AC=E4=BC=97?=
 =?UTF-8?q?=E5=8F=B7=E5=9C=A8=E7=94=B1=E7=AC=AC=E4=B8=89=E6=96=B9=E5=B9=B3?=
 =?UTF-8?q?=E5=8F=B0=E7=AE=A1=E7=90=86=E6=97=B6OAuth2Service=E6=8E=88?=
 =?UTF-8?q?=E6=9D=83=E7=9B=B8=E5=85=B3=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?=
 =?UTF-8?q?=202.=E4=BF=AE=E5=A4=8D=E5=85=AC=E4=BC=97=E5=8F=B7=E5=AF=B9?=
 =?UTF-8?q?=E8=AF=9D=E8=83=BD=E5=8A=9B=E6=9F=A5=E8=AF=A2=E6=A0=87=E7=AD=BE?=
 =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=8F=82=E6=95=B0=E9=94=99=E8=AF=AF=203.?=
 =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E5=B9=B3=E5=8F=B0=E5=A2=9E=E5=8A=A0?=
 =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=E4=BE=9D=E8=B5=96=E6=B3=A8?=
 =?UTF-8?q?=E5=85=A5=E7=9B=B8=E5=85=B3=E7=B1=BB=E5=92=8C=E7=9B=B8=E5=85=B3?=
 =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=A4=BA=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../common/service/WxOAuth2Service.java       |  4 +-
 .../service/WxOAuth2ServiceDecorator.java     | 16 +++++
 .../weixin/mp/api/WxMpGuideTagService.java    |  2 +
 .../mp/api/impl/WxMpGuideTagServiceImpl.java  |  2 +-
 .../open/api/WxOpenComponentService.java      |  9 ++-
 .../api/impl/WxOpenMpOAuth2ServiceImpl.java   | 61 ++++++++++++++++++
 .../open/api/impl/WxOpenMpServiceImpl.java    |  3 +-
 .../impl/WxOpenMpOAuth2ServiceImplTest.java   | 29 +++++++++
 .../weixin/open/test/ApiTestModule.java       | 64 +++++++++++++++++++
 .../weixin/open/test/TestConfigStorage.java   | 16 +++++
 .../src/test/resources/test-config.sample.xml |  5 +-
 11 files changed, 205 insertions(+), 6 deletions(-)
 create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOAuth2ServiceDecorator.java
 create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpOAuth2ServiceImpl.java
 create mode 100644 weixin-java-open/src/test/java/me/chanjar/weixin/open/api/impl/WxOpenMpOAuth2ServiceImplTest.java
 create mode 100644 weixin-java-open/src/test/java/me/chanjar/weixin/open/test/ApiTestModule.java
 create mode 100644 weixin-java-open/src/test/java/me/chanjar/weixin/open/test/TestConfigStorage.java

diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOAuth2Service.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOAuth2Service.java
index 97a74d2c68..5a53de010f 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOAuth2Service.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOAuth2Service.java
@@ -14,11 +14,11 @@ public interface WxOAuth2Service {
   /**
    * 
    * 构造oauth2授权的url连接.
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
+   * 详情请见: https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
    * 
* * @param redirectUri 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode - * @param scope scope + * @param scope scope,静默:snsapi_base, 带信息授权:snsapi_userinfo * @param state state * @return url */ diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOAuth2ServiceDecorator.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOAuth2ServiceDecorator.java new file mode 100644 index 0000000000..a495dbf828 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOAuth2ServiceDecorator.java @@ -0,0 +1,16 @@ +package me.chanjar.weixin.common.service; + +import lombok.AllArgsConstructor; +import lombok.experimental.Delegate; + +/** + * 微信 oauth2服务 装饰器 + * + * @author 广州跨界 + */ +@AllArgsConstructor +public class WxOAuth2ServiceDecorator implements WxOAuth2Service { + + @Delegate + private final WxOAuth2Service wxOAuth2Service; +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideTagService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideTagService.java index 554815b701..b2bb76d787 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideTagService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGuideTagService.java @@ -7,6 +7,8 @@ import java.util.List; /** + * 微信导购助手(现在叫对话能力)标签相关接口. + * * @author 广州跨界-宋心成 * @date 2021/5/13/013 */ diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java index 1bde21e9b2..2747cbdae7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java @@ -106,7 +106,7 @@ public List queryGuideBuyerByTag(String account, String openid, Integer body.put(ACCOUNT, account); body.put(OPENID, openid); body.put("push_count", pushCount); - body.put("tag_value", value); + body.put("tag_values", value); String returnString = this.mpService.post(WxMpApiUrl.Guide.QUERY_GUIDE_BUYER_BY_TAG, body); return WxGsonBuilder.create().fromJson(GsonParser.parse(returnString).getAsJsonArray("openid_list"), new TypeToken>() { diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java index b0faef7a69..26dc2ba7f2 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java @@ -1,8 +1,9 @@ package me.chanjar.weixin.open.api; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; -import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.open.bean.WxOpenCreateResult; import me.chanjar.weixin.open.bean.WxOpenGetResult; import me.chanjar.weixin.open.bean.WxOpenMaCodeTemplate; @@ -330,7 +331,10 @@ public interface WxOpenComponentService { * @param code the code * @return the wx mp o auth 2 access token * @throws WxErrorException the wx error exception + * @see WxMpService#getOAuth2Service() + * @deprecated 2021-05-21: 已修正公众号相关接口,请使用:WxOpenCommpentService.getWxMpServiceByAppid(mpAppId).getOAuth2Service().getAccessToken(code) */ + @Deprecated WxOAuth2AccessToken oauth2getAccessToken(String appid, String code) throws WxErrorException; /** @@ -362,7 +366,10 @@ public interface WxOpenComponentService { * @param scope the scope * @param state the state * @return the string + * @see WxMpService#getOAuth2Service() + * @deprecated 2021-05-21: 已修正公众号相关接口,请使用:WxOpenCommpentService.getWxMpServiceByAppid(mpAppId).getOAuth2Service().buildAuthorizationUrl(redirectUri, scope, state) */ + @Deprecated String oauth2buildAuthorizationUrl(String appid, String redirectUri, String scope, String state); /** diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpOAuth2ServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpOAuth2ServiceImpl.java new file mode 100644 index 0000000000..406e363481 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpOAuth2ServiceImpl.java @@ -0,0 +1,61 @@ +package me.chanjar.weixin.open.api.impl; + +import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.service.WxOAuth2Service; +import me.chanjar.weixin.common.service.WxOAuth2ServiceDecorator; +import me.chanjar.weixin.common.util.http.URIUtil; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; +import me.chanjar.weixin.open.api.WxOpenComponentService; +import org.apache.commons.lang3.StringUtils; + +/** + * 微信 第三方平台对于公众号 oauth2 的实现类 + * + * @author 广州跨界 + */ +public class WxOpenMpOAuth2ServiceImpl extends WxOAuth2ServiceDecorator { + + private final WxOpenComponentService wxOpenComponentService; + private final WxMpConfigStorage wxMpConfigStorage; + + + public WxOpenMpOAuth2ServiceImpl(WxOpenComponentService wxOpenComponentService, WxOAuth2Service wxOAuth2Service, WxMpConfigStorage wxMpConfigStorage) { + super(wxOAuth2Service); + this.wxOpenComponentService = wxOpenComponentService; + this.wxMpConfigStorage = wxMpConfigStorage; + } + + /** + * 第三方平台代公众号发起网页授权 + * 文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/Before_Develop/Official_Accounts/official_account_website_authorization.html + * + * @param code 微信授权code + * @return 微信用户信息 + * @throws WxErrorException 如果微信接口调用失败将抛出此异常 + */ + @Override + public WxOAuth2AccessToken getAccessToken(String code) throws WxErrorException { + String url = String.format( + WxOpenComponentService.OAUTH2_ACCESS_TOKEN_URL, + wxMpConfigStorage.getAppId(), + code, + wxOpenComponentService.getWxOpenConfigStorage().getComponentAppId() + ); + String responseContent = wxOpenComponentService.get(url); + return WxOAuth2AccessToken.fromJson(responseContent); + } + + @Override + public String buildAuthorizationUrl(String redirectUri, String scope, String state) { + return String.format( + WxOpenComponentService.CONNECT_OAUTH2_AUTHORIZE_URL, + wxMpConfigStorage.getAppId(), + URIUtil.encodeURIComponent(redirectUri), + scope, + StringUtils.trimToEmpty(state), + wxOpenComponentService.getWxOpenConfigStorage().getComponentAppId() + ); + } +} + diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java index 19e103fa24..8e55311536 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java @@ -10,7 +10,6 @@ import me.chanjar.weixin.open.bean.mp.FastRegisterResult; import java.net.URLEncoder; -import java.util.HashMap; import java.util.Objects; /** @@ -22,9 +21,11 @@ public class WxOpenMpServiceImpl extends WxMpServiceImpl implements WxOpenMpServ private String appId; public WxOpenMpServiceImpl(WxOpenComponentService wxOpenComponentService, String appId, WxMpConfigStorage wxMpConfigStorage) { +// wxOpenComponentService.oauth2getAccessToken(appId) this.wxOpenComponentService = wxOpenComponentService; this.appId = appId; this.wxMpConfigStorage = wxMpConfigStorage; + setOAuth2Service(new WxOpenMpOAuth2ServiceImpl(wxOpenComponentService, getOAuth2Service(), wxMpConfigStorage)); initHttp(); } diff --git a/weixin-java-open/src/test/java/me/chanjar/weixin/open/api/impl/WxOpenMpOAuth2ServiceImplTest.java b/weixin-java-open/src/test/java/me/chanjar/weixin/open/api/impl/WxOpenMpOAuth2ServiceImplTest.java new file mode 100644 index 0000000000..aab7af27d3 --- /dev/null +++ b/weixin-java-open/src/test/java/me/chanjar/weixin/open/api/impl/WxOpenMpOAuth2ServiceImplTest.java @@ -0,0 +1,29 @@ +package me.chanjar.weixin.open.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.api.WxOpenMpService; +import me.chanjar.weixin.open.test.ApiTestModule; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +@Guice(modules = ApiTestModule.class) +public class WxOpenMpOAuth2ServiceImplTest { + + @Inject + protected WxOpenMpService wxOpenMpService; + + + @Test + public void buildAuthorizationUrl() { + String url = wxOpenMpService.getOAuth2Service().buildAuthorizationUrl("https://t.aaxp.cn/api/base/mp/showCode", "snsapi_userinfo", ""); + System.out.println(url); + } + + @Test + public void getAccessToken() throws WxErrorException { + WxOAuth2AccessToken result = wxOpenMpService.getOAuth2Service().getAccessToken("041crm0005iFJL1b2l400I0s0k4crm0z"); + System.out.println(result); + } +} diff --git a/weixin-java-open/src/test/java/me/chanjar/weixin/open/test/ApiTestModule.java b/weixin-java-open/src/test/java/me/chanjar/weixin/open/test/ApiTestModule.java new file mode 100644 index 0000000000..8a3c3b9461 --- /dev/null +++ b/weixin-java-open/src/test/java/me/chanjar/weixin/open/test/ApiTestModule.java @@ -0,0 +1,64 @@ +package me.chanjar.weixin.open.test; + +import com.google.inject.Binder; +import com.google.inject.Module; +import com.thoughtworks.xstream.XStream; +import me.chanjar.weixin.common.error.WxRuntimeException; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import me.chanjar.weixin.open.api.WxOpenMaService; +import me.chanjar.weixin.open.api.WxOpenMpService; +import me.chanjar.weixin.open.api.WxOpenService; +import me.chanjar.weixin.open.api.impl.WxOpenServiceImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; + +public class ApiTestModule implements Module { + private final Logger log = LoggerFactory.getLogger(this.getClass()); + private static final String TEST_CONFIG_XML = "test-config.xml"; + + @Override + public void configure(Binder binder) { + try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(TEST_CONFIG_XML)) { + if (inputStream == null) { + throw new WxRuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到,请参照test-config-sample.xml文件生成"); + } + + TestConfigStorage config = this.fromXml(TestConfigStorage.class, inputStream); + WxOpenService service = new WxOpenServiceImpl(); + + service.setWxOpenConfigStorage(config); + + binder.bind(TestConfigStorage.class).toInstance(config); + binder.bind(WxOpenService.class).toInstance(service); + + if (config.getTestMpAppId() != null && !config.getTestMpAppId().isEmpty()) { + //如果配置了测试公众号,则构建公众号服务依赖 + binder.bind(WxOpenMpService.class).toInstance(service.getWxOpenComponentService().getWxMpServiceByAppid(config.getTestMpAppId())); + } else { + log.warn("建议参照参照 test-config-sample.xml 配置测试公众号"); + } + + if (config.getTestMaAppId() != null && !config.getTestMaAppId().isEmpty()) { + //如果配置了测试小程序,则构建小程序服务依赖 + binder.bind(WxOpenMaService.class).toInstance(service.getWxOpenComponentService().getWxMaServiceByAppid(config.getTestMaAppId())); + } else { + log.warn("建议参照参照 test-config-sample.xml 配置测试小程序"); + } + + } catch (IOException e) { + this.log.error(e.getMessage(), e); + } + } + + @SuppressWarnings("unchecked") + private T fromXml(Class clazz, InputStream is) { + XStream xstream = XStreamInitializer.getInstance(); + xstream.alias("xml", clazz); + xstream.processAnnotations(clazz); + return (T) xstream.fromXML(is); + } + +} diff --git a/weixin-java-open/src/test/java/me/chanjar/weixin/open/test/TestConfigStorage.java b/weixin-java-open/src/test/java/me/chanjar/weixin/open/test/TestConfigStorage.java new file mode 100644 index 0000000000..52e4fa8aa3 --- /dev/null +++ b/weixin-java-open/src/test/java/me/chanjar/weixin/open/test/TestConfigStorage.java @@ -0,0 +1,16 @@ +package me.chanjar.weixin.open.test; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import lombok.Getter; +import lombok.Setter; +import me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage; + +@Getter +@Setter +@XStreamAlias("xml") +public class TestConfigStorage extends WxOpenInMemoryConfigStorage { + + private String testMpAppId; + + private String testMaAppId; +} diff --git a/weixin-java-open/src/test/resources/test-config.sample.xml b/weixin-java-open/src/test/resources/test-config.sample.xml index 896969e438..f0130d0c83 100644 --- a/weixin-java-open/src/test/resources/test-config.sample.xml +++ b/weixin-java-open/src/test/resources/test-config.sample.xml @@ -1,7 +1,10 @@ 第三方平台appID 第三方平台appsecret + 第三方平台appsecret + 微信服务器推送过来的ticket 第三方平台Token 第三方平台EncodingAESKey - 测试APPID + 测试公众号 + 测试小程序 From 41791eb3d7205b3b556f291a168d9e7c26dc35b1 Mon Sep 17 00:00:00 2001 From: zpf <178668028@qq.com> Date: Wed, 23 Jun 2021 15:52:46 +0800 Subject: [PATCH 04/17] =?UTF-8?q?1.=E5=A2=9E=E5=8A=A0=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E5=8F=AF=E5=9B=9E=E9=80=80=E7=9A=84?= =?UTF-8?q?=E7=89=88=E6=9C=AC=20=E6=8E=A5=E5=8F=A3=202.=E5=B0=86WxOpenFast?= =?UTF-8?q?MaService=E6=A0=87=E8=AE=B0=E8=BF=87=E6=97=B6(=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=B9=B6=E9=9D=9E=E6=98=AF=E5=BF=AB=E9=80=9F=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=B0=8F=E7=A8=8B=E5=BA=8F=E7=8B=AC=E6=9C=89)?= =?UTF-8?q?=E5=B9=B6=E5=B0=86=E5=8E=9F=E6=9C=89=E6=96=B9=E6=B3=95=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=E5=88=B0WxOpenMaBasicService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../open/api/WxOpenComponentService.java | 2 + .../weixin/open/api/WxOpenFastMaService.java | 191 +---------------- .../weixin/open/api/WxOpenMaBasicService.java | 199 ++++++++++++++++++ .../weixin/open/api/WxOpenMaService.java | 17 ++ .../api/impl/WxOpenFastMaServiceImpl.java | 2 + .../api/impl/WxOpenMaBasicServiceImpl.java | 135 ++++++++++++ .../open/api/impl/WxOpenMaServiceImpl.java | 11 + .../open/bean/ma/WxOpenMaHistoryVersion.java | 34 +++ .../result/WxOpenMaHistoryVersionResult.java | 29 +++ 9 files changed, 432 insertions(+), 188 deletions(-) create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaHistoryVersion.java create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaHistoryVersionResult.java diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java index 26dc2ba7f2..4c7f5b0911 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java @@ -148,7 +148,9 @@ public interface WxOpenComponentService { * * @param appid . * @return . wx fast ma service by appid + * @deprecated 2021-06-23 本接口原有方法并非仅快速创建小程序的专用接口,普通小程序授权到第三方平台皆可使用,所以请使用 {@link WxOpenMaBasicService} 类替代。获取方法: WxOpenMaService.getBasicService() */ + @Deprecated WxOpenFastMaService getWxFastMaServiceByAppid(String appid); /** diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java index 8710689cdc..2114d1a816 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java @@ -1,11 +1,6 @@ package me.chanjar.weixin.open.api; import cn.binarywang.wx.miniapp.api.WxMaService; -import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.open.bean.ma.WxFastMaCategory; -import me.chanjar.weixin.open.bean.result.*; - -import java.util.List; /** *
@@ -16,189 +11,9 @@
  *
  * @author Hipple
  * @date 2019/01/23
+ * @deprecated 2021-06-23 本接口原有方法并非仅快速创建小程序的专用接口,普通小程序授权到第三方平台皆可使用,所以请使用 {@link WxOpenMaBasicService} 类替代。获取方法: WxOpenComponentService.getWxMaServiceByAppid(maApppId).getBasicService()
  */
-public interface WxOpenFastMaService extends WxMaService {
-  /**
-   * 1 获取帐号基本信息.
-   */
-  String OPEN_GET_ACCOUNT_BASIC_INFO = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo";
-
-  /**
-   * 2 小程序名称设置及改名.
-   */
-  String OPEN_SET_NICKNAME = "https://api.weixin.qq.com/wxa/setnickname";
-
-  /**
-   * 3 小程序改名审核状态查询.
-   */
-  String OPEN_API_WXA_QUERYNICKNAME = "https://api.weixin.qq.com/wxa/api_wxa_querynickname";
-
-  /**
-   * 4 微信认证名称检测.
-   */
-  String OPEN_CHECK_WX_VERIFY_NICKNAME = "https://api.weixin.qq.com/cgi-bin/wxverify/checkwxverifynickname";
-
-  /**
-   * 5 修改头像.
-   */
-  String OPEN_MODIFY_HEADIMAGE = "https://api.weixin.qq.com/cgi-bin/account/modifyheadimage";
-
-  /**
-   * 6修改功能介绍.
-   */
-  String OPEN_MODIFY_SIGNATURE = "https://api.weixin.qq.com/cgi-bin/account/modifysignature";
-
-  /**
-   * 7 换绑小程序管理员接口.
-   */
-  String OPEN_COMPONENT_REBIND_ADMIN = "https://api.weixin.qq.com/cgi-bin/account/componentrebindadmin";
-
-  /**
-   * 8.1 获取账号可以设置的所有类目
-   */
-  String OPEN_GET_ALL_CATEGORIES = "https://api.weixin.qq.com/cgi-bin/wxopen/getallcategories";
-  /**
-   * 8.2 添加类目
-   */
-  String OPEN_ADD_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/addcategory";
-  /**
-   * 8.3 删除类目
-   */
-  String OPEN_DELETE_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/deletecategory";
-  /**
-   * 8.4 获取账号已经设置的所有类目
-   */
-  String OPEN_GET_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/getcategory";
-  /**
-   * 8.5 修改类目
-   */
-  String OPEN_MODIFY_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/modifycategory";
-
-
-  /**
-   * 1.获取小程序的信息
-   *
-   * @return .
-   * @throws WxErrorException .
-   */
-  WxFastMaAccountBasicInfoResult getAccountBasicInfo() throws WxErrorException;
-
-  /**
-   * 2.小程序名称设置及改名
-   * 
-   *      若接口未返回audit_id,说明名称已直接设置成功,无需审核;若返回audit_id则名称正在审核中。
-   *  
- * - * @param nickname 昵称 - * @param idCard 身份证照片–临时素材mediaid(个人号必填) - * @param license 组织机构代码证或营业执照–临时素材mediaid(组织号必填) - * @param namingOtherStuff1 其他证明材料---临时素材 mediaid - * @param namingOtherStuff2 其他证明材料---临时素材 mediaid - * @return . - * @throws WxErrorException . - */ - WxFastMaSetNickameResult setNickname(String nickname, String idCard, String license, String namingOtherStuff1, - String namingOtherStuff2) throws WxErrorException; - - /** - * 3 小程序改名审核状态查询 - * - * @param auditId 审核单id - * @return . - * @throws WxErrorException . - */ - WxFastMaQueryNicknameStatusResult querySetNicknameStatus(String auditId) throws WxErrorException; - - /** - * 4. 微信认证名称检测 - * - * @param nickname 名称 - * @return . - * @throws WxErrorException . - */ - WxFastMaCheckNickameResult checkWxVerifyNickname(String nickname) throws WxErrorException; - - /** - * 5.修改头像 - *
-   *     图片格式只支持:BMP、JPEG、JPG、GIF、PNG,大小不超过2M
-   *      注:实际头像始终为正方形
-   * 
- * - * @param headImgMediaId 头像素材media_id - * @param x1 裁剪框左上角x坐标(取值范围:[0, 1]) - * @param y1 裁剪框左上角y坐标(取值范围:[0, 1]) - * @param x2 裁剪框右下角x坐标(取值范围:[0, 1]) - * @param y2 裁剪框右下角y坐标(取值范围:[0, 1]) - * @return . - * @throws WxErrorException . - */ - WxOpenResult modifyHeadImage(String headImgMediaId, float x1, float y1, float x2, float y2) throws WxErrorException; - - /** - * 6.修改功能介绍 - * - * @param signature 简介:4-120字 - * @return . - * @throws WxErrorException . - */ - WxOpenResult modifySignature(String signature) throws WxErrorException; - - /** - * 7.3 管理员换绑 - * - * @param taskId 换绑管理员任务序列号(公众平台最终点击提交回跳到第三方平台时携带) - * @return . - * @throws WxErrorException . - */ - WxOpenResult componentRebindAdmin(String taskId) throws WxErrorException; - - /** - * 8.1 获取账号可以设置的所有类目 - *
-   *     因为不同类目含有特定字段
-   *     目前没有完整的类目信息数据
-   *     为保证兼容性,放弃将response转换为实体
-   * 
- * - * @return . - * @throws WxErrorException . - */ - String getAllCategories() throws WxErrorException; - - /** - * 8.2添加类目 - * - * @param categoryList 类目列表 - * @return . - * @throws WxErrorException . - */ - WxOpenResult addCategory(List categoryList) throws WxErrorException; - - /** - * 8.3删除类目 - * - * @param first 一级类目ID - * @param second 二级类目ID - * @return . - * @throws WxErrorException . - */ - WxOpenResult deleteCategory(int first, int second) throws WxErrorException; - - /** - * 8.4获取账号已经设置的所有类目 - * - * @return . - * @throws WxErrorException . - */ - WxFastMaBeenSetCategoryResult getCategory() throws WxErrorException; +@Deprecated +public interface WxOpenFastMaService extends WxOpenMaBasicService, WxMaService { - /** - * 8.5修改类目 - * - * @param category 实体 - * @return . - * @throws WxErrorException . - */ - WxOpenResult modifyCategory(WxFastMaCategory category) throws WxErrorException; } diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java new file mode 100644 index 0000000000..194da4b9b3 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java @@ -0,0 +1,199 @@ +package me.chanjar.weixin.open.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.bean.ma.WxFastMaCategory; +import me.chanjar.weixin.open.bean.result.*; + +import java.util.List; + +/** + * 微信第三方平台 小程序基础信息接口 (小程序名称、头像、描述、类目等信息设置) + * https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/category/getallcategories.html + * + * @author 广州跨界 + */ +public interface WxOpenMaBasicService { + /** + * 1 获取帐号基本信息. + */ + String OPEN_GET_ACCOUNT_BASIC_INFO = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo"; + + /** + * 2 小程序名称设置及改名. + */ + String OPEN_SET_NICKNAME = "https://api.weixin.qq.com/wxa/setnickname"; + + /** + * 3 小程序改名审核状态查询. + */ + String OPEN_API_WXA_QUERYNICKNAME = "https://api.weixin.qq.com/wxa/api_wxa_querynickname"; + + /** + * 4 微信认证名称检测. + */ + String OPEN_CHECK_WX_VERIFY_NICKNAME = "https://api.weixin.qq.com/cgi-bin/wxverify/checkwxverifynickname"; + + /** + * 5 修改头像. + */ + String OPEN_MODIFY_HEADIMAGE = "https://api.weixin.qq.com/cgi-bin/account/modifyheadimage"; + + /** + * 6修改功能介绍. + */ + String OPEN_MODIFY_SIGNATURE = "https://api.weixin.qq.com/cgi-bin/account/modifysignature"; + + /** + * 7 换绑小程序管理员接口. + */ + String OPEN_COMPONENT_REBIND_ADMIN = "https://api.weixin.qq.com/cgi-bin/account/componentrebindadmin"; + + /** + * 8.1 获取账号可以设置的所有类目 + */ + String OPEN_GET_ALL_CATEGORIES = "https://api.weixin.qq.com/cgi-bin/wxopen/getallcategories"; + /** + * 8.2 添加类目 + */ + String OPEN_ADD_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/addcategory"; + /** + * 8.3 删除类目 + */ + String OPEN_DELETE_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/deletecategory"; + /** + * 8.4 获取账号已经设置的所有类目 + */ + String OPEN_GET_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/getcategory"; + /** + * 8.5 修改类目 + */ + String OPEN_MODIFY_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/modifycategory"; + + + /** + * 1.获取小程序的信息 + * + * @return . + * @throws WxErrorException . + */ + WxFastMaAccountBasicInfoResult getAccountBasicInfo() throws WxErrorException; + + /** + * 2.小程序名称设置及改名 + *
+   *      若接口未返回audit_id,说明名称已直接设置成功,无需审核;若返回audit_id则名称正在审核中。
+   *  
+ * + * @param nickname 昵称 + * @param idCard 身份证照片–临时素材mediaid(个人号必填) + * @param license 组织机构代码证或营业执照–临时素材mediaid(组织号必填) + * @param namingOtherStuff1 其他证明材料---临时素材 mediaid + * @param namingOtherStuff2 其他证明材料---临时素材 mediaid + * @return . + * @throws WxErrorException . + */ + WxFastMaSetNickameResult setNickname(String nickname, String idCard, String license, String namingOtherStuff1, + String namingOtherStuff2) throws WxErrorException; + + /** + * 3 小程序改名审核状态查询 + * + * @param auditId 审核单id + * @return . + * @throws WxErrorException . + */ + WxFastMaQueryNicknameStatusResult querySetNicknameStatus(String auditId) throws WxErrorException; + + /** + * 4. 微信认证名称检测 + * + * @param nickname 名称 + * @return . + * @throws WxErrorException . + */ + WxFastMaCheckNickameResult checkWxVerifyNickname(String nickname) throws WxErrorException; + + /** + * 5.修改头像 + *
+   *     图片格式只支持:BMP、JPEG、JPG、GIF、PNG,大小不超过2M
+   *      注:实际头像始终为正方形
+   * 
+ * + * @param headImgMediaId 头像素材media_id + * @param x1 裁剪框左上角x坐标(取值范围:[0, 1]) + * @param y1 裁剪框左上角y坐标(取值范围:[0, 1]) + * @param x2 裁剪框右下角x坐标(取值范围:[0, 1]) + * @param y2 裁剪框右下角y坐标(取值范围:[0, 1]) + * @return . + * @throws WxErrorException . + */ + WxOpenResult modifyHeadImage(String headImgMediaId, float x1, float y1, float x2, float y2) throws WxErrorException; + + /** + * 6.修改功能介绍 + * + * @param signature 简介:4-120字 + * @return . + * @throws WxErrorException . + */ + WxOpenResult modifySignature(String signature) throws WxErrorException; + + /** + * 7.3 管理员换绑 + * + * @param taskId 换绑管理员任务序列号(公众平台最终点击提交回跳到第三方平台时携带) + * @return . + * @throws WxErrorException . + */ + WxOpenResult componentRebindAdmin(String taskId) throws WxErrorException; + + /** + * 8.1 获取账号可以设置的所有类目 + *
+   *     因为不同类目含有特定字段
+   *     目前没有完整的类目信息数据
+   *     为保证兼容性,放弃将response转换为实体
+   * 
+ * + * @return . + * @throws WxErrorException . + */ + String getAllCategories() throws WxErrorException; + + /** + * 8.2添加类目 + * + * @param categoryList 类目列表 + * @return . + * @throws WxErrorException . + */ + WxOpenResult addCategory(List categoryList) throws WxErrorException; + + /** + * 8.3删除类目 + * + * @param first 一级类目ID + * @param second 二级类目ID + * @return . + * @throws WxErrorException . + */ + WxOpenResult deleteCategory(int first, int second) throws WxErrorException; + + /** + * 8.4获取账号已经设置的所有类目 + * + * @return . + * @throws WxErrorException . + */ + WxFastMaBeenSetCategoryResult getCategory() throws WxErrorException; + + /** + * 8.5修改类目 + * + * @param category 实体 + * @return . + * @throws WxErrorException . + */ + WxOpenResult modifyCategory(WxFastMaCategory category) throws WxErrorException; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java index ccaeeff019..9732e614ac 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java @@ -452,6 +452,16 @@ WxOpenMaDomainResult modifyDomain(String action, List requestDomains, Li */ WxOpenResult revertCodeRelease() throws WxErrorException; + /** + * 获取可回退的小程序版本 + * 调用本接口可以获取可回退的小程序版本(最多保存最近发布或回退的5个版本 + * 文档地址: https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/code/get_history_version.html + * + * @return 历史版本信息 + * @throws WxErrorException 如果调用微信接口失败抛出此异常 + */ + WxOpenMaHistoryVersionResult getHistoryVersion() throws WxErrorException; + /** * 15. 小程序审核撤回 *

@@ -583,4 +593,11 @@ WxOpenMaDomainResult modifyDomain(String action, List requestDomains, Li * @throws WxErrorException the wx error exception */ WxOpenResult publishQrcodeJump(String prefix) throws WxErrorException; + + /** + * 小程序基础信息服务 (小程序名称、头像、描述、类目等信息设置) + * + * @return 小程序基础信息服务 + */ + WxOpenMaBasicService getBasicService(); } diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java index 2cea9530bb..f5f2160d21 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java @@ -20,7 +20,9 @@ * * @author Hipple * @since 2019/1/23 15:27 + * @deprecated 请使用 {@link WxOpenMaServiceImpl} 替代 */ +@Deprecated public class WxOpenFastMaServiceImpl extends WxMaServiceImpl implements WxOpenFastMaService { private final WxOpenComponentService wxOpenComponentService; private final WxMaConfig wxMaConfig; diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java new file mode 100644 index 0000000000..4e4db75257 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java @@ -0,0 +1,135 @@ +package me.chanjar.weixin.open.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.api.WxOpenMaBasicService; +import me.chanjar.weixin.open.bean.ma.WxFastMaCategory; +import me.chanjar.weixin.open.bean.result.*; +import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 微信第三方平台 小程序基础信息接口 + * + * @author 广州跨界 + */ +public class WxOpenMaBasicServiceImpl implements WxOpenMaBasicService { + + private final WxMaService wxMaService; + + public WxOpenMaBasicServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + + @Override + public WxFastMaAccountBasicInfoResult getAccountBasicInfo() throws WxErrorException { + String response = wxMaService.get(OPEN_GET_ACCOUNT_BASIC_INFO, ""); + return WxOpenGsonBuilder.create().fromJson(response, WxFastMaAccountBasicInfoResult.class); + } + + @Override + public WxFastMaSetNickameResult setNickname(String nickname, String idCard, String license, String namingOtherStuff1, String namingOtherStuff2) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("nick_name", nickname); + params.addProperty("id_card", idCard); + params.addProperty("license", license); + params.addProperty("naming_other_stuff_1", namingOtherStuff1); + params.addProperty("naming_other_stuff_2", namingOtherStuff2); + String response = wxMaService.post(OPEN_SET_NICKNAME, params); + return WxOpenGsonBuilder.create().fromJson(response, WxFastMaSetNickameResult.class); + } + + @Override + public WxFastMaQueryNicknameStatusResult querySetNicknameStatus(String auditId) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("audit_id", auditId); + String response = wxMaService.post(OPEN_API_WXA_QUERYNICKNAME, params); + return WxOpenGsonBuilder.create().fromJson(response, WxFastMaQueryNicknameStatusResult.class); + } + + @Override + public WxFastMaCheckNickameResult checkWxVerifyNickname(String nickname) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("nick_name", nickname); + String response = wxMaService.post(OPEN_CHECK_WX_VERIFY_NICKNAME, params); + return WxOpenGsonBuilder.create().fromJson(response, WxFastMaCheckNickameResult.class); + } + + @Override + public WxOpenResult modifyHeadImage(String headImgMediaId, float x1, float y1, float x2, float y2) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("head_img_media_id", headImgMediaId); + params.addProperty("x1", x1); + params.addProperty("y1", y1); + params.addProperty("x2", x2); + params.addProperty("y2", y2); + String response = wxMaService.post(OPEN_MODIFY_HEADIMAGE, params); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + @Override + public WxOpenResult modifySignature(String signature) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("signature", signature); + String response = wxMaService.post(OPEN_MODIFY_SIGNATURE, params); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + @Override + public WxOpenResult componentRebindAdmin(String taskid) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("taskid", taskid); + String response = wxMaService.post(OPEN_COMPONENT_REBIND_ADMIN, params); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + @Override + public String getAllCategories() throws WxErrorException { + return wxMaService.get(OPEN_GET_ALL_CATEGORIES, ""); + } + + @Override + public WxOpenResult addCategory(List categoryList) throws WxErrorException { + Map map = new HashMap<>(); + map.put("categories", categoryList); + String response = wxMaService.post(OPEN_ADD_CATEGORY, WxOpenGsonBuilder.create().toJson(map)); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + @Override + public WxOpenResult deleteCategory(int first, int second) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("first", first); + params.addProperty("second", second); + String response = wxMaService.post(OPEN_DELETE_CATEGORY, params); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + @Override + public WxFastMaBeenSetCategoryResult getCategory() throws WxErrorException { + String response = wxMaService.get(OPEN_GET_CATEGORY, ""); + return WxOpenGsonBuilder.create().fromJson(response, WxFastMaBeenSetCategoryResult.class); + } + + @Override + public WxOpenResult modifyCategory(WxFastMaCategory category) throws WxErrorException { + String response = wxMaService.post(OPEN_MODIFY_CATEGORY, category); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + private JsonArray toJsonArray(List strList) { + JsonArray jsonArray = new JsonArray(); + if (strList != null && !strList.isEmpty()) { + for (String str : strList) { + jsonArray.add(str); + } + } + return jsonArray; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java index 24d9e23414..9febf639f4 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java @@ -7,8 +7,10 @@ import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import lombok.Getter; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.open.api.WxOpenComponentService; +import me.chanjar.weixin.open.api.WxOpenMaBasicService; import me.chanjar.weixin.open.api.WxOpenMaService; import me.chanjar.weixin.open.bean.ma.WxMaOpenCommitExtInfo; import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam; @@ -34,11 +36,14 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ private final WxOpenComponentService wxOpenComponentService; private final WxMaConfig wxMaConfig; private final String appId; + @Getter + private final WxOpenMaBasicService basicService; public WxOpenMaServiceImpl(WxOpenComponentService wxOpenComponentService, String appId, WxMaConfig wxMaConfig) { this.wxOpenComponentService = wxOpenComponentService; this.appId = appId; this.wxMaConfig = wxMaConfig; + this.basicService = new WxOpenMaBasicServiceImpl(this); initHttp(); } @@ -247,6 +252,12 @@ public WxOpenResult revertCodeRelease() throws WxErrorException { return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class); } + @Override + public WxOpenMaHistoryVersionResult getHistoryVersion() throws WxErrorException { + String response = get(API_REVERT_CODE_RELEASE, "action=get_history_version"); + return WxMaGsonBuilder.create().fromJson(response, WxOpenMaHistoryVersionResult.class); + } + @Override public WxOpenResult undoCodeAudit() throws WxErrorException { String response = get(API_UNDO_CODE_AUDIT, null); diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaHistoryVersion.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaHistoryVersion.java new file mode 100644 index 0000000000..6ef41c8bef --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaHistoryVersion.java @@ -0,0 +1,34 @@ +package me.chanjar.weixin.open.bean.ma; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; + +import java.io.Serializable; + +/** + * 微信开放平台小程序 可回退的小程序版本 + * + * @author 广州跨界 + */ +@Data +public class WxOpenMaHistoryVersion implements Serializable { + private static final long serialVersionUID = 98923601148793365L; + + @SerializedName("app_version") + private Integer appVersion; + + @SerializedName("user_version") + private String userVersion; + + @SerializedName("user_desc") + private String userDesc; + + @SerializedName("commit_time") + private Integer commitTime; + + @Override + public String toString() { + return WxOpenGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaHistoryVersionResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaHistoryVersionResult.java new file mode 100644 index 0000000000..61b9f5dddf --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaHistoryVersionResult.java @@ -0,0 +1,29 @@ +package me.chanjar.weixin.open.bean.result; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import me.chanjar.weixin.open.bean.ma.WxOpenMaHistoryVersion; +import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; + +import java.util.List; + +/** + * 微信开放平台小程序 可回退的小程序版本 返回 + * + * @author 广州跨界 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class WxOpenMaHistoryVersionResult extends WxOpenResult { + private static final long serialVersionUID = 4102311851687901079L; + + @SerializedName("template_list") + List templateList; + + @Override + public String toString() { + return WxOpenGsonBuilder.create().toJson(this); + } + +} From 1611b419dcf14a0393bd7eceb3cf6992283e8238 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Wed, 2 Jun 2021 23:36:36 +0800 Subject: [PATCH 05/17] =?UTF-8?q?:memo:=20=E6=9B=B4=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- .../me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java | 3 ++- .../weixin/cp/tp/service/impl/WxCpTpTagServiceImplTest.java | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2de114fac6..9c395fc670 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ ### 重要信息 -1. **2020-11-29 发布 [【4.0.0正式版】](https://mp.weixin.qq.com/s/OPoICwLifOZGVN_ZX_BBhw)**! +1. **2021-06-02 发布 [【4.1.0正式版】](https://mp.weixin.qq.com/s/nIk_xOf6dxkhKfqq830Cuw)**! 1. 新手重要提示:本项目仅是一个SDK开发工具包,未提供Web实现,建议使用 `maven` 或 `gradle` 引用本项目即可使用本SDK提供的各种功能,详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;另外微信开发新手请务必阅读[【开发文档 Wiki 首页】](https://github.com/Wechat-Group/WxJava/wiki)的常见问题部分,可以少走很多弯路,节省不少时间。 1. 技术交流群:想获得QQ群/微信群/钉钉企业群等信息的同学,请使用微信扫描上面的微信公众号二维码关注 `WxJava` 后点击相关菜单即可获取加入方式,同时也可以在微信中搜索 `weixin-java-tools` 或 `WxJava` 后选择正确的公众号进行关注,该公众号会及时通知SDK相关更新信息,并不定期分享微信Java开发相关技术知识; 1. 钉钉技术交流群: `30294972`(技术交流群),`35724728`(通知群,实时通知Github项目变更记录)。 @@ -67,7 +67,7 @@ com.github.binarywang (不同模块参考下文) - 4.0.0 + 4.1.0 ``` diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java index f6ab29df7f..1f6f73d068 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java @@ -7,6 +7,7 @@ import me.chanjar.weixin.cp.tp.message.WxCpTpMessageHandler; import me.chanjar.weixin.cp.tp.message.WxCpTpMessageRouter; import me.chanjar.weixin.cp.tp.service.WxCpTpService; +import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceApacheHttpClientImpl; import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceImpl; import org.testng.annotations.Test; @@ -21,7 +22,7 @@ public class WxCpTpMessageRouterTest { @Test public void testMessageRouter() { - WxCpTpService service = new WxCpTpServiceImpl(); + WxCpTpService service = new WxCpTpServiceApacheHttpClientImpl(); WxCpTpMessageRouter router = new WxCpTpMessageRouter(service); String xml = "\n" + diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpTagServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpTagServiceImplTest.java index 44c3ff68d1..1dc1148582 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpTagServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpTagServiceImplTest.java @@ -30,7 +30,7 @@ public class WxCpTpTagServiceImplTest { @Mock - private WxCpTpServiceImpl wxCpTpService; + private WxCpTpServiceApacheHttpClientImpl wxCpTpService; private WxCpTpConfigStorage configStorage; From 5d276b73e4d91ae6489a1b66c1ebaa88876f7861 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Wed, 2 Jun 2021 23:46:22 +0800 Subject: [PATCH 06/17] =?UTF-8?q?:memo:=20=E6=9B=B4=E6=96=B0=E9=83=A8?= =?UTF-8?q?=E5=88=86=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c395fc670..36f0dabf71 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ #### 开源项目: - 基于微信公众号的签到、抽奖、发送弹幕程序:https://github.com/workcheng/weiya -- XxPay聚合支付:https://github.com/jmdhappy/xxpay-master +- Jeepay 支付系统:https://gitee.com/jeequan/jeepay - 微同商城:https://gitee.com/fuyang_lipengjun/platform - 微信点餐系统:https://github.com/sqmax/springboot-project - 专注批量推送的小而美的工具:https://github.com/rememberber/WePush From 9279156fb8f7833fe8e8f36901bed13dc627dd76 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 3 Jun 2021 13:56:37 +0800 Subject: [PATCH 07/17] =?UTF-8?q?:art:=20=E4=BF=AE=E5=A4=8D=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java | 3 --- .../weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java | 2 +- ...plTest.java => WxCpTpServiceApacheHttpClientImplTest.java} | 4 ++-- weixin-java-cp/src/test/resources/testng.xml | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) rename weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/{WxCpTpServiceImplTest.java => WxCpTpServiceApacheHttpClientImplTest.java} (97%) diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java index 1f6f73d068..41c0b37968 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java @@ -8,13 +8,11 @@ import me.chanjar.weixin.cp.tp.message.WxCpTpMessageRouter; import me.chanjar.weixin.cp.tp.service.WxCpTpService; import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceApacheHttpClientImpl; -import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceImpl; import org.testng.annotations.Test; import java.util.Map; import static org.testng.Assert.assertNotNull; -import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNull; public class WxCpTpMessageRouterTest { @@ -51,7 +49,6 @@ public WxCpXmlOutMessage handle(WxCpTpXmlMessage wxMessage, Map assertNull(router.route(wxXmlMessage)); - System.out.println("over"); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java index 83ace79f3c..26ca567c12 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java @@ -23,7 +23,7 @@ * @date 2019-08-18 */ public class BaseWxCpTpServiceImplTest { - private final WxCpTpService tpService = Mockito.spy(new WxCpTpServiceImpl()); + private final WxCpTpService tpService = Mockito.spy(new WxCpTpServiceApacheHttpClientImpl()); @Test public void testCheckSignature() { diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java similarity index 97% rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceImplTest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java index f0b57f2100..e0ded23d26 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java @@ -21,7 +21,7 @@ * * @author zhangq */ -public class WxCpTpServiceImplTest { +public class WxCpTpServiceApacheHttpClientImplTest { public static final String API_URL = "https://qyapi.weixin.qq.com"; public static final String SUITE_ID = "xxxxxx"; @@ -41,7 +41,7 @@ public class WxCpTpServiceImplTest { @BeforeMethod public void setUp() { - wxCpTpService = new WxCpTpServiceImpl(); + wxCpTpService = new WxCpTpServiceApacheHttpClientImpl(); wxCpTpService.setWxCpTpConfigStorage(wxCpTpConfigStorage()); } diff --git a/weixin-java-cp/src/test/resources/testng.xml b/weixin-java-cp/src/test/resources/testng.xml index 0bd6fbdd23..96da66bd21 100644 --- a/weixin-java-cp/src/test/resources/testng.xml +++ b/weixin-java-cp/src/test/resources/testng.xml @@ -6,7 +6,7 @@ - + From 933e058e8ee805df631efa3a3a8b6f29e8c00d54 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 3 Jun 2021 14:06:57 +0800 Subject: [PATCH 08/17] :arrow_up: upgrade guava version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7eb8bb4865..4e0c717a3f 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ com.google.guava guava - 29.0-jre + 30.0-jre com.google.code.gson From 19058716762faaf452e731e4f8ddd8b1884c58bc Mon Sep 17 00:00:00 2001 From: arthur0201 <704538660@qq.com> Date: Fri, 4 Jun 2021 09:33:42 +0800 Subject: [PATCH 09/17] =?UTF-8?q?:new:=20#2142=20=E3=80=90=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1=E3=80=91=E8=A2=AB=E5=8A=A8=E5=9B=9E?= =?UTF-8?q?=E5=A4=8D=E6=B6=88=E6=81=AF=E5=86=85=E5=AE=B9=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=8D=A1=E7=89=87=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/common/api/WxConsts.java | 1 + .../common/util/xml/XStreamInitializer.java | 4 ++ .../util/xml/XStreamReplaceNameConverter.java | 8 +++ .../cp/bean/message/WxCpXmlOutMessage.java | 12 +++-- .../message/WxCpXmlOutTaskCardMessage.java | 24 +++++++++ .../bean/outxmlbuilder/TaskCardBuilder.java | 27 ++++++++++ .../cp/util/xml/XStreamTransformer.java | 18 ++++--- .../WxCpXmlOutTaskCardMessageTest.java | 49 +++++++++++++++++++ 8 files changed, 130 insertions(+), 13 deletions(-) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamReplaceNameConverter.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutTaskCardMessage.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/TaskCardBuilder.java create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutTaskCardMessageTest.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java index 1e953d080b..cfc7fc0f37 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java @@ -44,6 +44,7 @@ public static class XmlMsgType { public static final String DEVICE_STATUS = "device_status"; public static final String HARDWARE = "hardware"; public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; + public static final String UPDATE_TASKCARD = "update_taskcard"; } /** diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java index cf0fbb5ae9..6997eb490d 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java @@ -28,6 +28,8 @@ public HierarchicalStreamWriter createWriter(Writer out) { private static final String SUFFIX_CDATA = "]]>"; private static final String PREFIX_MEDIA_ID = ""; private static final String SUFFIX_MEDIA_ID = ""; + private static final String PREFIX_REPLACE_NAME = ""; + private static final String SUFFIX_REPLACE_NAME = ""; @Override protected void writeText(QuickWriter writer, String text) { @@ -35,6 +37,8 @@ protected void writeText(QuickWriter writer, String text) { writer.write(text); } else if (text.startsWith(PREFIX_MEDIA_ID) && text.endsWith(SUFFIX_MEDIA_ID)) { writer.write(text); + } else if (text.startsWith(PREFIX_REPLACE_NAME) && text.endsWith(SUFFIX_REPLACE_NAME)){ + writer.write(text); } else { super.writeText(writer, text); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamReplaceNameConverter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamReplaceNameConverter.java new file mode 100644 index 0000000000..a136934383 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamReplaceNameConverter.java @@ -0,0 +1,8 @@ +package me.chanjar.weixin.common.util.xml; + +public class XStreamReplaceNameConverter extends XStreamCDataConverter { + @Override + public String toString(Object obj) { + return "" + super.toString(obj) + ""; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutMessage.java index 96991a5403..ff036b4c0e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutMessage.java @@ -6,11 +6,7 @@ import com.thoughtworks.xstream.annotations.XStreamConverter; import lombok.Data; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; -import me.chanjar.weixin.cp.bean.outxmlbuilder.ImageBuilder; -import me.chanjar.weixin.cp.bean.outxmlbuilder.NewsBuilder; -import me.chanjar.weixin.cp.bean.outxmlbuilder.TextBuilder; -import me.chanjar.weixin.cp.bean.outxmlbuilder.VideoBuilder; -import me.chanjar.weixin.cp.bean.outxmlbuilder.VoiceBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.*; import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; import me.chanjar.weixin.cp.util.xml.XStreamTransformer; @@ -76,6 +72,12 @@ public static NewsBuilder NEWS() { return new NewsBuilder(); } + /** + * 获得任务卡片消息builder. + */ + public static TaskCardBuilder TASK_CARD() { + return new TaskCardBuilder(); + } protected String toXml() { return XStreamTransformer.toXml((Class) this.getClass(), this); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutTaskCardMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutTaskCardMessage.java new file mode 100644 index 0000000000..63816f7e4c --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutTaskCardMessage.java @@ -0,0 +1,24 @@ +package me.chanjar.weixin.cp.bean.message; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import lombok.Data; +import lombok.EqualsAndHashCode; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.util.xml.XStreamReplaceNameConverter; + +@XStreamAlias("xml") +@Data +@EqualsAndHashCode(callSuper = false) +public class WxCpXmlOutTaskCardMessage extends WxCpXmlOutMessage { + private static final long serialVersionUID = 7028014900972827324L; + + @XStreamAlias("TaskCard") + @XStreamConverter(value = XStreamReplaceNameConverter.class) + private String replaceName; + + public WxCpXmlOutTaskCardMessage() { + this.msgType = WxConsts.XmlMsgType.UPDATE_TASKCARD; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/TaskCardBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/TaskCardBuilder.java new file mode 100644 index 0000000000..e71c5bd71d --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/TaskCardBuilder.java @@ -0,0 +1,27 @@ +package me.chanjar.weixin.cp.bean.outxmlbuilder; + +import me.chanjar.weixin.cp.bean.message.WxCpXmlOutTaskCardMessage; + +/** + * 任务卡片消息builder + * + * @author tao zhang + */ +public final class TaskCardBuilder extends BaseBuilder { + + private String replaceName; + + public TaskCardBuilder replaceName(String replaceName) { + this.replaceName = replaceName; + return this; + } + + @Override + public WxCpXmlOutTaskCardMessage build() { + WxCpXmlOutTaskCardMessage m = new WxCpXmlOutTaskCardMessage(); + setCommon(m); + m.setReplaceName(this.replaceName); + return m; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java index ea90231112..aa907b7288 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java @@ -6,15 +6,8 @@ import com.thoughtworks.xstream.XStream; import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage; +import me.chanjar.weixin.cp.bean.message.*; import me.chanjar.weixin.cp.bean.WxCpTpXmlPackage; -import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage; -import me.chanjar.weixin.cp.bean.message.WxCpXmlOutImageMessage; -import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage; -import me.chanjar.weixin.cp.bean.message.WxCpXmlOutNewsMessage; -import me.chanjar.weixin.cp.bean.message.WxCpXmlOutTextMessage; -import me.chanjar.weixin.cp.bean.message.WxCpXmlOutVideoMessage; -import me.chanjar.weixin.cp.bean.message.WxCpXmlOutVoiceMessage; public class XStreamTransformer { @@ -60,6 +53,7 @@ private static Map configXStreamInstance() { map.put(WxCpXmlOutImageMessage.class, configWxCpXmlOutImageMessage()); map.put(WxCpXmlOutVideoMessage.class, configWxCpXmlOutVideoMessage()); map.put(WxCpXmlOutVoiceMessage.class, configWxCpXmlOutVoiceMessage()); + map.put(WxCpXmlOutTaskCardMessage.class, configWxCpXmlOutTaskCardMessage()); map.put(WxCpTpXmlPackage.class, configWxCpTpXmlPackage()); map.put(WxCpTpXmlMessage.class, configWxCpTpXmlMessage()); return map; @@ -118,6 +112,14 @@ private static XStream configWxCpXmlOutVoiceMessage() { return xstream; } + private static XStream configWxCpXmlOutTaskCardMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutTaskCardMessage.class); + return xstream; + } + private static XStream configWxCpTpXmlPackage() { XStream xstream = XStreamInitializer.getInstance(); xstream.processAnnotations(WxCpTpXmlPackage.class); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutTaskCardMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutTaskCardMessageTest.java new file mode 100644 index 0000000000..bc867b72d1 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlOutTaskCardMessageTest.java @@ -0,0 +1,49 @@ +package me.chanjar.weixin.cp.bean.message; + +import me.chanjar.weixin.cp.bean.message.WxCpXmlOutTaskCardMessage; +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test +public class WxCpXmlOutTaskCardMessageTest { + + public void test() { + WxCpXmlOutTaskCardMessage m = new WxCpXmlOutTaskCardMessage(); + m.setReplaceName("已驳回"); + m.setCreateTime(1122L); + m.setFromUserName("from"); + m.setToUserName("to"); + + String expected = "" + + "" + + "" + + "1122" + + "" + + "" + + ""; + System.out.println(m.toXml()); + Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); + } + + public void testBuild() { + WxCpXmlOutTaskCardMessage m = WxCpXmlOutMessage.TASK_CARD().replaceName("已驳回").fromUser("from").toUser("to").build(); + String expected = "" + + "" + + "" + + "1122" + + "" + + "" + + ""; + System.out.println(m.toXml()); + Assert.assertEquals( + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") + ); + } + +} From d47d687041c629cd5923490ae764311cca1b7649 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Jun 2021 09:34:07 +0800 Subject: [PATCH 10/17] :arrow_up: Bump httpclient from 4.5 to 4.5.13 (#2143) Bumps httpclient from 4.5 to 4.5.13. --- updated-dependencies: - dependency-name: org.apache.httpcomponents:httpclient dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4e0c717a3f..db21b75ce4 100644 --- a/pom.xml +++ b/pom.xml @@ -118,7 +118,7 @@ 1.8 UTF-8 - 4.5 + 4.5.13 9.4.38.v20210224 From 953b5f977df8a5d8ecad4abfb48f4f023e3685c2 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 4 Jun 2021 16:11:48 +0800 Subject: [PATCH 11/17] =?UTF-8?q?:art:=20=E4=BC=98=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/apache/ApacheHttpDnsClientBuilder.java | 17 +++++------------ .../apache/DefaultApacheHttpClientBuilder.java | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java index fe5472f3c0..af3a32ff71 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java @@ -1,12 +1,7 @@ package me.chanjar.weixin.common.util.http.apache; -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHost; -import org.apache.http.annotation.NotThreadSafe; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; @@ -25,10 +20,13 @@ import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.protocol.HttpContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.NotThreadSafe; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + /** * httpclient 连接管理器 自带DNS解析. *

大部分代码拷贝自:DefaultApacheHttpClientBuilder

@@ -50,12 +48,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { private DnsResolver dnsResover; - private HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { - @Override - public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { - return false; - } - }; + private HttpRequestRetryHandler httpRequestRetryHandler = (exception, executionCount, context) -> false; private SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory(); private PlainConnectionSocketFactory plainConnectionSocketFactory = PlainConnectionSocketFactory.getSocketFactory(); private String httpProxyHost; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java index 3fb08ab2c6..3bb0d6114c 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java @@ -4,7 +4,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHost; -import org.apache.http.annotation.NotThreadSafe; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; @@ -26,6 +25,7 @@ import org.apache.http.protocol.HttpContext; import org.apache.http.ssl.SSLContexts; +import javax.annotation.concurrent.NotThreadSafe; import javax.net.ssl.SSLContext; import java.io.IOException; import java.security.KeyManagementException; From a73662159018169654d68e60f8023e1f9e2e692e Mon Sep 17 00:00:00 2001 From: arthur0201 <704538660@qq.com> Date: Mon, 7 Jun 2021 11:37:38 +0800 Subject: [PATCH 12/17] =?UTF-8?q?:art:=20#2144=E3=80=90=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E3=80=91=E6=9B=B4=E6=96=B0=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=8D=A1=E7=89=87=E6=B6=88=E6=81=AF=E7=8A=B6=E6=80=81=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=8F=82=E6=95=B0=E8=B7=9F=E6=96=87=E6=A1=A3=E4=BF=9D?= =?UTF-8?q?=E6=8C=81=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java | 4 ++-- .../chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java index 5bf50d36dc..3d97cb9283 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java @@ -25,7 +25,7 @@ public interface WxCpTaskCardService { * * @param userIds 企业的成员ID列表 * @param taskId 任务卡片ID - * @param clickedKey 已点击按钮的Key + * @param replaceName 替换文案 */ - void update(List userIds, String taskId, String clickedKey) throws WxErrorException; + void update(List userIds, String taskId, String replaceName) throws WxErrorException; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java index 3993960642..384a3d30cd 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java @@ -26,14 +26,14 @@ public class WxCpTaskCardServiceImpl implements WxCpTaskCardService { private final WxCpService mainService; @Override - public void update(List userIds, String taskId, String clickedKey) throws WxErrorException { + public void update(List userIds, String taskId, String replaceName) throws WxErrorException { Integer agentId = this.mainService.getWxCpConfigStorage().getAgentId(); Map data = new HashMap<>(4); data.put("userids", userIds); data.put("agentid", agentId); data.put("task_id", taskId); - data.put("clicked_key", clickedKey); + data.put("replace_name", replaceName); String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPDATE_TASK_CARD); this.mainService.post(url, WxGsonBuilder.create().toJson(data)); From d1e8fe354ae96cee8a05e7d5efb41996124225a6 Mon Sep 17 00:00:00 2001 From: mrxiao <39647988+mr-xiaoyu@users.noreply.github.com> Date: Fri, 11 Jun 2021 11:51:43 +0800 Subject: [PATCH 13/17] =?UTF-8?q?:new:=20#2135=20=E3=80=90=E5=B0=8F?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E3=80=91=E5=AE=9E=E7=8E=B0=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=20URL=20Link=E6=8E=A5=E5=8F=A3=20=E4=BB=A5=E5=8F=8A=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E7=94=B5=E5=AD=90=E5=8F=91=E7=A5=A8=E6=8A=A5=E9=94=80?= =?UTF-8?q?=E6=96=B9=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wx/miniapp/api/WxMaLinkService.java | 16 ++ .../api/WxMaReimburseInvoiceService.java | 48 ++++++ .../wx/miniapp/api/WxMaService.java | 12 ++ .../miniapp/api/impl/BaseWxMaServiceImpl.java | 12 ++ .../miniapp/api/impl/WxMaLinkServiceImpl.java | 35 +++++ .../impl/WxMaReimburseInvoiceServiceImpl.java | 44 ++++++ .../reimburse/InvoiceBatchRequest.java | 41 ++++++ .../reimburse/InvoiceCommodityInfo.java | 34 +++++ .../invoice/reimburse/InvoiceInfoRequest.java | 53 +++++++ .../reimburse/InvoiceInfoResponse.java | 79 ++++++++++ .../invoice/reimburse/InvoiceUserInfo.java | 137 ++++++++++++++++++ .../reimburse/UpdateInvoiceStatusRequest.java | 60 ++++++++ .../reimburse/UpdateStatusBatchRequest.java | 58 ++++++++ .../wx/miniapp/bean/urllink/CloudBase.java | 60 ++++++++ .../bean/urllink/GenerateUrlLinkRequest.java | 85 +++++++++++ .../miniapp/constant/WxMaApiUrlConstants.java | 30 ++++ .../api/impl/WxMaLinkServiceImplTest.java | 31 ++++ .../WxMaReimburseInvoiceServiceImplTest.java | 89 ++++++++++++ 18 files changed, 924 insertions(+) create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLinkService.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaReimburseInvoiceService.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLinkServiceImpl.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaReimburseInvoiceServiceImpl.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceBatchRequest.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceCommodityInfo.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceInfoRequest.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceInfoResponse.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceUserInfo.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/UpdateInvoiceStatusRequest.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/UpdateStatusBatchRequest.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/urllink/CloudBase.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/urllink/GenerateUrlLinkRequest.java create mode 100644 weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaLinkServiceImplTest.java create mode 100644 weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaReimburseInvoiceServiceImplTest.java diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLinkService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLinkService.java new file mode 100644 index 0000000000..c3c4559a83 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLinkService.java @@ -0,0 +1,16 @@ +package cn.binarywang.wx.miniapp.api; + + +import cn.binarywang.wx.miniapp.bean.urllink.GenerateUrlLinkRequest; +import me.chanjar.weixin.common.error.WxErrorException; + +/** + * 获取小程序 URL Link接口 + * 接口文档: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html + * @author xiaoyu + * @since 2021-06-10 + */ +public interface WxMaLinkService { + + String generate(GenerateUrlLinkRequest request) throws WxErrorException; +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaReimburseInvoiceService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaReimburseInvoiceService.java new file mode 100644 index 0000000000..e8c2c5cfec --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaReimburseInvoiceService.java @@ -0,0 +1,48 @@ +package cn.binarywang.wx.miniapp.api; + +import cn.binarywang.wx.miniapp.bean.invoice.reimburse.*; +import me.chanjar.weixin.common.error.WxErrorException; + +import java.util.List; + +/** + * 电子发票报销方相关接口 + * 接口文档: https://developers.weixin.qq.com/doc/offiaccount/WeChat_Invoice/E_Invoice/Reimburser_API_List.html + * @author xiaoyu + * @since 2021-06-10 + */ +public interface WxMaReimburseInvoiceService { + + /** + * 查询报销发票信息 + * @param request {@link InvoiceInfoRequest} 查询报销发票信息参数 + * @return {@link InvoiceInfoResponse} 查询结果 + * @throws WxErrorException 查询失败时 + */ + InvoiceInfoResponse getInvoiceInfo(InvoiceInfoRequest request) throws WxErrorException; + + + /** + * 批量查询报销发票信息 + * @param request {@link InvoiceBatchRequest} 批量查询报销发票信息参数对象 + * @return {@link InvoiceInfoResponse} 查询结果列表 + * @throws WxErrorException 查询失败时 + */ + List getInvoiceBatch(InvoiceBatchRequest request) throws WxErrorException; + + + /** + * 更新发票状态 + * @param request {@link UpdateInvoiceStatusRequest} 更新发票状态参数 + * @throws WxErrorException 更新失败时 + */ + void updateInvoiceStatus(UpdateInvoiceStatusRequest request) throws WxErrorException; + + + /** + * 批量更新发票状态 + * @param request {@link UpdateStatusBatchRequest} 批量更新发票状态参数 + * @throws WxErrorException 更新失败时 + */ + void updateStatusBatch(UpdateStatusBatchRequest request) throws WxErrorException; +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java index 55af89289f..962424430f 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java @@ -402,4 +402,16 @@ public interface WxMaService extends WxService { * @return */ WxMaShopSpuService getShopSpuService(); + + /** + * 获取小程序 URL Link服务接口 + * @return + */ + WxMaLinkService getLinkService(); + + /** + * 获取电子发票报销方服务接口 + * @return + */ + WxMaReimburseInvoiceService getReimburseInvoiceService(); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java index 241d0b37f1..600ce0d076 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java @@ -65,6 +65,8 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH private final WxImgProcService imgProcService = new WxMaImgProcServiceImpl(this); private final WxMaShopSpuService shopSpuService = new WxMaShopSpuServiceImpl(this); private final WxMaShopOrderService shopOrderService = new WxMaShopOrderServiceImpl(this); + private final WxMaLinkService linkService = new WxMaLinkServiceImpl(this); + private final WxMaReimburseInvoiceService reimburseInvoiceService = new WxMaReimburseInvoiceServiceImpl(this); private Map configMap; private int retrySleepMillis = 1000; private int maxRetryTimes = 5; @@ -512,4 +514,14 @@ public WxMaShopSpuService getShopSpuService() { public WxMaShopOrderService getShopOrderService() { return this.shopOrderService; } + + @Override + public WxMaLinkService getLinkService() { + return this.linkService; + } + + @Override + public WxMaReimburseInvoiceService getReimburseInvoiceService() { + return this.reimburseInvoiceService; + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLinkServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLinkServiceImpl.java new file mode 100644 index 0000000000..c3b78e4e1e --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLinkServiceImpl.java @@ -0,0 +1,35 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaLinkService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.urllink.GenerateUrlLinkRequest; +import com.google.gson.JsonObject; +import lombok.AllArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonParser; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Link.GENERATE_URLLINK_URL; + +/** + * 获取小程序 URL Link接口实现 + * 接口文档: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html + * @author xiaoyu + * @since 2021-06-10 + */ +@AllArgsConstructor +public class WxMaLinkServiceImpl implements WxMaLinkService { + + private final WxMaService wxMaService; + + @Override + public String generate(GenerateUrlLinkRequest request) throws WxErrorException { + String result = this.wxMaService.post(GENERATE_URLLINK_URL,request); + String linkField = "url_link"; + JsonObject jsonObject = GsonParser.parse(result); + if(jsonObject.has(linkField)){ + return jsonObject.get(linkField).toString(); + } + throw new WxErrorException("无url_link"); + } + } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaReimburseInvoiceServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaReimburseInvoiceServiceImpl.java new file mode 100644 index 0000000000..3d217c8571 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaReimburseInvoiceServiceImpl.java @@ -0,0 +1,44 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaReimburseInvoiceService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.invoice.reimburse.*; +import lombok.AllArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; + +import java.util.List; + +import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Invoice.*; + +/** + * 电子发票报销方相关接口实现 + * 接口文档: https://developers.weixin.qq.com/doc/offiaccount/WeChat_Invoice/E_Invoice/Reimburser_API_List.html + * @author xiaoyu + * @since 2021-06-10 + */ +@AllArgsConstructor +public class WxMaReimburseInvoiceServiceImpl implements WxMaReimburseInvoiceService { + + private final WxMaService wxMaService; + + @Override + public InvoiceInfoResponse getInvoiceInfo(InvoiceInfoRequest request) throws WxErrorException { + return InvoiceInfoResponse.fromJson(this.wxMaService.post(GET_INVOICE_INFO,request.toJson())); + } + + @Override + public List getInvoiceBatch(InvoiceBatchRequest request) throws WxErrorException { + return InvoiceInfoResponse.toList(this.wxMaService.post(GET_INVOICE_BATCH,request.toJson())); + } + + @Override + public void updateInvoiceStatus(UpdateInvoiceStatusRequest request) throws WxErrorException { + this.wxMaService.post(UPDATE_INVOICE_STATUS,request.toJson()); + } + + @Override + public void updateStatusBatch(UpdateStatusBatchRequest request) throws WxErrorException { + this.wxMaService.post(UPDATE_STATUS_BATCH,request.toJson()); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceBatchRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceBatchRequest.java new file mode 100644 index 0000000000..2e974a7c01 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceBatchRequest.java @@ -0,0 +1,41 @@ +package cn.binarywang.wx.miniapp.bean.invoice.reimburse; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +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; + +/** + *
+ * 批量查询报销发票信息参数对象
+ * 
+ * @author xiaoyu + * @since 2021-03-23 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InvoiceBatchRequest implements Serializable { + + private static final long serialVersionUID = -9121443117105107231L; + + /** + * 发票卡券的card_id + *
+   * 是否必填: 是
+   * 
+ */ + @SerializedName("item_list") + private List itemList; + + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceCommodityInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceCommodityInfo.java new file mode 100644 index 0000000000..05302d1e1d --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceCommodityInfo.java @@ -0,0 +1,34 @@ +package cn.binarywang.wx.miniapp.bean.invoice.reimburse; + +import lombok.Data; + +/** + *
+ * 发票商品信息
+ * 
+ * @author xiaoyu + * @since 2021-03-23 + */ +@Data +public class InvoiceCommodityInfo { + + /** + * 项目(商品)名称 + */ + private String name; + + /** + * 项目数量 + */ + private Integer num; + + /** + * 项目单位 + */ + private String unit; + + /** + * 单价,以分为单位 + */ + private Integer price; +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceInfoRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceInfoRequest.java new file mode 100644 index 0000000000..37efe5a91b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceInfoRequest.java @@ -0,0 +1,53 @@ +package cn.binarywang.wx.miniapp.bean.invoice.reimburse; + + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + *
+ * 查询报销发票信息参数对象
+ * 
+ * @author xiaoyu + * @since 2021-03-23 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InvoiceInfoRequest implements Serializable { + + private static final long serialVersionUID = 7854633127026139444L; + + + /** + * 发票卡券的card_id + *
+  * 是否必填: 是
+  * 
+ */ + @SerializedName("card_id") + private String cardId; + + + /** + * 发票卡券的加密code,和card_id共同构成一张发票卡券的唯一标识 + *
+  * 是否必填: 是
+  * 
+ */ + @SerializedName("encrypt_code") + private String encryptCode; + + + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceInfoResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceInfoResponse.java new file mode 100644 index 0000000000..d8348fdc5b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceInfoResponse.java @@ -0,0 +1,79 @@ +package cn.binarywang.wx.miniapp.bean.invoice.reimburse; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; +import lombok.Data; +import me.chanjar.weixin.common.util.json.GsonParser; + +import java.util.List; + +/** + *
+ * 查询报销发票信息响应对象
+ * 
+ * @author xiaoyu + * @since 2021-03-23 + */ +@Data +public class InvoiceInfoResponse { + + /** + * 发票ID + */ + @SerializedName("card_id") + private String cardId; + + + /** + * 发票的有效期起始时间 + */ + @SerializedName("begin_time") + private Integer beginTime; + + /** + * 发票的有效期截止时间 + */ + @SerializedName("end_time") + private Integer endTime; + + /** + * 用户标识 + */ + private String openid; + + /** + * 发票的类型 + */ + private String type; + + /** + * 发票的收款方 + */ + private String payee; + + /** + * 发票详情 + */ + private String detail; + + /** + * 用户可在发票票面看到的主要信息 + */ + @SerializedName("user_info") + private InvoiceUserInfo userInfo; + + + public static InvoiceInfoResponse fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, InvoiceInfoResponse.class); + } + + + public static List toList(String json) { + JsonObject jsonObject = GsonParser.parse(json); + return WxMaGsonBuilder.create().fromJson(jsonObject.get("item_list").toString(), + new TypeToken>() { + }.getType()); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceUserInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceUserInfo.java new file mode 100644 index 0000000000..7e646089fc --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/InvoiceUserInfo.java @@ -0,0 +1,137 @@ +package cn.binarywang.wx.miniapp.bean.invoice.reimburse; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.util.List; + +/** + *
+ * 用户可在发票票面看到的主要信息
+ * 
+ * @author xiaoyu + * @since 2021-03-23 + */ +@Data +public class InvoiceUserInfo { + + /** + * 发票加税合计金额,以分为单位 + */ + private Integer fee; + + /** + * 发票的抬头 + */ + private String title; + + /** + * 开票时间 + */ + @SerializedName("billing_time") + private Integer billingTime; + + /** + * 发票代码 + */ + @SerializedName("billing_no") + private String billingNo; + + /** + * 发票号码 + */ + @SerializedName("billing_code") + private String billingCode; + + /** + * 不含税金额,以分为单位 + */ + @SerializedName("fee_without_tax") + private Integer feeWithoutTax; + + /** + * 税额,以分为单位 + */ + private Integer tax; + + /** + * 发票对应的PDF_URL + */ + @SerializedName("pdf_url") + private String pdfUrl; + + /** + * 其它消费凭证附件对应的URL + */ + @SerializedName("trip_pdf_url") + private String tripPdfUrl; + + /** + * 发票报销状态 + */ + @SerializedName("reimburse_status") + private String reimburseStatus; + + /** + * 校验码 + */ + @SerializedName("check_code") + private String checkCode; + + /** + * 购买方纳税人识别号 + */ + @SerializedName("buyer_number") + private String buyerNumber; + + /** + * 购买方地址、电话 + */ + @SerializedName("buyer_address_and_phone") + private String buyerAddressAndPhone; + + /** + * 购买方开户行及账号 + */ + @SerializedName("buyer_bank_account") + private String buyerBankAccount; + + /** + * 销售方纳税人识别号 + */ + @SerializedName("seller_number") + private String sellerNumber; + + /** + * 销售方地址、电话 + */ + @SerializedName("seller_address_and_phone") + private String sellerAddressAndPhone; + + /** + * 销售方开户行及账号 + */ + @SerializedName("seller_bank_account") + private String sellerBankAccount; + + /** + * 备注 + */ + private String remarks; + + /** + * 收款人 + */ + private String cashier; + + /** + * 开票人 + */ + private String maker; + + /** + * 商品信息结构 + */ + private List info; +} + diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/UpdateInvoiceStatusRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/UpdateInvoiceStatusRequest.java new file mode 100644 index 0000000000..74b30b49fc --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/UpdateInvoiceStatusRequest.java @@ -0,0 +1,60 @@ +package cn.binarywang.wx.miniapp.bean.invoice.reimburse; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; + +/** + *
+ * 更新发票状态参数对象
+ * 
+ * @author xiaoyu + * @since 2021-03-23 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UpdateInvoiceStatusRequest implements Serializable { + + private static final long serialVersionUID = -4122242332481909977L; + + + /** + * 发票卡券的card_id + *
+   * 是否必填: 是
+   * 
+ */ + @SerializedName("card_id") + private String cardId; + + + /** + * 发票卡券的加密code,和card_id共同构成一张发票卡券的唯一标识 + *
+   * 是否必填: 是
+   * 
+ */ + @SerializedName("encrypt_code") + private String encryptCode; + + + /** + * 发票报销状态 + *
+   * 是否必填: 是
+   * 
+ */ + @SerializedName("reimburse_status") + private String reimburseStatus; + + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/UpdateStatusBatchRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/UpdateStatusBatchRequest.java new file mode 100644 index 0000000000..c2e020356d --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/invoice/reimburse/UpdateStatusBatchRequest.java @@ -0,0 +1,58 @@ +package cn.binarywang.wx.miniapp.bean.invoice.reimburse; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +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; + +/** + *
+ * 批量更新发票状态参数对象
+ * 
+ * @author xiaoyu + * @since 2021-03-23 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UpdateStatusBatchRequest implements Serializable { + + private static final long serialVersionUID = 7016357689566912199L; + /** + * 用户openid + *
+   * 是否必填: 是
+   * 
+ */ + private String openid; + + /** + * 发票报销状态 + *
+   * 是否必填: 是
+   * 
+ */ + @SerializedName("reimburse_status") + private String reimburseStatus; + + /** + * 发票列表 + *
+   * 是否必填: 是
+   * 
+ */ + @SerializedName("invoice_list") + private List invoiceList; + + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/urllink/CloudBase.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/urllink/CloudBase.java new file mode 100644 index 0000000000..7e0d645b5d --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/urllink/CloudBase.java @@ -0,0 +1,60 @@ +package cn.binarywang.wx.miniapp.bean.urllink; + +import com.google.gson.annotations.SerializedName; +import lombok.Builder; +import lombok.Data; + +/** + *
+ * 云开发静态网站自定义 H5 配置参数
+ * 
+ * @author xiaoyu + * @since 2021-06-11 + */ +@Data +@Builder +public class CloudBase { + + /** + * 云开发环境 + *
+   * 是否必填: 是
+   * 
+ */ + private String env; + + /** + * 静态网站自定义域名,不填则使用默认域名 + *
+   * 是否必填: 否
+   * 
+ */ + private String domain; + + /** + * 云开发静态网站 H5 页面路径,不可携带 query + *
+   * 默认值:/
+   * 是否必填: 否
+   * 
+ */ + private String path; + + /** + * 云开发静态网站 H5 页面 query 参数,最大 1024 个字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~ + *
+   * 是否必填: 否
+   * 
+ */ + private String query; + + /** + * 第三方批量代云开发时必填,表示创建该 env 的 appid (小程序/第三方平台) + *
+   * 是否必填: 否
+   * 
+ */ + @SerializedName("resource_appid") + private String resourceAppid; + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/urllink/GenerateUrlLinkRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/urllink/GenerateUrlLinkRequest.java new file mode 100644 index 0000000000..207aa3deee --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/urllink/GenerateUrlLinkRequest.java @@ -0,0 +1,85 @@ +package cn.binarywang.wx.miniapp.bean.urllink; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; + +/** + *
+ * 获取小程序 URL Link参数对象
+ * 
+ * @author xiaoyu + * @since 2021-06-11 + */ +@Data +@Builder +public class GenerateUrlLinkRequest implements Serializable { + + private static final long serialVersionUID = -2183685760797791910L; + + /** + * 通过 URL Link 进入的小程序页面路径,必须是已经发布的小程序存在的页面,不可携带 query 。path 为空时会跳转小程序主页 + *
+   * 是否必填: 是
+   * 
+ */ + private String path; + + /** + * 通过 URL Link 进入小程序时的query,最大1024个字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~ + *
+   * 是否必填: 是
+   * 
+ */ + private String query; + + /** + * 生成的 URL Link 类型,到期失效:true,永久有效:false + *
+   * 默认值:false
+   * 是否必填: 否
+   * 
+ */ + @SerializedName("is_expire") + private Boolean isExpire; + + /** + * 小程序 URL Link 失效类型,失效时间:0,失效间隔天数:1 + *
+   * 是否必填: 是
+   * 
+ */ + @SerializedName("expire_type") + private Integer expireType; + + /** + * 到期失效的 URL Link 的失效时间,为 Unix 时间戳。生成的到期失效 URL Link 在该时间前有效。最长有效期为1年。expire_type 为 0 必填 + *
+   * 是否必填: 是
+   * 
+ */ + @SerializedName("expire_time") + private Integer expireTime; + + /** + * 到期失效的URL Link的失效间隔天数。生成的到期失效URL Link在该间隔时间到达前有效。最长间隔天数为365天。expire_type 为 1 必填 + *
+   * 是否必填: 是
+   * 
+ */ + @SerializedName("expire_interval") + private Integer expireInterval; + + /** + * 云开发静态网站自定义 H5 配置参数,可配置中转的云开发 H5 页面。不填默认用官方 H5 页面 + *
+   * 是否必填: 否
+   * 
+ */ + @SerializedName("cloud_base") + private CloudBase cloudBase; + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java index 71ee8500e0..d2d15b8f50 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java @@ -222,6 +222,10 @@ public interface Scheme { String GENERATE_SCHEME_URL = "https://api.weixin.qq.com/wxa/generatescheme"; } + public interface Link { + String GENERATE_URLLINK_URL = "https://api.weixin.qq.com/wxa/generate_urllink"; + } + public interface SecCheck { String IMG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/img_sec_check"; String MSG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/msg_sec_check"; @@ -316,4 +320,30 @@ interface Order { String ORDER_GET = "https://api.weixin.qq.com/shop/order/get"; } } + + /** + * 电子发票报销方 + */ + public interface Invoice{ + + /** + * 报销方查询报销发票信息 + */ + String GET_INVOICE_INFO = "https://api.weixin.qq.com/card/invoice/reimburse/getinvoiceinfo"; + + /** + * 报销方批量查询报销发票信息 + */ + String GET_INVOICE_BATCH = "https://api.weixin.qq.com/card/invoice/reimburse/getinvoicebatch"; + + /** + * 报销方更新发票状态 + */ + String UPDATE_INVOICE_STATUS = "https://api.weixin.qq.com/card/invoice/reimburse/updateinvoicestatus"; + + /** + * 报销方批量更新发票状态 + */ + String UPDATE_STATUS_BATCH = "https://api.weixin.qq.com/card/invoice/reimburse/updatestatusbatch"; + } } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaLinkServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaLinkServiceImplTest.java new file mode 100644 index 0000000000..68ca9b6214 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaLinkServiceImplTest.java @@ -0,0 +1,31 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.urllink.GenerateUrlLinkRequest; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaLinkServiceImplTest { + + @Inject + private WxMaService wxMaService; + + @Test + public void testGenerate() throws WxErrorException { + + GenerateUrlLinkRequest request = GenerateUrlLinkRequest.builder() + .path("pages/tabBar/home/home") + .build(); + + String url = this.wxMaService.getLinkService().generate(request); + + System.out.println(url); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaReimburseInvoiceServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaReimburseInvoiceServiceImplTest.java new file mode 100644 index 0000000000..a7263bdf59 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaReimburseInvoiceServiceImplTest.java @@ -0,0 +1,89 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.invoice.reimburse.*; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.gson.GsonBuilder; +import com.google.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.testng.Assert.*; + +@Slf4j +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaReimburseInvoiceServiceImplTest { + + @Inject + private WxMaService wxMaService; + + @Test + public void testGetInvoiceInfo() throws WxErrorException { + + InvoiceInfoRequest request = InvoiceInfoRequest.builder() + .cardId("**********************") + .encryptCode("**********************") + .build(); + + InvoiceInfoResponse response = this.wxMaService.getReimburseInvoiceService().getInvoiceInfo(request); + + log.info("response: {}", new GsonBuilder().create().toJson(response)); + } + + @Test + public void testGetInvoiceBatch() throws WxErrorException { + + List invoices = new ArrayList<>(); + InvoiceInfoRequest r = InvoiceInfoRequest.builder() + .cardId("**********************") + .encryptCode("********************************************") + .build(); + invoices.add(r); + r = InvoiceInfoRequest.builder() + .cardId("**********************") + .encryptCode("********************************************") + .build(); + invoices.add(r); + + InvoiceBatchRequest request = InvoiceBatchRequest.builder().itemList(invoices).build(); + + List responses = this.wxMaService.getReimburseInvoiceService().getInvoiceBatch(request); + log.info("responses: {}",new GsonBuilder().create().toJson(responses)); + } + + @Test + public void testUpdateInvoiceStatus() throws WxErrorException { + UpdateInvoiceStatusRequest request = UpdateInvoiceStatusRequest.builder() + .cardId("**********************") + .encryptCode("********************************************") + .reimburseStatus("INVOICE_REIMBURSE_INIT") + .build(); + + this.wxMaService.getReimburseInvoiceService().updateInvoiceStatus(request); + } + + @Test + public void testUpdateStatusBatch() throws WxErrorException { + + List invoices = new ArrayList<>(); + InvoiceInfoRequest r = InvoiceInfoRequest.builder() + .cardId("**************") + .encryptCode("**************") + .build(); + invoices.add(r); + + UpdateStatusBatchRequest request = UpdateStatusBatchRequest.builder() + .invoiceList(invoices) + .openid("**************") + .reimburseStatus("INVOICE_REIMBURSE_LOCK") + .build(); + + this.wxMaService.getReimburseInvoiceService().updateStatusBatch(request); + } +} From d6d3625b4cc2297e0769b4c7b4584497622ad872 Mon Sep 17 00:00:00 2001 From: pg Date: Mon, 21 Jun 2021 11:58:13 +0800 Subject: [PATCH 14/17] =?UTF-8?q?:art:=20#2155=20=E3=80=90=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1=E3=80=91=E5=8F=91=E9=80=81=E6=96=B0?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E6=AC=A2=E8=BF=8E=E8=AF=AD=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E8=A7=86=E9=A2=91=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E6=94=AF=E6=8C=81=EF=BC=8C=E5=90=8C=E6=97=B6=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E7=BB=93=E6=9E=84=E4=B8=8D=E6=AD=A3=E7=A1=AE=E7=9A=84?= =?UTF-8?q?=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 ce744b9f24..ade49684ce 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 0000000000..0c64b9bf63 --- /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 0000000000..237fb75cfe --- /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 4a41fa8f71..69db78efbe 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 29089d478d..4b6221d175 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 4f5be601e05ceeb241916efa263abf9a55143134 Mon Sep 17 00:00:00 2001 From: pg Date: Tue, 22 Jun 2021 10:57:32 +0800 Subject: [PATCH 15/17] =?UTF-8?q?:new:=20#2150=20=E3=80=90=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1=E3=80=91=E8=A1=A5=E5=85=85=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E9=83=A8=E5=88=86=E5=AE=A2=E6=88=B7=E8=81=94=E7=B3=BB?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=8C=E4=BB=A5=E5=8F=8A=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=95=86=E6=A8=A1=E5=BC=8F=E5=A4=96=E9=83=A8=E8=81=94=E7=B3=BB?= =?UTF-8?q?=E4=BA=BAopenid=E8=BD=AC=E6=8D=A2=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 | 113 ++++++++++++++++++ .../impl/WxCpExternalContactServiceImpl.java | 63 ++++++++++ ...WxCpUserExternalGroupChatTransferResp.java | 51 ++++++++ .../external/WxCpUserTransferCustomerReq.java | 49 ++++++++ .../WxCpUserTransferCustomerResp.java | 60 ++++++++++ .../external/WxCpUserTransferResultResp.java | 92 ++++++++++++++ .../weixin/cp/constant/WxCpApiPathConsts.java | 7 ++ .../WxCpExternalContactServiceImplTest.java | 52 +++++++- 8 files changed, 486 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 231e0bfa3e..cd65ad3771 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; @@ -134,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; + /** * 批量获取客户详情. *
@@ -225,9 +234,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 transferResult(@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 resignedTransferResult(@NotNull String handOverUserid, @NotNull String takeOverUserid, String cursor)  throws WxErrorException;
+
   /**
    * 
    * 该接口用于获取配置过客户群管理的客户群列表。
@@ -260,6 +345,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 +508,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 19e7cdfe79..8065d21980 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,8 @@
 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.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;
@@ -15,6 +17,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;
@@ -106,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,
@@ -176,6 +189,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 transferResult(@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 resignedTransferResult(@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 +257,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 0000000000..ff6fb82374
--- /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 0000000000..e8b8142cc6
--- /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 0000000000..27d1c0ad4c
--- /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 0000000000..e1b8cc4591
--- /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 bc96269ea8..c60a1bddbd 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,13 +175,20 @@ 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=";
     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 4b6221d175..8869a6a02b 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().transferResult("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().resignedTransferResult("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 b6092dbb5c4bd137250462134077867d0c6e0901 Mon Sep 17 00:00:00 2001
From: arthur0201 <704538660@qq.com>
Date: Wed, 23 Jun 2021 13:47:24 +0800
Subject: [PATCH 16/17] =?UTF-8?q?:new:=20#2161=20=E3=80=90=E5=85=AC?=
 =?UTF-8?q?=E4=BC=97=E5=8F=B7=E3=80=91=E5=BE=AE=E4=BF=A1=E6=8E=A8=E9=80=81?=
 =?UTF-8?q?=E6=B6=88=E6=81=AF=E7=B1=BB=E5=A2=9E=E5=8A=A0=E7=BE=A4=E5=8F=91?=
 =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E4=BA=8B=E4=BB=B6=E7=9B=B8=E5=85=B3=E5=AD=97?=
 =?UTF-8?q?=E6=AE=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/me/chanjar/weixin/common/api/WxConsts.java   | 11 +++++++++++
 .../external/contact/WxCpExternalContactInfo.java     |  3 +++
 2 files changed, 14 insertions(+)

diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
index cfc7fc0f37..3e08462017 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
@@ -156,6 +156,12 @@ public static class MassMsgStatus {
     public static final String ERR_20013 = "err(20013)";
     public static final String ERR_22000 = "err(22000)";
     public static final String ERR_21000 = "err(21000)";
+    public static final String ERR_30001 = "err(30001)";
+    public static final String ERR_30002 = "err(30002)";
+    public static final String ERR_30003 = "err(30003)";
+    public static final String ERR_40001 = "err(40001)";
+    public static final String ERR_40002 = "err(40002)";
+
 
     /**
      * 群发反馈消息代码所对应的文字描述.
@@ -174,6 +180,11 @@ public static class MassMsgStatus {
       STATUS_DESC.put(ERR_20013, "涉嫌版权");
       STATUS_DESC.put(ERR_22000, "涉嫌互推_互相宣传");
       STATUS_DESC.put(ERR_21000, "涉嫌其他");
+      STATUS_DESC.put(ERR_30001, "原创校验出现系统错误且用户选择了被判为转载就不群发");
+      STATUS_DESC.put(ERR_30002, "原创校验被判定为不能群发");
+      STATUS_DESC.put(ERR_30003, "原创校验被判定为转载文且用户选择了被判为转载就不群发");
+      STATUS_DESC.put(ERR_40001, "管理员拒绝");
+      STATUS_DESC.put(ERR_40002, "管理员30分钟内无响应,超时");
     }
   }
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/contact/WxCpExternalContactInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/contact/WxCpExternalContactInfo.java
index bd7229384c..468aa53f1e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/contact/WxCpExternalContactInfo.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/contact/WxCpExternalContactInfo.java
@@ -26,6 +26,9 @@ public class WxCpExternalContactInfo implements Serializable {
   @SerializedName("follow_user")
   private List followedUsers;
 
+  @SerializedName("next_cursor")
+  private String nextCursor;
+
   public static WxCpExternalContactInfo fromJson(String json) {
     return WxCpGsonBuilder.create().fromJson(json, WxCpExternalContactInfo.class);
   }

From e56eb911e729493ad962f522b253ab42749b30e6 Mon Sep 17 00:00:00 2001
From: zpf <178668028@qq.com>
Date: Wed, 23 Jun 2021 15:52:46 +0800
Subject: [PATCH 17/17] =?UTF-8?q?1.=E5=A2=9E=E5=8A=A0=E6=9F=A5=E8=AF=A2?=
 =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E5=8F=AF=E5=9B=9E=E9=80=80=E7=9A=84?=
 =?UTF-8?q?=E7=89=88=E6=9C=AC=20=E6=8E=A5=E5=8F=A3=202.=E5=B0=86WxOpenFast?=
 =?UTF-8?q?MaService=E6=A0=87=E8=AE=B0=E8=BF=87=E6=97=B6(=E6=8E=A5?=
 =?UTF-8?q?=E5=8F=A3=E5=B9=B6=E9=9D=9E=E6=98=AF=E5=BF=AB=E9=80=9F=E5=88=9B?=
 =?UTF-8?q?=E5=BB=BA=E5=B0=8F=E7=A8=8B=E5=BA=8F=E7=8B=AC=E6=9C=89)?=
 =?UTF-8?q?=E5=B9=B6=E5=B0=86=E5=8E=9F=E6=9C=89=E6=96=B9=E6=B3=95=E5=A4=8D?=
 =?UTF-8?q?=E5=88=B6=E5=88=B0WxOpenMaBasicService?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../open/api/WxOpenComponentService.java      |   2 +
 .../weixin/open/api/WxOpenFastMaService.java  | 191 +----------------
 .../weixin/open/api/WxOpenMaBasicService.java | 199 ++++++++++++++++++
 .../weixin/open/api/WxOpenMaService.java      |  17 ++
 .../api/impl/WxOpenFastMaServiceImpl.java     |   2 +
 .../api/impl/WxOpenMaBasicServiceImpl.java    | 135 ++++++++++++
 .../open/api/impl/WxOpenMaServiceImpl.java    |  11 +
 .../open/bean/ma/WxOpenMaHistoryVersion.java  |  34 +++
 .../result/WxOpenMaHistoryVersionResult.java  |  29 +++
 9 files changed, 432 insertions(+), 188 deletions(-)
 create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java
 create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java
 create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaHistoryVersion.java
 create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaHistoryVersionResult.java

diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java
index 26dc2ba7f2..4c7f5b0911 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java
@@ -148,7 +148,9 @@ public interface WxOpenComponentService {
    *
    * @param appid .
    * @return . wx fast ma service by appid
+   * @deprecated 2021-06-23 本接口原有方法并非仅快速创建小程序的专用接口,普通小程序授权到第三方平台皆可使用,所以请使用 {@link WxOpenMaBasicService} 类替代。获取方法: WxOpenMaService.getBasicService()
    */
+  @Deprecated
   WxOpenFastMaService getWxFastMaServiceByAppid(String appid);
 
   /**
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java
index 8710689cdc..2114d1a816 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java
@@ -1,11 +1,6 @@
 package me.chanjar.weixin.open.api;
 
 import cn.binarywang.wx.miniapp.api.WxMaService;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.open.bean.ma.WxFastMaCategory;
-import me.chanjar.weixin.open.bean.result.*;
-
-import java.util.List;
 
 /**
  * 
@@ -16,189 +11,9 @@
  *
  * @author Hipple
  * @date 2019/01/23
+ * @deprecated 2021-06-23 本接口原有方法并非仅快速创建小程序的专用接口,普通小程序授权到第三方平台皆可使用,所以请使用 {@link WxOpenMaBasicService} 类替代。获取方法: WxOpenComponentService.getWxMaServiceByAppid(maApppId).getBasicService()
  */
-public interface WxOpenFastMaService extends WxMaService {
-  /**
-   * 1 获取帐号基本信息.
-   */
-  String OPEN_GET_ACCOUNT_BASIC_INFO = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo";
-
-  /**
-   * 2 小程序名称设置及改名.
-   */
-  String OPEN_SET_NICKNAME = "https://api.weixin.qq.com/wxa/setnickname";
-
-  /**
-   * 3 小程序改名审核状态查询.
-   */
-  String OPEN_API_WXA_QUERYNICKNAME = "https://api.weixin.qq.com/wxa/api_wxa_querynickname";
-
-  /**
-   * 4 微信认证名称检测.
-   */
-  String OPEN_CHECK_WX_VERIFY_NICKNAME = "https://api.weixin.qq.com/cgi-bin/wxverify/checkwxverifynickname";
-
-  /**
-   * 5 修改头像.
-   */
-  String OPEN_MODIFY_HEADIMAGE = "https://api.weixin.qq.com/cgi-bin/account/modifyheadimage";
-
-  /**
-   * 6修改功能介绍.
-   */
-  String OPEN_MODIFY_SIGNATURE = "https://api.weixin.qq.com/cgi-bin/account/modifysignature";
-
-  /**
-   * 7 换绑小程序管理员接口.
-   */
-  String OPEN_COMPONENT_REBIND_ADMIN = "https://api.weixin.qq.com/cgi-bin/account/componentrebindadmin";
-
-  /**
-   * 8.1 获取账号可以设置的所有类目
-   */
-  String OPEN_GET_ALL_CATEGORIES = "https://api.weixin.qq.com/cgi-bin/wxopen/getallcategories";
-  /**
-   * 8.2 添加类目
-   */
-  String OPEN_ADD_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/addcategory";
-  /**
-   * 8.3 删除类目
-   */
-  String OPEN_DELETE_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/deletecategory";
-  /**
-   * 8.4 获取账号已经设置的所有类目
-   */
-  String OPEN_GET_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/getcategory";
-  /**
-   * 8.5 修改类目
-   */
-  String OPEN_MODIFY_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/modifycategory";
-
-
-  /**
-   * 1.获取小程序的信息
-   *
-   * @return .
-   * @throws WxErrorException .
-   */
-  WxFastMaAccountBasicInfoResult getAccountBasicInfo() throws WxErrorException;
-
-  /**
-   * 2.小程序名称设置及改名
-   * 
-   *      若接口未返回audit_id,说明名称已直接设置成功,无需审核;若返回audit_id则名称正在审核中。
-   *  
- * - * @param nickname 昵称 - * @param idCard 身份证照片–临时素材mediaid(个人号必填) - * @param license 组织机构代码证或营业执照–临时素材mediaid(组织号必填) - * @param namingOtherStuff1 其他证明材料---临时素材 mediaid - * @param namingOtherStuff2 其他证明材料---临时素材 mediaid - * @return . - * @throws WxErrorException . - */ - WxFastMaSetNickameResult setNickname(String nickname, String idCard, String license, String namingOtherStuff1, - String namingOtherStuff2) throws WxErrorException; - - /** - * 3 小程序改名审核状态查询 - * - * @param auditId 审核单id - * @return . - * @throws WxErrorException . - */ - WxFastMaQueryNicknameStatusResult querySetNicknameStatus(String auditId) throws WxErrorException; - - /** - * 4. 微信认证名称检测 - * - * @param nickname 名称 - * @return . - * @throws WxErrorException . - */ - WxFastMaCheckNickameResult checkWxVerifyNickname(String nickname) throws WxErrorException; - - /** - * 5.修改头像 - *
-   *     图片格式只支持:BMP、JPEG、JPG、GIF、PNG,大小不超过2M
-   *      注:实际头像始终为正方形
-   * 
- * - * @param headImgMediaId 头像素材media_id - * @param x1 裁剪框左上角x坐标(取值范围:[0, 1]) - * @param y1 裁剪框左上角y坐标(取值范围:[0, 1]) - * @param x2 裁剪框右下角x坐标(取值范围:[0, 1]) - * @param y2 裁剪框右下角y坐标(取值范围:[0, 1]) - * @return . - * @throws WxErrorException . - */ - WxOpenResult modifyHeadImage(String headImgMediaId, float x1, float y1, float x2, float y2) throws WxErrorException; - - /** - * 6.修改功能介绍 - * - * @param signature 简介:4-120字 - * @return . - * @throws WxErrorException . - */ - WxOpenResult modifySignature(String signature) throws WxErrorException; - - /** - * 7.3 管理员换绑 - * - * @param taskId 换绑管理员任务序列号(公众平台最终点击提交回跳到第三方平台时携带) - * @return . - * @throws WxErrorException . - */ - WxOpenResult componentRebindAdmin(String taskId) throws WxErrorException; - - /** - * 8.1 获取账号可以设置的所有类目 - *
-   *     因为不同类目含有特定字段
-   *     目前没有完整的类目信息数据
-   *     为保证兼容性,放弃将response转换为实体
-   * 
- * - * @return . - * @throws WxErrorException . - */ - String getAllCategories() throws WxErrorException; - - /** - * 8.2添加类目 - * - * @param categoryList 类目列表 - * @return . - * @throws WxErrorException . - */ - WxOpenResult addCategory(List categoryList) throws WxErrorException; - - /** - * 8.3删除类目 - * - * @param first 一级类目ID - * @param second 二级类目ID - * @return . - * @throws WxErrorException . - */ - WxOpenResult deleteCategory(int first, int second) throws WxErrorException; - - /** - * 8.4获取账号已经设置的所有类目 - * - * @return . - * @throws WxErrorException . - */ - WxFastMaBeenSetCategoryResult getCategory() throws WxErrorException; +@Deprecated +public interface WxOpenFastMaService extends WxOpenMaBasicService, WxMaService { - /** - * 8.5修改类目 - * - * @param category 实体 - * @return . - * @throws WxErrorException . - */ - WxOpenResult modifyCategory(WxFastMaCategory category) throws WxErrorException; } diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java new file mode 100644 index 0000000000..194da4b9b3 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java @@ -0,0 +1,199 @@ +package me.chanjar.weixin.open.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.bean.ma.WxFastMaCategory; +import me.chanjar.weixin.open.bean.result.*; + +import java.util.List; + +/** + * 微信第三方平台 小程序基础信息接口 (小程序名称、头像、描述、类目等信息设置) + * https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/category/getallcategories.html + * + * @author 广州跨界 + */ +public interface WxOpenMaBasicService { + /** + * 1 获取帐号基本信息. + */ + String OPEN_GET_ACCOUNT_BASIC_INFO = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo"; + + /** + * 2 小程序名称设置及改名. + */ + String OPEN_SET_NICKNAME = "https://api.weixin.qq.com/wxa/setnickname"; + + /** + * 3 小程序改名审核状态查询. + */ + String OPEN_API_WXA_QUERYNICKNAME = "https://api.weixin.qq.com/wxa/api_wxa_querynickname"; + + /** + * 4 微信认证名称检测. + */ + String OPEN_CHECK_WX_VERIFY_NICKNAME = "https://api.weixin.qq.com/cgi-bin/wxverify/checkwxverifynickname"; + + /** + * 5 修改头像. + */ + String OPEN_MODIFY_HEADIMAGE = "https://api.weixin.qq.com/cgi-bin/account/modifyheadimage"; + + /** + * 6修改功能介绍. + */ + String OPEN_MODIFY_SIGNATURE = "https://api.weixin.qq.com/cgi-bin/account/modifysignature"; + + /** + * 7 换绑小程序管理员接口. + */ + String OPEN_COMPONENT_REBIND_ADMIN = "https://api.weixin.qq.com/cgi-bin/account/componentrebindadmin"; + + /** + * 8.1 获取账号可以设置的所有类目 + */ + String OPEN_GET_ALL_CATEGORIES = "https://api.weixin.qq.com/cgi-bin/wxopen/getallcategories"; + /** + * 8.2 添加类目 + */ + String OPEN_ADD_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/addcategory"; + /** + * 8.3 删除类目 + */ + String OPEN_DELETE_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/deletecategory"; + /** + * 8.4 获取账号已经设置的所有类目 + */ + String OPEN_GET_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/getcategory"; + /** + * 8.5 修改类目 + */ + String OPEN_MODIFY_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/modifycategory"; + + + /** + * 1.获取小程序的信息 + * + * @return . + * @throws WxErrorException . + */ + WxFastMaAccountBasicInfoResult getAccountBasicInfo() throws WxErrorException; + + /** + * 2.小程序名称设置及改名 + *
+   *      若接口未返回audit_id,说明名称已直接设置成功,无需审核;若返回audit_id则名称正在审核中。
+   *  
+ * + * @param nickname 昵称 + * @param idCard 身份证照片–临时素材mediaid(个人号必填) + * @param license 组织机构代码证或营业执照–临时素材mediaid(组织号必填) + * @param namingOtherStuff1 其他证明材料---临时素材 mediaid + * @param namingOtherStuff2 其他证明材料---临时素材 mediaid + * @return . + * @throws WxErrorException . + */ + WxFastMaSetNickameResult setNickname(String nickname, String idCard, String license, String namingOtherStuff1, + String namingOtherStuff2) throws WxErrorException; + + /** + * 3 小程序改名审核状态查询 + * + * @param auditId 审核单id + * @return . + * @throws WxErrorException . + */ + WxFastMaQueryNicknameStatusResult querySetNicknameStatus(String auditId) throws WxErrorException; + + /** + * 4. 微信认证名称检测 + * + * @param nickname 名称 + * @return . + * @throws WxErrorException . + */ + WxFastMaCheckNickameResult checkWxVerifyNickname(String nickname) throws WxErrorException; + + /** + * 5.修改头像 + *
+   *     图片格式只支持:BMP、JPEG、JPG、GIF、PNG,大小不超过2M
+   *      注:实际头像始终为正方形
+   * 
+ * + * @param headImgMediaId 头像素材media_id + * @param x1 裁剪框左上角x坐标(取值范围:[0, 1]) + * @param y1 裁剪框左上角y坐标(取值范围:[0, 1]) + * @param x2 裁剪框右下角x坐标(取值范围:[0, 1]) + * @param y2 裁剪框右下角y坐标(取值范围:[0, 1]) + * @return . + * @throws WxErrorException . + */ + WxOpenResult modifyHeadImage(String headImgMediaId, float x1, float y1, float x2, float y2) throws WxErrorException; + + /** + * 6.修改功能介绍 + * + * @param signature 简介:4-120字 + * @return . + * @throws WxErrorException . + */ + WxOpenResult modifySignature(String signature) throws WxErrorException; + + /** + * 7.3 管理员换绑 + * + * @param taskId 换绑管理员任务序列号(公众平台最终点击提交回跳到第三方平台时携带) + * @return . + * @throws WxErrorException . + */ + WxOpenResult componentRebindAdmin(String taskId) throws WxErrorException; + + /** + * 8.1 获取账号可以设置的所有类目 + *
+   *     因为不同类目含有特定字段
+   *     目前没有完整的类目信息数据
+   *     为保证兼容性,放弃将response转换为实体
+   * 
+ * + * @return . + * @throws WxErrorException . + */ + String getAllCategories() throws WxErrorException; + + /** + * 8.2添加类目 + * + * @param categoryList 类目列表 + * @return . + * @throws WxErrorException . + */ + WxOpenResult addCategory(List categoryList) throws WxErrorException; + + /** + * 8.3删除类目 + * + * @param first 一级类目ID + * @param second 二级类目ID + * @return . + * @throws WxErrorException . + */ + WxOpenResult deleteCategory(int first, int second) throws WxErrorException; + + /** + * 8.4获取账号已经设置的所有类目 + * + * @return . + * @throws WxErrorException . + */ + WxFastMaBeenSetCategoryResult getCategory() throws WxErrorException; + + /** + * 8.5修改类目 + * + * @param category 实体 + * @return . + * @throws WxErrorException . + */ + WxOpenResult modifyCategory(WxFastMaCategory category) throws WxErrorException; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java index ccaeeff019..9732e614ac 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java @@ -452,6 +452,16 @@ WxOpenMaDomainResult modifyDomain(String action, List requestDomains, Li */ WxOpenResult revertCodeRelease() throws WxErrorException; + /** + * 获取可回退的小程序版本 + * 调用本接口可以获取可回退的小程序版本(最多保存最近发布或回退的5个版本 + * 文档地址: https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/code/get_history_version.html + * + * @return 历史版本信息 + * @throws WxErrorException 如果调用微信接口失败抛出此异常 + */ + WxOpenMaHistoryVersionResult getHistoryVersion() throws WxErrorException; + /** * 15. 小程序审核撤回 *

@@ -583,4 +593,11 @@ WxOpenMaDomainResult modifyDomain(String action, List requestDomains, Li * @throws WxErrorException the wx error exception */ WxOpenResult publishQrcodeJump(String prefix) throws WxErrorException; + + /** + * 小程序基础信息服务 (小程序名称、头像、描述、类目等信息设置) + * + * @return 小程序基础信息服务 + */ + WxOpenMaBasicService getBasicService(); } diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java index 2cea9530bb..f5f2160d21 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java @@ -20,7 +20,9 @@ * * @author Hipple * @since 2019/1/23 15:27 + * @deprecated 请使用 {@link WxOpenMaServiceImpl} 替代 */ +@Deprecated public class WxOpenFastMaServiceImpl extends WxMaServiceImpl implements WxOpenFastMaService { private final WxOpenComponentService wxOpenComponentService; private final WxMaConfig wxMaConfig; diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java new file mode 100644 index 0000000000..4e4db75257 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java @@ -0,0 +1,135 @@ +package me.chanjar.weixin.open.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.api.WxOpenMaBasicService; +import me.chanjar.weixin.open.bean.ma.WxFastMaCategory; +import me.chanjar.weixin.open.bean.result.*; +import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 微信第三方平台 小程序基础信息接口 + * + * @author 广州跨界 + */ +public class WxOpenMaBasicServiceImpl implements WxOpenMaBasicService { + + private final WxMaService wxMaService; + + public WxOpenMaBasicServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + + @Override + public WxFastMaAccountBasicInfoResult getAccountBasicInfo() throws WxErrorException { + String response = wxMaService.get(OPEN_GET_ACCOUNT_BASIC_INFO, ""); + return WxOpenGsonBuilder.create().fromJson(response, WxFastMaAccountBasicInfoResult.class); + } + + @Override + public WxFastMaSetNickameResult setNickname(String nickname, String idCard, String license, String namingOtherStuff1, String namingOtherStuff2) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("nick_name", nickname); + params.addProperty("id_card", idCard); + params.addProperty("license", license); + params.addProperty("naming_other_stuff_1", namingOtherStuff1); + params.addProperty("naming_other_stuff_2", namingOtherStuff2); + String response = wxMaService.post(OPEN_SET_NICKNAME, params); + return WxOpenGsonBuilder.create().fromJson(response, WxFastMaSetNickameResult.class); + } + + @Override + public WxFastMaQueryNicknameStatusResult querySetNicknameStatus(String auditId) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("audit_id", auditId); + String response = wxMaService.post(OPEN_API_WXA_QUERYNICKNAME, params); + return WxOpenGsonBuilder.create().fromJson(response, WxFastMaQueryNicknameStatusResult.class); + } + + @Override + public WxFastMaCheckNickameResult checkWxVerifyNickname(String nickname) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("nick_name", nickname); + String response = wxMaService.post(OPEN_CHECK_WX_VERIFY_NICKNAME, params); + return WxOpenGsonBuilder.create().fromJson(response, WxFastMaCheckNickameResult.class); + } + + @Override + public WxOpenResult modifyHeadImage(String headImgMediaId, float x1, float y1, float x2, float y2) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("head_img_media_id", headImgMediaId); + params.addProperty("x1", x1); + params.addProperty("y1", y1); + params.addProperty("x2", x2); + params.addProperty("y2", y2); + String response = wxMaService.post(OPEN_MODIFY_HEADIMAGE, params); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + @Override + public WxOpenResult modifySignature(String signature) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("signature", signature); + String response = wxMaService.post(OPEN_MODIFY_SIGNATURE, params); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + @Override + public WxOpenResult componentRebindAdmin(String taskid) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("taskid", taskid); + String response = wxMaService.post(OPEN_COMPONENT_REBIND_ADMIN, params); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + @Override + public String getAllCategories() throws WxErrorException { + return wxMaService.get(OPEN_GET_ALL_CATEGORIES, ""); + } + + @Override + public WxOpenResult addCategory(List categoryList) throws WxErrorException { + Map map = new HashMap<>(); + map.put("categories", categoryList); + String response = wxMaService.post(OPEN_ADD_CATEGORY, WxOpenGsonBuilder.create().toJson(map)); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + @Override + public WxOpenResult deleteCategory(int first, int second) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("first", first); + params.addProperty("second", second); + String response = wxMaService.post(OPEN_DELETE_CATEGORY, params); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + @Override + public WxFastMaBeenSetCategoryResult getCategory() throws WxErrorException { + String response = wxMaService.get(OPEN_GET_CATEGORY, ""); + return WxOpenGsonBuilder.create().fromJson(response, WxFastMaBeenSetCategoryResult.class); + } + + @Override + public WxOpenResult modifyCategory(WxFastMaCategory category) throws WxErrorException { + String response = wxMaService.post(OPEN_MODIFY_CATEGORY, category); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + private JsonArray toJsonArray(List strList) { + JsonArray jsonArray = new JsonArray(); + if (strList != null && !strList.isEmpty()) { + for (String str : strList) { + jsonArray.add(str); + } + } + return jsonArray; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java index 24d9e23414..9febf639f4 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java @@ -7,8 +7,10 @@ import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import lombok.Getter; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.open.api.WxOpenComponentService; +import me.chanjar.weixin.open.api.WxOpenMaBasicService; import me.chanjar.weixin.open.api.WxOpenMaService; import me.chanjar.weixin.open.bean.ma.WxMaOpenCommitExtInfo; import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam; @@ -34,11 +36,14 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ private final WxOpenComponentService wxOpenComponentService; private final WxMaConfig wxMaConfig; private final String appId; + @Getter + private final WxOpenMaBasicService basicService; public WxOpenMaServiceImpl(WxOpenComponentService wxOpenComponentService, String appId, WxMaConfig wxMaConfig) { this.wxOpenComponentService = wxOpenComponentService; this.appId = appId; this.wxMaConfig = wxMaConfig; + this.basicService = new WxOpenMaBasicServiceImpl(this); initHttp(); } @@ -247,6 +252,12 @@ public WxOpenResult revertCodeRelease() throws WxErrorException { return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class); } + @Override + public WxOpenMaHistoryVersionResult getHistoryVersion() throws WxErrorException { + String response = get(API_REVERT_CODE_RELEASE, "action=get_history_version"); + return WxMaGsonBuilder.create().fromJson(response, WxOpenMaHistoryVersionResult.class); + } + @Override public WxOpenResult undoCodeAudit() throws WxErrorException { String response = get(API_UNDO_CODE_AUDIT, null); diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaHistoryVersion.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaHistoryVersion.java new file mode 100644 index 0000000000..6ef41c8bef --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaHistoryVersion.java @@ -0,0 +1,34 @@ +package me.chanjar.weixin.open.bean.ma; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; + +import java.io.Serializable; + +/** + * 微信开放平台小程序 可回退的小程序版本 + * + * @author 广州跨界 + */ +@Data +public class WxOpenMaHistoryVersion implements Serializable { + private static final long serialVersionUID = 98923601148793365L; + + @SerializedName("app_version") + private Integer appVersion; + + @SerializedName("user_version") + private String userVersion; + + @SerializedName("user_desc") + private String userDesc; + + @SerializedName("commit_time") + private Integer commitTime; + + @Override + public String toString() { + return WxOpenGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaHistoryVersionResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaHistoryVersionResult.java new file mode 100644 index 0000000000..61b9f5dddf --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaHistoryVersionResult.java @@ -0,0 +1,29 @@ +package me.chanjar.weixin.open.bean.result; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import me.chanjar.weixin.open.bean.ma.WxOpenMaHistoryVersion; +import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; + +import java.util.List; + +/** + * 微信开放平台小程序 可回退的小程序版本 返回 + * + * @author 广州跨界 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class WxOpenMaHistoryVersionResult extends WxOpenResult { + private static final long serialVersionUID = 4102311851687901079L; + + @SerializedName("template_list") + List templateList; + + @Override + public String toString() { + return WxOpenGsonBuilder.create().toJson(this); + } + +}