add some methods for creating/editing/getting products
This commit is contained in:
10
ENDPOINTS.md
10
ENDPOINTS.md
@@ -7,14 +7,14 @@
|
|||||||
|
|
||||||
## Uploading and updating products
|
## Uploading and updating products
|
||||||
- [x] Create or update a product
|
- [x] Create or update a product
|
||||||
- [ ] Get the product import status
|
- [x] Get the product import status
|
||||||
- [ ] Create a product by Ozon ID
|
- [x] Create a product by Ozon ID
|
||||||
- [ ] Upload and update product images
|
- [x] Upload and update product images
|
||||||
- [ ] Check products images uploading status
|
- [x] Check products images uploading status
|
||||||
- [x] List of products
|
- [x] List of products
|
||||||
- [x] Product details
|
- [x] Product details
|
||||||
- [x] Get products' content rating by SKU
|
- [x] Get products' content rating by SKU
|
||||||
- [ ] Get a list of products by identifiers
|
- [x] Get a list of products by identifiers
|
||||||
- [ ] Get a description of the product characteristics
|
- [ ] Get a description of the product characteristics
|
||||||
- [ ] Get product description
|
- [ ] Get product description
|
||||||
- [ ] Product range limit, limits on product creation and update
|
- [ ] Product range limit, limits on product creation and update
|
||||||
|
|||||||
705
ozon/products.go
705
ozon/products.go
@@ -105,225 +105,228 @@ type GetProductDetailsResponse struct {
|
|||||||
core.CommonResponse
|
core.CommonResponse
|
||||||
|
|
||||||
// Request results
|
// Request results
|
||||||
Result struct {
|
Result ProductDetails `json:"Result"`
|
||||||
// Barcode
|
|
||||||
Barcode string `json:"barcode"`
|
|
||||||
|
|
||||||
// All product barcodes
|
|
||||||
Barcodes []string `json:"barcodes"`
|
|
||||||
|
|
||||||
// Main offer price on Ozon.
|
|
||||||
//
|
|
||||||
// The field is deprecated. Returns an empty string ""
|
|
||||||
BuyboxPrice string `json:"buybox_price"`
|
|
||||||
|
|
||||||
// Category identifier
|
|
||||||
CategoryId int64 `json:"category_id"`
|
|
||||||
|
|
||||||
// Marketing color
|
|
||||||
ColorImage string `json:"color_image"`
|
|
||||||
|
|
||||||
// Commission fees details
|
|
||||||
Commissions []struct {
|
|
||||||
// Delivery cost
|
|
||||||
DeliveryAmount float64 `json:"deliveryAmount"`
|
|
||||||
|
|
||||||
// Minimum commission fee
|
|
||||||
MinValue float64 `json:"minValue"`
|
|
||||||
|
|
||||||
// Commission percentage
|
|
||||||
Percent float64 `json:"percent"`
|
|
||||||
|
|
||||||
// Return cost
|
|
||||||
ReturnAmount float64 `json:"returnAmount"`
|
|
||||||
|
|
||||||
// Sale scheme
|
|
||||||
SaleSchema string `json:"saleSchema"`
|
|
||||||
|
|
||||||
// Commission fee amount
|
|
||||||
Value float64 `json:"value"`
|
|
||||||
} `json:"commissions"`
|
|
||||||
|
|
||||||
// Date and time when the product was created
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
|
|
||||||
// SKU of the product that is sold from the Ozon warehouse (FBO)
|
|
||||||
FBOSKU int64 `json:"fbo_sku"`
|
|
||||||
|
|
||||||
// SKU of the product that is sold from the seller's warehouse (FBS and rFBS)
|
|
||||||
FBSSKU int64 `json:"fbs_sku"`
|
|
||||||
|
|
||||||
// Document generation task number
|
|
||||||
Id int64 `json:"id"`
|
|
||||||
|
|
||||||
// An array of links to images. The images in the array are arranged in the order of their arrangement on the site. If the `primary_image` parameter is not specified, the first image in the list is the main one for the product
|
|
||||||
Images []string `json:"images"`
|
|
||||||
|
|
||||||
// Main product image
|
|
||||||
PrimaryImage string `json:"primary_image"`
|
|
||||||
|
|
||||||
// Array of 360 images
|
|
||||||
Images360 []string `json:"images360"`
|
|
||||||
|
|
||||||
// true if the product has markdown equivalents at the Ozon warehouse
|
|
||||||
HasDiscountedItem bool `json:"has_discounted_item"`
|
|
||||||
|
|
||||||
// Indication of a markdown product:
|
|
||||||
//
|
|
||||||
// * true if the product was created by the seller as a markdown
|
|
||||||
//
|
|
||||||
// * false if the product is not markdown or was marked down by Ozon
|
|
||||||
IsDiscounted bool `json:"is_discounted"`
|
|
||||||
|
|
||||||
// Markdown products stocks
|
|
||||||
DiscountedStocks struct {
|
|
||||||
// Quantity of products to be supplied
|
|
||||||
Coming int32 `json:"coming"`
|
|
||||||
|
|
||||||
// Quantity of products in warehouse
|
|
||||||
Present int32 `json:"present"`
|
|
||||||
|
|
||||||
// Quantity of products reserved
|
|
||||||
Reserved int32 `json:"reserved"`
|
|
||||||
} `json:"discounted_stocks"`
|
|
||||||
|
|
||||||
// Indication of a bulky product
|
|
||||||
IsKGT bool `json:"is_kgt"`
|
|
||||||
|
|
||||||
// Indication of mandatory prepayment for the product:
|
|
||||||
//
|
|
||||||
// * true — to buy a product, you need to make a prepayment.
|
|
||||||
//
|
|
||||||
// * false—prepayment is not required
|
|
||||||
IsPrepayment bool `json:"is_prepayment"`
|
|
||||||
|
|
||||||
// If prepayment is possible, the value is true
|
|
||||||
IsPrepaymentAllowed bool `json:"is_prepayment_allowed"`
|
|
||||||
|
|
||||||
// Currency of your prices. It matches the currency set in the personal account settings
|
|
||||||
CurrencyCode string `json:"currency_code"`
|
|
||||||
|
|
||||||
// The price of the product including all promotion discounts. This value will be shown on the Ozon storefront
|
|
||||||
MarketingPrice string `json:"marketing_price"`
|
|
||||||
|
|
||||||
// Minimum price for similar products on Ozon.
|
|
||||||
//
|
|
||||||
// The field is deprecated. Returns an empty string ""
|
|
||||||
MinOzonPrice string `json:"min_ozon_price"`
|
|
||||||
|
|
||||||
// Minimum product price with all promotions applied
|
|
||||||
MinPrice string `json:"min_price"`
|
|
||||||
|
|
||||||
// Name
|
|
||||||
Name string `json:"name"`
|
|
||||||
|
|
||||||
// Product identifier in the seller's system
|
|
||||||
OfferId string `json:"offer_id"`
|
|
||||||
|
|
||||||
// Price before discounts. Displayed strikethrough on the product description page
|
|
||||||
OldPrice string `json:"old_price"`
|
|
||||||
|
|
||||||
// Price for customers with an Ozon Premium subscription
|
|
||||||
PremiumPrice string `json:"premium_price"`
|
|
||||||
|
|
||||||
// Product price including discounts. This value is shown on the product description page
|
|
||||||
Price string `json:"price"`
|
|
||||||
|
|
||||||
// Price index. Learn more in Help Center
|
|
||||||
PriceIndex string `json:"price_idnex"`
|
|
||||||
|
|
||||||
// Product price suggested by the system based on similar offers
|
|
||||||
RecommendedPrice string `json:"recommended_price"`
|
|
||||||
|
|
||||||
// Product state description
|
|
||||||
Status struct {
|
|
||||||
// Product state
|
|
||||||
State string `json:"state"`
|
|
||||||
|
|
||||||
// Product state on the transition to which an error occurred
|
|
||||||
StateFailed string `json:"state_failed"`
|
|
||||||
|
|
||||||
// Moderation status
|
|
||||||
ModerateStatus string `json:"moderate_status"`
|
|
||||||
|
|
||||||
// Product decline reasons
|
|
||||||
DeclineReasons []string `json:"decline_reasons"`
|
|
||||||
|
|
||||||
// Validation status
|
|
||||||
ValidationsState string `json:"validation_state"`
|
|
||||||
|
|
||||||
// Product status name
|
|
||||||
StateName string `json:"state_name"`
|
|
||||||
|
|
||||||
// Product state description
|
|
||||||
StateDescription string `json:"state_description"`
|
|
||||||
|
|
||||||
// Indiction that there were errors while creating products
|
|
||||||
IsFailed bool `json:"is_failed"`
|
|
||||||
|
|
||||||
// Indiction that the product was created
|
|
||||||
IsCreated bool `json:"is_created"`
|
|
||||||
|
|
||||||
// Tooltips for the current product state
|
|
||||||
StateTooltip string `json:"state_tooltip"`
|
|
||||||
|
|
||||||
// Product loading errors
|
|
||||||
ItemErrors []GetProductDetailsResponseItemError `json:"item_errors"`
|
|
||||||
|
|
||||||
// The last time product state changed
|
|
||||||
StateUpdatedAt time.Time `json:"state_updated_at"`
|
|
||||||
} `json:"status"`
|
|
||||||
|
|
||||||
// Details about the sources of similar offers. Learn more in Help Сenter
|
|
||||||
Sources []struct {
|
|
||||||
// Indication that the source is taken into account when calculating the market value
|
|
||||||
IsEnabled bool `json:"is_enabled"`
|
|
||||||
|
|
||||||
// Product identifier in the Ozon system, SKU
|
|
||||||
SKU int64 `json:"sku"`
|
|
||||||
|
|
||||||
// Link to the source
|
|
||||||
Source string `json:"source"`
|
|
||||||
} `json:"sources"`
|
|
||||||
|
|
||||||
// Details about product stocks
|
|
||||||
Stocks struct {
|
|
||||||
// Supply expected
|
|
||||||
Coming int32 `json:"coming"`
|
|
||||||
|
|
||||||
// Currently at the warehouse
|
|
||||||
Present int32 `json:"present"`
|
|
||||||
|
|
||||||
// Reserved
|
|
||||||
Reserved int32 `json:"reserved"`
|
|
||||||
} `json:"stocks"`
|
|
||||||
|
|
||||||
// Date of the last product update
|
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
|
|
||||||
// Product VAT rate
|
|
||||||
VAT string `json:"vat"`
|
|
||||||
|
|
||||||
// Product visibility settings
|
|
||||||
VisibilityDetails struct {
|
|
||||||
// If the product is active, the value is true
|
|
||||||
ActiveProduct bool `json:"active_product"`
|
|
||||||
|
|
||||||
// If the price is set, the value is true
|
|
||||||
HasPrice bool `json:"has_price"`
|
|
||||||
|
|
||||||
// If there is stock at the warehouses, the value is true
|
|
||||||
HasStock bool `json:"has_stock"`
|
|
||||||
} `json:"visibility_details"`
|
|
||||||
|
|
||||||
// If the product is on sale, the value is true
|
|
||||||
Visible bool `json:"visible"`
|
|
||||||
|
|
||||||
// Product volume weight
|
|
||||||
VolumeWeight float64 `json:"volume_weights"`
|
|
||||||
} `json:"Result"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProductDetails struct {
|
||||||
|
// Barcode
|
||||||
|
Barcode string `json:"barcode"`
|
||||||
|
|
||||||
|
// All product barcodes
|
||||||
|
Barcodes []string `json:"barcodes"`
|
||||||
|
|
||||||
|
// Main offer price on Ozon.
|
||||||
|
//
|
||||||
|
// The field is deprecated. Returns an empty string ""
|
||||||
|
BuyboxPrice string `json:"buybox_price"`
|
||||||
|
|
||||||
|
// Category identifier
|
||||||
|
CategoryId int64 `json:"category_id"`
|
||||||
|
|
||||||
|
// Marketing color
|
||||||
|
ColorImage string `json:"color_image"`
|
||||||
|
|
||||||
|
// Commission fees details
|
||||||
|
Commissions []struct {
|
||||||
|
// Delivery cost
|
||||||
|
DeliveryAmount float64 `json:"deliveryAmount"`
|
||||||
|
|
||||||
|
// Minimum commission fee
|
||||||
|
MinValue float64 `json:"minValue"`
|
||||||
|
|
||||||
|
// Commission percentage
|
||||||
|
Percent float64 `json:"percent"`
|
||||||
|
|
||||||
|
// Return cost
|
||||||
|
ReturnAmount float64 `json:"returnAmount"`
|
||||||
|
|
||||||
|
// Sale scheme
|
||||||
|
SaleSchema string `json:"saleSchema"`
|
||||||
|
|
||||||
|
// Commission fee amount
|
||||||
|
Value float64 `json:"value"`
|
||||||
|
} `json:"commissions"`
|
||||||
|
|
||||||
|
// Date and time when the product was created
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
|
||||||
|
// SKU of the product that is sold from the Ozon warehouse (FBO)
|
||||||
|
FBOSKU int64 `json:"fbo_sku"`
|
||||||
|
|
||||||
|
// SKU of the product that is sold from the seller's warehouse (FBS and rFBS)
|
||||||
|
FBSSKU int64 `json:"fbs_sku"`
|
||||||
|
|
||||||
|
// Document generation task number
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
|
||||||
|
// An array of links to images. The images in the array are arranged in the order of their arrangement on the site. If the `primary_image` parameter is not specified, the first image in the list is the main one for the product
|
||||||
|
Images []string `json:"images"`
|
||||||
|
|
||||||
|
// Main product image
|
||||||
|
PrimaryImage string `json:"primary_image"`
|
||||||
|
|
||||||
|
// Array of 360 images
|
||||||
|
Images360 []string `json:"images360"`
|
||||||
|
|
||||||
|
// true if the product has markdown equivalents at the Ozon warehouse
|
||||||
|
HasDiscountedItem bool `json:"has_discounted_item"`
|
||||||
|
|
||||||
|
// Indication of a markdown product:
|
||||||
|
//
|
||||||
|
// * true if the product was created by the seller as a markdown
|
||||||
|
//
|
||||||
|
// * false if the product is not markdown or was marked down by Ozon
|
||||||
|
IsDiscounted bool `json:"is_discounted"`
|
||||||
|
|
||||||
|
// Markdown products stocks
|
||||||
|
DiscountedStocks ProductDiscountedStocks `json:"discounted_stocks"`
|
||||||
|
|
||||||
|
// Indication of a bulky product
|
||||||
|
IsKGT bool `json:"is_kgt"`
|
||||||
|
|
||||||
|
// Indication of mandatory prepayment for the product:
|
||||||
|
//
|
||||||
|
// * true — to buy a product, you need to make a prepayment.
|
||||||
|
//
|
||||||
|
// * false—prepayment is not required
|
||||||
|
IsPrepayment bool `json:"is_prepayment"`
|
||||||
|
|
||||||
|
// If prepayment is possible, the value is true
|
||||||
|
IsPrepaymentAllowed bool `json:"is_prepayment_allowed"`
|
||||||
|
|
||||||
|
// Currency of your prices. It matches the currency set in the personal account settings
|
||||||
|
CurrencyCode string `json:"currency_code"`
|
||||||
|
|
||||||
|
// The price of the product including all promotion discounts. This value will be shown on the Ozon storefront
|
||||||
|
MarketingPrice string `json:"marketing_price"`
|
||||||
|
|
||||||
|
// Minimum price for similar products on Ozon.
|
||||||
|
//
|
||||||
|
// The field is deprecated. Returns an empty string ""
|
||||||
|
MinOzonPrice string `json:"min_ozon_price"`
|
||||||
|
|
||||||
|
// Minimum product price with all promotions applied
|
||||||
|
MinPrice string `json:"min_price"`
|
||||||
|
|
||||||
|
// Name
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Product identifier in the seller's system
|
||||||
|
OfferId string `json:"offer_id"`
|
||||||
|
|
||||||
|
// Price before discounts. Displayed strikethrough on the product description page
|
||||||
|
OldPrice string `json:"old_price"`
|
||||||
|
|
||||||
|
// Price for customers with an Ozon Premium subscription
|
||||||
|
PremiumPrice string `json:"premium_price"`
|
||||||
|
|
||||||
|
// Product price including discounts. This value is shown on the product description page
|
||||||
|
Price string `json:"price"`
|
||||||
|
|
||||||
|
// Price index. Learn more in Help Center
|
||||||
|
PriceIndex string `json:"price_idnex"`
|
||||||
|
|
||||||
|
// Product price suggested by the system based on similar offers
|
||||||
|
RecommendedPrice string `json:"recommended_price"`
|
||||||
|
|
||||||
|
// Product state description
|
||||||
|
Status struct {
|
||||||
|
// Product state
|
||||||
|
State string `json:"state"`
|
||||||
|
|
||||||
|
// Product state on the transition to which an error occurred
|
||||||
|
StateFailed string `json:"state_failed"`
|
||||||
|
|
||||||
|
// Moderation status
|
||||||
|
ModerateStatus string `json:"moderate_status"`
|
||||||
|
|
||||||
|
// Product decline reasons
|
||||||
|
DeclineReasons []string `json:"decline_reasons"`
|
||||||
|
|
||||||
|
// Validation status
|
||||||
|
ValidationsState string `json:"validation_state"`
|
||||||
|
|
||||||
|
// Product status name
|
||||||
|
StateName string `json:"state_name"`
|
||||||
|
|
||||||
|
// Product state description
|
||||||
|
StateDescription string `json:"state_description"`
|
||||||
|
|
||||||
|
// Indiction that there were errors while creating products
|
||||||
|
IsFailed bool `json:"is_failed"`
|
||||||
|
|
||||||
|
// Indiction that the product was created
|
||||||
|
IsCreated bool `json:"is_created"`
|
||||||
|
|
||||||
|
// Tooltips for the current product state
|
||||||
|
StateTooltip string `json:"state_tooltip"`
|
||||||
|
|
||||||
|
// Product loading errors
|
||||||
|
ItemErrors []GetProductDetailsResponseItemError `json:"item_errors"`
|
||||||
|
|
||||||
|
// The last time product state changed
|
||||||
|
StateUpdatedAt time.Time `json:"state_updated_at"`
|
||||||
|
} `json:"status"`
|
||||||
|
|
||||||
|
// Details about the sources of similar offers. Learn more in Help Сenter
|
||||||
|
Sources []struct {
|
||||||
|
// Indication that the source is taken into account when calculating the market value
|
||||||
|
IsEnabled bool `json:"is_enabled"`
|
||||||
|
|
||||||
|
// Product identifier in the Ozon system, SKU
|
||||||
|
SKU int64 `json:"sku"`
|
||||||
|
|
||||||
|
// Link to the source
|
||||||
|
Source string `json:"source"`
|
||||||
|
} `json:"sources"`
|
||||||
|
|
||||||
|
// Details about product stocks
|
||||||
|
Stocks struct {
|
||||||
|
// Supply expected
|
||||||
|
Coming int32 `json:"coming"`
|
||||||
|
|
||||||
|
// Currently at the warehouse
|
||||||
|
Present int32 `json:"present"`
|
||||||
|
|
||||||
|
// Reserved
|
||||||
|
Reserved int32 `json:"reserved"`
|
||||||
|
} `json:"stocks"`
|
||||||
|
|
||||||
|
// Date of the last product update
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
|
||||||
|
// Product VAT rate
|
||||||
|
VAT string `json:"vat"`
|
||||||
|
|
||||||
|
// Product visibility settings
|
||||||
|
VisibilityDetails struct {
|
||||||
|
// If the product is active, the value is true
|
||||||
|
ActiveProduct bool `json:"active_product"`
|
||||||
|
|
||||||
|
// If the price is set, the value is true
|
||||||
|
HasPrice bool `json:"has_price"`
|
||||||
|
|
||||||
|
// If there is stock at the warehouses, the value is true
|
||||||
|
HasStock bool `json:"has_stock"`
|
||||||
|
} `json:"visibility_details"`
|
||||||
|
|
||||||
|
// If the product is on sale, the value is true
|
||||||
|
Visible bool `json:"visible"`
|
||||||
|
|
||||||
|
// Product volume weight
|
||||||
|
VolumeWeight float64 `json:"volume_weights"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductDiscountedStocks struct {
|
||||||
|
// Quantity of products to be supplied
|
||||||
|
Coming int32 `json:"coming"`
|
||||||
|
|
||||||
|
// Quantity of products in warehouse
|
||||||
|
Present int32 `json:"present"`
|
||||||
|
|
||||||
|
// Quantity of products reserved
|
||||||
|
Reserved int32 `json:"reserved"`
|
||||||
|
}
|
||||||
type GetProductDetailsResponseItemError struct {
|
type GetProductDetailsResponseItemError struct {
|
||||||
// Error code
|
// Error code
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
@@ -927,3 +930,271 @@ func (c Products) GetProductsRatingBySKU(params *GetProductsRatingBySKUParams) (
|
|||||||
|
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetProductImportStatusParams struct {
|
||||||
|
// Importing products task code
|
||||||
|
TaskId int64 `json:"task_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetProductImportStatusResponse struct {
|
||||||
|
core.CommonResponse
|
||||||
|
|
||||||
|
// Method result
|
||||||
|
Result struct {
|
||||||
|
// Product details
|
||||||
|
Items []struct {
|
||||||
|
// Product identifier in the seller's system.
|
||||||
|
//
|
||||||
|
// The maximum length of a string is 50 characters
|
||||||
|
OfferId string `json:"offer_id"`
|
||||||
|
|
||||||
|
// Product identifier
|
||||||
|
ProductId int64 `json:"product_id"`
|
||||||
|
|
||||||
|
// Product creation status. Product information is processed in queues. Possible parameter values:
|
||||||
|
// - pending — product in the processing queue;
|
||||||
|
// - imported — product loaded successfully;
|
||||||
|
// - failed — product loaded with errors
|
||||||
|
Status string `json:"status"`
|
||||||
|
|
||||||
|
// Array of errors
|
||||||
|
Errors []struct {
|
||||||
|
GetProductDetailsResponseItemError
|
||||||
|
|
||||||
|
// Error technical description
|
||||||
|
Message string `json:"message"`
|
||||||
|
} `json:"errors"`
|
||||||
|
} `json:"items"`
|
||||||
|
|
||||||
|
// Product identifier in the seller's system
|
||||||
|
Total int32 `json:"total"`
|
||||||
|
} `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allows you to get the status of a product description page creation process
|
||||||
|
func (c Products) GetProductImportStatus(params *GetProductImportStatusParams) (*GetProductImportStatusResponse, error) {
|
||||||
|
url := "/v1/product/import/info"
|
||||||
|
|
||||||
|
resp := &GetProductImportStatusResponse{}
|
||||||
|
|
||||||
|
response, err := c.client.Request(http.MethodPost, url, params, resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.CopyCommonResponse(&resp.CommonResponse)
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateProductByOzonIDParams struct {
|
||||||
|
// Products details
|
||||||
|
Items []CreateProductsByOzonIDItem `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateProductsByOzonIDItem struct {
|
||||||
|
// Product name. Up to 500 characters
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Product identifier in the seller's system.
|
||||||
|
//
|
||||||
|
// The maximum length of a string is 50 characters
|
||||||
|
OfferId string `json:"offer_id"`
|
||||||
|
|
||||||
|
// Price before discounts. Displayed strikethrough on the product description page. Specified in rubles.
|
||||||
|
// The fractional part is separated by decimal point, up to two digits after the decimal point
|
||||||
|
OldPrice string `json:"old_price"`
|
||||||
|
|
||||||
|
// Price for customers with an Ozon Premium subscription
|
||||||
|
PremiumPrice string `json:"premium_price"`
|
||||||
|
|
||||||
|
// Product price including discounts. This value is shown on the product description page.
|
||||||
|
// If there are no discounts, pass the old_price value in this parameter
|
||||||
|
Price string `json:"price"`
|
||||||
|
|
||||||
|
// Currency of your prices. The passed value must be the same as the one set in the personal account settings.
|
||||||
|
// By default, the passed value is RUB, Russian ruble.
|
||||||
|
//
|
||||||
|
// For example, if your currency set in the settings is yuan, pass the value CNY, otherwise an error will be returned
|
||||||
|
CurrencyCode string `json:"currency_code"`
|
||||||
|
|
||||||
|
// Product identifier in the Ozon system, SKU
|
||||||
|
SKU int64 `json:"sku"`
|
||||||
|
|
||||||
|
// VAT rate for the product:
|
||||||
|
// - 0 — not subject to VAT,
|
||||||
|
// - 0.1 — 10%,
|
||||||
|
// - 0.2 — 20%
|
||||||
|
VAT string `json:"vat"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateProductByOzonIDResponse struct {
|
||||||
|
core.CommonResponse
|
||||||
|
|
||||||
|
// Products import task code
|
||||||
|
TaskId int64 `json:"task_id"`
|
||||||
|
|
||||||
|
// Products identifiers list
|
||||||
|
UnmatchedSKUList []int64 `json:"unmatched_sku_list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a product by the specified Ozon ID. The number of products is unlimited.
|
||||||
|
//
|
||||||
|
// It's not possible to update products using Ozon ID
|
||||||
|
func (c Products) CreateProductByOzonID(params *CreateProductByOzonIDParams) (*CreateProductByOzonIDResponse, error) {
|
||||||
|
url := "/v1/product/import-by-sku"
|
||||||
|
|
||||||
|
resp := &CreateProductByOzonIDResponse{}
|
||||||
|
|
||||||
|
response, err := c.client.Request(http.MethodPost, url, params, resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.CopyCommonResponse(&resp.CommonResponse)
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateProductImagesParams struct {
|
||||||
|
// Marketing color
|
||||||
|
ColorImage string `json:"color_image"`
|
||||||
|
|
||||||
|
// Array of links to images. The images in the array are arranged in the order of their arrangement on the site.
|
||||||
|
// The first image in the list is the main one for the product.
|
||||||
|
//
|
||||||
|
// Pass links to images in the public cloud storage. The image format is JPG
|
||||||
|
Images []string `json:"images"`
|
||||||
|
|
||||||
|
// Array of 360 images—up to 70 files
|
||||||
|
Images360 []string `json:"images360"`
|
||||||
|
|
||||||
|
// Product identfier
|
||||||
|
ProductId int64 `json:"product_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductInfoResponse struct {
|
||||||
|
core.CommonResponse
|
||||||
|
|
||||||
|
// Method result
|
||||||
|
Result struct {
|
||||||
|
// Pictures
|
||||||
|
Pictures []struct {
|
||||||
|
// Attribute of a 360 image
|
||||||
|
Is360 bool `json:"is_360"`
|
||||||
|
|
||||||
|
// Attribute of a marketing color
|
||||||
|
IsColor bool `json:"is_color"`
|
||||||
|
|
||||||
|
// Attribute of a marketing color
|
||||||
|
IsPrimary bool `json:"is_primary"`
|
||||||
|
|
||||||
|
// Product identifier
|
||||||
|
ProductId int64 `json:"product_id"`
|
||||||
|
|
||||||
|
// Image uploading status.
|
||||||
|
//
|
||||||
|
// If the `/v1/product/pictures/import` method was called, the response will always be imported—image not processed.
|
||||||
|
// To see the final status, call the `/v1/product/pictures/info` method after about 10 seconds.
|
||||||
|
//
|
||||||
|
// If you called the `/v1/product/pictures/info` method, one of the statuses will appear:
|
||||||
|
// - uploaded — image uploaded;
|
||||||
|
// - failed — image was not uploaded
|
||||||
|
State string `json:"state"`
|
||||||
|
|
||||||
|
// The link to the image in the public cloud storage. The image format is JPG or PNG
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"pictures"`
|
||||||
|
} `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// The method for uploading and updating product images.
|
||||||
|
//
|
||||||
|
// Each time you call the method, pass all the images that should be on the product description page.
|
||||||
|
// For example, if you call a method and upload 10 images,
|
||||||
|
// and then call the method a second time and load one imahe, then all 10 previous ones will be erased.
|
||||||
|
//
|
||||||
|
// To upload image, pass a link to it in a public cloud storage. The image format is JPG or PNG.
|
||||||
|
//
|
||||||
|
// Arrange the pictures in the images array as you want to see them on the site.
|
||||||
|
// The first picture in the array will be the main one for the product.
|
||||||
|
//
|
||||||
|
// You can upload up to 15 pictures for each product.
|
||||||
|
//
|
||||||
|
// To upload 360 images, use the images360 field, and to upload a marketing color use color_image.
|
||||||
|
//
|
||||||
|
// If you want to add, remove, or replace some images, or change their order,
|
||||||
|
// first get the details using `/v2/product/info` or `/v2/product/info/list` methods.
|
||||||
|
// Using them you can get the current list of images and their order.
|
||||||
|
// Copy the data from the images, images360, and color_image fields and make the necessary changes to it
|
||||||
|
func (c Products) UpdateProductImages(params *UpdateProductImagesParams) (*ProductInfoResponse, error) {
|
||||||
|
url := "/v1/product/pictures/import"
|
||||||
|
|
||||||
|
resp := &ProductInfoResponse{}
|
||||||
|
|
||||||
|
response, err := c.client.Request(http.MethodPost, url, params, resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.CopyCommonResponse(&resp.CommonResponse)
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type CheckImageUploadingStatusParams struct {
|
||||||
|
// Product identifiers list
|
||||||
|
ProductId []int64 `json:"product_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check products images uploading status
|
||||||
|
func (c Products) CheckImageUploadingStatus(params *CheckImageUploadingStatusParams) (*ProductInfoResponse, error) {
|
||||||
|
url := "/v1/product/pictures/info"
|
||||||
|
|
||||||
|
resp := &ProductInfoResponse{}
|
||||||
|
|
||||||
|
response, err := c.client.Request(http.MethodPost, url, params, resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.CopyCommonResponse(&resp.CommonResponse)
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListProductsByIDsParams struct {
|
||||||
|
// Product identifier in the seller's system
|
||||||
|
OfferId []string `json:"offer_id"`
|
||||||
|
|
||||||
|
// Product identifier
|
||||||
|
ProductId []int64 `json:"product_id"`
|
||||||
|
|
||||||
|
// Product identifier in the Ozon system, SKU
|
||||||
|
SKU []int64 `json:"sku"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListProductsByIDsResponse struct {
|
||||||
|
core.CommonResponse
|
||||||
|
|
||||||
|
// Request results
|
||||||
|
Result struct {
|
||||||
|
// Data array
|
||||||
|
Items []ProductDetails `json:"items"`
|
||||||
|
} `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method for getting an array of products by their identifiers.
|
||||||
|
//
|
||||||
|
// The request body must contain an array of identifiers of the same type. The response will contain an items array.
|
||||||
|
//
|
||||||
|
// For each shipment in the items array the fields match the ones recieved in the /v2/product/info method
|
||||||
|
func (c Products) ListProductsByIDs(params *ListProductsByIDsParams) (*ListProductsByIDsResponse, error) {
|
||||||
|
url := "/v2/product/info/list"
|
||||||
|
|
||||||
|
resp := &ListProductsByIDsResponse{}
|
||||||
|
|
||||||
|
response, err := c.client.Request(http.MethodPost, url, params, resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.CopyCommonResponse(&resp.CommonResponse)
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1006,3 +1006,472 @@ func TestGetProductsRatingBySKU(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetProductImportStatus(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
statusCode int
|
||||||
|
headers map[string]string
|
||||||
|
params *GetProductImportStatusParams
|
||||||
|
response string
|
||||||
|
}{
|
||||||
|
// Test Ok
|
||||||
|
{
|
||||||
|
http.StatusOK,
|
||||||
|
map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
|
||||||
|
&GetProductImportStatusParams{
|
||||||
|
TaskId: 172549793,
|
||||||
|
},
|
||||||
|
`{
|
||||||
|
"result": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"offer_id": "143210608",
|
||||||
|
"product_id": 137285792,
|
||||||
|
"status": "imported",
|
||||||
|
"errors": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 1
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
// Test No Client-Id or Api-Key
|
||||||
|
{
|
||||||
|
http.StatusUnauthorized,
|
||||||
|
map[string]string{},
|
||||||
|
&GetProductImportStatusParams{},
|
||||||
|
`{
|
||||||
|
"code": 16,
|
||||||
|
"message": "Client-Id and Api-Key headers are required"
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers))
|
||||||
|
|
||||||
|
resp, err := c.Products().GetProductImportStatus(test.params)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != test.statusCode {
|
||||||
|
t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
if len(resp.Result.Items) > 0 {
|
||||||
|
if resp.Result.Items[0].ProductId == 0 {
|
||||||
|
t.Errorf("Product id cannot be 0")
|
||||||
|
}
|
||||||
|
if resp.Result.Items[0].OfferId == "" {
|
||||||
|
t.Errorf("Offer id cannot be empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateProductByOzonID(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
statusCode int
|
||||||
|
headers map[string]string
|
||||||
|
params *CreateProductByOzonIDParams
|
||||||
|
response string
|
||||||
|
}{
|
||||||
|
// Test Ok
|
||||||
|
{
|
||||||
|
http.StatusOK,
|
||||||
|
map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
|
||||||
|
&CreateProductByOzonIDParams{
|
||||||
|
Items: []CreateProductsByOzonIDItem{
|
||||||
|
{
|
||||||
|
Name: "string",
|
||||||
|
OfferId: "91132",
|
||||||
|
OldPrice: "2590",
|
||||||
|
Price: "2300",
|
||||||
|
PremiumPrice: "2200",
|
||||||
|
CurrencyCode: "RUB",
|
||||||
|
SKU: 298789742,
|
||||||
|
VAT: "0.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
`{
|
||||||
|
"result": {
|
||||||
|
"task_id": 176594213,
|
||||||
|
"unmatched_sku_list": []
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
// Test No Client-Id or Api-Key
|
||||||
|
{
|
||||||
|
http.StatusUnauthorized,
|
||||||
|
map[string]string{},
|
||||||
|
&CreateProductByOzonIDParams{},
|
||||||
|
`{
|
||||||
|
"code": 16,
|
||||||
|
"message": "Client-Id and Api-Key headers are required"
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers))
|
||||||
|
|
||||||
|
resp, err := c.Products().CreateProductByOzonID(test.params)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != test.statusCode {
|
||||||
|
t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateProductImages(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
statusCode int
|
||||||
|
headers map[string]string
|
||||||
|
params *UpdateProductImagesParams
|
||||||
|
response string
|
||||||
|
}{
|
||||||
|
// Test Ok
|
||||||
|
{
|
||||||
|
http.StatusOK,
|
||||||
|
map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
|
||||||
|
&UpdateProductImagesParams{
|
||||||
|
ColorImage: "string",
|
||||||
|
Images: []string{"string"},
|
||||||
|
Images360: []string{"string"},
|
||||||
|
ProductId: 12345,
|
||||||
|
},
|
||||||
|
`{
|
||||||
|
"result": {
|
||||||
|
"pictures": [
|
||||||
|
{
|
||||||
|
"is_360": true,
|
||||||
|
"is_color": true,
|
||||||
|
"is_primary": true,
|
||||||
|
"product_id": 12345,
|
||||||
|
"state": "string",
|
||||||
|
"url": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"is_360": false,
|
||||||
|
"is_color": true,
|
||||||
|
"is_primary": true,
|
||||||
|
"product_id": 12345,
|
||||||
|
"state": "string",
|
||||||
|
"url": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
// Test No Client-Id or Api-Key
|
||||||
|
{
|
||||||
|
http.StatusUnauthorized,
|
||||||
|
map[string]string{},
|
||||||
|
&UpdateProductImagesParams{},
|
||||||
|
`{
|
||||||
|
"code": 16,
|
||||||
|
"message": "Client-Id and Api-Key headers are required"
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers))
|
||||||
|
|
||||||
|
resp, err := c.Products().UpdateProductImages(test.params)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != test.statusCode {
|
||||||
|
t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
if len(resp.Result.Pictures) != len(test.params.Images)+len(test.params.Images360) {
|
||||||
|
t.Errorf("Amount of pictures in request and response are not equal")
|
||||||
|
}
|
||||||
|
if len(resp.Result.Pictures) > 0 {
|
||||||
|
if resp.Result.Pictures[0].ProductId != test.params.ProductId {
|
||||||
|
t.Errorf("Product ids in request and response are not equal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckImageUploadingStatus(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
statusCode int
|
||||||
|
headers map[string]string
|
||||||
|
params *CheckImageUploadingStatusParams
|
||||||
|
response string
|
||||||
|
}{
|
||||||
|
// Test Ok
|
||||||
|
{
|
||||||
|
http.StatusOK,
|
||||||
|
map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
|
||||||
|
&CheckImageUploadingStatusParams{
|
||||||
|
ProductId: []int64{123456},
|
||||||
|
},
|
||||||
|
`{
|
||||||
|
"result": {
|
||||||
|
"pictures": [
|
||||||
|
{
|
||||||
|
"is_360": true,
|
||||||
|
"is_color": true,
|
||||||
|
"is_primary": true,
|
||||||
|
"product_id": 123456,
|
||||||
|
"state": "string",
|
||||||
|
"url": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
// Test No Client-Id or Api-Key
|
||||||
|
{
|
||||||
|
http.StatusUnauthorized,
|
||||||
|
map[string]string{},
|
||||||
|
&CheckImageUploadingStatusParams{},
|
||||||
|
`{
|
||||||
|
"code": 16,
|
||||||
|
"message": "Client-Id and Api-Key headers are required"
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers))
|
||||||
|
|
||||||
|
resp, err := c.Products().CheckImageUploadingStatus(test.params)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != test.statusCode {
|
||||||
|
t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
if len(resp.Result.Pictures) > 0 {
|
||||||
|
if resp.Result.Pictures[0].ProductId != test.params.ProductId[0] {
|
||||||
|
t.Errorf("Product ids in request and response are not equal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListProductsByIDs(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
statusCode int
|
||||||
|
headers map[string]string
|
||||||
|
params *ListProductsByIDsParams
|
||||||
|
response string
|
||||||
|
}{
|
||||||
|
// Test Ok
|
||||||
|
{
|
||||||
|
http.StatusOK,
|
||||||
|
map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
|
||||||
|
&ListProductsByIDsParams{
|
||||||
|
OfferId: []string{"010", "23"},
|
||||||
|
},
|
||||||
|
`{
|
||||||
|
"result": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": 78712196,
|
||||||
|
"name": "Как выбрать детские музыкальные инструменты. Ксилофон, бубен, маракасы и другие инструменты для детей до 6 лет. Мастер-класс о раннем музыкальном развитии от Монтессори-педагога",
|
||||||
|
"offer_id": "010",
|
||||||
|
"barcode": "",
|
||||||
|
"barcodes": [
|
||||||
|
"2335900005",
|
||||||
|
"7533900005"
|
||||||
|
],
|
||||||
|
"buybox_price": "",
|
||||||
|
"category_id": 93726157,
|
||||||
|
"created_at": "2021-06-03T03:40:05.871465Z",
|
||||||
|
"images": [],
|
||||||
|
"has_discounted_item": true,
|
||||||
|
"is_discounted": true,
|
||||||
|
"discounted_stocks": {
|
||||||
|
"coming": 0,
|
||||||
|
"present": 0,
|
||||||
|
"reserved": 0
|
||||||
|
},
|
||||||
|
"currency_code": "RUB",
|
||||||
|
"marketing_price": "",
|
||||||
|
"min_price": "",
|
||||||
|
"old_price": "1000.0000",
|
||||||
|
"premium_price": "590.0000",
|
||||||
|
"price": "690.0000",
|
||||||
|
"recommended_price": "",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"is_enabled": true,
|
||||||
|
"sku": 269628393,
|
||||||
|
"source": "fbo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"is_enabled": true,
|
||||||
|
"sku": 269628396,
|
||||||
|
"source": "fbs"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"state": "",
|
||||||
|
"stocks": {
|
||||||
|
"coming": 0,
|
||||||
|
"present": 13,
|
||||||
|
"reserved": 0
|
||||||
|
},
|
||||||
|
"errors": [],
|
||||||
|
"updated_at": "2023-02-09T06:46:44.152Z",
|
||||||
|
"vat": "0.0",
|
||||||
|
"visible": true,
|
||||||
|
"visibility_details": {
|
||||||
|
"has_price": false,
|
||||||
|
"has_stock": true,
|
||||||
|
"active_product": false,
|
||||||
|
"reasons": {}
|
||||||
|
},
|
||||||
|
"price_index": "0.00",
|
||||||
|
"images360": [],
|
||||||
|
"is_kgt": false,
|
||||||
|
"color_image": "",
|
||||||
|
"primary_image": "https://cdn1.ozone.ru/s3/multimedia-y/6077810038.jpg",
|
||||||
|
"status": {
|
||||||
|
"state": "price_sent",
|
||||||
|
"state_failed": "",
|
||||||
|
"moderate_status": "approved",
|
||||||
|
"decline_reasons": [],
|
||||||
|
"validation_state": "success",
|
||||||
|
"state_name": "Продается",
|
||||||
|
"state_description": "",
|
||||||
|
"is_failed": false,
|
||||||
|
"is_created": true,
|
||||||
|
"state_tooltip": "",
|
||||||
|
"item_errors": [],
|
||||||
|
"state_updated_at": "2021-07-26T04:50:08.486697Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 76723583,
|
||||||
|
"name": "Онлайн-курс по дрессировке собак \"Собака: инструкция по применению. Одинокий волк\"",
|
||||||
|
"offer_id": "23",
|
||||||
|
"barcode": "",
|
||||||
|
"buybox_price": "",
|
||||||
|
"category_id": 90635895,
|
||||||
|
"created_at": "2021-05-26T20:26:07.565586Z",
|
||||||
|
"images": [],
|
||||||
|
"marketing_price": "",
|
||||||
|
"min_price": "",
|
||||||
|
"old_price": "12200.0000",
|
||||||
|
"premium_price": "5490.0000",
|
||||||
|
"price": "6100.0000",
|
||||||
|
"recommended_price": "",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"is_enabled": true,
|
||||||
|
"sku": 267684495,
|
||||||
|
"source": "fbo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"is_enabled": true,
|
||||||
|
"sku": 267684498,
|
||||||
|
"source": "fbs"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"state": "",
|
||||||
|
"stocks": {
|
||||||
|
"coming": 0,
|
||||||
|
"present": 19,
|
||||||
|
"reserved": 0
|
||||||
|
},
|
||||||
|
"errors": [],
|
||||||
|
"updated_at": "2023-02-09T06:46:44.152Z",
|
||||||
|
"vat": "0.0",
|
||||||
|
"visible": true,
|
||||||
|
"visibility_details": {
|
||||||
|
"has_price": false,
|
||||||
|
"has_stock": true,
|
||||||
|
"active_product": false,
|
||||||
|
"reasons": {}
|
||||||
|
},
|
||||||
|
"price_index": "0.00",
|
||||||
|
"images360": [],
|
||||||
|
"is_kgt": false,
|
||||||
|
"color_image": "",
|
||||||
|
"primary_image": "https://cdn1.ozone.ru/s3/multimedia-v/6062554531.jpg",
|
||||||
|
"status": {
|
||||||
|
"state": "price_sent",
|
||||||
|
"state_failed": "",
|
||||||
|
"moderate_status": "approved",
|
||||||
|
"decline_reasons": [],
|
||||||
|
"validation_state": "success",
|
||||||
|
"state_name": "Продается",
|
||||||
|
"state_description": "",
|
||||||
|
"is_failed": false,
|
||||||
|
"is_created": true,
|
||||||
|
"state_tooltip": "",
|
||||||
|
"item_errors": [],
|
||||||
|
"state_updated_at": "2021-05-31T12:35:09.714641Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
// Test No Client-Id or Api-Key
|
||||||
|
{
|
||||||
|
http.StatusUnauthorized,
|
||||||
|
map[string]string{},
|
||||||
|
&ListProductsByIDsParams{},
|
||||||
|
`{
|
||||||
|
"code": 16,
|
||||||
|
"message": "Client-Id and Api-Key headers are required"
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers))
|
||||||
|
|
||||||
|
resp, err := c.Products().ListProductsByIDs(test.params)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != test.statusCode {
|
||||||
|
t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
if len(resp.Result.Items) != len(test.params.OfferId) {
|
||||||
|
t.Errorf("Amount of offer ids in request and response are not equal")
|
||||||
|
}
|
||||||
|
if len(resp.Result.Items) > 0 {
|
||||||
|
if resp.Result.Items[0].OfferId != test.params.OfferId[0] {
|
||||||
|
t.Errorf("Offer ids in request and response are not equal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user