package maycur import ( "crypto/hmac" "crypto/md5" "encoding/hex" "encoding/json" "fmt" "github.com/rdlucklib/rdluck_tools/common" "hongze/hz_crm_api/models" "hongze/hz_crm_api/services/alarm_msg" "hongze/hz_crm_api/utils" "io/ioutil" "net/http" "net/url" "sort" "strconv" "strings" "time" ) const ( ShanghaiCRMCompanyListUrl = `/v2/Customer/basicSaleCustomerRelation` ShanghaiCRMSellerListUrl = `/v2/AdminUser/EquitySaleDeptMemberList` ShanghaiCRMCompanyListUrlRelease = `https://crm.hzinsights.com/openapi/v2/Customer/basicSaleCustomerRelation` ShanghaiCRMSellerListUrlRelease = `https://crm.hzinsights.com/openapi/v2/AdminUser/EquitySaleDeptMemberList` ) // openApiParamsBuild 生成Api参数(含签名) func openApiParamsBuild(paramMap map[string]string) (params url.Values) { // 公共参数 strRand := utils.GetRandStringNoSpecialChar(32) timestamp := fmt.Sprint(time.Now().Unix()) values := map[string]string{ "app_key": utils.CRM_OPEN_API_APP_KEY, "nonce_str": strRand, "timestamp": timestamp, } // ASCII排序 keys := make([]string, 0) keys = append(keys, "app_key", "nonce_str", "timestamp") for k, v := range paramMap { keys = append(keys, k) values[k] = v } sort.Strings(keys) params = make(map[string][]string) signArr := make([]string, 0) // 参与签名生成的参数 for _, k := range keys { params.Add(k, values[k]) signArr = append(signArr, fmt.Sprint(k, "=", values[k])) } // 签名 strA := strings.Join(signArr, "&") h := hmac.New(md5.New, []byte(utils.CRM_OPEN_API_APP_SECRET)) h.Write([]byte(strA)) strB := hex.EncodeToString(h.Sum([]byte(""))) strD := common.UrlEncode(strB) params.Add("signature", strD) return } // PublicOfferingCompanyApiResp 客户列表响应体 type PublicOfferingCompanyApiResp struct { Code int `description:"状态码: 1-成功; 0-失败; >1-指定错误"` Msg string `description:"提示信息"` Time int64 `description:"时间戳"` Data struct { Paginator struct { Total int `description:"数据总量"` CurrentPage int `description:"当前页码" json:"current_page"` ListRow int `description:"每页数据量" json:"list_row"` LastPage int `description:"最后一页页码" json:"last_page"` } `description:"分页信息"` Data []struct { Name string `description:"公司名称"` ShortName string `description:"公司简称" json:"short_name"` Social string `description:"公司社会信用码"` UserId string `description:"销售ID" json:"user_id"` Username string `description:"销售名称"` } `description:"公司列表"` } `description:"响应数据"` } // CurlPublicOfferingCompanyApi 请求客户列表接口 func CurlPublicOfferingCompanyApi(strParams string) (body []byte, err error) { //curlUrl := fmt.Sprintf("%s%s?%s", utils.CRM_OPEN_API_URL, ShanghaiCRMCompanyListUrl, strParams) curlUrl := fmt.Sprintf("%s?%s", ShanghaiCRMCompanyListUrlRelease, strParams) res, e := http.Get(curlUrl) if e != nil { err = fmt.Errorf("http get err: %s", e.Error()) return } defer func() { _ = res.Body.Close() }() body, e = ioutil.ReadAll(res.Body) if e != nil { err = fmt.Errorf("http body err: %s", e.Error()) return } //utils.FileLog.Info("open api http resp: %s", string(body)) return } // PublicOfferingSaleApiResp 销售列表响应体 type PublicOfferingSaleApiResp struct { Code int `description:"状态码: 1-成功; 0-失败; >1-指定错误"` Msg string `description:"提示信息"` Time int64 `description:"时间戳"` Data []struct { Mobile string `description:"手机号"` Nickname string `description:"销售姓名"` DeptText string `description:"部门描述" json:"dept_text"` IsLeader int `description:"是否为负责人: 0-否; 1-是" json:"is_leader"` } `description:"响应数据"` } // CurlEquitySaleListApi 请求公募销售列表接口 func CurlEquitySaleListApi(strParams string) (body []byte, err error) { //curlUrl := fmt.Sprintf("%s%s?%s", utils.CRM_OPEN_API_URL, ShanghaiCRMSellerListUrl, strParams) curlUrl := fmt.Sprintf("%s?%s", ShanghaiCRMSellerListUrlRelease, strParams) res, e := http.Get(curlUrl) if e != nil { err = fmt.Errorf("http get err: %s", e.Error()) return } defer func() { _ = res.Body.Close() }() body, e = ioutil.ReadAll(res.Body) if e != nil { err = fmt.Errorf("http body err: %s", e.Error()) return } utils.FileLog.Info("open api http resp: %s", string(body)) return } // SyncPublicOfferingSale 同步公募销售 func SyncPublicOfferingSale() (err error) { defer func() { if err != nil { msg := fmt.Sprintf("每刻-同步公募销售失败, ErrMsg: %s", err.Error()) utils.FileLog.Error(msg) go alarm_msg.SendAlarmMsg(msg, 3) } }() paramMap := make(map[string]string) params := openApiParamsBuild(paramMap) strParams := params.Encode() res, e := CurlEquitySaleListApi(strParams) if e != nil { err = fmt.Errorf("获取公募销售列表失败, Err: %s", e.Error()) return } if len(res) == 0 { err = fmt.Errorf("公募销售数据为空") return } var resp PublicOfferingSaleApiResp if e := json.Unmarshal(res, &resp); e != nil { err = fmt.Errorf("解析公募销售数据失败, Err: %s; Body: %s", e.Error(), string(res)) return } if resp.Code != 1 { err = fmt.Errorf("获取公募销售数据失败, Body: %s", string(res)) return } sales := resp.Data // 去重 saleOB := new(models.MaycurPublicOfferingSale) saleCond := `` salePars := make([]interface{}, 0) origins, e := saleOB.GetItemsByCondition(saleCond, salePars, []string{}, "") if e != nil { err = fmt.Errorf("获取公募销售留档失败, Err: %s", e.Error()) return } salesNameVal := make(map[string]*models.MaycurPublicOfferingSale) for _, s := range origins { salesNameVal[s.Nickname] = s } // 新增 inserts := make([]*models.MaycurPublicOfferingSale, 0) updateCols := []string{"Mobile", "DeptText", "IsLeader", "ModifyTime"} for _, v := range sales { s := salesNameVal[v.Nickname] if s != nil { s.Mobile = v.Mobile s.DeptText = v.DeptText s.IsLeader = v.IsLeader s.ModifyTime = time.Now().Local() if e = s.Update(updateCols); e != nil { err = fmt.Errorf("更新公募销售信息失败, Err: %s", e.Error()) return } continue } inserts = append(inserts, &models.MaycurPublicOfferingSale{ Mobile: v.Mobile, Nickname: v.Nickname, CreateTime: time.Now().Local(), ModifyTime: time.Now().Local(), }) } if e = saleOB.CreateMulti(inserts); e != nil { err = fmt.Errorf("新增公募销售失败, Err: %s", e.Error()) return } return } // SyncPublicOfferingCompany 同步客户列表, 过滤出公募客户入库留档 func SyncPublicOfferingCompany() (err error) { defer func() { if err != nil { msg := fmt.Sprintf("每刻-同步公募客户失败, ErrMsg: %s", err.Error()) utils.FileLog.Error(msg) go alarm_msg.SendAlarmMsg(msg, 3) } }() // 去重 companyOB := new(models.MaycurPublicOfferingCompany) companyCond := `` companyPars := make([]interface{}, 0) origins, e := companyOB.GetItemsByCondition(companyCond, companyPars, []string{}, "") if e != nil { err = fmt.Errorf("获取公募客户留档失败, Err: %s", e.Error()) return } companyCodeVal := make(map[string]*models.MaycurPublicOfferingCompany) for _, s := range origins { companyCodeVal[s.Social] = s } // 获取公募销售 saleOB := new(models.MaycurPublicOfferingSale) sales, e := saleOB.GetItemsByCondition(``, make([]interface{}, 0), []string{}, "") if e != nil { err = fmt.Errorf("获取公募销售列表失败, Err: %s", e.Error()) return } saleArr := make([]string, 0) for _, s := range sales { saleArr = append(saleArr, s.Nickname) } currentPage := 1 pageSize := 100 updateCols := []string{"SaleNames", "ModifyTime"} codeSales := make(map[string][]string) for { paramMap := make(map[string]string) paramMap["limit"] = strconv.Itoa(pageSize) paramMap["f_e"] = "Equity" paramMap["page"] = strconv.Itoa(currentPage) params := openApiParamsBuild(paramMap) strParams := params.Encode() res, e := CurlPublicOfferingCompanyApi(strParams) if e != nil { err = fmt.Errorf("获取公募销售列表失败, Err: %s", e.Error()) return } if len(res) == 0 { err = fmt.Errorf("公募销售数据为空") return } var resp PublicOfferingCompanyApiResp if e := json.Unmarshal(res, &resp); e != nil { err = fmt.Errorf("解析公募客户数据失败, Err: %s; Body: %s", e.Error(), string(res)) return } if resp.Code != 1 { err = fmt.Errorf("获取公募客户数据失败, Body: %s", string(res)) return } data := resp.Data companies := data.Data codeCompany := make(map[string]*models.MaycurPublicOfferingCompany) for _, c := range companies { // 过滤测试客户 if strings.Contains(c.Name, "测试") || strings.Contains(strings.ToLower(c.Name), "test") { continue } // 如果该客户的销售中无公募销售, 则忽略 if !utils.InArrayByStr(saleArr, c.Username) { continue } if codeCompany[c.Social] == nil { v := &models.MaycurPublicOfferingCompany{ Name: c.Name, ShortName: c.ShortName, Social: c.Social, CreateTime: time.Now().Local(), ModifyTime: time.Now().Local(), } codeCompany[c.Social] = v } if c.Username != "" && !utils.InArrayByStr(codeSales[c.Social], c.Username) { codeSales[c.Social] = append(codeSales[c.Social], c.Username) } } inserts := make([]*models.MaycurPublicOfferingCompany, 0) for _, c := range codeCompany { saleNames := strings.Join(codeSales[c.Social], ",") ex := companyCodeVal[c.Social] if ex != nil { // 更新销售 ex.SaleNames = saleNames ex.ModifyTime = time.Now().Local() if e = ex.Update(updateCols); e != nil { err = fmt.Errorf("更新客户信息失败, Err: %s", e.Error()) return } continue } c.SaleNames = saleNames inserts = append(inserts, c) // 本次新增的客户也加入map, 因为可能出现下一页有上一页的客户, 下一次循环时更新 companyCodeVal[c.Social] = c } ob := new(models.MaycurPublicOfferingCompany) if e = ob.CreateMulti(inserts); e != nil { err = fmt.Errorf("批量新增客户信息失败, Err: %s", e.Error()) return } // 最后一页 if data.Paginator.LastPage == currentPage { break } currentPage += 1 } return } // GetPublicOfferingSaleLeader 获取公募销售对应的组长 func GetPublicOfferingSaleLeader() (leaderMap map[string][]string, err error) { saleOB := new(models.MaycurPublicOfferingSale) sales, e := saleOB.GetItemsByCondition(``, make([]interface{}, 0), []string{}, "") if e != nil { err = fmt.Errorf("获取公募销售列表失败, Err: %s", e.Error()) return } if sales == nil { return } if len(sales) == 0 { return } // 销售组组长 groupsLeader := make(map[string][]string) for _, s := range sales { // 存在这种数据->北京组、上海组 gs := strings.Split(s.DeptText, "、") for _, g := range gs { if s.IsLeader == 1 { groupsLeader[g] = append(groupsLeader[g], s.Nickname) } } } // 销售对应组长 leaderMap = make(map[string][]string) for _, s := range sales { // 组长置空 ls := make([]string, 0) if s.IsLeader == 1 { leaderMap[s.Nickname] = ls continue } // 组员 gs := strings.Split(s.DeptText, "、") for _, g := range gs { if len(groupsLeader[g]) > 0 { for _, l := range groupsLeader[g] { if !utils.InArrayByStr(ls, l) { ls = append(ls, l) } } } } leaderMap[s.Nickname] = ls } return }