| func (c EspoCRMAPIConfig) apiUploadAttachmentURL() string { | func (c EspoCRMAPIConfig) apiUploadAttachmentURL() string { | ||||
| return c.apiURL("Attachment/action/upload") | return c.apiURL("Attachment/action/upload") | ||||
| } | } | ||||
| func (c EspoCRMAPIConfig) apiConvertLeadURL() string { | |||||
| return c.apiURL("Lead/action/convert") | |||||
| } |
| package main | |||||
| import ( | |||||
| "encoding/json" | |||||
| "log" | |||||
| ) | |||||
| type crmdContact struct { | |||||
| crmdEntityBase | |||||
| SolutationName string `json:"solutationName,omitempty"` | |||||
| FirstName string `json:"firstName,omitempty"` | |||||
| LastName string `json:"lastName,omitempty"` | |||||
| AccountID string `json:"accountID,omitempty"` | |||||
| Title string `json:"title,omitempty"` | |||||
| EmailAddress string `json:"emailAddress,omitempty"` | |||||
| PhoneNumber string `json:"phoneNumber,omitempty"` | |||||
| DoNotCall bool `json:"doNotCall,omitempty"` | |||||
| AddressStreet string `json:"addressStreet,omitempty"` | |||||
| AddressCity string `json:"addressCity,omitempty"` | |||||
| AddressState string `json:"addressState,omitempty"` | |||||
| AddressCountry string `json:"addressCountry,omitempty"` | |||||
| AddresPostalCode string `json:"addressPostalcode,omitempty"` | |||||
| AccountType string `json:"accountType,omitempty"` | |||||
| EmailAddressData []struct { | |||||
| EmailAddress string `json:"emailAddress,omitempty"` | |||||
| Lower string `json:"lower,omitempty"` | |||||
| Primary bool `json:"primary,omitempty"` | |||||
| OptOut bool `json:"optOut,omitempty"` | |||||
| Invalid bool `json:"invalid,omitempty"` | |||||
| } `json:"emailAddressData,omitempty"` | |||||
| PhoneNumberData []struct { | |||||
| PhoneNumber string `json:"phoneNumber,omitempty"` | |||||
| Primary bool `json:"primary,omitempty"` | |||||
| Type string `json:"type,omitempty"` | |||||
| } `json:"phoneNumberData,omitempty"` | |||||
| AccountName string `json:"accountName,omitempty"` | |||||
| AccountIDs []string `json:"accountsIds,omitempty"` | |||||
| AccountNames map[string]string `json:"accountsNames,omitempty"` | |||||
| AccountsColumns map[string]struct { | |||||
| Role string `json:"role,omitempty"` | |||||
| } `json:"accountsColumns,omitempty"` | |||||
| CompainID string `json:"campainId,omitempty"` | |||||
| CampainName string `json:"campainName,omitempty"` | |||||
| PortalUserID string `json:"portalUserId,omitempty"` | |||||
| PortalUserName string `json:"portalUserName,omitempty"` | |||||
| OriginalLeadID string `json:"originalLeadId,omitempty"` | |||||
| OriginalLeadName string `json:"originalLeadName,omitempty"` | |||||
| IsFollowed bool `json:"isFollowed,omitempty"` | |||||
| FollwersIDs []string `json:"followersIds,omitempty"` | |||||
| FollowersNames map[string]string `json:"followersNames,omitempty"` | |||||
| } | |||||
| type crmdConvert struct { | |||||
| ID string `json:"id,omitempty"` | |||||
| Records struct { | |||||
| Contact crmdContact `json:"Contact,omitempty"` | |||||
| } `json:"records,omitempty"` | |||||
| } | |||||
| func (m *crmdContact) convertFromLead(leadID string) (err error) { | |||||
| url := CRMConfig.apiConvertLeadURL() | |||||
| lead, err := crmGetLead(leadID) | |||||
| if err != nil { | |||||
| log.Println(err) | |||||
| return | |||||
| } | |||||
| convert := crmdConvert{} | |||||
| convert.ID = leadID | |||||
| convert.Records.Contact.copyFromLead(lead) | |||||
| jsonB, err := json.Marshal(convert) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| jsonStr, err := postRAW(jsonB, url, crmBuildCommonAPIHeader()) | |||||
| //log.Println(jsonStr) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| entity, err := crmJSON2Entity("Lead", jsonStr) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| convertedLead := entity.(crmdLead) | |||||
| entity, err = crmGetEntity("Contact", convertedLead.CreatedContactID) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| *m = entity.(crmdContact) | |||||
| return | |||||
| } | |||||
| func (m *crmdContact) copyFromLead(lead crmdLead) { | |||||
| m.SolutationName = lead.SalutationName | |||||
| m.FirstName = lead.FirstName | |||||
| m.LastName = lead.LastName | |||||
| m.EmailAddressData = lead.EmailAddressData | |||||
| m.PhoneNumberData = lead.PhoneNumberData | |||||
| } |
| package main | |||||
| import ( | |||||
| "encoding/json" | |||||
| "testing" | |||||
| "time" | |||||
| ) | |||||
| func TestConvertLead2Contact(t *testing.T) { | |||||
| //create a lead | |||||
| l := crmdLead{} | |||||
| l.FirstName = "testConvert" + time.Now().Format(getCrmTimeLayout()) | |||||
| l.LastName = "temp lead (deletable)" | |||||
| l.Status = "Deletable" | |||||
| l.Password = "password" | |||||
| l.EmailAddress = "non-exit-fake@badmail.com" | |||||
| l.PhoneNumber = "12345678-1" | |||||
| l.ForceDuplicate = true | |||||
| jsonB, err := json.Marshal(l) | |||||
| AssertEqual(t, err, nil, "") | |||||
| entity, err := crmCreateEntity("Lead", jsonB) | |||||
| AssertEqual(t, err, nil, "") | |||||
| lead := entity.(crmdLead) | |||||
| AssertEqual(t, lead.ID != "", true, "") | |||||
| //conver to contact | |||||
| cc := crmdContact{} | |||||
| err = cc.convertFromLead(lead.ID) | |||||
| AssertEqual(t, err, nil, "") | |||||
| AssertEqual(t, cc.OriginalLeadID, lead.ID, "") | |||||
| AssertEqual(t, cc.FirstName, lead.FirstName, "") | |||||
| AssertEqual(t, cc.LastName, lead.LastName, "") | |||||
| AssertEqual(t, cc.EmailAddress, lead.EmailAddress, "") | |||||
| AssertEqual(t, cc.PhoneNumber, lead.PhoneNumber, "") | |||||
| //delete lead | |||||
| crmDeleteEntity("Lead", lead.ID) | |||||
| //delete contact | |||||
| crmDeleteEntity("Contact", cc.ID) | |||||
| } |
| r = e | r = e | ||||
| case "Account": | case "Account": | ||||
| //r = crmdAccount{} | //r = crmdAccount{} | ||||
| case "Contact": | |||||
| e := crmdContact{} | |||||
| err = json.Unmarshal([]byte(data), &e) | |||||
| r = e | |||||
| default: | default: | ||||
| log.Fatalf("crmJSON2Entity: Unknown EntityType %s", entityType) | log.Fatalf("crmJSON2Entity: Unknown EntityType %s", entityType) | ||||
| } | } |
| } | } | ||||
| } | } | ||||
| } | } | ||||
| func (m crmdLead) crmLeadConvert2Contact() (newContact crmdContact) { | |||||
| newContact.convertFromLead(m.ID) | |||||
| return | |||||
| } |
| if err == nil { | if err == nil { | ||||
| w.Write(pixel) | w.Write(pixel) | ||||
| } else { | } else { | ||||
| fmt.Fprint(w, "decodig wrong") | |||||
| fmt.Fprint(w, "decodig pixel image wrong") | |||||
| } | } | ||||
| } | } | ||||
| { | |||||
| "id": "5961bfac40e1b4e69", | |||||
| "records": { | |||||
| "Contact": { | |||||
| "firstName": "Anonymous", | |||||
| "lastName": "User 127.0.0.1:49261", | |||||
| "salutationName": "", | |||||
| "title": "", | |||||
| "addressStreet": "", | |||||
| "addressCity": "", | |||||
| "addressState": "", | |||||
| "addressCountry": "", | |||||
| "addressPostalCode": "", | |||||
| "emailAddress": null, | |||||
| "emailAddressData": [], | |||||
| "phoneNumber": null, | |||||
| "phoneNumberData": [], | |||||
| "doNotCall": false, | |||||
| "description": "Anonymous user from 127.0.0.1:49261", | |||||
| "assignedUserId": null, | |||||
| "assignedUserName": null, | |||||
| "teamsIds": [], | |||||
| "teamsNames": {}, | |||||
| "campaignId": null, | |||||
| "campaignName": null | |||||
| } | |||||
| } | |||||
| } | |||||
| //converted by lead | |||||
| { | |||||
| "id": "5961bfac40e1b4e69", | |||||
| "name": "Anonymous User 127.0.0.1:49261", | |||||
| "deleted": false, | |||||
| "salutationName": null, | |||||
| "firstName": "Anonymous", | |||||
| "lastName": "User 127.0.0.1:49261", | |||||
| "title": null, | |||||
| "status": "Converted", | |||||
| "source": "", | |||||
| "industry": "", | |||||
| "opportunityAmount": null, | |||||
| "website": null, | |||||
| "addressStreet": null, | |||||
| "addressCity": null, | |||||
| "addressState": null, | |||||
| "addressCountry": null, | |||||
| "addressPostalCode": null, | |||||
| "emailAddress": null, | |||||
| "phoneNumber": null, | |||||
| "doNotCall": false, | |||||
| "description": "Anonymous user from 127.0.0.1:49261", | |||||
| "createdAt": "2017-07-09 05:31:24", | |||||
| "modifiedAt": "2017-07-09 11:11:45", | |||||
| "accountName": null, | |||||
| "password": "Password", | |||||
| "wechatOpenID": null, | |||||
| "opportunityAmountCurrency": null, | |||||
| "opportunityAmountConverted": null, | |||||
| "emailAddressData": [], | |||||
| "phoneNumberData": [], | |||||
| "createdById": "58ef420cac3cf6c95", | |||||
| "createdByName": "wechat robot", | |||||
| "modifiedById": "1", | |||||
| "modifiedByName": "Admin", | |||||
| "assignedUserId": null, | |||||
| "assignedUserName": null, | |||||
| "teamsIds": [], | |||||
| "teamsNames": {}, | |||||
| "campaignId": null, | |||||
| "campaignName": null, | |||||
| "createdAccountId": null, | |||||
| "createdAccountName": null, | |||||
| "createdContactId": "59620f71ae30391e8", | |||||
| "createdContactName": "Anonymous User 127.0.0.1:49261", | |||||
| "createdOpportunityId": null, | |||||
| "createdOpportunityName": null, | |||||
| "isFollowed": false, | |||||
| "followersIds": [], | |||||
| "followersNames": {}, | |||||
| "avatarId": null, | |||||
| "avatarName": null | |||||
| } |
| { | |||||
| "id": "59620f71ae30391e8", | |||||
| "name": "Anonymous User 127.0.0.1:49261", | |||||
| "deleted": false, | |||||
| "salutationName": "", | |||||
| "firstName": "Anonymous", | |||||
| "lastName": "User 127.0.0.1:49261", | |||||
| "accountId": null, | |||||
| "title": null, | |||||
| "description": "Anonymous user from 127.0.0.1:49261", | |||||
| "emailAddress": null, | |||||
| "phoneNumber": null, | |||||
| "doNotCall": false, | |||||
| "addressStreet": "", | |||||
| "addressCity": "", | |||||
| "addressState": "", | |||||
| "addressCountry": "", | |||||
| "addressPostalCode": "", | |||||
| "accountType": null, | |||||
| "createdAt": "2017-07-09 11:11:45", | |||||
| "modifiedAt": "2017-07-09 11:11:45", | |||||
| "emailAddressData": [], | |||||
| "phoneNumberData": [], | |||||
| "accountName": null, | |||||
| "accountsIds": [], | |||||
| "accountsNames": {}, | |||||
| "accountsColumns": {}, | |||||
| "campaignId": null, | |||||
| "campaignName": null, | |||||
| "createdById": "1", | |||||
| "createdByName": "Admin", | |||||
| "modifiedById": null, | |||||
| "modifiedByName": null, | |||||
| "assignedUserId": null, | |||||
| "assignedUserName": null, | |||||
| "teamsIds": [], | |||||
| "teamsNames": {}, | |||||
| "portalUserId": null, | |||||
| "portalUserName": null, | |||||
| "originalLeadId": "5961bfac40e1b4e69", | |||||
| "originalLeadName": "Anonymous User 127.0.0.1:49261", | |||||
| "isFollowed": false, | |||||
| "followersIds": [], | |||||
| "followersNames": {} | |||||
| } | |||||
| { | |||||
| "id": "57efb926aa6725fdd", | |||||
| "name": "Vincent Zhang", | |||||
| "deleted": false, | |||||
| "salutationName": "Mr.", | |||||
| "firstName": "Vincent", | |||||
| "lastName": "Zhang", | |||||
| "accountId": "57e3de733402c8d5f", | |||||
| "title": "IT Admin", | |||||
| "description": "\u5e7f\u4e1c\u6885\u53bf\u4eba\uff0c1982\u5e74\u51fa\u751f\uff0c \u5728\u6089\u5c3c\u5927\u5b66\u5b66\u4e60\u8fc7 \u4e2d\u5b66\u6559\u80b2\u3002\n\nMM \u7684\u7f51\u9875\u4ecb\u7ecd\nVincent has taught Mandarin in China, Indonesia and Australia.\n\nHis qualifications include a Bachelor of Arts in Teaching Chinese as a Second Language from Jinan University, Guangzhou, a Master of Education from the University of Sydney, and a Diploma in Education from the University of New South Wales.\n\nI always cater to the needs of individual students. I like to develop my students\u2019 speaking and listening skills using a range of methods, such as conversation, discussion and debate. \u2013 Vincent", | |||||
| "emailAddress": null, | |||||
| "phoneNumber": null, | |||||
| "doNotCall": false, | |||||
| "addressStreet": "", | |||||
| "addressCity": "", | |||||
| "addressState": "", | |||||
| "addressCountry": "", | |||||
| "addressPostalCode": "", | |||||
| "accountType": "Customer", | |||||
| "createdAt": "2016-10-01 13:24:54", | |||||
| "modifiedAt": "2016-10-10 06:18:54", | |||||
| "emailAddressData": [], | |||||
| "phoneNumberData": [], | |||||
| "accountName": "Macquarie Mandarin", | |||||
| "accountsIds": [ | |||||
| "57e3de733402c8d5f" | |||||
| ], | |||||
| "accountsNames": { | |||||
| "57e3de733402c8d5f": "Macquarie Mandarin" | |||||
| }, | |||||
| "accountsColumns": { | |||||
| "57e3de733402c8d5f": { | |||||
| "role": "IT Admin" | |||||
| } | |||||
| }, | |||||
| "campaignId": null, | |||||
| "campaignName": null, | |||||
| "createdById": "1", | |||||
| "createdByName": "\u5b59\u9e4f sunpeng", | |||||
| "modifiedById": "1", | |||||
| "modifiedByName": "\u5b59\u9e4f sunpeng", | |||||
| "assignedUserId": "1", | |||||
| "assignedUserName": "\u5b59\u9e4f sunpeng", | |||||
| "teamsIds": [], | |||||
| "teamsNames": {}, | |||||
| "portalUserId": null, | |||||
| "portalUserName": null, | |||||
| "originalLeadId": null, | |||||
| "originalLeadName": null, | |||||
| "isFollowed": true, | |||||
| "followersIds": [ | |||||
| "1" | |||||
| ], | |||||
| "followersNames": { | |||||
| "1": "\u5b59\u9e4f sunpeng" | |||||
| }, | |||||
| "avatarId": "57fb32cd3de8755df", | |||||
| "avatarName": "06_vincen.jpg", | |||||
| "namecardId": null, | |||||
| "namecardName": null, | |||||
| "namecardbackId": null, | |||||
| "namecardbackName": null | |||||
| } |