refactor logic for posting deals

This commit is contained in:
Pavel 2024-05-05 15:22:54 +03:00
parent f21dadfd01
commit 02263b0ed0
9 changed files with 95 additions and 97 deletions

2
go.mod

@ -12,7 +12,7 @@ require (
github.com/twmb/franz-go v1.16.1 github.com/twmb/franz-go v1.16.1
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.0
google.golang.org/protobuf v1.33.0 google.golang.org/protobuf v1.33.0
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240504123552-f1d3073dc9f1 penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240505074742-07895eccdd07
penahub.gitlab.yandexcloud.net/backend/quiz/core.git v0.0.0-20240219174804-d78fd38511af penahub.gitlab.yandexcloud.net/backend/quiz/core.git v0.0.0-20240219174804-d78fd38511af
) )

4
go.sum

@ -151,7 +151,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6 h1:oV+/HNX+JPoQ3/GUx08hio7d45WpY0AMGrFs7j70QlA= penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6 h1:oV+/HNX+JPoQ3/GUx08hio7d45WpY0AMGrFs7j70QlA=
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6/go.mod h1:lTmpjry+8evVkXWbEC+WMOELcFkRD1lFMc7J09mOndM= penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6/go.mod h1:lTmpjry+8evVkXWbEC+WMOELcFkRD1lFMc7J09mOndM=
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240504123552-f1d3073dc9f1 h1:H+2MgBImU5ab8vIFLQCUw0Az85BHKNXi2yPqKtX8sR0= penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240505074742-07895eccdd07 h1:ttTQdCfoOj5L/C6xv9GEVDd23LWGkvgZCCEXvSXzjEo=
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240504123552-f1d3073dc9f1/go.mod h1:oRyhT55ctjqp/7ZxIzkR7OsQ7T/NLibsfrbb7Ytns64= penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240505074742-07895eccdd07/go.mod h1:oRyhT55ctjqp/7ZxIzkR7OsQ7T/NLibsfrbb7Ytns64=
penahub.gitlab.yandexcloud.net/backend/quiz/core.git v0.0.0-20240219174804-d78fd38511af h1:jQ7HaXSutDX5iepU7VRImxhikK7lV/lBKkiloOZ4Emo= penahub.gitlab.yandexcloud.net/backend/quiz/core.git v0.0.0-20240219174804-d78fd38511af h1:jQ7HaXSutDX5iepU7VRImxhikK7lV/lBKkiloOZ4Emo=
penahub.gitlab.yandexcloud.net/backend/quiz/core.git v0.0.0-20240219174804-d78fd38511af/go.mod h1:5S5YwjSXWmnEKjBjG6MtyGtFmljjukDRS8CwHk/CF/I= penahub.gitlab.yandexcloud.net/backend/quiz/core.git v0.0.0-20240219174804-d78fd38511af/go.mod h1:5S5YwjSXWmnEKjBjG6MtyGtFmljjukDRS8CwHk/CF/I=

