From 02263b0ed038cb54c5ae6b72b33ff537913527e4 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 5 May 2024 15:22:54 +0300 Subject: [PATCH] refactor logic for posting deals --- go.mod | 2 +- go.sum | 4 +- internal/controllers/fields.go | 2 +- internal/controllers/user.go | 2 +- internal/models/createDeal.go | 33 +++--- internal/tools/construct.go | 103 ++++++++++-------- internal/tools/for_rules.go | 2 +- .../workers/post_fields_worker/post_worker.go | 38 +++---- pkg/amoClient/amo.go | 6 +- 9 files changed, 95 insertions(+), 97 deletions(-) diff --git a/go.mod b/go.mod index f5da30c..ecf3281 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/twmb/franz-go v1.16.1 go.uber.org/zap v1.27.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 ) diff --git a/go.sum b/go.sum index e0f1b4b..f7ffb1d 100644 --- a/go.sum +++ b/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= 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/quiz/common.git v0.0.0-20240504123552-f1d3073dc9f1 h1:H+2MgBImU5ab8vIFLQCUw0Az85BHKNXi2yPqKtX8sR0= -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 h1:ttTQdCfoOj5L/C6xv9GEVDd23LWGkvgZCCEXvSXzjEo= +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/go.mod h1:5S5YwjSXWmnEKjBjG6MtyGtFmljjukDRS8CwHk/CF/I= diff --git a/internal/controllers/fields.go b/internal/controllers/fields.go index dbba02a..a38872f 100644 --- a/internal/controllers/fields.go +++ b/internal/controllers/fields.go @@ -29,7 +29,7 @@ func (c *Controller) UpdateListCustom(ctx *fiber.Ctx) error { return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required") } - //accountID := "64f2cd7a7047f28fdabf6d9e" + //accountID := "654a8909725f47e926f0bebc" err := c.service.UpdateListCustom(ctx.Context(), accountID) if err != nil { diff --git a/internal/controllers/user.go b/internal/controllers/user.go index 442beb4..2a6c0ba 100644 --- a/internal/controllers/user.go +++ b/internal/controllers/user.go @@ -12,7 +12,7 @@ func (c *Controller) UpdateListUsers(ctx *fiber.Ctx) error { return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required") } - //accountID := "64f2cd7a7047f28fdabf6d9e" + //accountID := "654a8909725f47e926f0bebc" err := c.service.UpdateListUsers(ctx.Context(), accountID) diff --git a/internal/models/createDeal.go b/internal/models/createDeal.go index d9f5289..9b51b2e 100644 --- a/internal/models/createDeal.go +++ b/internal/models/createDeal.go @@ -15,6 +15,7 @@ type DealReq struct { CustomFieldsValues []FieldsValues `json:"custom_fields_values"` // Массив полей которые заполняются значениями TagsToAdd []Tag `json:"tags_to_add"` // Массив тегов для добавления Embed Embedd `json:"_embedded"` + RequestID string `json:"request_id"` } type FieldsValues struct { @@ -34,17 +35,24 @@ type Embedd struct { } type Contact struct { - //ID int32 `json:"id"` // ID контакта - //IsMain bool `json:"is_main"` // Флаг, показывающий, является контакт главным или нет + //ID int32 `json:"id"` // ID контакта + IsMain bool `json:"is_main"` // Флаг, показывающий, является контакт главным или нет Name string `json:"first_name"` - CreatedAT int64 `json:"created_at"` + CreatedAt int64 `json:"created_at"` UpdatedBy int `json:"updated_by"` ResponsibleUserID int32 `json:"responsible_user_id"` // ID пользователя, ответственного за сделку, в нашем случае PerformerID CustomFieldsValues []FieldsValues `json:"custom_fields_values"` // Массив полей которые заполняются значениями } 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 { @@ -53,16 +61,9 @@ type Source struct { } type DealResp struct { - Link struct { - SelfLink `json:"self"` - } `json:"_links"` - Embed struct { - Leads []struct { - ID int `json:"id"` - RequestID string `json:"request_id"` - Links struct { - SelfLink `json:"self"` - } `json:"_links"` - } - } `json:"_embedded"` + DealID int `json:"id"` // ID сделки + ContactID int `json:"contact_id"` // ID контакта + CompanyID int `json:"company_id"` // ID компании + Merged bool `json:"merged"` // Флаг, который показывает, найден дубль подходящий под условия поиска дублей и произведено объединение или нет + RequestID []string `json:"request_id"` // Массив строк с пользовательскими идентификаторами, которые были переданы с каждой сущностью } diff --git a/internal/tools/construct.go b/internal/tools/construct.go index 63c0e22..397a73a 100644 --- a/internal/tools/construct.go +++ b/internal/tools/construct.go @@ -3,6 +3,7 @@ package tools import ( "amocrm/internal/models" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model" + "time" ) func ToPipeline(amoPipelines []models.Pipeline) []model.Pipeline { @@ -64,66 +65,72 @@ func ToField(amoField []models.CustomField, entity model.EntityType) []model.Fie return fields } -func ConstructField(allAnswers []model.ResultAnswer, fieldsRule model.Fieldsrule) []models.FieldsValues { - fieldsMap := make(map[int][]models.Values) +// todo Для добавляемых сущностей (сделка, контакт, компания), можно передать не более 40 значений дополнительных полей. +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 { - for _, rule := range fieldsRule.Lead { + entityRules := make(map[model.EntityType][]model.FieldRule) + 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 { if fieldID, ok := rule.Questionid[int(data.QuestionID)]; ok { - values := fieldsMap[fieldID] + values := entityFieldsMap[entityType][fieldID] values = append(values, models.Values{Value: data.Content}) - fieldsMap[fieldID] = values + entityFieldsMap[entityType][fieldID] = values } } } } - if fieldsRule.Contact != nil { - for _, rule := range fieldsRule.Contact { - 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 leadFields []models.FieldsValues + var contactFields []models.FieldsValues + var companyFields []models.FieldsValues + var customerFields []models.FieldsValues + + for entityType, fieldMap := range entityFieldsMap { + 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 { - for _, rule := range fieldsRule.Company { - 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 - } - } + return leadFields, []models.Contact{ + { + Name: result.PerformerName, + CreatedAt: time.Now().Unix(), + UpdatedBy: 0, + ResponsibleUserID: result.PerformerID, + 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 } diff --git a/internal/tools/for_rules.go b/internal/tools/for_rules.go index 7d01e26..9499852 100644 --- a/internal/tools/for_rules.go +++ b/internal/tools/for_rules.go @@ -51,7 +51,7 @@ func ToCreatedUpdateQuestionRules(questionsTypeMap map[model.EntityType][]model. for _, question := range questions { matched := false for _, field := range currentFields { - if question.Title == field.Name { + if question.Title == field.Name && entity == field.Entity { toUpdate[int(question.Id)] = int(field.Amoid) matched = true break diff --git a/internal/workers/post_fields_worker/post_worker.go b/internal/workers/post_fields_worker/post_worker.go index 7ba4964..876816e 100644 --- a/internal/workers/post_fields_worker/post_worker.go +++ b/internal/workers/post_fields_worker/post_worker.go @@ -8,6 +8,7 @@ import ( "fmt" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal" + "strconv" "time" ) @@ -32,7 +33,7 @@ func NewPostFieldsWC(deps Deps) *PostFields { } func (wc *PostFields) Start(ctx context.Context) { - ticker := time.NewTicker(10 * time.Second) + ticker := time.NewTicker(30 * time.Second) defer ticker.Stop() 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)) return } + //todo За один запрос можно передать не более 50 сделок. deal := models.DealReq{ Name: fmt.Sprintf("deal quiz number %d", result.QuizID), - StatusID: 48703678, //result.StepID, - PipelineID: 5505076, //result.PipelineID, - CreatedBy: 0, //result.AmoAccountID, + StatusID: result.StepID, + PipelineID: result.PipelineID, + CreatedBy: 0, //result.AmoAccountID, UpdatedBy: 0, CreatedAt: time.Now().Unix(), ResponsibleUserID: result.PerformerID, Embed: models.Embedd{ - Contact: []models.Contact{ - { - Name: "Дмитрий", - CreatedAT: time.Now().Unix(), - UpdatedBy: 0, - ResponsibleUserID: result.PerformerID, - CustomFieldsValues: []models.FieldsValues{ - { - FieldID: 1153687, - Values: []models.Values{ - { - Value: "Saint_Petersburg", - }, - }, - }, - }, - }, - }, + Company: []models.Company{}, Source: models.Source{ 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) } diff --git a/pkg/amoClient/amo.go b/pkg/amoClient/amo.go index 9a76428..a24f01b 100644 --- a/pkg/amoClient/amo.go +++ b/pkg/amoClient/amo.go @@ -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 { if a.rateLimiter.Check() { 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) } - var resp models.DealResp + var resp []models.DealResp err = json.Unmarshal(resBody, &resp) if err != nil { a.logger.Error("error unmarshal response body in Creating Deal:", zap.Error(err)) return nil, err } - return &resp, nil + return resp, nil } time.Sleep(a.rateLimiter.Interval) }