add fields with files need work
This commit is contained in:
parent
75970295b3
commit
74dfb8d4be
2
go.mod
2
go.mod
@ -13,7 +13,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-20240507175756-10399fe4c21f
|
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240510090920-72cb7d7da6e9
|
||||||
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
4
go.sum
@ -169,7 +169,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-20240507175756-10399fe4c21f h1:xUo4CsauxNgFhiTfv+5BKfF4Ekk6SHeR+ohwrBuJIrU=
|
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240510090920-72cb7d7da6e9 h1:rEOS5bsCduPSYv5QNvU8YvXroTOeqeSNP/833ZvCUAA=
|
||||||
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240507175756-10399fe4c21f/go.mod h1:oRyhT55ctjqp/7ZxIzkR7OsQ7T/NLibsfrbb7Ytns64=
|
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240510090920-72cb7d7da6e9/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=
|
||||||
|
@ -72,7 +72,6 @@ func Run(ctx context.Context, config initialize.Config, logger *zap.Logger) erro
|
|||||||
|
|
||||||
amoClient := amoClient.NewAmoClient(amoClient.AmoDeps{
|
amoClient := amoClient.NewAmoClient(amoClient.AmoDeps{
|
||||||
BaseApiURL: config.ApiURL,
|
BaseApiURL: config.ApiURL,
|
||||||
UserInfoURL: config.UserInfoURL,
|
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
RedirectionURL: config.ReturnURL,
|
RedirectionURL: config.ReturnURL,
|
||||||
IntegrationID: config.IntegrationID,
|
IntegrationID: config.IntegrationID,
|
||||||
|
@ -26,8 +26,6 @@ type Config struct {
|
|||||||
IntegrationID string `env:"INTEGRATION_ID" envDefault:"2dbd6329-9be6-41f2-aa5f-964b9e723e49"`
|
IntegrationID string `env:"INTEGRATION_ID" envDefault:"2dbd6329-9be6-41f2-aa5f-964b9e723e49"`
|
||||||
// секрет интеграции
|
// секрет интеграции
|
||||||
IntegrationSecret string `env:"INTEGRATION_SECRET" envDefault:"tNK3LwL4ovP0OBK4jKDHJ3646PqRJDOKQYgY6P2t6DCuV8LEzDzszTDY0Fhwmzc8"`
|
IntegrationSecret string `env:"INTEGRATION_SECRET" envDefault:"tNK3LwL4ovP0OBK4jKDHJ3646PqRJDOKQYgY6P2t6DCuV8LEzDzszTDY0Fhwmzc8"`
|
||||||
// uri о которому получать информацию о пользователе https://www.amocrm.ru/developers/content/crm_platform/account-info
|
|
||||||
UserInfoURL string `env:"USER_INFO_URL" envDefault:"https://penadigitaltech.amocrm.ru/api/v4/account"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadConfig() (*Config, error) {
|
func LoadConfig() (*Config, error) {
|
||||||
|
@ -19,14 +19,24 @@ type DealReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FieldsValues struct {
|
type FieldsValues struct {
|
||||||
FieldID int `json:"field_id"`
|
FieldID int `json:"field_id"`
|
||||||
Values []Values `json:"values"`
|
Values []interface{} `json:"values"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Values struct {
|
type Values struct {
|
||||||
Value string `json:"value"` // пока так пока не понятно
|
Value string `json:"value"` // пока так пока не понятно
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ValuesFile struct {
|
||||||
|
Value ValueFile `json:"value"`
|
||||||
|
}
|
||||||
|
type ValueFile struct {
|
||||||
|
FileUUID string `json:"file_uuid"`
|
||||||
|
VersionUUID string `json:"version_uuid"`
|
||||||
|
FileName string `json:"file_name"`
|
||||||
|
FileSize int64 `json:"file_size"`
|
||||||
|
}
|
||||||
|
|
||||||
type Embedd struct {
|
type Embedd struct {
|
||||||
Tags []Tag `json:"tags"` // Данные тегов, добавляемых к сделке
|
Tags []Tag `json:"tags"` // Данные тегов, добавляемых к сделке
|
||||||
Contact []Contact `json:"contacts"` // Данные контактов, которые будет прикреплены к сделке
|
Contact []Contact `json:"contacts"` // Данные контактов, которые будет прикреплены к сделке
|
||||||
@ -110,3 +120,53 @@ type EmbeddedCreateCustomers struct {
|
|||||||
RequestID string `json:"request_id"`
|
RequestID string `json:"request_id"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateSession struct {
|
||||||
|
FileName string `json:"file_name"` // обязательное поле
|
||||||
|
FileSize int64 `json:"file_size"` // обязательное поле
|
||||||
|
FileUUID string `json:"file_uuid"` // UUID файла, для которого загружается новая версия файла. Если UUID не задан, то будет создан новый файл.
|
||||||
|
ContentType string `json:"content_type"` // MIME-тип файла
|
||||||
|
WithPreview bool `json:"with_preview"` // При установке данного флага для файла будет сгенерировано превью
|
||||||
|
}
|
||||||
|
|
||||||
|
// представляет данные о созданной сессии загрузки файла
|
||||||
|
type UploadSession struct {
|
||||||
|
SessionID int `json:"session_id"`
|
||||||
|
UploadURL string `json:"upload_url"`
|
||||||
|
MaxFileSize int64 `json:"max_file_size"`
|
||||||
|
MaxPartSize int64 `json:"max_part_size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// представляет информацию о загруженном файле
|
||||||
|
type UploadedFile struct {
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
IsTrashed bool `json:"is_trashed"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
SanitizedName string `json:"sanitized_name"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
SourceID int `json:"source_id"`
|
||||||
|
VersionUUID string `json:"version_uuid"`
|
||||||
|
HasMultipleVersions bool `json:"has_multiple_versions"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
CreatedBy struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
} `json:"created_by"`
|
||||||
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
|
DeletedAt int64 `json:"deleted_at"`
|
||||||
|
DeletedBy interface{} `json:"deleted_by"`
|
||||||
|
Metadata Metadata `json:"metadata"`
|
||||||
|
Previews []PreviewFile `json:"previews"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
Extension string `json:"extension"`
|
||||||
|
MIMEType string `json:"mime_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PreviewFile struct {
|
||||||
|
DownloadLink string `json:"download_link"`
|
||||||
|
Width int `json:"width"`
|
||||||
|
Height int `json:"height"`
|
||||||
|
}
|
||||||
|
@ -2,11 +2,9 @@ package tools
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"amocrm/internal/models"
|
"amocrm/internal/models"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -69,105 +67,6 @@ func ToField(amoField []models.CustomField, entity model.EntityType) []model.Fie
|
|||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConstructField(allAnswers []model.ResultAnswer, result model.AmoUsersTrueResults) ([]models.FieldsValues, []models.Contact, []models.Company, []models.Customer, error) {
|
|
||||||
dateCreating := time.Now().Unix()
|
|
||||||
|
|
||||||
entityFieldsMap := make(map[model.EntityType]map[int][]models.Values)
|
|
||||||
entityFieldsMap[model.LeadsType] = make(map[int][]models.Values)
|
|
||||||
entityFieldsMap[model.CompaniesType] = make(map[int][]models.Values)
|
|
||||||
entityFieldsMap[model.CustomersType] = make(map[int][]models.Values)
|
|
||||||
|
|
||||||
entityRules := make(map[model.EntityType][]model.FieldRule)
|
|
||||||
entityRules[model.LeadsType] = result.FieldsRule.Lead
|
|
||||||
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 := entityFieldsMap[entityType][fieldID]
|
|
||||||
values = append(values, models.Values{Value: emojiUnicode(data.Content)})
|
|
||||||
entityFieldsMap[entityType][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.CompaniesType:
|
|
||||||
companyFields = append(companyFields, field)
|
|
||||||
case model.CustomersType:
|
|
||||||
customerFields = append(customerFields, field)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultInfo model.ResultContent
|
|
||||||
err := json.Unmarshal([]byte(result.Content), &resultInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
name := resultInfo.Name
|
|
||||||
if name == "" {
|
|
||||||
name = fmt.Sprintf("empty name, quiz %d, triggered by answer - %d", result.QuizID, result.AnswerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
contactRuleMap := result.FieldsRule.Contact.ContactRuleMap
|
|
||||||
|
|
||||||
contactFields = addContactField(contactFields, resultInfo.Name, model.TypeContactName, contactRuleMap)
|
|
||||||
contactFields = addContactField(contactFields, resultInfo.Phone, model.TypeContactPhone, contactRuleMap)
|
|
||||||
contactFields = addContactField(contactFields, resultInfo.Text, model.TypeContactText, contactRuleMap)
|
|
||||||
contactFields = addContactField(contactFields, resultInfo.Email, model.TypeContactEmail, contactRuleMap)
|
|
||||||
contactFields = addContactField(contactFields, resultInfo.Address, model.TypeContactAddress, contactRuleMap)
|
|
||||||
|
|
||||||
return leadFields, []models.Contact{
|
|
||||||
{
|
|
||||||
Name: name,
|
|
||||||
ResponsibleUserID: result.PerformerID,
|
|
||||||
CreatedBy: 0,
|
|
||||||
UpdatedBy: 0,
|
|
||||||
CreatedAt: dateCreating,
|
|
||||||
CustomFieldsValues: contactFields,
|
|
||||||
},
|
|
||||||
}, []models.Company{
|
|
||||||
{
|
|
||||||
Name: fmt.Sprintf("Компания %d", result.AnswerID),
|
|
||||||
ResponsibleUserID: result.PerformerID,
|
|
||||||
CreatedBy: 0,
|
|
||||||
UpdatedBy: 0,
|
|
||||||
CreatedAt: dateCreating,
|
|
||||||
CustomFieldsValues: companyFields,
|
|
||||||
},
|
|
||||||
}, []models.Customer{
|
|
||||||
{
|
|
||||||
// в амо имя покупателя не может быть пустым, надо как то с этим жить
|
|
||||||
Name: name,
|
|
||||||
ResponsibleUserID: result.PerformerID,
|
|
||||||
//StatusID: ,
|
|
||||||
CreatedBy: 0,
|
|
||||||
UpdatedBy: 0,
|
|
||||||
CreatedAt: dateCreating,
|
|
||||||
CustomFields: customerFields,
|
|
||||||
RequestID: fmt.Sprint(result.AnswerID),
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isEmoji(r rune) bool {
|
func isEmoji(r rune) bool {
|
||||||
// https://symbl.cc/ru/unicode/blocks/emoticons/
|
// https://symbl.cc/ru/unicode/blocks/emoticons/
|
||||||
|
|
||||||
@ -194,7 +93,7 @@ func isEmoji(r rune) bool {
|
|||||||
(r >= 0xE0100 && r <= 0xE01EF) // Дополнение к селекторам вариантов начертания
|
(r >= 0xE0100 && r <= 0xE01EF) // Дополнение к селекторам вариантов начертания
|
||||||
}
|
}
|
||||||
|
|
||||||
func emojiUnicode(text string) string {
|
func EmojiUnicode(text string) string {
|
||||||
var result strings.Builder
|
var result strings.Builder
|
||||||
for len(text) > 0 {
|
for len(text) > 0 {
|
||||||
r, size := utf8.DecodeRuneInString(text)
|
r, size := utf8.DecodeRuneInString(text)
|
||||||
@ -213,15 +112,14 @@ func emojiUnicode(text string) string {
|
|||||||
return result.String()
|
return result.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func addContactField(contactFields []models.FieldsValues, fieldValue string, fieldType model.ContactQuizConfig, fieldMap map[string]int) []models.FieldsValues {
|
func AddContactFields(contactFields []models.FieldsValues, fieldValue string, fieldType model.ContactQuizConfig, fieldMap map[string]int) []models.FieldsValues {
|
||||||
if fieldValue != "" {
|
if fieldValue != "" {
|
||||||
|
values := make([]interface{}, 0)
|
||||||
|
values = append(values, models.Values{Value: fieldValue})
|
||||||
|
|
||||||
contactFields = append(contactFields, models.FieldsValues{
|
contactFields = append(contactFields, models.FieldsValues{
|
||||||
FieldID: fieldMap[string(fieldType)],
|
FieldID: fieldMap[string(fieldType)],
|
||||||
Values: []models.Values{
|
Values: values,
|
||||||
{
|
|
||||||
Value: fieldValue,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return contactFields
|
return contactFields
|
||||||
|
@ -6,9 +6,11 @@ import (
|
|||||||
"amocrm/internal/tools"
|
"amocrm/internal/tools"
|
||||||
"amocrm/pkg/amoClient"
|
"amocrm/pkg/amoClient"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"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"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/amo"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/amo"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -87,9 +89,9 @@ func (wc *PostDeals) startFetching(ctx context.Context) {
|
|||||||
RequestID: strconv.Itoa(int(result.AnswerID)),
|
RequestID: strconv.Itoa(int(result.AnswerID)),
|
||||||
}
|
}
|
||||||
|
|
||||||
leadFields, contactData, companyData, customerToCreate, err := tools.ConstructField(allAnswers, result)
|
leadFields, contactData, companyData, customerToCreate, err := wc.constructField(ctx, allAnswers, result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wc.logger.Error("error serialization resultContent to model ResultContent", zap.Error(err))
|
wc.logger.Error("error construct fields", zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +178,124 @@ func (wc *PostDeals) saveDealToDB(ctx context.Context, resp []models.DealResp, a
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (wc *PostDeals) constructField(ctx context.Context, allAnswers []model.ResultAnswer, result model.AmoUsersTrueResults) ([]models.FieldsValues, []models.Contact, []models.Company, []models.Customer, error) {
|
||||||
|
dateCreating := time.Now().Unix()
|
||||||
|
|
||||||
|
entityFieldsMap := make(map[model.EntityType]map[int][]interface{})
|
||||||
|
entityFieldsMap[model.LeadsType] = make(map[int][]interface{})
|
||||||
|
entityFieldsMap[model.CompaniesType] = make(map[int][]interface{})
|
||||||
|
entityFieldsMap[model.CustomersType] = make(map[int][]interface{})
|
||||||
|
|
||||||
|
entityRules := make(map[model.EntityType][]model.FieldRule)
|
||||||
|
entityRules[model.LeadsType] = result.FieldsRule.Lead
|
||||||
|
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 {
|
||||||
|
|
||||||
|
fieldData, err := wc.amoRepo.AmoRepo.GetFieldByID(ctx, int32(fieldID))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if fieldData.Type == model.TypeAmoText {
|
||||||
|
values := entityFieldsMap[entityType][fieldID]
|
||||||
|
values = append(values, models.Values{Value: tools.EmojiUnicode(data.Content)})
|
||||||
|
entityFieldsMap[entityType][fieldID] = values
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if fieldData.Type == model.TypeFile && data.Content != "" {
|
||||||
|
value, err := wc.amoClient.UploadFileToAmo(data.Content, result.AccessToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, nil, err
|
||||||
|
}
|
||||||
|
values := entityFieldsMap[entityType][fieldID]
|
||||||
|
values = append(values, value)
|
||||||
|
entityFieldsMap[entityType][fieldID] = values
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.CompaniesType:
|
||||||
|
companyFields = append(companyFields, field)
|
||||||
|
case model.CustomersType:
|
||||||
|
customerFields = append(customerFields, field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultInfo model.ResultContent
|
||||||
|
err := json.Unmarshal([]byte(result.Content), &resultInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name := resultInfo.Name
|
||||||
|
if name == "" {
|
||||||
|
name = fmt.Sprintf("empty name, quiz %d, triggered by answer - %d", result.QuizID, result.AnswerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
contactRuleMap := result.FieldsRule.Contact.ContactRuleMap
|
||||||
|
|
||||||
|
contactFields = tools.AddContactFields(contactFields, resultInfo.Name, model.TypeContactName, contactRuleMap)
|
||||||
|
contactFields = tools.AddContactFields(contactFields, resultInfo.Phone, model.TypeContactPhone, contactRuleMap)
|
||||||
|
contactFields = tools.AddContactFields(contactFields, resultInfo.Text, model.TypeContactText, contactRuleMap)
|
||||||
|
contactFields = tools.AddContactFields(contactFields, resultInfo.Email, model.TypeContactEmail, contactRuleMap)
|
||||||
|
contactFields = tools.AddContactFields(contactFields, resultInfo.Address, model.TypeContactAddress, contactRuleMap)
|
||||||
|
|
||||||
|
return leadFields, []models.Contact{
|
||||||
|
{
|
||||||
|
Name: name,
|
||||||
|
ResponsibleUserID: result.PerformerID,
|
||||||
|
CreatedBy: 0,
|
||||||
|
UpdatedBy: 0,
|
||||||
|
CreatedAt: dateCreating,
|
||||||
|
CustomFieldsValues: contactFields,
|
||||||
|
},
|
||||||
|
}, []models.Company{
|
||||||
|
{
|
||||||
|
Name: fmt.Sprintf("Компания %d", result.AnswerID),
|
||||||
|
ResponsibleUserID: result.PerformerID,
|
||||||
|
CreatedBy: 0,
|
||||||
|
UpdatedBy: 0,
|
||||||
|
CreatedAt: dateCreating,
|
||||||
|
CustomFieldsValues: companyFields,
|
||||||
|
},
|
||||||
|
}, []models.Customer{
|
||||||
|
{
|
||||||
|
// в амо имя покупателя не может быть пустым, надо как то с этим жить
|
||||||
|
Name: name,
|
||||||
|
ResponsibleUserID: result.PerformerID,
|
||||||
|
CreatedBy: 0,
|
||||||
|
UpdatedBy: 0,
|
||||||
|
CreatedAt: dateCreating,
|
||||||
|
CustomFields: customerFields,
|
||||||
|
RequestID: fmt.Sprint(result.AnswerID),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (wc *PostDeals) Stop(_ context.Context) error {
|
func (wc *PostDeals) Stop(_ context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,13 @@ package amoClient
|
|||||||
import (
|
import (
|
||||||
"amocrm/internal/models"
|
"amocrm/internal/models"
|
||||||
"amocrm/internal/workers/limiter"
|
"amocrm/internal/workers/limiter"
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -15,7 +19,6 @@ import (
|
|||||||
|
|
||||||
type Amo struct {
|
type Amo struct {
|
||||||
baseApiURL string
|
baseApiURL string
|
||||||
userInfoURL string
|
|
||||||
fiberClient *fiber.Client
|
fiberClient *fiber.Client
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
redirectionURL string
|
redirectionURL string
|
||||||
@ -26,7 +29,6 @@ type Amo struct {
|
|||||||
|
|
||||||
type AmoDeps struct {
|
type AmoDeps struct {
|
||||||
BaseApiURL string
|
BaseApiURL string
|
||||||
UserInfoURL string
|
|
||||||
FiberClient *fiber.Client
|
FiberClient *fiber.Client
|
||||||
Logger *zap.Logger
|
Logger *zap.Logger
|
||||||
RedirectionURL string
|
RedirectionURL string
|
||||||
@ -41,7 +43,6 @@ func NewAmoClient(deps AmoDeps) *Amo {
|
|||||||
}
|
}
|
||||||
return &Amo{
|
return &Amo{
|
||||||
baseApiURL: deps.BaseApiURL,
|
baseApiURL: deps.BaseApiURL,
|
||||||
userInfoURL: deps.UserInfoURL,
|
|
||||||
fiberClient: deps.FiberClient,
|
fiberClient: deps.FiberClient,
|
||||||
logger: deps.Logger,
|
logger: deps.Logger,
|
||||||
redirectionURL: deps.RedirectionURL,
|
redirectionURL: deps.RedirectionURL,
|
||||||
@ -277,7 +278,8 @@ func (a *Amo) GetListTags(req models.GetListTagsReq, accessToken string) (*model
|
|||||||
func (a *Amo) GetUserInfo(accessToken string) (*models.AmocrmUserInformation, error) {
|
func (a *Amo) GetUserInfo(accessToken string) (*models.AmocrmUserInformation, error) {
|
||||||
for {
|
for {
|
||||||
if a.rateLimiter.Check() {
|
if a.rateLimiter.Check() {
|
||||||
agent := a.fiberClient.Get(a.userInfoURL)
|
url := fmt.Sprintf("%s/api/v4/account", a.baseApiURL)
|
||||||
|
agent := a.fiberClient.Get(url)
|
||||||
agent.Set("Authorization", "Bearer "+accessToken)
|
agent.Set("Authorization", "Bearer "+accessToken)
|
||||||
statusCode, resBody, errs := agent.Bytes()
|
statusCode, resBody, errs := agent.Bytes()
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
@ -539,3 +541,170 @@ func (a *Amo) CreatingCustomer(req []models.Customer, accessToken string) (*mode
|
|||||||
time.Sleep(a.rateLimiter.Interval)
|
time.Sleep(a.rateLimiter.Interval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Amo) downloadFile(urlFile string) (*os.File, error) {
|
||||||
|
var err error
|
||||||
|
agent := a.fiberClient.Get(urlFile)
|
||||||
|
|
||||||
|
statusCode, resBody, errs := agent.Bytes()
|
||||||
|
if len(errs) > 0 {
|
||||||
|
for _, err = range errs {
|
||||||
|
a.logger.Error("error sending request for getting file by url", zap.Error(err))
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("request failed: %v", errs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusCode != fiber.StatusOK {
|
||||||
|
errorMessage := fmt.Sprintf("received an incorrect response from getting file by url: %s", string(resBody))
|
||||||
|
a.logger.Error(errorMessage, zap.Int("status", statusCode))
|
||||||
|
return nil, fmt.Errorf(errorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpFile, err := os.CreateTemp("", "downloaded_file_*")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer tmpFile.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(tmpFile, bytes.NewReader(resBody))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmpFile, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Amo) UploadFileToAmo(urlFile string, accessToken string) (*models.ValuesFile, error) {
|
||||||
|
fmt.Println(urlFile)
|
||||||
|
localFile, err := a.downloadFile(urlFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer os.Remove(localFile.Name())
|
||||||
|
|
||||||
|
fileInfo, err := os.Stat(localFile.Name())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileSize := fileInfo.Size()
|
||||||
|
createSessionData := &models.CreateSession{
|
||||||
|
FileName: urlFile,
|
||||||
|
FileSize: fileSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("%s/v1.0/sessions", "https://drive-b.amocrm.ru")
|
||||||
|
bodyBytes, err := json.Marshal(createSessionData)
|
||||||
|
if err != nil {
|
||||||
|
a.logger.Error("error marshal create session data:", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
agent := a.fiberClient.Post(uri)
|
||||||
|
agent.Set("Content-Type", "application/json").Body(bodyBytes)
|
||||||
|
agent.Set("Authorization", "Bearer "+accessToken)
|
||||||
|
|
||||||
|
statusCode, resBody, errs := agent.Bytes()
|
||||||
|
if len(errs) > 0 {
|
||||||
|
for _, err = range errs {
|
||||||
|
a.logger.Error("error sending request to create session for upload file in amo", zap.Error(err))
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("request failed: %v", errs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusCode != fiber.StatusOK {
|
||||||
|
errorMessage := fmt.Sprintf("received an incorrect response from creating upload file session: %s", string(resBody))
|
||||||
|
a.logger.Error(errorMessage, zap.Int("status", statusCode))
|
||||||
|
return nil, fmt.Errorf(errorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp models.UploadSession
|
||||||
|
err = json.Unmarshal(resBody, &resp)
|
||||||
|
if err != nil {
|
||||||
|
a.logger.Error("error unmarshal response body in creating upload file session:", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := a.createPart(resp, localFile)
|
||||||
|
|
||||||
|
return &models.ValuesFile{
|
||||||
|
Value: models.ValueFile{
|
||||||
|
FileUUID: response.UUID,
|
||||||
|
VersionUUID: response.VersionUUID,
|
||||||
|
FileName: response.Name,
|
||||||
|
FileSize: response.Size,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Amo) createPart(uploadData models.UploadSession, file *os.File) (*models.UploadedFile, error) {
|
||||||
|
fileInfo, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileSize := fileInfo.Size()
|
||||||
|
|
||||||
|
var uploadedFile models.UploadedFile
|
||||||
|
var remainingSize = fileSize
|
||||||
|
var start int64 = 0
|
||||||
|
|
||||||
|
for remainingSize > 0 {
|
||||||
|
end := start + uploadData.MaxPartSize
|
||||||
|
if end > fileSize {
|
||||||
|
end = fileSize
|
||||||
|
}
|
||||||
|
|
||||||
|
partSize := end - start
|
||||||
|
|
||||||
|
partFile, err := os.OpenFile(file.Name(), os.O_RDONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer partFile.Close()
|
||||||
|
|
||||||
|
_, err = partFile.Seek(start, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := make([]byte, partSize)
|
||||||
|
_, err = partFile.Read(buffer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
agent := a.fiberClient.Post(uploadData.UploadURL).Body(buffer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
statusCode, resBody, errs := agent.Bytes()
|
||||||
|
if len(errs) > 0 {
|
||||||
|
for _, err = range errs {
|
||||||
|
a.logger.Error("error sending request to upload part file to amo", zap.Error(err))
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("request failed: %v", errs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("failed to upload part file to amo, status: %d", statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
start = end
|
||||||
|
remainingSize -= partSize
|
||||||
|
|
||||||
|
var newUploadData models.UploadSession
|
||||||
|
if err := json.Unmarshal(resBody, &newUploadData); err == nil {
|
||||||
|
uploadData = newUploadData
|
||||||
|
} else {
|
||||||
|
if err := json.Unmarshal(resBody, &uploadedFile); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &uploadedFile, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user