diff --git a/client.go b/client.go index 1d97d03..806376d 100644 --- a/client.go +++ b/client.go @@ -593,7 +593,7 @@ func (c *Client) CustomersCombine(customers []Customer, resultCustomer Customer) // // var client = retailcrm.New("https://demo.url", "09jIJ") // -// data, status, err := client.CustomersCombine(retailcrm.Customer{ +// data, status, err := client.CustomerCreate(retailcrm.Customer{ // FirstName: "Ivan", // LastName: "Ivanov", // Patronymic: "Ivanovich", @@ -5135,6 +5135,34 @@ func (c *Client) Inventories(parameters InventoriesRequest) (InventoriesResponse return resp, status, nil } +// StoreInventories returns leftover stocks and purchasing prices. +// +// For more information see https://docs.retailcrm.ru/Developers/API/APIMethods#get--api-v5-store-inventories +// +// Example: +// +// var client = retailcrm.New("https://demo.url", "09jIJ") +// +// data, status, err := client.StoreInventories(retailcrm.StoreInventoriesRequest{ +// Filter: retailcrm.InventoriesFilter{Details: 1, ProductActive: 1}, +// Page: 1, +// }) +// +// 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) +// } +// +// for _, value := range data.Offers { +// log.Printf("%v\n", value) +// } +func (c *Client) StoreInventories(parameters StoreInventoriesRequest) (StoreInventoriesResponse, int, error) { + return c.Inventories(parameters) +} + // InventoriesUpload updates the leftover stocks and purchasing prices // // For more information see http://www.simla.com/docs/Developers/API/APIVersions/APIv5#post--api-v5-store-inventories-upload @@ -5342,6 +5370,36 @@ func (c *Client) Products(parameters ProductsRequest) (ProductsResponse, int, er return resp, status, nil } +// StoreProducts returns list of products and SKU. +// +// For more information see https://docs.retailcrm.ru/Developers/API/APIMethods#get--api-v5-store-products +// +// Example: +// +// var client = retailcrm.New("https://demo.url", "09jIJ") +// +// data, status, err := client.StoreProducts(retailcrm.StoreProductsRequest{ +// Filter: retailcrm.ProductsFilter{ +// Active: 1, +// MinPrice: 1000, +// }, +// }) +// +// 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) +// } +// +// for _, value := range data.Products { +// log.Printf("%v\n", value) +// } +func (c *Client) StoreProducts(parameters StoreProductsRequest) (StoreProductsResponse, int, error) { + return c.Products(parameters) +} + // ProductsProperties returns list of item properties, matching the specified filters // // For more information see http://www.simla.com/docs/Developers/API/APIVersions/APIv5#get--api-v5-store-products-properties diff --git a/client_test.go b/client_test.go index 94f0ef5..e166756 100644 --- a/client_test.go +++ b/client_test.go @@ -6180,10 +6180,11 @@ func TestClient_Packs(t *testing.T) { gock.New(crmURL). Get("/orders/packs"). MatchParam("page", "1"). + MatchParam("filter[stores][]", "main"). Reply(200). BodyString(`{"success": true}`) - data, status, err := c.Packs(PacksRequest{Filter: PacksFilter{}, Page: 1}) + data, status, err := c.Packs(PacksRequest{Filter: PacksFilter{Stores: []string{"main"}}, Page: 1}) if err != nil { t.Errorf("%v", err) } @@ -6267,6 +6268,52 @@ func TestClient_Inventories_Fail(t *testing.T) { } } +func TestClient_StoreInventories(t *testing.T) { + c := client() + + defer gock.Off() + + gock.New(crmURL). + Get("/store/inventories"). + MatchParam("filter[details]", "1"). + MatchParam("filter[productActive]", "1"). + MatchParam("filter[offerActive]", "1"). + MatchParam("filter[offerExternalId][]", "offer-1"). + MatchParam("limit", "250"). + Reply(http.StatusOK). + BodyString(`{ + "success": true, + "offers": [{ + "id": 76, + "externalId": "offer-1", + "xmlId": "xml-1", + "quantity": 5, + "stores": [{"store": "main", "quantity": 5, "purchasePrice": 10}] + }] + }`) + + data, status, err := c.StoreInventories(StoreInventoriesRequest{ + Filter: InventoriesFilter{ + Details: 1, + ProductActive: 1, + OfferActive: 1, + OfferExternalID: []string{"offer-1"}, + }, + Limit: 250, + }) + if err != nil { + t.Errorf("%v", err) + } + + if status != http.StatusOK { + t.Errorf("%v", err) + } + + assert.True(t, data.Success) + assert.Len(t, data.Offers, 1) + assert.Equal(t, "main", data.Offers[0].Stores[0].Store) +} + func TestClient_Segments(t *testing.T) { c := client() @@ -6679,6 +6726,62 @@ func TestClient_Products(t *testing.T) { } } +func TestClient_StoreProducts(t *testing.T) { + c := client() + + defer gock.Off() + + gock.New(crmURL). + Get("/store/products"). + MatchParam("filter[groups][]", "10"). + MatchParam("filter[catalogs][]", "2"). + MatchParam("filter[offerXmlId]", "offer-xml-id"). + MatchParam("filter[groupExternalId]", "group-external-id"). + MatchParam("filter[sinceUpdatedAt]", "2026-05-06 12:00:00"). + MatchParam("filter[sinceId]", "75"). + MatchParam("filter[productType]", "product"). + MatchParam("filter[markable]", "1"). + Reply(http.StatusOK). + BodyString(`{ + "success": true, + "products": [{ + "id": 222, + "catalogId": 2, + "type": "product", + "externalId": "product-external-id", + "groups": [{"id": 10, "externalId": "group-external-id"}], + "offers": [{"id": 76, "xmlId": "offer-xml-id"}], + "markingProvider": "chestny_znak" + }] + }`) + + g, status, err := c.StoreProducts(StoreProductsRequest{ + Filter: ProductsFilter{ + Groups: []int{10}, + Catalogs: []int{2}, + OfferXMLID: "offer-xml-id", + GroupExternalID: "group-external-id", + SinceUpdatedAt: "2026-05-06 12:00:00", + SinceID: 75, + ProductType: "product", + Markable: 1, + }, + }) + if err != nil { + t.Errorf("%v", err) + } + + if status != http.StatusOK { + t.Errorf("%v", err) + } + + assert.True(t, g.Success) + assert.Len(t, g.Products, 1) + assert.Equal(t, "group-external-id", g.Products[0].Groups[0].ExternalID) + assert.Equal(t, "offer-xml-id", g.Products[0].Offers[0].XMLID) + assert.Equal(t, "chestny_znak", g.Products[0].MarkingProvider) +} + func TestClient_Products_Fail(t *testing.T) { c := client() @@ -6744,7 +6847,7 @@ func TestClient_DeliveryTracking(t *testing.T) { defer gock.Off() p := url.Values{ - "statusUpdate": {`[{"deliveryId":"123","history":[{"code":"1","updatedAt":"2020-01-01T00:00:00:000"}]}]`}, + "statusUpdate": {`[{"deliveryId":"123","cost":99.5,"history":[{"code":"1","updatedAt":"2020-01-01T00:00:00:000"}],"extraData":{"gate":"A1"}}]`}, } gock.New(crmURL). @@ -6756,10 +6859,12 @@ func TestClient_DeliveryTracking(t *testing.T) { g, status, err := c.DeliveryTracking([]DeliveryTrackingRequest{{ DeliveryID: "123", + Cost: 99.5, History: []DeliveryHistoryRecord{{ Code: "1", UpdatedAt: "2020-01-01T00:00:00:000", }}, + ExtraData: map[string]string{"gate": "A1"}, }}, "subcode") if err != nil { diff --git a/filters.go b/filters.go index 2ead571..93e6fd6 100644 --- a/filters.go +++ b/filters.go @@ -298,7 +298,7 @@ type SegmentsFilter struct { // PacksFilter type. type PacksFilter struct { Ids []int `url:"ids,omitempty,brackets"` - Stores []string `url:"stores,omitempty"` + Stores []string `url:"stores,omitempty,brackets"` ItemID int `url:"itemId,omitempty"` OfferXMLID string `url:"offerXmlId,omitempty"` OfferExternalID string `url:"offerExternalId,omitempty"` @@ -338,6 +338,7 @@ type ProductsFilter struct { Ids []int `url:"ids,omitempty,brackets"` OfferIds []int `url:"offerIds,omitempty,brackets"` Active int `url:"active,omitempty"` + Markable int `url:"markable,omitempty"` Recommended int `url:"recommended,omitempty"` Novelty int `url:"novelty,omitempty"` Stock int `url:"stock,omitempty"` @@ -348,7 +349,7 @@ type ProductsFilter struct { MinPurchasePrice float32 `url:"minPurchasePrice,omitempty"` MaxPrice float32 `url:"maxPrice,omitempty"` MinPrice float32 `url:"minPrice,omitempty"` - Groups string `url:"groups,omitempty"` + Groups []int `url:"groups,omitempty,brackets"` Name string `url:"name,omitempty"` ClassSegment string `url:"classSegment,omitempty"` XMLID string `url:"xmlId,omitempty"` @@ -357,7 +358,13 @@ type ProductsFilter struct { URL string `url:"url,omitempty"` URLLike string `url:"urlLike,omitempty"` PriceType string `url:"priceType,omitempty"` + Catalogs []int `url:"catalogs,omitempty,brackets"` OfferExternalID string `url:"offerExternalId,omitempty"` + OfferXMLID string `url:"offerXmlId,omitempty"` + GroupExternalID string `url:"groupExternalId,omitempty"` + SinceUpdatedAt string `url:"sinceUpdatedAt,omitempty"` + SinceID int `url:"sinceId,omitempty"` + ProductType string `url:"productType,omitempty"` Sites []string `url:"sites,omitempty,brackets"` Properties map[string]string `url:"properties,omitempty,brackets"` } diff --git a/request.go b/request.go index d635940..b74d480 100644 --- a/request.go +++ b/request.go @@ -158,6 +158,9 @@ type InventoriesRequest struct { Page int `url:"page,omitempty"` } +// StoreInventoriesRequest type. +type StoreInventoriesRequest = InventoriesRequest + // ProductsGroupsRequest type. type ProductsGroupsRequest struct { Filter ProductsGroupsFilter `url:"filter,omitempty"` @@ -172,6 +175,9 @@ type ProductsRequest struct { Page int `url:"page,omitempty"` } +// StoreProductsRequest type. +type StoreProductsRequest = ProductsRequest + // ProductsPropertiesRequest type. type ProductsPropertiesRequest struct { Filter ProductsPropertiesFilter `url:"filter,omitempty"` @@ -183,6 +189,7 @@ type ProductsPropertiesRequest struct { type DeliveryTrackingRequest struct { DeliveryID string `json:"deliveryId,omitempty"` TrackNumber string `json:"trackNumber,omitempty"` + Cost float32 `json:"cost,omitempty"` History []DeliveryHistoryRecord `json:"history,omitempty"` ExtraData map[string]string `json:"extraData,omitempty"` } diff --git a/response.go b/response.go index 5c35310..5df7648 100644 --- a/response.go +++ b/response.go @@ -362,6 +362,9 @@ type InventoriesResponse struct { Offers []Offer `json:"offers,omitempty"` } +// StoreInventoriesResponse type. +type StoreInventoriesResponse = InventoriesResponse + // StoreUploadResponse type. type StoreUploadResponse struct { Success bool `json:"success"` @@ -383,6 +386,9 @@ type ProductsResponse struct { Products []Product `json:"products,omitempty"` } +// StoreProductsResponse type. +type StoreProductsResponse = ProductsResponse + type ProductEditNotFoundResponse struct { ID string `json:"id"` ExternalID string `json:"externalId,omitempty"` diff --git a/types.go b/types.go index 39567fd..28b2c0a 100644 --- a/types.go +++ b/types.go @@ -42,6 +42,7 @@ type Pagination struct { // Address type. type Address struct { + ID int `json:"id,omitempty"` Index string `json:"index,omitempty"` CountryIso string `json:"countryIso,omitempty"` Region string `json:"region,omitempty"` @@ -61,6 +62,8 @@ type Address struct { Metro string `json:"metro,omitempty"` Notes string `json:"notes,omitempty"` Text string `json:"text,omitempty"` + ExternalID string `json:"externalId,omitempty"` + Name string `json:"name,omitempty"` } // GeoID type. Can be empty string. @@ -124,6 +127,7 @@ type Property struct { type IdentifiersPair struct { ID int `json:"id,omitempty"` ExternalID string `json:"externalId,omitempty"` + Name string `json:"name,omitempty"` } // DeliveryTime type. @@ -139,43 +143,60 @@ Customer related types // Customer type. type Customer struct { - ID int `json:"id,omitempty"` - ExternalID string `json:"externalId,omitempty"` - FirstName string `json:"firstName,omitempty"` - LastName string `json:"lastName,omitempty"` - Patronymic string `json:"patronymic,omitempty"` - Sex string `json:"sex,omitempty"` - Email string `json:"email,omitempty"` - Phones []Phone `json:"phones,omitempty"` - Address *Address `json:"address,omitempty"` - CreatedAt string `json:"createdAt,omitempty"` - Birthday string `json:"birthday,omitempty"` - ManagerID int `json:"managerId,omitempty"` - Vip bool `json:"vip,omitempty"` - Bad bool `json:"bad,omitempty"` - IsContact bool `json:"isContact,omitempty"` - Site string `json:"site,omitempty"` - Source *Source `json:"source,omitempty"` - Contragent *Contragent `json:"contragent,omitempty"` - PersonalDiscount float32 `json:"personalDiscount,omitempty"` - CumulativeDiscount float32 `json:"cumulativeDiscount,omitempty"` - DiscountCardNumber string `json:"discountCardNumber,omitempty"` - EmailMarketingUnsubscribedAt string `json:"emailMarketingUnsubscribedAt,omitempty"` - AvgMarginSumm float32 `json:"avgMarginSumm,omitempty"` - MarginSumm float32 `json:"marginSumm,omitempty"` - TotalSumm float32 `json:"totalSumm,omitempty"` - AverageSumm float32 `json:"averageSumm,omitempty"` - OrdersCount int `json:"ordersCount,omitempty"` - CostSumm float32 `json:"costSumm,omitempty"` - MaturationTime int `json:"maturationTime,omitempty"` - FirstClientID string `json:"firstClientId,omitempty"` - LastClientID string `json:"lastClientId,omitempty"` - BrowserID string `json:"browserId,omitempty"` - MgCustomerID string `json:"mgCustomerId,omitempty"` - PhotoURL string `json:"photoUrl,omitempty"` - CustomFields CustomFieldMap `json:"customFields,omitempty"` - Tags []Tag `json:"tags,omitempty"` - CustomerSubscriptions []CustomerSubscription `json:"customerSubscriptions,omitempty"` + ID int `json:"id,omitempty"` + Type string `json:"type,omitempty"` + ExternalID string `json:"externalId,omitempty"` + FirstName string `json:"firstName,omitempty"` + LastName string `json:"lastName,omitempty"` + Patronymic string `json:"patronymic,omitempty"` + Sex string `json:"sex,omitempty"` + PresumableSex string `json:"presumableSex,omitempty"` + Email string `json:"email,omitempty"` + Phones []Phone `json:"phones,omitempty"` + Address *Address `json:"address,omitempty"` + CreatedAt string `json:"createdAt,omitempty"` + Birthday string `json:"birthday,omitempty"` + ManagerID int `json:"managerId,omitempty"` + Vip bool `json:"vip,omitempty"` + Bad bool `json:"bad,omitempty"` + IsContact bool `json:"isContact,omitempty"` + Site string `json:"site,omitempty"` + Source *Source `json:"source,omitempty"` + Contragent *Contragent `json:"contragent,omitempty"` + PersonalDiscount float32 `json:"personalDiscount,omitempty"` + CumulativeDiscount float32 `json:"cumulativeDiscount,omitempty"` + DiscountCardNumber string `json:"discountCardNumber,omitempty"` + EmailMarketingUnsubscribedAt string `json:"emailMarketingUnsubscribedAt,omitempty"` + AvgMarginSumm float32 `json:"avgMarginSumm,omitempty"` + MarginSumm float32 `json:"marginSumm,omitempty"` + TotalSumm float32 `json:"totalSumm,omitempty"` + AverageSumm float32 `json:"averageSumm,omitempty"` + OrdersCount int `json:"ordersCount,omitempty"` + CostSumm float32 `json:"costSumm,omitempty"` + MaturationTime int `json:"maturationTime,omitempty"` + FirstClientID string `json:"firstClientId,omitempty"` + LastClientID string `json:"lastClientId,omitempty"` + BrowserID string `json:"browserId,omitempty"` + MgCustomerID string `json:"mgCustomerId,omitempty"` + MgCustomers []MGCustomer `json:"mgCustomers,omitempty"` + PhotoURL string `json:"photoUrl,omitempty"` + Subscribed bool `json:"subscribed,omitempty"` + AttachedTag string `json:"attachedTag,omitempty"` + Nickname string `json:"nickName,omitempty"` + CustomFields CustomFieldMap `json:"customFields,omitempty"` + Tags []Tag `json:"tags,omitempty"` + Segments []Segment `json:"segments,omitempty"` + CustomerSubscriptions []CustomerSubscription `json:"customerSubscriptions,omitempty"` + MainAddress *IdentifiersPair `json:"mainAddress,omitempty"` + MainCustomerContact *CorporateCustomerContact `json:"mainCustomerContact,omitempty"` + MainCompany *IdentifiersPair `json:"mainCompany,omitempty"` +} + +// MGCustomer type. +type MGCustomer struct { + ID int `json:"id,omitempty"` + ExternalID string `json:"externalId,omitempty"` + MGChannel *MGChannel `json:"mgChannel,omitempty"` } // CustomerSubscription type. @@ -275,6 +296,7 @@ type Company struct { ID int `json:"id,omitempty"` IsMain bool `json:"isMain,omitempty"` ExternalID string `json:"externalId,omitempty"` + Customer *Customer `json:"customer,omitempty"` Active bool `json:"active,omitempty"` Name string `json:"name,omitempty"` Brand string `json:"brand,omitempty"` @@ -346,61 +368,68 @@ type Properties map[string]Property // Order type. type Order struct { - ID int `json:"id,omitempty"` - ExternalID string `json:"externalId,omitempty"` - Number string `json:"number,omitempty"` - FirstName string `json:"firstName,omitempty"` - LastName string `json:"lastName,omitempty"` - Patronymic string `json:"patronymic,omitempty"` - Email string `json:"email,omitempty"` - Phone string `json:"phone,omitempty"` - AdditionalPhone string `json:"additionalPhone,omitempty"` - CreatedAt string `json:"createdAt,omitempty"` - StatusUpdatedAt string `json:"statusUpdatedAt,omitempty"` - ManagerID int `json:"managerId,omitempty"` - Mark int `json:"mark,omitempty"` - Call bool `json:"call,omitempty"` - Expired bool `json:"expired,omitempty"` - FromAPI bool `json:"fromApi,omitempty"` - MarkDatetime string `json:"markDatetime,omitempty"` - CustomerComment string `json:"customerComment,omitempty"` - ManagerComment string `json:"managerComment,omitempty"` - Status string `json:"status,omitempty"` - StatusComment string `json:"statusComment,omitempty"` - FullPaidAt string `json:"fullPaidAt,omitempty"` - Site string `json:"site,omitempty"` - OrderType string `json:"orderType,omitempty"` - OrderMethod string `json:"orderMethod,omitempty"` - CountryIso string `json:"countryIso,omitempty"` - Summ float32 `json:"summ,omitempty"` - TotalSumm float32 `json:"totalSumm,omitempty"` - PrepaySum float32 `json:"prepaySum,omitempty"` - PurchaseSumm float32 `json:"purchaseSumm,omitempty"` - DiscountManualAmount float32 `json:"discountManualAmount,omitempty"` - DiscountManualPercent float32 `json:"discountManualPercent,omitempty"` - Weight float32 `json:"weight,omitempty"` - Length int `json:"length,omitempty"` - Width int `json:"width,omitempty"` - Height int `json:"height,omitempty"` - ShipmentStore string `json:"shipmentStore,omitempty"` - ShipmentDate string `json:"shipmentDate,omitempty"` - ClientID string `json:"clientId,omitempty"` - Shipped bool `json:"shipped,omitempty"` - UploadedToExternalStoreSystem bool `json:"uploadedToExternalStoreSystem,omitempty"` - Source *Source `json:"source,omitempty"` - Contragent *Contragent `json:"contragent,omitempty"` - Customer *Customer `json:"customer,omitempty"` - Contact *Customer `json:"contact,omitempty"` - Delivery *OrderDelivery `json:"delivery,omitempty"` - Marketplace *OrderMarketplace `json:"marketplace,omitempty"` - Items []OrderItem `json:"items,omitempty"` - CustomFields CustomFieldMap `json:"customFields,omitempty"` - Payments OrderPayments `json:"payments,omitempty"` - ApplyRound *bool `json:"applyRound,omitempty"` - PrivilegeType string `json:"privilegeType,omitempty"` - DialogID int `json:"dialogId,omitempty"` - Links []OrderLink `json:"links,omitempty"` - Currency string `json:"currency,omitempty"` + ID int `json:"id,omitempty"` + Slug int `json:"slug,omitempty"` + ExternalID string `json:"externalId,omitempty"` + Number string `json:"number,omitempty"` + FirstName string `json:"firstName,omitempty"` + LastName string `json:"lastName,omitempty"` + Patronymic string `json:"patronymic,omitempty"` + Email string `json:"email,omitempty"` + Phone string `json:"phone,omitempty"` + AdditionalPhone string `json:"additionalPhone,omitempty"` + CreatedAt string `json:"createdAt,omitempty"` + StatusUpdatedAt string `json:"statusUpdatedAt,omitempty"` + ManagerID int `json:"managerId,omitempty"` + Mark int `json:"mark,omitempty"` + Call bool `json:"call,omitempty"` + Expired bool `json:"expired,omitempty"` + FromAPI bool `json:"fromApi,omitempty"` + MarkDatetime string `json:"markDatetime,omitempty"` + CustomerComment string `json:"customerComment,omitempty"` + ManagerComment string `json:"managerComment,omitempty"` + Status string `json:"status,omitempty"` + StatusComment string `json:"statusComment,omitempty"` + FullPaidAt string `json:"fullPaidAt,omitempty"` + Site string `json:"site,omitempty"` + OrderType string `json:"orderType,omitempty"` + OrderMethod string `json:"orderMethod,omitempty"` + CountryIso string `json:"countryIso,omitempty"` + Summ float32 `json:"summ,omitempty"` + TotalSumm float32 `json:"totalSumm,omitempty"` + PrepaySum float32 `json:"prepaySum,omitempty"` + PurchaseSumm float32 `json:"purchaseSumm,omitempty"` + DiscountManualAmount float32 `json:"discountManualAmount,omitempty"` + DiscountManualPercent float32 `json:"discountManualPercent,omitempty"` + PersonalDiscountPercent float32 `json:"personalDiscountPercent,omitempty"` + Weight float32 `json:"weight,omitempty"` + Length int `json:"length,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + ShipmentStore string `json:"shipmentStore,omitempty"` + ShipmentDate string `json:"shipmentDate,omitempty"` + ClientID string `json:"clientId,omitempty"` + Shipped bool `json:"shipped,omitempty"` + UploadedToExternalStoreSystem bool `json:"uploadedToExternalStoreSystem,omitempty"` + Source *Source `json:"source,omitempty"` + Contragent *Contragent `json:"contragent,omitempty"` + Customer *Customer `json:"customer,omitempty"` + Contact *Customer `json:"contact,omitempty"` + Company *Company `json:"company,omitempty"` + Delivery *OrderDelivery `json:"delivery,omitempty"` + Marketplace *OrderMarketplace `json:"marketplace,omitempty"` + Items []OrderItem `json:"items,omitempty"` + CustomFields CustomFieldMap `json:"customFields,omitempty"` + Payments OrderPayments `json:"payments,omitempty"` + ApplyRound *bool `json:"applyRound,omitempty"` + PrivilegeType string `json:"privilegeType,omitempty"` + LoyaltyLevel *LoyaltyLevel `json:"loyaltyLevel,omitempty"` + LoyaltyEventDiscountID int `json:"loyaltyEventDiscountId,omitempty"` + LoyaltyEventDiscount *LoyaltyEventDiscount `json:"loyaltyEventDiscount,omitempty"` + DialogID int `json:"dialogId,omitempty"` + IsFromCart bool `json:"isFromCart,omitempty"` + Links []OrderLink `json:"links,omitempty"` + Currency string `json:"currency,omitempty"` BonusesCreditTotal float32 `json:"bonusesCreditTotal,omitempty"` BonusesChargeTotal float32 `json:"bonusesChargeTotal,omitempty"` @@ -485,17 +514,120 @@ type OrderDeliveryTime struct { // OrderDeliveryService type. type OrderDeliveryService struct { - Name string `json:"name,omitempty"` - Code string `json:"code,omitempty"` - Active bool `json:"active,omitempty"` + Name string `json:"name,omitempty"` + Code string `json:"code,omitempty"` + Active bool `json:"active,omitempty"` + DeliveryType string `json:"deliveryType,omitempty"` } // OrderDeliveryDataBasic type. type OrderDeliveryDataBasic struct { - TrackNumber string `json:"trackNumber,omitempty"` - Status string `json:"status,omitempty"` - PickuppointAddress string `json:"pickuppointAddress,omitempty"` - PayerType string `json:"payerType,omitempty"` + ExternalID string `json:"externalId,omitempty"` + TrackNumber string `json:"trackNumber,omitempty"` + Status string `json:"status,omitempty"` + Locked bool `json:"locked,omitempty"` + PickuppointAddress string `json:"pickuppointAddress,omitempty"` + Days int `json:"days,omitempty"` + StatusText string `json:"statusText,omitempty"` + StatusDate string `json:"statusDate,omitempty"` + Tariff string `json:"tariff,omitempty"` + TariffName string `json:"tariffName,omitempty"` + PickuppointID string `json:"pickuppointId,omitempty"` + PickuppointName string `json:"pickuppointName,omitempty"` + PickuppointSchedule string `json:"pickuppointSchedule,omitempty"` + PickuppointPhone string `json:"pickuppointPhone,omitempty"` + PickuppointCoordinateLatitude float64 `json:"pickuppointCoordinateLatitude,omitempty"` + PickuppointCoordinateLongitude float64 `json:"pickuppointCoordinateLongitude,omitempty"` + PayerType string `json:"payerType,omitempty"` + StatusComment string `json:"statusComment,omitempty"` + Cost float32 `json:"cost,omitempty"` + MinTerm int `json:"minTerm,omitempty"` + MaxTerm int `json:"maxTerm,omitempty"` + ShipmentpointID string `json:"shipmentpointId,omitempty"` + ShipmentpointName string `json:"shipmentpointName,omitempty"` + ShipmentpointAddress string `json:"shipmentpointAddress,omitempty"` + ShipmentpointSchedule string `json:"shipmentpointSchedule,omitempty"` + ShipmentpointPhone string `json:"shipmentpointPhone,omitempty"` + ShipmentpointCoordinateLatitude float64 `json:"shipmentpointCoordinateLatitude,omitempty"` + ShipmentpointCoordinateLongitude float64 `json:"shipmentpointCoordinateLongitude,omitempty"` + ExtraData StringMap `json:"extraData,omitempty"` + ItemDeclaredValues []DeliveryItemDeclaredValue `json:"itemDeclaredValues,omitempty"` + Packages []DeliveryPackage `json:"packages,omitempty"` + ID int `json:"id,omitempty"` + FirstName string `json:"firstName,omitempty"` + LastName string `json:"lastName,omitempty"` + Patronymic string `json:"patronymic,omitempty"` + Active bool `json:"active,omitempty"` + Email string `json:"email,omitempty"` + Phone *Phone `json:"phone,omitempty"` + Description string `json:"description,omitempty"` + CourierID string `json:"courierId,omitempty"` + ServiceType string `json:"serviceType,omitempty"` + Pickuppoint string `json:"pickuppoint,omitempty"` + ReceiverWarehouseTypeRef string `json:"receiverWarehouseTypeRef,omitempty"` + StatusName string `json:"statusName,omitempty"` + Price float32 `json:"price,omitempty"` + ReceiverCity string `json:"receiverCity,omitempty"` + ReceiverCityRef string `json:"receiverCityRef,omitempty"` + ReceiverStreet string `json:"receiverStreet,omitempty"` + ReceiverStreetRef string `json:"receiverStreetRef,omitempty"` + SeatsAmount int `json:"seatsAmount,omitempty"` + CargoType string `json:"cargoType,omitempty"` + CargoDescription string `json:"cargoDescription,omitempty"` + CashPayerType string `json:"cashPayerType,omitempty"` + PaymentForm string `json:"paymentForm,omitempty"` + OwnershipForm string `json:"ownershipForm,omitempty"` + PackageNumber string `json:"packageNumber,omitempty"` + AccompanyingDocument string `json:"accompanyingDocument,omitempty"` + Notes string `json:"notes,omitempty"` + PreferredDeliveryDate string `json:"preferredDeliveryDate,omitempty"` + TimeInterval string `json:"timeInterval,omitempty"` + SaturdayDelivery bool `json:"saturdayDelivery,omitempty"` + DeliveryDate string `json:"deliveryDate,omitempty"` + DenieReason string `json:"denieReason,omitempty"` + BackwardDelivery bool `json:"backwardDelivery,omitempty"` + BackwardDeliveryCargoType string `json:"backwardDeliveryCargoType,omitempty"` + BackwardDeliveryPayerType string `json:"backwardDeliveryPayerType,omitempty"` + BackwardDeliveryRedeliveryString string `json:"backwardDeliveryRedeliveryString,omitempty"` + AfterpaymentOnGoodsCost float32 `json:"afterpaymentOnGoodsCost,omitempty"` + DeclaredValue float32 `json:"declaredValue,omitempty"` + SendDate string `json:"sendDate,omitempty"` + DeliveryType string `json:"deliveryType,omitempty"` + DeliveryName string `json:"deliveryName,omitempty"` + PickupType string `json:"pickupType,omitempty"` + PickuppointDescription string `json:"pickuppointDescription,omitempty"` + PlacesCount int `json:"placesCount,omitempty"` + Services []string `json:"services,omitempty"` + Comment string `json:"comment,omitempty"` +} + +// DeliveryItemDeclaredValue type. +type DeliveryItemDeclaredValue struct { + OrderProduct OrderProductIdentifier `json:"orderProduct,omitempty"` + Value float32 `json:"value,omitempty"` +} + +// DeliveryPackage type. +type DeliveryPackage struct { + PackageID string `json:"packageId,omitempty"` + Weight float32 `json:"weight,omitempty"` + Length int `json:"length,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + Items []DeliveryPackageItem `json:"items,omitempty"` +} + +// DeliveryPackageItem type. +type DeliveryPackageItem struct { + OrderProduct OrderProductIdentifier `json:"orderProduct,omitempty"` + Quantity float32 `json:"quantity,omitempty"` +} + +// OrderProductIdentifier type. +type OrderProductIdentifier struct { + ID int `json:"id,omitempty"` + ExternalID string `json:"externalId,omitempty"` + ExternalIDs []CodeValueModel `json:"externalIds,omitempty"` } // OrderDeliveryData type. @@ -663,25 +795,37 @@ type OrderPayment struct { // OrderItem type. type OrderItem struct { - ID int `json:"id,omitempty"` - InitialPrice float32 `json:"initialPrice,omitempty"` - PurchasePrice float32 `json:"purchasePrice,omitempty"` - DiscountTotal float32 `json:"discountTotal,omitempty"` - DiscountManualAmount float32 `json:"discountManualAmount,omitempty"` - DiscountManualPercent float32 `json:"discountManualPercent,omitempty"` - ProductName string `json:"productName,omitempty"` - VatRate string `json:"vatRate,omitempty"` - CreatedAt string `json:"createdAt,omitempty"` - Quantity float32 `json:"quantity,omitempty"` - Status string `json:"status,omitempty"` - Comment string `json:"comment,omitempty"` - IsCanceled bool `json:"isCanceled,omitempty"` - Offer Offer `json:"offer,omitempty"` - Properties Properties `json:"properties,omitempty"` - PriceType *PriceType `json:"priceType,omitempty"` - BonusesChargeTotal float32 `json:"bonusesChargeTotal,omitempty"` - BonusesCreditTotal float32 `json:"bonusesCreditTotal,omitempty"` - Discounts []ItemDiscount `json:"discounts,omitempty"` + ID int `json:"id,omitempty"` + ExternalID string `json:"externalId,omitempty"` + ExternalIDs []CodeValueModel `json:"externalIds,omitempty"` + MarkingCodes []string `json:"markingCodes,omitempty"` + MarkingObjects []MarkingObject `json:"markingObjects,omitempty"` + InitialPrice float32 `json:"initialPrice,omitempty"` + PurchasePrice float32 `json:"purchasePrice,omitempty"` + DiscountTotal float32 `json:"discountTotal,omitempty"` + DiscountManualAmount float32 `json:"discountManualAmount,omitempty"` + DiscountManualPercent float32 `json:"discountManualPercent,omitempty"` + ProductName string `json:"productName,omitempty"` + VatRate string `json:"vatRate,omitempty"` + CreatedAt string `json:"createdAt,omitempty"` + Quantity float32 `json:"quantity,omitempty"` + Status string `json:"status,omitempty"` + Comment string `json:"comment,omitempty"` + Ordering int `json:"ordering,omitempty"` + IsCanceled bool `json:"isCanceled,omitempty"` + Offer Offer `json:"offer,omitempty"` + Properties Properties `json:"properties,omitempty"` + PriceType *PriceType `json:"priceType,omitempty"` + Prices []OrderProductPriceItem `json:"prices,omitempty"` + BonusesChargeTotal float32 `json:"bonusesChargeTotal,omitempty"` + BonusesCreditTotal float32 `json:"bonusesCreditTotal,omitempty"` + Discounts []ItemDiscount `json:"discounts,omitempty"` +} + +// MarkingObject type. +type MarkingObject struct { + Code string `json:"code,omitempty"` + Provider string `json:"provider,omitempty"` } type ItemDiscount struct { @@ -736,9 +880,11 @@ type Pack struct { // PackItem type. type PackItem struct { - ID int `json:"id,omitempty"` - Order *Order `json:"order,omitempty"` - Offer *Offer `json:"offer,omitempty"` + ID int `json:"id,omitempty"` + ExternalID string `json:"externalId,omitempty"` + ExternalIDs []CodeValueModel `json:"externalIds,omitempty"` + Order *Order `json:"order,omitempty"` + Offer *Offer `json:"offer,omitempty"` } // PacksHistoryRecord type. diff --git a/types_test.go b/types_test.go index 8c57a9c..330cdee 100644 --- a/types_test.go +++ b/types_test.go @@ -9,10 +9,10 @@ import ( func TestClient_OrderDeliveryData(t *testing.T) { d := OrderDeliveryData{ OrderDeliveryDataBasic: OrderDeliveryDataBasic{ - "track", - "status", - "address", - "type", + TrackNumber: "track", + Status: "status", + PickuppointAddress: "address", + PayerType: "type", }, } @@ -37,10 +37,10 @@ func TestClient_OrderDeliveryData(t *testing.T) { json.Unmarshal(data, &d) expected := OrderDeliveryData{ OrderDeliveryDataBasic: OrderDeliveryDataBasic{ - "track", - "status", - "address", - "type", + TrackNumber: "track", + Status: "status", + PickuppointAddress: "address", + PayerType: "type", }, AdditionalFields: map[string]interface{}{ "customFirst": "one", @@ -80,3 +80,65 @@ func TestCustomer_IsContactJSON(t *testing.T) { t.Fatalf("expected IsContact=true after unmarshal") } } + +func TestAPIMethodDTOFieldsJSON(t *testing.T) { + order := Order{ + Company: &Company{ID: 10, ExternalID: "company-ext"}, + LoyaltyEventDiscountID: 55, + IsFromCart: true, + Items: []OrderItem{{ + ExternalID: "item-ext", + ExternalIDs: []CodeValueModel{{Code: "marketplace", Value: "item-1"}}, + MarkingCodes: []string{"mark-1"}, + MarkingObjects: []MarkingObject{{Code: "mark-2", Provider: "chestny_znak"}}, + Ordering: 2, + }}, + Delivery: &OrderDelivery{ + Service: &OrderDeliveryService{DeliveryType: "courier"}, + Data: &OrderDeliveryData{OrderDeliveryDataBasic: OrderDeliveryDataBasic{ + ExternalID: "delivery-ext", + Cost: 100, + ExtraData: StringMap{"terminal": "A1"}, + ItemDeclaredValues: []DeliveryItemDeclaredValue{{ + OrderProduct: OrderProductIdentifier{ExternalID: "item-ext"}, + Value: 500, + }}, + Packages: []DeliveryPackage{{ + PackageID: "box-1", + Items: []DeliveryPackageItem{{ + OrderProduct: OrderProductIdentifier{ExternalID: "item-ext"}, + Quantity: 1, + }}, + }}, + }}, + }, + } + + data, err := json.Marshal(order) + if err != nil { + t.Fatalf("marshal order: %v", err) + } + + var payload map[string]interface{} + if err := json.Unmarshal(data, &payload); err != nil { + t.Fatalf("unmarshal order payload: %v", err) + } + + if _, ok := payload["company"]; !ok { + t.Fatalf("expected company in marshaled order: %s", data) + } + if payload["loyaltyEventDiscountId"].(float64) != 55 { + t.Fatalf("expected loyaltyEventDiscountId=55, got %#v", payload["loyaltyEventDiscountId"]) + } + if payload["isFromCart"] != true { + t.Fatalf("expected isFromCart=true, got %#v", payload["isFromCart"]) + } + + var decodedPack Pack + if err := json.Unmarshal([]byte(`{"item":{"id":1,"externalId":"item-ext","externalIds":[{"code":"marketplace","value":"item-1"}]}}`), &decodedPack); err != nil { + t.Fatalf("unmarshal pack: %v", err) + } + if decodedPack.Item == nil || decodedPack.Item.ExternalIDs[0].Code != "marketplace" { + t.Fatalf("expected pack item externalIds, got %#v", decodedPack.Item) + } +}