diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c36b28..aaa8081 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,7 @@ jobs: version: v1.45.2 only-new-issues: true skip-pkg-cache: true + args: --build-tags=testutils tests: name: Tests runs-on: ubuntu-latest @@ -58,13 +59,13 @@ jobs: env: COVERAGE: ${{ matrix.coverage }} if: env.COVERAGE != 1 - run: go test ./... + run: go test -tags=testutils ./... - name: Tests with coverage env: COVERAGE: ${{ matrix.coverage }} if: env.COVERAGE == 1 run: | - go test ./... -race -coverprofile=coverage.txt -covermode=atomic "$d" + go test -tags=testutils ./... -race -coverprofile=coverage.txt -covermode=atomic "$d" - name: Coverage env: COVERAGE: ${{ matrix.coverage }} diff --git a/.golangci.yml b/.golangci.yml index f1e7ff7..16dd100 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,8 @@ run: skip-dirs-use-default: true allow-parallel-runners: true + skip-files: + - testutils.go output: format: colored-line-number diff --git a/client.go b/client.go index 1861c52..0e58345 100644 --- a/client.go +++ b/client.go @@ -5834,7 +5834,7 @@ func (c *Client) LoyaltyAccountCreate(site string, loyaltyAccount SerializedCrea // if data.Success == true { // log.Printf("%v", data.LoyaltyAccount.PhoneNumber) // } -func (c *Client) LoyaltyAccountEdit(ID int, loyaltyAccount SerializedEditLoyaltyAccount) (EditLoyaltyAccountResponse, int, error) { +func (c *Client) LoyaltyAccountEdit(id int, loyaltyAccount SerializedEditLoyaltyAccount) (EditLoyaltyAccountResponse, int, error) { var result EditLoyaltyAccountResponse loyaltyAccountJSON, _ := json.Marshal(loyaltyAccount) @@ -5842,7 +5842,7 @@ func (c *Client) LoyaltyAccountEdit(ID int, loyaltyAccount SerializedEditLoyalty "loyaltyAccount": {string(loyaltyAccountJSON)}, } - resp, status, err := c.PostRequest(fmt.Sprintf("/loyalty/account/%d/edit", ID), p) + resp, status, err := c.PostRequest(fmt.Sprintf("/loyalty/account/%d/edit", id), p) if err != nil { return result, status, err @@ -5878,10 +5878,10 @@ func (c *Client) LoyaltyAccountEdit(ID int, loyaltyAccount SerializedEditLoyalty // if data.Success == true { // log.Printf("%v", data.LoyaltyAccount.PhoneNumber) // } -func (c *Client) LoyaltyAccount(ID int) (LoyaltyAccountResponse, int, error) { +func (c *Client) LoyaltyAccount(id int) (LoyaltyAccountResponse, int, error) { var result LoyaltyAccountResponse - resp, status, err := c.GetRequest(fmt.Sprintf("/loyalty/account/%d", ID)) + resp, status, err := c.GetRequest(fmt.Sprintf("/loyalty/account/%d", id)) if err != nil { return result, status, err @@ -5917,10 +5917,10 @@ func (c *Client) LoyaltyAccount(ID int) (LoyaltyAccountResponse, int, error) { // if data.Success == true { // log.Printf("%v", data.LoyaltyAccount.Active) // } -func (c *Client) LoyaltyAccountActivate(ID int) (LoyaltyAccountActivateResponse, int, error) { +func (c *Client) LoyaltyAccountActivate(id int) (LoyaltyAccountActivateResponse, int, error) { var result LoyaltyAccountActivateResponse - resp, status, err := c.PostRequest(fmt.Sprintf("/loyalty/account/%d/activate", ID), strings.NewReader("")) + resp, status, err := c.PostRequest(fmt.Sprintf("/loyalty/account/%d/activate", id), strings.NewReader("")) if err != nil { return result, status, err @@ -5962,11 +5962,11 @@ func (c *Client) LoyaltyAccountActivate(ID int) (LoyaltyAccountActivateResponse, // if data.Success == true { // log.Printf("%v", data.LoyaltyBonus.ActivationDate) // } -func (c *Client) LoyaltyBonusCredit(ID int, req LoyaltyBonusCreditRequest) (LoyaltyBonusCreditResponse, int, error) { +func (c *Client) LoyaltyBonusCredit(id int, req LoyaltyBonusCreditRequest) (LoyaltyBonusCreditResponse, int, error) { var result LoyaltyBonusCreditResponse p, _ := query.Values(req) - resp, status, err := c.PostRequest(fmt.Sprintf("/loyalty/account/%d/bonus/credit", ID), p) + resp, status, err := c.PostRequest(fmt.Sprintf("/loyalty/account/%d/bonus/credit", id), p) if err != nil { return result, status, err @@ -6010,13 +6010,13 @@ func (c *Client) LoyaltyBonusCredit(ID int, req LoyaltyBonusCreditRequest) (Loya // } // } func (c *Client) LoyaltyBonusStatusDetails( - ID int, statusType string, request LoyaltyBonusStatusDetailsRequest, + id int, statusType string, request LoyaltyBonusStatusDetailsRequest, ) (LoyaltyBonusDetailsResponse, int, error) { var result LoyaltyBonusDetailsResponse p, _ := query.Values(request) - resp, status, err := c.GetRequest(fmt.Sprintf("/loyalty/account/%d/bonus/%s/details?%s", ID, statusType, p.Encode())) + resp, status, err := c.GetRequest(fmt.Sprintf("/loyalty/account/%d/bonus/%s/details?%s", id, statusType, p.Encode())) if err != nil { return result, status, err @@ -6040,13 +6040,13 @@ func (c *Client) LoyaltyBonusStatusDetails( // var client = retailcrm.New("https://demo.url", "09jIJ") // // req := LoyaltyAccountsRequest{ -// Filter: LoyaltyAccountApiFilter{ +// Filter: LoyaltyAccountAPIFilter{ // Status: "activated", // PhoneNumber: "89185556363", // Ids: []int{14}, // Level: 5, // Loyalties: []int{2}, -// CustomerId: "109", +// CustomerID: "109", // }, // } // @@ -6129,7 +6129,7 @@ func (c *Client) LoyaltyAccounts(req LoyaltyAccountsRequest) (LoyaltyAccountsRes func (c *Client) LoyaltyCalculate(req LoyaltyCalculateRequest) (LoyaltyCalculateResponse, int, error) { var result LoyaltyCalculateResponse - orderJSON, err := json.Marshal(req.Order) + orderJSON, _ := json.Marshal(req.Order) p := url.Values{ "site": {req.Site}, @@ -6152,7 +6152,7 @@ func (c *Client) LoyaltyCalculate(req LoyaltyCalculateRequest) (LoyaltyCalculate return result, status, nil } -// GetLoyalties calculations of the maximum discount +// GetLoyalties returns list of loyalty programs // // For more information see https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#get--api-v5-loyalty-loyalties // @@ -6161,7 +6161,7 @@ func (c *Client) LoyaltyCalculate(req LoyaltyCalculateRequest) (LoyaltyCalculate // var client = retailcrm.New("https://demo.url", "09jIJ") // // req := LoyaltiesRequest{ -// Filter: LoyaltyApiFilter{ +// Filter: LoyaltyAPIFilter{ // Active: active, // Ids: []int{2}, // Sites: []string{"main"}, @@ -6204,15 +6204,15 @@ func (c *Client) GetLoyalties(req LoyaltiesRequest) (LoyaltiesResponse, int, err return result, status, nil } -// GetLoyaltyById calculations of the maximum discount +// GetLoyaltyByID return program of loyalty by id // -// For more information see https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#get--api-v5-loyalty-loyalties +// For more information see https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#get--api-v5-loyalty-loyalties-id // // Example: // // var client = retailcrm.New("https://demo.url", "09jIJ") // -// data, status, err := client.GetLoyaltyById(2) +// data, status, err := client.GetLoyaltyByID(2) // // if err != nil { // if apiErr, ok := retailcrm.AsAPIError(err); ok { @@ -6226,10 +6226,10 @@ func (c *Client) GetLoyalties(req LoyaltiesRequest) (LoyaltiesResponse, int, err // log.Printf("%v", res.Loyalty.ID) // log.Printf("%v", res.Loyalty.Active) // } -func (c *Client) GetLoyaltyById(ID int) (LoyaltyResponse, int, error) { +func (c *Client) GetLoyaltyByID(id int) (LoyaltyResponse, int, error) { var result LoyaltyResponse - resp, status, err := c.GetRequest(fmt.Sprintf("/loyalty/loyalties/%d", ID)) + resp, status, err := c.GetRequest(fmt.Sprintf("/loyalty/loyalties/%d", id)) if err != nil { return result, status, err @@ -6244,10 +6244,36 @@ func (c *Client) GetLoyaltyById(ID int) (LoyaltyResponse, int, error) { return result, status, nil } -func (c *Client) OrderIntegrationDeliveryCancel(by string, force bool, ID string) (SuccessfulResponse, int, error) { +// OrderIntegrationDeliveryCancel cancels of integration delivery +// +// For more information see https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#post--api-v5-orders-externalId-delivery-cancel +// +// Example: +// +// var client = retailcrm.New("https://demo.url", "09jIJ") +// +// data, status, err := client.OrderIntegrationDeliveryCancel("externalId", false, "1001C") +// +// if err != nil { +// if apiErr, ok := retailcrm.AsAPIError(err); ok { +// log.Fatalf("http status: %d, %s", status, apiErr.String()) +// } +// +// log.Fatalf("http status: %d, error: %s", status, err) +// } +// +// if data.Success == true { +// log.Printf("%v", res.Success) +// } +func (c *Client) OrderIntegrationDeliveryCancel(by string, force bool, id string) (SuccessfulResponse, int, error) { var result SuccessfulResponse - resp, status, err := c.PostRequest(fmt.Sprintf("/orders/%s/delivery/cancel?by=%s&force=%t", ID, checkBy(by), force), strings.NewReader("")) + p := url.Values{ + "by": {checkBy(by)}, + "force": {fmt.Sprintf("%t", force)}, + } + + resp, status, err := c.PostRequest(fmt.Sprintf("/orders/%s/delivery/cancel?%s", id, p.Encode()), strings.NewReader("")) if err != nil { return result, status, err @@ -6261,3 +6287,159 @@ func (c *Client) OrderIntegrationDeliveryCancel(by string, force bool, ID string return result, status, nil } + +// CreateProductsGroup adds a product group +// +// For more information see https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#post--api-v5-store-product-groups-create +// +// Example: +// +// var client = retailcrm.New("https://demo.url", "09jIJ") +// +// group := ProductGroup{ +// ParentID: 125, +// Name: "Фрукты", +// Site: "main", +// Active: true, +// ExternalID: "abc22", +// } +// +// data, status, err := client.CreateProductsGroup(group) +// +// if err != nil { +// if apiErr, ok := retailcrm.AsAPIError(err); ok { +// log.Fatalf("http status: %d, %s", status, apiErr.String()) +// } +// +// log.Fatalf("http status: %d, error: %s", status, err) +// } +// +// if data.Success == true { +// log.Printf("%v", res.ID) +// } +func (c *Client) CreateProductsGroup(group ProductGroup) (ActionProductsGroupResponse, int, error) { + var result ActionProductsGroupResponse + + groupJSON, _ := json.Marshal(group) + + p := url.Values{ + "productGroup": {string(groupJSON)}, + } + + resp, status, err := c.PostRequest("/store/product-groups/create", p) + + if err != nil { + return result, status, err + } + + err = json.Unmarshal(resp, &result) + + if err != nil { + return result, status, err + } + + return result, status, nil +} + +// EditProductsGroup edits a product group +// +// For more information see https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#post--api-v5-store-product-groups-externalId-edit +// +// Example: +// +// var client = retailcrm.New("https://demo.url", "09jIJ") +// +// group := ProductGroup{ +// Name: "Овощи", +// Active: true, +// ExternalID: "abc22", +// } +// +// data, status, err := client.EditProductsGroup("by", "125", "main", group) +// +// if err != nil { +// if apiErr, ok := retailcrm.AsAPIError(err); ok { +// log.Fatalf("http status: %d, %s", status, apiErr.String()) +// } +// +// log.Fatalf("http status: %d, error: %s", status, err) +// } +// +// if data.Success == true { +// log.Printf("%v", res.ID) +// } +func (c *Client) EditProductsGroup(by, id, site string, group ProductGroup) (ActionProductsGroupResponse, int, error) { + var result ActionProductsGroupResponse + + groupJSON, _ := json.Marshal(group) + + p := url.Values{ + "by": {checkBy(by)}, + "site": {site}, + "productGroup": {string(groupJSON)}, + } + + resp, status, err := c.PostRequest(fmt.Sprintf("/store/product-groups/%s/edit", id), p) + + if err != nil { + return result, status, err + } + + err = json.Unmarshal(resp, &result) + + if err != nil { + return result, status, err + } + + return result, status, nil +} + +func (c *Client) GetOrderPlate(by, orderID, site string, plateID int) (io.ReadCloser, int, error) { + p := url.Values{ + "by": {checkBy(by)}, + "site": {site}, + } + + requestURL := fmt.Sprintf("%s/api/v5/orders/%s/plates/%d/print?%s", c.URL, orderID, plateID, p.Encode()) + req, err := http.NewRequest("GET", requestURL, nil) + + if err != nil { + return nil, 0, err + } + + req.Header.Set("X-API-KEY", c.Key) + + if c.Debug { + c.writeLog("API Request: %s %s", requestURL, c.Key) + } + + resp, err := c.httpClient.Do(req) + + if err != nil { + return nil, 0, err + } + + if resp.StatusCode >= http.StatusInternalServerError { + return nil, resp.StatusCode, CreateGenericAPIError( + fmt.Sprintf("HTTP request error. Status code: %d.", resp.StatusCode)) + } + + if resp.StatusCode >= http.StatusBadRequest && resp.StatusCode < http.StatusInternalServerError { + res, err := buildRawResponse(resp) + + if err != nil { + return nil, 0, err + } + + return nil, resp.StatusCode, CreateAPIError(res) + } + + reader := resp.Body + err = reader.Close() + + if err != nil { + return nil, 0, err + } + + return reader, resp.StatusCode, nil +} diff --git a/client_test.go b/client_test.go index 41c43fa..863357c 100644 --- a/client_test.go +++ b/client_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "github.com/google/go-querystring/query" + "io" "io/ioutil" "log" "math/rand" @@ -523,7 +524,7 @@ func TestClient_CustomersUpload(t *testing.T) { func TestClient_CustomersUpload_Fail(t *testing.T) { c := client() - customers := []Customer{{ExternalID: strconv.Itoa(iCodeFail)}} + customers := []Customer{{ExternalID: strconv.Itoa(iCodeFail)}, {FirstName: "John"}} defer gock.Off() @@ -531,13 +532,29 @@ func TestClient_CustomersUpload_Fail(t *testing.T) { p := url.Values{ "customers": {string(str)}, } - + // TODO ??? gock.New(crmURL). Post("/api/v5/customers/upload"). MatchType("url"). BodyString(p.Encode()). Reply(460). - BodyString(`{"success": false, "errorMsg": "Customers are loaded with ErrorsList"}`) + BodyString(fmt.Sprintf(`{ + "success": false, + "uploadedCustomers": [ + { + "id": 132 + } + ], + "failedCustomers": [ + { + "externalId": "%d" + } + ], + "errorMsg": "Customers are loaded with errors", + "errors": { + "managerId": "Something went wrong" + } + }`, iCodeFail)) data, _, err := c.CustomersUpload(customers) if err == nil { @@ -5176,9 +5193,19 @@ func TestClient_IntegrationModule(t *testing.T) { }, } + integrations, err := json.Marshal(integrationModule.Integrations) + assert.NoError(t, err) + jsonData := fmt.Sprintf( - `{"code":"%s","integrationCode":"%s","active":false,"name":"%s","logo":"%s","clientId":"%s","baseUrl":"%s","accountUrl":"%s"}`, - code, code, integrationModule.Name, integrationModule.Logo, integrationModule.ClientID, integrationModule.BaseURL, integrationModule.AccountURL, + `{"code":"%s","integrationCode":"%s","active":false,"name":"%s","logo":"%s","clientId":"%s","baseUrl":"%s","accountUrl":"%s","integrations":%s}`, + code, + code, + integrationModule.Name, + integrationModule.Logo, + integrationModule.ClientID, + integrationModule.BaseURL, + integrationModule.AccountURL, + integrations, ) pr := url.Values{ @@ -7302,13 +7329,13 @@ func TestClient_LoyaltyAccounts(t *testing.T) { defer gock.Off() req := LoyaltyAccountsRequest{ - Filter: LoyaltyAccountApiFilter{ + Filter: LoyaltyAccountAPIFilter{ Status: "activated", PhoneNumber: "89185556363", Ids: []int{14}, Level: 5, Loyalties: []int{2}, - CustomerId: "109", + CustomerID: "109", }, } @@ -7413,7 +7440,7 @@ func TestClient_GetLoyalties(t *testing.T) { *active = 1 req := LoyaltiesRequest{ - Filter: LoyaltyApiFilter{ + Filter: LoyaltyAPIFilter{ Active: active, Ids: []int{2}, Sites: []string{"main"}, @@ -7463,7 +7490,7 @@ func TestClient_GetLoyaltyById(t *testing.T) { Reply(http.StatusOK). JSON(getLoyaltyResponse()) - res, status, err := client().GetLoyaltyById(2) + res, status, err := client().GetLoyaltyByID(2) if err != nil { t.Errorf("%v", err) @@ -7514,3 +7541,134 @@ func TestClient_OrderIntegrationDeliveryCancel(t *testing.T) { t.Errorf("%v", err) } } + +func TestClient_CreateProductsGroup(t *testing.T) { + defer gock.Off() + + group := ProductGroup{ + ParentID: 19, + Name: "Подкатегория хлама", + Site: "main", + Active: true, + Description: "Ну и хлам!", + ExternalID: "ti22", + } + + body, err := json.Marshal(group) + assert.NoError(t, err) + + p := url.Values{ + "productGroup": {string(body)}, + } + + gock.New(crmURL). + Post(prefix + "/store/product-groups/create"). + BodyString(p.Encode()). + Reply(http.StatusCreated). + JSON(`{"success":true,"id":32}`) + + res, status, err := client().CreateProductsGroup(group) + + if err != nil { + t.Errorf("%v", err) + } + + if !statuses[status] { + t.Errorf("%v", err) + } + + if res.Success != true { + t.Errorf("%v", err) + } + + assert.Equal(t, 32, res.ID) +} + +func TestClient_EditProductsGroup(t *testing.T) { + defer gock.Off() + + group := ProductGroup{ + Name: "Ценнейший хлам из хламов", + Active: true, + ExternalID: "ti22", + } + + body, err := json.Marshal(group) + assert.NoError(t, err) + + p := url.Values{ + "by": {"id"}, + "site": {"main"}, + "productGroup": {string(body)}, + } + + gock.New(crmURL). + Post(prefix + "/store/product-groups/32/edit"). + BodyString(p.Encode()). + Reply(http.StatusOK). + JSON(`{"success":true,"id":32}`) + + res, status, err := client().EditProductsGroup("id", "32", "main", group) + + if err != nil { + t.Errorf("%v", err) + } + + if !statuses[status] { + t.Errorf("%v", err) + } + + if res.Success != true { + t.Errorf("%v", err) + } + + assert.Equal(t, 32, res.ID) +} + +func TestClient_GetOrderPlate(t *testing.T) { + defer gock.Off() + + gock.New(crmURL). + Get(prefix + "/orders/124/plates/1/print"). + MatchParams(map[string]string{ + "by": "id", + "site": "main", + }). + Reply(200). + Body(io.NopCloser(strings.NewReader("PDF"))) + + data, status, err := client().GetOrderPlate("id", "124", "main", 1) + + if err != nil { + t.Errorf("%v", err) + } + + assert.NotNil(t, data) + assert.Equal(t, status, http.StatusOK) +} + +func TestClient_GetOrderPlateFail(t *testing.T) { + defer gock.Off() + + gock.New(crmURL). + Get(prefix + "/orders/124/plates/1/print"). + MatchParams(map[string]string{ + "by": "id", + "site": "main", + }). + Reply(404). + JSON(`{ + "success": false, + "errorMsg": "Not found" + }`) + + data, status, err := client().GetOrderPlate("id", "124", "main", 1) + + if err == nil { + t.Error("Expected error") + } + + assert.Nil(t, data) + assert.Equal(t, status, http.StatusNotFound) + assert.Equal(t, "Not found", err.(APIError).Error()) //nolint:errorlint +} diff --git a/filters.go b/filters.go index a5f3bce..762ae4f 100644 --- a/filters.go +++ b/filters.go @@ -440,11 +440,11 @@ type AccountBonusOperationsFilter struct { CreatedAtTo string `url:"createdAtTo,omitempty"` } -type LoyaltyBonusApiFilterType struct { +type LoyaltyBonusAPIFilterType struct { Date string `url:"date,omitempty"` } -type LoyaltyAccountApiFilter struct { +type LoyaltyAccountAPIFilter struct { ID string `url:"id,omitempty"` Status string `url:"status,,omitempty"` Customer string `url:"customer,omitempty"` @@ -463,11 +463,11 @@ type LoyaltyAccountApiFilter struct { BurnDateFrom string `url:"burnDateFrom,omitempty"` BurnDateTo string `url:"burnDateTo,omitempty"` CustomFields []string `url:"customFields,omitempty,brackets"` - CustomerId string `url:"customerId,omitempty"` - CustomerExternalId string `url:"customerExternalId,omitempty"` + CustomerID string `url:"customerId,omitempty"` + CustomerExternalID string `url:"customerExternalId,omitempty"` } -type LoyaltyApiFilter struct { +type LoyaltyAPIFilter struct { Active *int `url:"active,omitempty"` Blocked *int `url:"blocked,omitempty"` Ids []int `url:"ids,omitempty,brackets"` diff --git a/request.go b/request.go index 90850f2..543a115 100644 --- a/request.go +++ b/request.go @@ -256,13 +256,13 @@ type LoyaltyBonusCreditRequest struct { type LoyaltyBonusStatusDetailsRequest struct { Limit int `url:"limit,omitempty"` Page int `url:"page,omitempty"` - Filter LoyaltyBonusApiFilterType `url:"filter,omitempty"` + Filter LoyaltyBonusAPIFilterType `url:"filter,omitempty"` } type LoyaltyAccountsRequest struct { Limit int `url:"limit,omitempty"` Page int `url:"limit,omitempty"` - Filter LoyaltyAccountApiFilter `url:"filter,omitempty"` + Filter LoyaltyAccountAPIFilter `url:"filter,omitempty"` } type LoyaltyCalculateRequest struct { @@ -274,7 +274,7 @@ type LoyaltyCalculateRequest struct { type LoyaltiesRequest struct { Limit int `url:"limit,omitempty"` Page int `url:"page,omitempty"` - Filter LoyaltyApiFilter `url:"filter,omitempty"` + Filter LoyaltyAPIFilter `url:"filter,omitempty"` } // SystemURL returns system URL from the connection request without trailing slash. diff --git a/response.go b/response.go index 917a371..1c7eaf3 100644 --- a/response.go +++ b/response.go @@ -644,3 +644,8 @@ type LoyaltyResponse struct { SuccessfulResponse Loyalty Loyalty `json:"loyalty"` } + +type ActionProductsGroupResponse struct { + SuccessfulResponse + ID int `json:"id"` +} diff --git a/types.go b/types.go index 0b34bd4..cf99fcf 100644 --- a/types.go +++ b/types.go @@ -785,7 +785,7 @@ type DeliveryType struct { VatRate string `json:"vatRate,omitempty"` DefaultForCrm bool `json:"defaultForCrm,omitempty"` DeliveryServices []string `json:"deliveryServices,omitempty"` - PaymentTypes []string `json:"paymentTypes,omitempty"` //Deprecated, use DeliveryPaymentTypes + PaymentTypes []string `json:"paymentTypes,omitempty"` // Deprecated, use DeliveryPaymentTypes DeliveryPaymentTypes []DeliveryPaymentType `json:"deliveryPaymentTypes,omitempty"` } @@ -927,7 +927,7 @@ type Site struct { DefaultForCRM bool `json:"defaultForCrm,omitempty"` Ordering int `json:"ordering,omitempty"` IsDemo bool `json:"isDemo,omitempty"` - CatalogId string `json:"catalogId,omitempty"` + CatalogID string `json:"catalogId,omitempty"` IsCatalogMainSite bool `json:"isCatalogMainSite,omitempty"` } @@ -948,11 +948,14 @@ type Store struct { // ProductGroup type. type ProductGroup struct { - ID int `json:"id,omitempty"` - ParentID int `json:"parentId,omitempty"` - Name string `json:"name,omitempty"` - Site string `json:"site,omitempty"` - Active bool `json:"active,omitempty"` + ID int `json:"id,omitempty"` + ParentID int `json:"parentId,omitempty"` + Name string `json:"name,omitempty"` + Site string `json:"site,omitempty"` + Active bool `json:"active,omitempty"` + Description string `json:"description,omitempty"` + ExternalID string `json:"externalId,omitempty"` + ParentExternalID string `json:"parentExternalId,omitempty"` } // BaseProduct type.