external_user.go 16 KB

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