external_user.go 18 KB

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