external_user.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. package externalcontact
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/silenceper/wechat/v2/util"
  6. )
  7. const (
  8. // fetchExternalContactUserListURL 获取客户列表
  9. fetchExternalContactUserListURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/list"
  10. // fetchExternalContactUserDetailURL 获取客户详情
  11. fetchExternalContactUserDetailURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get"
  12. // fetchBatchExternalContactUserDetailURL 批量获取客户详情
  13. fetchBatchExternalContactUserDetailURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/batch/get_by_user"
  14. // updateUserRemarkURL 更新客户备注信息
  15. updateUserRemarkURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/remark"
  16. // listCustomerStrategyURL 获取规则组列表
  17. listCustomerStrategyURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_strategy/list?access_token=%s"
  18. // getCustomerStrategyURL 获取规则组详情
  19. getCustomerStrategyURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_strategy/get?access_token=%s"
  20. // getRangeCustomerStrategyURL 获取规则组管理范围
  21. getRangeCustomerStrategyURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_strategy/get_range?access_token=%s"
  22. // createCustomerStrategyURL 创建新的规则组
  23. createCustomerStrategyURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_strategy/create?access_token=%s"
  24. // editCustomerStrategyURL 编辑规则组及其管理范围
  25. editCustomerStrategyURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_strategy/edit?access_token=%s"
  26. // delCustomerStrategyURL 删除规则组
  27. delCustomerStrategyURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/customer_strategy/del?access_token=%s"
  28. )
  29. // ExternalUserListResponse 外部联系人列表响应
  30. type ExternalUserListResponse struct {
  31. util.CommonError
  32. ExternalUserID []string `json:"external_userid"`
  33. }
  34. // GetExternalUserList 获取客户列表
  35. // @see https://developer.work.weixin.qq.com/document/path/92113
  36. func (r *Client) GetExternalUserList(userID string) ([]string, error) {
  37. accessToken, err := r.GetAccessToken()
  38. if err != nil {
  39. return nil, err
  40. }
  41. var response []byte
  42. response, err = util.HTTPGet(fmt.Sprintf("%s?access_token=%v&userid=%v", fetchExternalContactUserListURL, accessToken, userID))
  43. if err != nil {
  44. return nil, err
  45. }
  46. var result ExternalUserListResponse
  47. err = util.DecodeWithError(response, &result, "GetExternalUserList")
  48. return result.ExternalUserID, err
  49. }
  50. // ExternalUserDetailResponse 外部联系人详情响应
  51. type ExternalUserDetailResponse struct {
  52. util.CommonError
  53. ExternalContact ExternalUser `json:"external_contact"`
  54. FollowUser []FollowUser `json:"follow_user"`
  55. NextCursor string `json:"next_cursor"`
  56. }
  57. // ExternalUser 外部联系人
  58. type ExternalUser struct {
  59. ExternalUserID string `json:"external_userid"`
  60. Name string `json:"name"`
  61. Avatar string `json:"avatar"`
  62. Type int64 `json:"type"`
  63. Gender int64 `json:"gender"`
  64. UnionID string `json:"unionid"`
  65. Position string `json:"position"`
  66. CorpName string `json:"corp_name"`
  67. CorpFullName string `json:"corp_full_name"`
  68. ExternalProfile *ExternalProfile `json:"external_profile,omitempty"`
  69. }
  70. // FollowUser 跟进用户(指企业内部用户)
  71. type FollowUser struct {
  72. UserID string `json:"userid"`
  73. Remark string `json:"remark"`
  74. Description string `json:"description"`
  75. CreateTime int64 `json:"createtime"`
  76. Tags []Tag `json:"tags"`
  77. RemarkCorpName string `json:"remark_corp_name"`
  78. RemarkMobiles []string `json:"remark_mobiles"`
  79. OperUserID string `json:"oper_userid"`
  80. AddWay int64 `json:"add_way"`
  81. WeChatChannels WechatChannel `json:"wechat_channels"`
  82. State string `json:"state"`
  83. }
  84. // Tag 已绑定在外部联系人的标签
  85. type Tag struct {
  86. GroupName string `json:"group_name"`
  87. TagName string `json:"tag_name"`
  88. Type int64 `json:"type"`
  89. TagID string `json:"tag_id"`
  90. }
  91. // WechatChannel 视频号添加的场景
  92. type WechatChannel struct {
  93. NickName string `json:"nickname"`
  94. Source int `json:"source"`
  95. }
  96. // ExternalProfile 外部联系人的自定义展示信息,可以有多个字段和多种类型,包括文本,网页和小程序
  97. type ExternalProfile struct {
  98. ExternalCorpName string `json:"external_corp_name"`
  99. WechatChannels WechatChannels `json:"wechat_channels"`
  100. ExternalAttr []ExternalAttr `json:"external_attr"`
  101. }
  102. // WechatChannels 视频号属性。须从企业绑定到企业微信的视频号中选择,可在“我的企业”页中查看绑定的视频号
  103. type WechatChannels struct {
  104. Nickname string `json:"nickname"`
  105. Status int `json:"status"`
  106. }
  107. // ExternalAttr 属性列表,目前支持文本、网页、小程序三种类型
  108. type ExternalAttr struct {
  109. Type int `json:"type"`
  110. Name string `json:"name"`
  111. Text *Text `json:"text,omitempty"`
  112. Web *Web `json:"web,omitempty"`
  113. MiniProgram *MiniProgram `json:"miniprogram,omitempty"`
  114. }
  115. // Text 文本
  116. type Text struct {
  117. Value string `json:"value"`
  118. }
  119. // Web 网页
  120. type Web struct {
  121. URL string `json:"url"`
  122. Title string `json:"title"`
  123. }
  124. // MiniProgram 小程序
  125. type MiniProgram struct {
  126. AppID string `json:"appid"`
  127. Pagepath string `json:"pagepath"`
  128. Title string `json:"title"`
  129. }
  130. // GetExternalUserDetail 获取外部联系人详情
  131. // @see https://developer.work.weixin.qq.com/document/path/92114
  132. func (r *Client) GetExternalUserDetail(externalUserID string, nextCursor ...string) (*ExternalUserDetailResponse, error) {
  133. accessToken, err := r.GetAccessToken()
  134. if err != nil {
  135. return nil, err
  136. }
  137. var response []byte
  138. var cursor string
  139. if len(nextCursor) > 0 {
  140. cursor = nextCursor[0]
  141. }
  142. response, err = util.HTTPGet(fmt.Sprintf("%s?access_token=%v&external_userid=%v&cursor=%v", fetchExternalContactUserDetailURL, accessToken, externalUserID, cursor))
  143. if err != nil {
  144. return nil, err
  145. }
  146. result := &ExternalUserDetailResponse{}
  147. err = util.DecodeWithError(response, result, "get_external_user_detail")
  148. return result, err
  149. }
  150. // BatchGetExternalUserDetailsRequest 批量获取外部联系人详情请求
  151. type BatchGetExternalUserDetailsRequest struct {
  152. UserIDList []string `json:"userid_list"`
  153. Cursor string `json:"cursor"`
  154. Limit int `json:"limit,omitempty"`
  155. }
  156. // ExternalUserDetailListResponse 批量获取外部联系人详情响应
  157. type ExternalUserDetailListResponse struct {
  158. util.CommonError
  159. ExternalContactList []ExternalUserForBatch `json:"external_contact_list"`
  160. NextCursor string `json:"next_cursor"`
  161. }
  162. // ExternalUserForBatch 批量获取外部联系人客户列表
  163. type ExternalUserForBatch struct {
  164. ExternalContact ExternalContact `json:"external_contact"`
  165. FollowInfo FollowInfo `json:"follow_info"`
  166. }
  167. // ExternalContact 批量获取外部联系人用户信息
  168. type ExternalContact struct {
  169. ExternalUserID string `json:"external_userid"`
  170. Name string `json:"name"`
  171. Position string `json:"position"`
  172. Avatar string `json:"avatar"`
  173. CorpName string `json:"corp_name"`
  174. CorpFullName string `json:"corp_full_name"`
  175. Type int64 `json:"type"`
  176. Gender int64 `json:"gender"`
  177. UnionID string `json:"unionid"`
  178. ExternalProfile *ExternalProfile `json:"external_profile"`
  179. }
  180. // FollowInfo 批量获取外部联系人跟进人信息
  181. type FollowInfo struct {
  182. UserID string `json:"userid"`
  183. Remark string `json:"remark"`
  184. Description string `json:"description"`
  185. CreateTime int64 `json:"createtime"`
  186. TagID []string `json:"tag_id"`
  187. RemarkCorpName string `json:"remark_corp_name"`
  188. RemarkMobiles []string `json:"remark_mobiles"`
  189. OperUserID string `json:"oper_userid"`
  190. AddWay int64 `json:"add_way"`
  191. WeChatChannels WechatChannel `json:"wechat_channels"`
  192. }
  193. // BatchGetExternalUserDetails 批量获取外部联系人详情
  194. // @see https://developer.work.weixin.qq.com/document/path/92994
  195. func (r *Client) BatchGetExternalUserDetails(request BatchGetExternalUserDetailsRequest) ([]ExternalUserForBatch, string, error) {
  196. accessToken, err := r.GetAccessToken()
  197. if err != nil {
  198. return nil, "", err
  199. }
  200. var response []byte
  201. jsonData, err := json.Marshal(request)
  202. if err != nil {
  203. return nil, "", err
  204. }
  205. response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", fetchBatchExternalContactUserDetailURL, accessToken), string(jsonData))
  206. if err != nil {
  207. return nil, "", err
  208. }
  209. var result ExternalUserDetailListResponse
  210. err = util.DecodeWithError(response, &result, "BatchGetExternalUserDetails")
  211. return result.ExternalContactList, result.NextCursor, err
  212. }
  213. // UpdateUserRemarkRequest 修改客户备注信息请求体
  214. type UpdateUserRemarkRequest struct {
  215. UserID string `json:"userid"`
  216. ExternalUserID string `json:"external_userid"`
  217. Remark string `json:"remark"`
  218. Description string `json:"description"`
  219. RemarkCompany string `json:"remark_company"`
  220. RemarkMobiles []string `json:"remark_mobiles"`
  221. RemarkPicMediaID string `json:"remark_pic_mediaid"`
  222. }
  223. // UpdateUserRemark 修改客户备注信息
  224. // @see https://developer.work.weixin.qq.com/document/path/92115
  225. func (r *Client) UpdateUserRemark(request UpdateUserRemarkRequest) error {
  226. accessToken, err := r.GetAccessToken()
  227. if err != nil {
  228. return err
  229. }
  230. var response []byte
  231. jsonData, err := json.Marshal(request)
  232. if err != nil {
  233. return err
  234. }
  235. response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", updateUserRemarkURL, accessToken), string(jsonData))
  236. if err != nil {
  237. return err
  238. }
  239. return util.DecodeWithCommonError(response, "UpdateUserRemark")
  240. }
  241. // ListCustomerStrategyRequest 获取规则组列表请求
  242. type ListCustomerStrategyRequest struct {
  243. Cursor string `json:"cursor"`
  244. Limit int `json:"limit"`
  245. }
  246. // ListCustomerStrategyResponse 获取规则组列表响应
  247. type ListCustomerStrategyResponse struct {
  248. util.CommonError
  249. Strategy []StrategyID `json:"strategy"`
  250. NextCursor string `json:"next_cursor"`
  251. }
  252. // StrategyID 规则组ID
  253. type StrategyID struct {
  254. StrategyID int `json:"strategy_id"`
  255. }
  256. // ListCustomerStrategy 获取规则组列表
  257. // @see https://developer.work.weixin.qq.com/document/path/94883#%E8%8E%B7%E5%8F%96%E8%A7%84%E5%88%99%E7%BB%84%E5%88%97%E8%A1%A8
  258. func (r *Client) ListCustomerStrategy(req *ListCustomerStrategyRequest) (*ListCustomerStrategyResponse, error) {
  259. var (
  260. accessToken string
  261. err error
  262. )
  263. if accessToken, err = r.GetAccessToken(); err != nil {
  264. return nil, err
  265. }
  266. var response []byte
  267. if response, err = util.PostJSON(fmt.Sprintf(listCustomerStrategyURL, accessToken), req); err != nil {
  268. return nil, err
  269. }
  270. result := &ListCustomerStrategyResponse{}
  271. err = util.DecodeWithError(response, result, "ListCustomerStrategy")
  272. return result, err
  273. }
  274. // GetCustomerStrategyRequest 获取规则组详情请求
  275. type GetCustomerStrategyRequest struct {
  276. StrategyID int `json:"strategy_id"`
  277. }
  278. // GetCustomerStrategyResponse 获取规则组详情响应
  279. type GetCustomerStrategyResponse struct {
  280. util.CommonError
  281. Strategy Strategy `json:"strategy"`
  282. }
  283. // Strategy 规则组
  284. type Strategy struct {
  285. StrategyID int `json:"strategy_id"`
  286. ParentID int `json:"parent_id"`
  287. StrategyName string `json:"strategy_name"`
  288. CreateTime int64 `json:"create_time"`
  289. AdminList []string `json:"admin_list"`
  290. Privilege Privilege `json:"privilege"`
  291. }
  292. // Privilege 权限
  293. type Privilege struct {
  294. ViewCustomerList bool `json:"view_customer_list"`
  295. ViewCustomerData bool `json:"view_customer_data"`
  296. ViewRoomList bool `json:"view_room_list"`
  297. ContactMe bool `json:"contact_me"`
  298. JoinRoom bool `json:"join_room"`
  299. ShareCustomer bool `json:"share_customer"`
  300. OperResignCustomer bool `json:"oper_resign_customer"`
  301. OperResignGroup bool `json:"oper_resign_group"`
  302. SendCustomerMsg bool `json:"send_customer_msg"`
  303. EditWelcomeMsg bool `json:"edit_welcome_msg"`
  304. ViewBehaviorData bool `json:"view_behavior_data"`
  305. ViewRoomData bool `json:"view_room_data"`
  306. SendGroupMsg bool `json:"send_group_msg"`
  307. RoomDeduplication bool `json:"room_deduplication"`
  308. RapidReply bool `json:"rapid_reply"`
  309. OnjobCustomerTransfer bool `json:"onjob_customer_transfer"`
  310. EditAntiSpamRule bool `json:"edit_anti_spam_rule"`
  311. ExportCustomerList bool `json:"export_customer_list"`
  312. ExportCustomerData bool `json:"export_customer_data"`
  313. ExportCustomerGroupList bool `json:"export_customer_group_list"`
  314. ManageCustomerTag bool `json:"manage_customer_tag"`
  315. }
  316. // GetCustomerStrategy 获取规则组详情
  317. // @see https://developer.work.weixin.qq.com/document/path/94883#%E8%8E%B7%E5%8F%96%E8%A7%84%E5%88%99%E7%BB%84%E8%AF%A6%E6%83%85
  318. func (r *Client) GetCustomerStrategy(req *GetCustomerStrategyRequest) (*GetCustomerStrategyResponse, error) {
  319. var (
  320. accessToken string
  321. err error
  322. )
  323. if accessToken, err = r.GetAccessToken(); err != nil {
  324. return nil, err
  325. }
  326. var response []byte
  327. if response, err = util.PostJSON(fmt.Sprintf(getCustomerStrategyURL, accessToken), req); err != nil {
  328. return nil, err
  329. }
  330. result := &GetCustomerStrategyResponse{}
  331. err = util.DecodeWithError(response, result, "GetCustomerStrategy")
  332. return result, err
  333. }
  334. // GetRangeCustomerStrategyRequest 获取规则组管理范围请求
  335. type GetRangeCustomerStrategyRequest struct {
  336. StrategyID int `json:"strategy_id"`
  337. Cursor string `json:"cursor"`
  338. Limit int `json:"limit"`
  339. }
  340. // GetRangeCustomerStrategyResponse 获取规则组管理范围响应
  341. type GetRangeCustomerStrategyResponse struct {
  342. util.CommonError
  343. Range []Range `json:"range"`
  344. NextCursor string `json:"next_cursor"`
  345. }
  346. // Range 管理范围节点
  347. type Range struct {
  348. Type int `json:"type"`
  349. UserID string `json:"userid,omitempty"`
  350. PartyID int `json:"partyid,omitempty"`
  351. }
  352. // GetRangeCustomerStrategy 获取规则组管理范围
  353. // @see https://developer.work.weixin.qq.com/document/path/94883#%E8%8E%B7%E5%8F%96%E8%A7%84%E5%88%99%E7%BB%84%E7%AE%A1%E7%90%86%E8%8C%83%E5%9B%B4
  354. func (r *Client) GetRangeCustomerStrategy(req *GetRangeCustomerStrategyRequest) (*GetRangeCustomerStrategyResponse, error) {
  355. var (
  356. accessToken string
  357. err error
  358. )
  359. if accessToken, err = r.GetAccessToken(); err != nil {
  360. return nil, err
  361. }
  362. var response []byte
  363. if response, err = util.PostJSON(fmt.Sprintf(getRangeCustomerStrategyURL, accessToken), req); err != nil {
  364. return nil, err
  365. }
  366. result := &GetRangeCustomerStrategyResponse{}
  367. err = util.DecodeWithError(response, result, "GetRangeCustomerStrategy")
  368. return result, err
  369. }
  370. // CreateCustomerStrategyRequest 创建新的规则组请求
  371. type CreateCustomerStrategyRequest struct {
  372. ParentID int `json:"parent_id"`
  373. StrategyName string `json:"strategy_name"`
  374. AdminList []string `json:"admin_list"`
  375. Privilege Privilege `json:"privilege"`
  376. Range []Range `json:"range"`
  377. }
  378. // CreateCustomerStrategyResponse 创建新的规则组响应
  379. type CreateCustomerStrategyResponse struct {
  380. util.CommonError
  381. StrategyID int `json:"strategy_id"`
  382. }
  383. // CreateCustomerStrategy 创建新的规则组
  384. // @see https://developer.work.weixin.qq.com/document/path/94883#%E5%88%9B%E5%BB%BA%E6%96%B0%E7%9A%84%E8%A7%84%E5%88%99%E7%BB%84
  385. func (r *Client) CreateCustomerStrategy(req *CreateCustomerStrategyRequest) (*CreateCustomerStrategyResponse, error) {
  386. var (
  387. accessToken string
  388. err error
  389. )
  390. if accessToken, err = r.GetAccessToken(); err != nil {
  391. return nil, err
  392. }
  393. var response []byte
  394. if response, err = util.PostJSON(fmt.Sprintf(createCustomerStrategyURL, accessToken), req); err != nil {
  395. return nil, err
  396. }
  397. result := &CreateCustomerStrategyResponse{}
  398. err = util.DecodeWithError(response, result, "CreateCustomerStrategy")
  399. return result, err
  400. }
  401. // EditCustomerStrategyRequest 编辑规则组及其管理范围请求
  402. type EditCustomerStrategyRequest struct {
  403. StrategyID int `json:"strategy_id"`
  404. StrategyName string `json:"strategy_name"`
  405. AdminList []string `json:"admin_list"`
  406. Privilege Privilege `json:"privilege"`
  407. RangeAdd []Range `json:"range_add"`
  408. RangeDel []Range `json:"range_del"`
  409. }
  410. // EditCustomerStrategy 编辑规则组及其管理范围
  411. // see https://developer.work.weixin.qq.com/document/path/94883#%E7%BC%96%E8%BE%91%E8%A7%84%E5%88%99%E7%BB%84%E5%8F%8A%E5%85%B6%E7%AE%A1%E7%90%86%E8%8C%83%E5%9B%B4
  412. func (r *Client) EditCustomerStrategy(req *EditCustomerStrategyRequest) error {
  413. var (
  414. accessToken string
  415. err error
  416. )
  417. if accessToken, err = r.GetAccessToken(); err != nil {
  418. return err
  419. }
  420. var response []byte
  421. if response, err = util.PostJSON(fmt.Sprintf(editCustomerStrategyURL, accessToken), req); err != nil {
  422. return err
  423. }
  424. return util.DecodeWithCommonError(response, "EditCustomerStrategy")
  425. }
  426. // DelCustomerStrategyRequest 删除规则组请求
  427. type DelCustomerStrategyRequest struct {
  428. StrategyID int `json:"strategy_id"`
  429. }
  430. // DelCustomerStrategy 删除规则组
  431. // see https://developer.work.weixin.qq.com/document/path/94883#%E5%88%A0%E9%99%A4%E8%A7%84%E5%88%99%E7%BB%84
  432. func (r *Client) DelCustomerStrategy(req *DelCustomerStrategyRequest) error {
  433. var (
  434. accessToken string
  435. err error
  436. )
  437. if accessToken, err = r.GetAccessToken(); err != nil {
  438. return err
  439. }
  440. var response []byte
  441. if response, err = util.PostJSON(fmt.Sprintf(delCustomerStrategyURL, accessToken), req); err != nil {
  442. return err
  443. }
  444. return util.DecodeWithCommonError(response, "DelCustomerStrategy")
  445. }