@ -29,7 +29,7 @@ func (c *Controller) UpdateListCustom(ctx *fiber.Ctx) error {
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required") return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
} }
//accountID := "64f2cd7a7047f28fdabf6d9e" //accountID := "654a8909725f47e926f0bebc"
err := c.service.UpdateListCustom(ctx.Context(), accountID) err := c.service.UpdateListCustom(ctx.Context(), accountID)
if err != nil { if err != nil {

@ -12,7 +12,7 @@ func (c *Controller) UpdateListUsers(ctx *fiber.Ctx) error {
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required") return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
} }
//accountID := "64f2cd7a7047f28fdabf6d9e" //accountID := "654a8909725f47e926f0bebc"
err := c.service.UpdateListUsers(ctx.Context(), accountID) err := c.service.UpdateListUsers(ctx.Context(), accountID)

@ -15,6 +15,7 @@ type DealReq struct {
CustomFieldsValues []FieldsValues `json:"custom_fields_values"` // Массив полей которые заполняются значениями CustomFieldsValues []FieldsValues `json:"custom_fields_values"` // Массив полей которые заполняются значениями
TagsToAdd []Tag `json:"tags_to_add"` // Массив тегов для добавления TagsToAdd []Tag `json:"tags_to_add"` // Массив тегов для добавления
Embed Embedd `json:"_embedded"` Embed Embedd `json:"_embedded"`
RequestID string `json:"request_id"`
} }
type FieldsValues struct { type FieldsValues struct {
@ -34,17 +35,24 @@ type Embedd struct {
} }
type Contact struct { type Contact struct {
//ID int32 `json:"id"` // ID контакта //ID int32 `json:"id"` // ID контакта
//IsMain bool `json:"is_main"` // Флаг, показывающий, является контакт главным или нет IsMain bool `json:"is_main"` // Флаг, показывающий, является контакт главным или нет
Name string `json:"first_name"` Name string `json:"first_name"`
CreatedAT int64 `json:"created_at"` CreatedAt int64 `json:"created_at"`
UpdatedBy int `json:"updated_by"` UpdatedBy int `json:"updated_by"`
ResponsibleUserID int32 `json:"responsible_user_id"` // ID пользователя, ответственного за сделку, в нашем случае PerformerID ResponsibleUserID int32 `json:"responsible_user_id"` // ID пользователя, ответственного за сделку, в нашем случае PerformerID
CustomFieldsValues []FieldsValues `json:"custom_fields_values"` // Массив полей которые заполняются значениями CustomFieldsValues []FieldsValues `json:"custom_fields_values"` // Массив полей которые заполняются значениями
} }
type Company struct { type Company struct {
ID int `json:"id"` // ID компании //ID int32 `json:"id"` // ID компании
Name string `json:"name"` // Название компании
ResponsibleUserID int32 `json:"responsible_user_id"` // ID пользователя, ответственного за сделку, в нашем случае PerformerID
CreatedBy int32 `json:"created_by"` // id пользователя amoid который создает сделку (тот кто подключил интеграцию)
UpdatedBy int `json:"updated_by"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"` // Дата изменения сделки, передается в Unix Timestamp
CustomFieldsValues []FieldsValues `json:"custom_fields_values"` // Массив полей которые заполняются значениями
} }
type Source struct { type Source struct {
@ -53,16 +61,9 @@ type Source struct {
} }
type DealResp struct { type DealResp struct {
Link struct { DealID int `json:"id"` // ID сделки
SelfLink `json:"self"` ContactID int `json:"contact_id"` // ID контакта
} `json:"_links"` CompanyID int `json:"company_id"` // ID компании
Embed struct { Merged bool `json:"merged"` // Флаг, который показывает, найден дубль подходящий под условия поиска дублей и произведено объединение или нет
Leads []struct { RequestID []string `json:"request_id"` // Массив строк с пользовательскими идентификаторами, которые были переданы с каждой сущностью
ID int `json:"id"`
RequestID string `json:"request_id"`
Links struct {
SelfLink `json:"self"`
} `json:"_links"`
}
} `json:"_embedded"`
} }

@ -3,6 +3,7 @@ package tools
import ( import (
"amocrm/internal/models" "amocrm/internal/models"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
"time"
) )
func ToPipeline(amoPipelines []models.Pipeline) []model.Pipeline { func ToPipeline(amoPipelines []models.Pipeline) []model.Pipeline {
@ -64,66 +65,72 @@ func ToField(amoField []models.CustomField, entity model.EntityType) []model.Fie
return fields return fields
} }
func ConstructField(allAnswers []model.ResultAnswer, fieldsRule model.Fieldsrule) []models.FieldsValues { // todo Для добавляемых сущностей (сделка, контакт, компания), можно передать не более 40 значений дополнительных полей.
fieldsMap := make(map[int][]models.Values) func ConstructField(allAnswers []model.ResultAnswer, result model.AmoUsersTrueResults) ([]models.FieldsValues, []models.Contact, []models.Company) {
entityFieldsMap := make(map[model.EntityType]map[int][]models.Values)
entityFieldsMap[model.LeadsType] = make(map[int][]models.Values)
entityFieldsMap[model.ContactsType] = make(map[int][]models.Values)
entityFieldsMap[model.CompaniesType] = make(map[int][]models.Values)
entityFieldsMap[model.CustomersType] = make(map[int][]models.Values)
if fieldsRule.Lead != nil { entityRules := make(map[model.EntityType][]model.FieldRule)
for _, rule := range fieldsRule.Lead { entityRules[model.LeadsType] = result.FieldsRule.Lead
entityRules[model.ContactsType] = result.FieldsRule.Contact
entityRules[model.CompaniesType] = result.FieldsRule.Company
entityRules[model.CustomersType] = result.FieldsRule.Customer
for entityType, ruleList := range entityRules {
for _, rule := range ruleList {
for _, data := range allAnswers { for _, data := range allAnswers {
if fieldID, ok := rule.Questionid[int(data.QuestionID)]; ok { if fieldID, ok := rule.Questionid[int(data.QuestionID)]; ok {
values := fieldsMap[fieldID] values := entityFieldsMap[entityType][fieldID]
values = append(values, models.Values{Value: data.Content}) values = append(values, models.Values{Value: data.Content})
fieldsMap[fieldID] = values entityFieldsMap[entityType][fieldID] = values
} }
} }
} }
} }
if fieldsRule.Contact != nil { var leadFields []models.FieldsValues
for _, rule := range fieldsRule.Contact { var contactFields []models.FieldsValues
for _, data := range allAnswers { var companyFields []models.FieldsValues
if fieldID, ok := rule.Questionid[int(data.QuestionID)]; ok { var customerFields []models.FieldsValues
values := fieldsMap[fieldID]
values = append(values, models.Values{Value: data.Content}) for entityType, fieldMap := range entityFieldsMap {
fieldsMap[fieldID] = values for fieldID, values := range fieldMap {
} field := models.FieldsValues{
FieldID: fieldID,
Values: values,
}
switch entityType {
case model.LeadsType:
leadFields = append(leadFields, field)
case model.ContactsType:
contactFields = append(contactFields, field)
case model.CompaniesType:
companyFields = append(companyFields, field)
case model.CustomersType:
customerFields = append(customerFields, field)
} }
} }
} }
if fieldsRule.Company != nil { return leadFields, []models.Contact{
for _, rule := range fieldsRule.Company { {
for _, data := range allAnswers { Name: result.PerformerName,
if fieldID, ok := rule.Questionid[int(data.QuestionID)]; ok { CreatedAt: time.Now().Unix(),
values := fieldsMap[fieldID] UpdatedBy: 0,
values = append(values, models.Values{Value: data.Content}) ResponsibleUserID: result.PerformerID,
fieldsMap[fieldID] = values CustomFieldsValues: contactFields,
} },
} }, []models.Company{
{
Name: "OOO PENA CO",
ResponsibleUserID: result.PerformerID,
CreatedBy: 0,
UpdatedBy: 0,
CreatedAt: time.Now().Unix(),
CustomFieldsValues: companyFields,
},
} }
}
if fieldsRule.Customer != nil {
for _, rule := range fieldsRule.Customer {
for _, data := range allAnswers {
if fieldID, ok := rule.Questionid[int(data.QuestionID)]; ok {
values := fieldsMap[fieldID]
values = append(values, models.Values{Value: data.Content})
fieldsMap[fieldID] = values
}
}
}
}
var fields []models.FieldsValues
for fieldID, values := range fieldsMap {
field := models.FieldsValues{
FieldID: fieldID,
Values: values,
}
fields = append(fields, field)
}
return fields
} }

@ -51,7 +51,7 @@ func ToCreatedUpdateQuestionRules(questionsTypeMap map[model.EntityType][]model.
for _, question := range questions { for _, question := range questions {
matched := false matched := false
for _, field := range currentFields { for _, field := range currentFields {
if question.Title == field.Name { if question.Title == field.Name && entity == field.Entity {
toUpdate[int(question.Id)] = int(field.Amoid) toUpdate[int(question.Id)] = int(field.Amoid)
matched = true matched = true
break break

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"go.uber.org/zap" "go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
"strconv"
"time" "time"
) )
@ -32,7 +33,7 @@ func NewPostFieldsWC(deps Deps) *PostFields {
} }
func (wc *PostFields) Start(ctx context.Context) { func (wc *PostFields) Start(ctx context.Context) {
ticker := time.NewTicker(10 * time.Second) ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop() defer ticker.Stop()
for { for {
@ -61,41 +62,30 @@ func (wc *PostFields) startFetching(ctx context.Context) {
wc.logger.Error("error getting all user answers by result session", zap.Error(err)) wc.logger.Error("error getting all user answers by result session", zap.Error(err))
return return
} }
//todo За один запрос можно передать не более 50 сделок.
deal := models.DealReq{ deal := models.DealReq{
Name: fmt.Sprintf("deal quiz number %d", result.QuizID), Name: fmt.Sprintf("deal quiz number %d", result.QuizID),
StatusID: 48703678, //result.StepID, StatusID: result.StepID,
PipelineID: 5505076, //result.PipelineID, PipelineID: result.PipelineID,
CreatedBy: 0, //result.AmoAccountID, CreatedBy: 0, //result.AmoAccountID,
UpdatedBy: 0, UpdatedBy: 0,
CreatedAt: time.Now().Unix(), CreatedAt: time.Now().Unix(),
ResponsibleUserID: result.PerformerID, ResponsibleUserID: result.PerformerID,
Embed: models.Embedd{ Embed: models.Embedd{
Contact: []models.Contact{ Company: []models.Company{},
{
Name: "Дмитрий",
CreatedAT: time.Now().Unix(),
UpdatedBy: 0,
ResponsibleUserID: result.PerformerID,
CustomFieldsValues: []models.FieldsValues{
{
FieldID: 1153687,
Values: []models.Values{
{
Value: "Saint_Petersburg",
},
},
},
},
},
},
Source: models.Source{ Source: models.Source{
Type: "widget", Type: "widget",
}, },
}, },
// строка которая будет возвращенна в респонсе чтоб понимать кто есть что
RequestID: strconv.Itoa(int(result.AnswerID)),
} }
fields := tools.ConstructField(allAnswers, result.FieldsRule)
deal.CustomFieldsValues = fields leadFields, contactData, companyData := tools.ConstructField(allAnswers, result)
deal.CustomFieldsValues = leadFields
deal.Embed.Contact = contactData
deal.Embed.Company = companyData
mapDealReq[result.AccessToken] = append(mapDealReq[result.AccessToken], deal) mapDealReq[result.AccessToken] = append(mapDealReq[result.AccessToken], deal)
} }

@ -428,7 +428,7 @@ func (a *Amo) AddFields(req []models.AddLeadsFields, entity model.EntityType, ac
} }
} }
func (a *Amo) CreatingDeal(req []models.DealReq, accessToken string) (*models.DealResp, error) { func (a *Amo) CreatingDeal(req []models.DealReq, accessToken string) ([]models.DealResp, error) {
for { for {
if a.rateLimiter.Check() { if a.rateLimiter.Check() {
uri := fmt.Sprintf("%s/api/v4/leads/complex", a.baseApiURL) uri := fmt.Sprintf("%s/api/v4/leads/complex", a.baseApiURL)
@ -456,14 +456,14 @@ func (a *Amo) CreatingDeal(req []models.DealReq, accessToken string) (*models.De
return nil, fmt.Errorf(errorMessage) return nil, fmt.Errorf(errorMessage)
} }
var resp models.DealResp var resp []models.DealResp
err = json.Unmarshal(resBody, &resp) err = json.Unmarshal(resBody, &resp)
if err != nil { if err != nil {
a.logger.Error("error unmarshal response body in Creating Deal:", zap.Error(err)) a.logger.Error("error unmarshal response body in Creating Deal:", zap.Error(err))
return nil, err return nil, err
} }
return &resp, nil return resp, nil
} }
time.Sleep(a.rateLimiter.Interval) time.Sleep(a.rateLimiter.Interval)
} }