You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

232 lines
6.8KB

  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io/ioutil"
  7. "log"
  8. "net/http"
  9. "time"
  10. )
  11. type crmdLead struct {
  12. crmdEntityBase
  13. //ID string `json:"id,omitempty"`
  14. //Name string `json:"name,omitempty"`
  15. //Deleted bool `json:"deleted,omitempty"`
  16. AvatarID string `json:"avatarId,omitempty"`
  17. AvatarName string `json:"avatarName,omitempty"`
  18. SalutationName string `json:"salutationName,omitempty"`
  19. FirstName string `json:"firstName,omitempty"`
  20. LastName string `json:"lastName,omitempty"`
  21. Title string `json:"title,omitempty"`
  22. Status string `json:"status,omitempty"`
  23. Source string `json:"source,omitempty"`
  24. Industry string `json:"industry,omitempty"`
  25. OpportunityAmount int `json:"opportunityAmount,omitempty"`
  26. Website string `json:"website,omitempty"`
  27. AddressStreet string `json:"addressStreet,omitempty"`
  28. AddressCity string `json:"addressCity,omitempty"`
  29. AddressState string `json:"addressState,omitempty"`
  30. AddressCountry string `json:"addressCountry,omitempty"`
  31. AddressPostalCode string `json:"addresPostalCode,omitempty"`
  32. EmailAddress string `json:"emailAddress,omitempty"`
  33. PhoneNumber string `json:"phoneNumber,omitempty"`
  34. DoNotCall bool `json:"doNotCall,omitempty"`
  35. //Description string `json:"description,omitempty"`
  36. //CreatedAt string `json:"createdAt,omitempty"`
  37. //ModifiedAt string `json:"ModifiedAt,omitempty"`
  38. AccountName string `json:"accountName,omitempty"`
  39. Password string `json:"password,omitempty"`
  40. WechatHitxyID string `json:"wechatOpenID,omitempty"`
  41. OpportunityAmountCurrency string `json:"opportunityAmountCurrency,omitempty"`
  42. OpportunityAmountConverted int `json:"opportunityAmountConverted,omitempty"`
  43. EmailAddressData []struct {
  44. EmailAddress string `json:"emailAddress,omitempty"`
  45. Lower string `json:"lower,omitempty"`
  46. Primary bool `json:"primary,omitempty"`
  47. OptOut bool `json:"optOut,omitempty"`
  48. Invalid bool `json:"invalid,omitempty"`
  49. } `json:"emailAddressData,omitempty"`
  50. PhoneNumberData []struct {
  51. PhoneNumber string `json:"phoneNumber,omitempty"`
  52. Primary bool `json:"primary,omitempty"`
  53. Type string `json:"type,omitempty"`
  54. } `json:"phoneNumberData,omitempty"`
  55. //CreatedByID string `json:"createdById,omitempty"`
  56. //CreatedByName string `json:"createdByName,omitempty"`
  57. //ModifiedByID string `json:"modifiedById,omitempty"`
  58. //ModifiedByName string `json:"modifiedByName,omitempty"`
  59. //AssignedUserID string `json:"assignedUserId,omitempty"`
  60. //AssignedUserName string `json:"assignedUserName,omitempty"`
  61. CampaignID string `json:"campaignId,omitempty"`
  62. CreatedAccountID string `json:"createdAccountId,omitempty"`
  63. CreatedContactID string `json:"createdContactId,omitempty"`
  64. CreatedOpportunityID string `json:"createdOpportunityId,omitempty"`
  65. ForceDuplicate bool `json:"forceDuplicate,omitempty"` //when purposely creating duplicated record, we need to set this to true
  66. }
  67. type crmdSearchLead struct {
  68. Total int `json:"total"`
  69. List []crmdLead `json:"list"`
  70. }
  71. func crmFindLeadByOpenID(openID string) (info crmdLead, found bool, err error) {
  72. total, list, err := crmFindEntityByAttr("Lead", "wechatOpenID", openID)
  73. if err != nil {
  74. return
  75. }
  76. if total == 1 {
  77. found = true
  78. info = list.([]crmdLead)[0]
  79. return
  80. }
  81. found = false
  82. if total > 1 {
  83. msg := fmt.Sprintf("wechatOpenID %s has %d record", openID, total)
  84. log.Printf(msg)
  85. }
  86. return
  87. }
  88. func crmGetLead(id string) (r crmdLead, err error) {
  89. entity, err := crmGetEntity("Lead", id)
  90. if err == nil && entity != nil {
  91. r = entity.(crmdLead)
  92. }
  93. return
  94. }
  95. func crmPatchLeadInfo(newInfo crmdLead) (updatedLead crmdLead, err error) {
  96. b, err := json.Marshal(newInfo)
  97. if err != nil {
  98. log.Printf("Failed to Patch new Info for Lead")
  99. log.Println(newInfo)
  100. return
  101. }
  102. newEntity, err := crmUpdateEntity("Lead", newInfo.ID, b)
  103. if err != nil {
  104. return
  105. }
  106. updatedLead, ok := newEntity.(crmdLead)
  107. if !ok {
  108. err = errors.New("Update Lead result in wrong entityType")
  109. }
  110. return
  111. }
  112. func crmLeadSetStatusNew(id string) {
  113. crmLeadSetStatus(id, "New")
  114. }
  115. func crmLeadSetStatusDead(id string) {
  116. crmLeadSetStatus(id, "Dead")
  117. }
  118. func crmLeadSetStatus(id string, status string) {
  119. newLead := crmdLead{}
  120. newLead.ID = id
  121. newLead.Status = status
  122. crmPatchLeadInfo(newLead)
  123. }
  124. //WechatUserList 超过一万个也可能呢。
  125. //Decode Wechat user List {"total":2,"count":2,"data":{"openid":["","OPENID1","OPENID2"]},"next_openid":"NEXT_OPENID"}
  126. type WechatUserList struct {
  127. Total int `json:"total,omitempty"`
  128. Count int `json:"count,omitempty"`
  129. Data struct {
  130. OpenID []string `json:"openid"`
  131. } `json:"data,omitempty"`
  132. NextOpenID string `json:"next_openid,omitempty"`
  133. }
  134. func importExistingWechatUserAsLead() {
  135. //当公众号关注者数量超过10000时,可通过填写next_openid的值,从而多次拉取列表的方式来满足需求。
  136. atk, _ := GetAccessToken()
  137. nextOpenID := ""
  138. url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s&next_openid=%s", atk, nextOpenID)
  139. req, err := http.NewRequest("GET", url, nil)
  140. var myClient = &http.Client{Timeout: 20 * time.Second}
  141. r, err := myClient.Do(req)
  142. if err != nil {
  143. log.Printf("Fail to get URL: %s", req.RequestURI)
  144. log.Println(err)
  145. }
  146. defer r.Body.Close()
  147. jsonB, err := ioutil.ReadAll(r.Body)
  148. users := WechatUserList{}
  149. err = json.Unmarshal(jsonB, &users)
  150. if err != nil {
  151. return
  152. }
  153. for _, openID := range users.Data.OpenID {
  154. log.Println(openID)
  155. _, found, err := crmFindLeadByOpenID(openID)
  156. if !found && err == nil {
  157. crmCreateLeadByOpenID(openID)
  158. }
  159. }
  160. }
  161. func crmCreateLeadByOpenID(openID string) (newuser crmdLead, err error) {
  162. info := WechatUserInfo{}
  163. info.getUserInfo(openID, "zh_CN")
  164. return info.registerNewLeadWithInfo(openID)
  165. }
  166. func (m crmdLead) crmLeadConvert2Contact() (newContact crmdContact) {
  167. newContact.convertFromLead(m.ID)
  168. return
  169. }
  170. func (m crmdLead) Save() (newlead crmdLead, err error) {
  171. jsonB, err := json.Marshal(m)
  172. log.Println(string(jsonB))
  173. if err != nil {
  174. return
  175. }
  176. if m.ID != "" {
  177. entity, err := crmUpdateEntity("Lead", m.ID, jsonB)
  178. if err != nil {
  179. return newlead, err
  180. }
  181. newlead = entity.(crmdLead)
  182. } else {
  183. entity, err := crmCreateEntity("Lead", jsonB)
  184. if err != nil {
  185. return newlead, err
  186. }
  187. newlead = entity.(crmdLead)
  188. }
  189. return
  190. }
  191. func (m crmdLead) Delete() bool {
  192. if m.ID != "" {
  193. deleted, err := crmDeleteEntity("Lead", m.ID)
  194. return err == nil && deleted == true
  195. }
  196. return false
  197. }
  198. func (m crmdLead) AvatarCacheURL() string {
  199. if m.AvatarID != "" {
  200. u := CRMConfig.CacheSiteURL + "?a=" + m.AvatarID
  201. return buildSignatureAppend2Url(u, IntraAPIConfig.CRMSecrete)
  202. }
  203. return GlobalPath.ThisSiteURL + "spa/assets/img/user.png"
  204. }