external_user.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  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. if err != nil {
  49. return nil, err
  50. }
  51. return result.ExternalUserID, nil
  52. }
  53. // ExternalUserDetailResponse 外部联系人详情响应
  54. type ExternalUserDetailResponse struct {
  55. util.CommonError
  56. ExternalContact ExternalUser `json:"external_contact"`
  57. FollowUser []FollowUser `json:"follow_user"`
  58. NextCursor string `json:"next_cursor"`
  59. }
  60. // ExternalUser 外部联系人
  61. type ExternalUser struct {
  62. ExternalUserID string `json:"external_userid"`
  63. Name string `json:"name"`
  64. Avatar string `json:"avatar"`
  65. Type int64 `json:"type"`
  66. Gender int64 `json:"gender"`
  67. UnionID string `json:"unionid"`
  68. Position string `json:"position"`
  69. CorpName string `json:"corp_name"`
  70. CorpFullName string `json:"corp_full_name"`
  71. ExternalProfile string `json:"external_profile"`
  72. }
  73. // FollowUser 跟进用户(指企业内部用户)
  74. type FollowUser struct {
  75. UserID string `json:"userid"`
  76. Remark string `json:"remark"`
  77. Description string `json:"description"`
  78. CreateTime int64 `json:"createtime"`
  79. Tags []Tag `json:"tags"`
  80. RemarkCorpName string `json:"remark_corp_name"`
  81. RemarkMobiles []string `json:"remark_mobiles"`
  82. OperUserID string `json:"oper_userid"`
  83. AddWay int64 `json:"add_way"`
  84. WeChatChannels WechatChannel `json:"wechat_channels"`
  85. State string `json:"state"`
  86. }
  87. // Tag 已绑定在外部联系人的标签
  88. type Tag struct {
  89. GroupName string `json:"group_name"`
  90. TagName string `json:"tag_name"`
  91. Type int64 `json:"type"`
  92. TagID string `json:"tag_id"`
  93. }
  94. // WechatChannel 视频号添加的场景
  95. type WechatChannel struct {
  96. NickName string `json:"nickname"`
  97. Source string `json:"source"`
  98. }
  99. // GetExternalUserDetail 获取外部联系人详情
  100. // @see https://developer.work.weixin.qq.com/document/path/92114
  101. func (r *Client) GetExternalUserDetail(externalUserID string, nextCursor ...string) (*ExternalUserDetailResponse, error) {
  102. accessToken, err := r.GetAccessToken()
  103. if err != nil {
  104. return nil, err
  105. }
  106. var response []byte
  107. var cursor string
  108. if len(nextCursor) > 0 {
  109. cursor = nextCursor[0]
  110. }
  111. response, err = util.HTTPGet(fmt.Sprintf("%s?access_token=%v&external_userid=%v&cursor=%v", fetchExternalContactUserDetailURL, accessToken, externalUserID, cursor))
  112. if err != nil {
  113. return nil, err
  114. }
  115. result := &ExternalUserDetailResponse{}
  116. err = util.DecodeWithError(response, result, "get_external_user_detail")
  117. if err != nil {
  118. return nil, err
  119. }
  120. return result, nil
  121. }
  122. // BatchGetExternalUserDetailsRequest 批量获取外部联系人详情请求
  123. type BatchGetExternalUserDetailsRequest struct {
  124. UserIDList []string `json:"userid_list"`
  125. Cursor string `json:"cursor"`
  126. Limit int `json:"limit,omitempty"`
  127. }
  128. // ExternalUserDetailListResponse 批量获取外部联系人详情响应
  129. type ExternalUserDetailListResponse struct {
  130. util.CommonError
  131. ExternalContactList []ExternalUserForBatch `json:"external_contact_list"`
  132. }
  133. // ExternalUserForBatch 批量获取外部联系人客户列表
  134. type ExternalUserForBatch struct {
  135. ExternalContact ExternalContact `json:"external_contact"`
  136. FollowInfo FollowInfo `json:"follow_info"`
  137. }
  138. // ExternalContact 批量获取外部联系人用户信息
  139. type ExternalContact struct {
  140. ExternalUserID string `json:"external_userid"`
  141. Name string `json:"name"`
  142. Position string `json:"position"`
  143. Avatar string `json:"avatar"`
  144. CorpName string `json:"corp_name"`
  145. CorpFullName string `json:"corp_full_name"`
  146. Type int64 `json:"type"`
  147. Gender int64 `json:"gender"`
  148. UnionID string `json:"unionid"`
  149. ExternalProfile string `json:"external_profile"`
  150. }
  151. // FollowInfo 批量获取外部联系人跟进人信息
  152. type FollowInfo struct {
  153. UserID string `json:"userid"`
  154. Remark string `json:"remark"`
  155. Description string `json:"description"`
  156. CreateTime int64 `json:"createtime"`
  157. TagID []string `json:"tag_id"`
  158. RemarkCorpName string `json:"remark_corp_name"`
  159. RemarkMobiles []string `json:"remark_mobiles"`
  160. OperUserID string `json:"oper_userid"`
  161. AddWay int64 `json:"add_way"`
  162. WeChatChannels WechatChannel `json:"wechat_channels"`
  163. }
  164. // BatchGetExternalUserDetails 批量获取外部联系人详情
  165. // @see https://developer.work.weixin.qq.com/document/path/92994
  166. func (r *Client) BatchGetExternalUserDetails(request BatchGetExternalUserDetailsRequest) ([]ExternalUserForBatch, error) {
  167. accessToken, err := r.GetAccessToken()
  168. if err != nil {
  169. return nil, err
  170. }
  171. var response []byte
  172. jsonData, err := json.Marshal(request)
  173. if err != nil {
  174. return nil, err
  175. }
  176. response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", fetchBatchExternalContactUserDetailURL, accessToken), string(jsonData))
  177. if err != nil {
  178. return nil, err
  179. }
  180. var result ExternalUserDetailListResponse
  181. err = util.DecodeWithError(response, &result, "BatchGetExternalUserDetails")
  182. if err != nil {
  183. return nil, err
  184. }
  185. return result.ExternalContactList, nil
  186. }
  187. // UpdateUserRemarkRequest 修改客户备注信息请求体
  188. type UpdateUserRemarkRequest struct {
  189. UserID string `json:"userid"`
  190. ExternalUserID string `json:"external_userid"`
  191. Remark string `json:"remark"`
  192. Description string `json:"description"`
  193. RemarkCompany string `json:"remark_company"`
  194. RemarkMobiles []string `json:"remark_mobiles"`
  195. RemarkPicMediaID string `json:"remark_pic_mediaid"`
  196. }
  197. // UpdateUserRemark 修改客户备注信息
  198. // @see https://developer.work.weixin.qq.com/document/path/92115
  199. func (r *Client) UpdateUserRemark(request UpdateUserRemarkRequest) error {
  200. accessToken, err := r.GetAccessToken()
  201. if err != nil {
  202. return err
  203. }
  204. var response []byte
  205. jsonData, err := json.Marshal(request)
  206. if err != nil {
  207. return err
  208. }
  209. response, err = util.HTTPPost(fmt.Sprintf("%s?access_token=%v", updateUserRemarkURL, accessToken), string(jsonData))
  210. if err != nil {
  211. return err
  212. }
  213. return util.DecodeWithCommonError(response, "UpdateUserRemark")
  214. }
  215. // ListCustomerStrategyRequest 获取规则组列表请求
  216. type ListCustomerStrategyRequest struct {
  217. Cursor string `json:"cursor"`
  218. Limit int `json:"limit"`
  219. }
  220. // ListCustomerStrategyResponse 获取规则组列表响应
  221. type ListCustomerStrategyResponse struct {
  222. util.CommonError
  223. Strategy []StrategyID `json:"strategy"`
  224. NextCursor string `json:"next_cursor"`
  225. }
  226. // StrategyID 规则组ID
  227. type StrategyID struct {
  228. StrategyID int `json:"strategy_id"`
  229. }
  230. // ListCustomerStrategy 获取规则组列表
  231. // @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
  232. func (r *Client) ListCustomerStrategy(req *ListCustomerStrategyRequest) (*ListCustomerStrategyResponse, error) {
  233. var (
  234. accessToken string
  235. err error
  236. )
  237. if accessToken, err = r.GetAccessToken(); err != nil {
  238. return nil, err
  239. }
  240. var response []byte
  241. if response, err = util.PostJSON(fmt.Sprintf(listCustomerStrategyURL, accessToken), req); err != nil {
  242. return nil, err
  243. }
  244. result := &ListCustomerStrategyResponse{}
  245. if err = util.DecodeWithError(response, result, "ListCustomerStrategy"); err != nil {
  246. return nil, err
  247. }
  248. return result, nil
  249. }
  250. // GetCustomerStrategyRequest 获取规则组详情请求
  251. type GetCustomerStrategyRequest struct {
  252. StrategyID int `json:"strategy_id"`
  253. }
  254. // GetCustomerStrategyResponse 获取规则组详情响应
  255. type GetCustomerStrategyResponse struct {
  256. util.CommonError
  257. Strategy Strategy `json:"strategy"`
  258. }
  259. // Strategy 规则组
  260. type Strategy struct {
  261. StrategyID int `json:"strategy_id"`
  262. ParentID int `json:"parent_id"`
  263. StrategyName string `json:"strategy_name"`
  264. CreateTime int64 `json:"create_time"`
  265. AdminList []string `json:"admin_list"`
  266. Privilege Privilege `json:"privilege"`
  267. }
  268. // Privilege 权限
  269. type Privilege struct {
  270. ViewCustomerList bool `json:"view_customer_list"`
  271. ViewCustomerData bool `json:"view_customer_data"`
  272. ViewRoomList bool `json:"view_room_list"`
  273. ContactMe bool `json:"contact_me"`
  274. JoinRoom bool `json:"join_room"`
  275. ShareCustomer bool `json:"share_customer"`
  276. OperResignCustomer bool `json:"oper_resign_customer"`
  277. OperResignGroup bool `json:"oper_resign_group"`
  278. SendCustomerMsg bool `json:"send_customer_msg"`
  279. EditWelcomeMsg bool `json:"edit_welcome_msg"`
  280. ViewBehaviorData bool `json:"view_behavior_data"`
  281. ViewRoomData bool `json:"view_room_data"`
  282. SendGroupMsg bool `json:"send_group_msg"`
  283. RoomDeduplication bool `json:"room_deduplication"`
  284. RapidReply bool `json:"rapid_reply"`
  285. OnjobCustomerTransfer bool `json:"onjob_customer_transfer"`
  286. EditAntiSpamRule bool `json:"edit_anti_spam_rule"`
  287. ExportCustomerList bool `json:"export_customer_list"`
  288. ExportCustomerData bool `json:"export_customer_data"`
  289. ExportCustomerGroupList bool `json:"export_customer_group_list"`
  290. ManageCustomerTag bool `json:"manage_customer_tag"`
  291. }
  292. // GetCustomerStrategy 获取规则组详情
  293. // @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
  294. func (r *Client) GetCustomerStrategy(req *GetCustomerStrategyRequest) (*GetCustomerStrategyResponse, error) {
  295. var (
  296. accessToken string
  297. err error
  298. )
  299. if accessToken, err = r.GetAccessToken(); err != nil {
  300. return nil, err
  301. }
  302. var response []byte
  303. if response, err = util.PostJSON(fmt.Sprintf(getCustomerStrategyURL, accessToken), req); err != nil {
  304. return nil, err
  305. }
  306. result := &GetCustomerStrategyResponse{}
  307. if err = util.DecodeWithError(response, result, "GetCustomerStrategy"); err != nil {
  308. return nil, err
  309. }
  310. return result, nil
  311. }
  312. // GetRangeCustomerStrategyRequest 获取规则组管理范围请求
  313. type GetRangeCustomerStrategyRequest struct {
  314. StrategyID int `json:"strategy_id"`
  315. Cursor string `json:"cursor"`
  316. Limit int `json:"limit"`
  317. }
  318. // GetRangeCustomerStrategyResponse 获取规则组管理范围响应
  319. type GetRangeCustomerStrategyResponse struct {
  320. util.CommonError
  321. Range []Range `json:"range"`
  322. NextCursor string `json:"next_cursor"`
  323. }
  324. // Range 管理范围节点
  325. type Range struct {
  326. Type int `json:"type"`
  327. UserID string `json:"userid,omitempty"`
  328. PartyID int `json:"partyid,omitempty"`
  329. }
  330. // GetRangeCustomerStrategy 获取规则组管理范围
  331. // @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
  332. func (r *Client) GetRangeCustomerStrategy(req *GetRangeCustomerStrategyRequest) (*GetRangeCustomerStrategyResponse, error) {
  333. var (
  334. accessToken string
  335. err error
  336. )
  337. if accessToken, err = r.GetAccessToken(); err != nil {
  338. return nil, err
  339. }
  340. var response []byte
  341. if response, err = util.PostJSON(fmt.Sprintf(getRangeCustomerStrategyURL, accessToken), req); err != nil {
  342. return nil, err
  343. }
  344. result := &GetRangeCustomerStrategyResponse{}
  345. if err = util.DecodeWithError(response, result, "GetRangeCustomerStrategy"); err != nil {
  346. return nil, err
  347. }
  348. return result, nil
  349. }
  350. // CreateCustomerStrategyRequest 创建新的规则组请求
  351. type CreateCustomerStrategyRequest struct {
  352. ParentID int `json:"parent_id"`
  353. StrategyName string `json:"strategy_name"`
  354. AdminList []string `json:"admin_list"`
  355. Privilege Privilege `json:"privilege"`
  356. Range []Range `json:"range"`
  357. }
  358. // CreateCustomerStrategyResponse 创建新的规则组响应
  359. type CreateCustomerStrategyResponse struct {
  360. util.CommonError
  361. StrategyID int `json:"strategy_id"`
  362. }
  363. // CreateCustomerStrategy 创建新的规则组
  364. // @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
  365. func (r *Client) CreateCustomerStrategy(req *CreateCustomerStrategyRequest) (*CreateCustomerStrategyResponse, error) {
  366. var (
  367. accessToken string
  368. err error
  369. )
  370. if accessToken, err = r.GetAccessToken(); err != nil {
  371. return nil, err
  372. }
  373. var response []byte
  374. if response, err = util.PostJSON(fmt.Sprintf(createCustomerStrategyURL, accessToken), req); err != nil {
  375. return nil, err
  376. }
  377. result := &CreateCustomerStrategyResponse{}
  378. if err = util.DecodeWithError(response, result, "CreateCustomerStrategy"); err != nil {
  379. return nil, err
  380. }
  381. return result, nil
  382. }
  383. // EditCustomerStrategyRequest 编辑规则组及其管理范围请求
  384. type EditCustomerStrategyRequest struct {
  385. StrategyID int `json:"strategy_id"`
  386. StrategyName string `json:"strategy_name"`
  387. AdminList []string `json:"admin_list"`
  388. Privilege Privilege `json:"privilege"`
  389. RangeAdd []Range `json:"range_add"`
  390. RangeDel []Range `json:"range_del"`
  391. }
  392. // EditCustomerStrategy 编辑规则组及其管理范围
  393. // 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
  394. func (r *Client) EditCustomerStrategy(req *EditCustomerStrategyRequest) error {
  395. var (
  396. accessToken string
  397. err error
  398. )
  399. if accessToken, err = r.GetAccessToken(); err != nil {
  400. return err
  401. }
  402. var response []byte
  403. if response, err = util.PostJSON(fmt.Sprintf(editCustomerStrategyURL, accessToken), req); err != nil {
  404. return err
  405. }
  406. return util.DecodeWithCommonError(response, "EditCustomerStrategy")
  407. }
  408. // DelCustomerStrategyRequest 删除规则组请求
  409. type DelCustomerStrategyRequest struct {
  410. StrategyID int `json:"strategy_id"`
  411. }
  412. // DelCustomerStrategy 删除规则组
  413. // 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
  414. func (r *Client) DelCustomerStrategy(req *DelCustomerStrategyRequest) error {
  415. var (
  416. accessToken string
  417. err error
  418. )
  419. if accessToken, err = r.GetAccessToken(); err != nil {
  420. return err
  421. }
  422. var response []byte
  423. if response, err = util.PostJSON(fmt.Sprintf(delCustomerStrategyURL, accessToken), req); err != nil {
  424. return err
  425. }
  426. return util.DecodeWithCommonError(response, "DelCustomerStrategy")
  427. }