Compare commits
	
		
			30 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a1c92ae26f | ||
| 
						 | 
					08180d901c | ||
| 
						 | 
					838f28d3d9 | ||
| 
						 | 
					226f40275a | ||
| 
						 | 
					4139692ac3 | ||
| 
						 | 
					3507be6ec2 | ||
| 
						 | 
					9990719060 | ||
| 
						 | 
					18470fcae5 | ||
| 
						 | 
					3af6ad40c5 | ||
| 
						 | 
					89816cb239 | ||
| 
						 | 
					3f1f0711c8 | ||
| 
						 | 
					6b921ad101 | ||
| 
						 | 
					021a577bf9 | ||
| 
						 | 
					c1661f8cb9 | ||
| 
						 | 
					098b257746 | ||
| 
						 | 
					9effb88b5f | ||
| 
						 | 
					533a2439de | ||
| 
						 | 
					9875a196e9 | ||
| 
						 | 
					9f7c22237c | ||
| 
						 | 
					5fb08c30cb | ||
| 
						 | 
					c307bc31bd | ||
| 
						 | 
					f108c846b0 | ||
| 
						 | 
					9592e3a2d3 | ||
| 
						 | 
					7b4ed2a988 | ||
| 
						 | 
					ec7ea5e1ef | ||
| 
						 | 
					da9bedf63b | ||
| 
						 | 
					0fe3d86c48 | ||
| 
						 | 
					159e1501df | ||
| 
						 | 
					1d6a3f3eb8 | ||
| 
						 | 
					466cbc6379 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +1,2 @@
 | 
			
		||||
*.out
 | 
			
		||||
mistakes.md
 | 
			
		||||
							
								
								
									
										211
									
								
								ENDPOINTS.md
									
									
									
									
									
								
							
							
						
						
									
										211
									
								
								ENDPOINTS.md
									
									
									
									
									
								
							@@ -1,30 +1,30 @@
 | 
			
		||||
# Supported Endpoints
 | 
			
		||||
 | 
			
		||||
## Ozon attributes and characteristics
 | 
			
		||||
- [ ] Product category tree
 | 
			
		||||
- [ ] Category characteristics list
 | 
			
		||||
- [ ] Characteristics value directory
 | 
			
		||||
- [x] Product category tree
 | 
			
		||||
- [x] Category characteristics list
 | 
			
		||||
- [x] Characteristics value directory
 | 
			
		||||
 | 
			
		||||
## Uploading and updating products
 | 
			
		||||
- [x] Create or update a product
 | 
			
		||||
- [ ] Get the product import status
 | 
			
		||||
- [ ] Create a product by Ozon ID
 | 
			
		||||
- [ ] Upload and update product images
 | 
			
		||||
- [ ] Check products images uploading status
 | 
			
		||||
- [x] Get the product import status
 | 
			
		||||
- [x] Create a product by Ozon ID
 | 
			
		||||
- [x] Upload and update product images
 | 
			
		||||
- [x] Check products images uploading status
 | 
			
		||||
- [x] List of products
 | 
			
		||||
- [x] Product details
 | 
			
		||||
- [x] Get products' content rating by SKU
 | 
			
		||||
- [ ] Get a list of products by identifiers
 | 
			
		||||
- [ ] Get a description of the product characteristics
 | 
			
		||||
- [ ] Get product description
 | 
			
		||||
- [ ] Product range limit, limits on product creation and update
 | 
			
		||||
- [ ] Change product identifiers from the seller's system
 | 
			
		||||
- [ ] Archive a product
 | 
			
		||||
- [ ] Unarchive a product
 | 
			
		||||
- [ ] Remove a product without an SKU from the archive
 | 
			
		||||
- [ ] Get a list of geo-restrictions for services
 | 
			
		||||
- [ ] Upload activation codes for services and digital products
 | 
			
		||||
- [ ] Status of uploading activation codes
 | 
			
		||||
- [x] Get a list of products by identifiers
 | 
			
		||||
- [x] Get a description of the product characteristics
 | 
			
		||||
- [x] Get product description
 | 
			
		||||
- [x] Product range limit, limits on product creation and update
 | 
			
		||||
- [x] Change product identifiers from the seller's system
 | 
			
		||||
- [x] Archive a product
 | 
			
		||||
- [x] Unarchive a product
 | 
			
		||||
- [x] Remove a product without an SKU from the archive
 | 
			
		||||
- [x] Get a list of geo-restrictions for services
 | 
			
		||||
- [x] Upload activation codes for services and digital products
 | 
			
		||||
- [x] Status of uploading activation codes
 | 
			
		||||
 | 
			
		||||
## Prices and Stocks
 | 
			
		||||
- [x] Update stocks
 | 
			
		||||
@@ -32,124 +32,123 @@
 | 
			
		||||
- [x] Information about product quantity
 | 
			
		||||
- [x] Stocks in seller's warehouses (FBS и rFBS)
 | 
			
		||||
- [x] Update prices
 | 
			
		||||
- [ ] Get product price information
 | 
			
		||||
- [ ] Get information about the markdown and the main product by the markdown product SKU
 | 
			
		||||
- [ ] Set a discount on a markdown product
 | 
			
		||||
- [x] Get product price information
 | 
			
		||||
- [x] Get information about the markdown and the main product by the markdown product SKU
 | 
			
		||||
- [x] Set a discount on a markdown product
 | 
			
		||||
 | 
			
		||||
## Promotions
 | 
			
		||||
- [x] Available promotions
 | 
			
		||||
- [ ] Products that can participate in a promotion
 | 
			
		||||
- [ ] Products in a promotion
 | 
			
		||||
- [x] Products that can participate in a promotion
 | 
			
		||||
- [x] Products in a promotion
 | 
			
		||||
- [x] Add products to promotion
 | 
			
		||||
- [ ] Remove products from promotion
 | 
			
		||||
- [ ] List of available Hot Sale promotions
 | 
			
		||||
- [ ] List of products participating in the Hot Sale promotion
 | 
			
		||||
- [ ] Add products to the Hot Sale promotion
 | 
			
		||||
- [ ] Remove product from the Hot Sale promotion
 | 
			
		||||
- [ ] List of discount requests
 | 
			
		||||
- [ ] Approve a discount request
 | 
			
		||||
- [ ] Decline a discount request
 | 
			
		||||
- [x] Remove products from promotion
 | 
			
		||||
- [x] List of available Hot Sale promotions
 | 
			
		||||
- [x] List of products participating in the Hot Sale promotion
 | 
			
		||||
- [x] Add products to the Hot Sale promotion
 | 
			
		||||
- [x] Remove product from the Hot Sale promotion
 | 
			
		||||
- [x] List of discount requests
 | 
			
		||||
- [x] Approve a discount request
 | 
			
		||||
- [x] Decline a discount request
 | 
			
		||||
 | 
			
		||||
## Brand certificates
 | 
			
		||||
- [ ] List of certified brands
 | 
			
		||||
- [x] List of certified brands
 | 
			
		||||
 | 
			
		||||
## Quality certificates
 | 
			
		||||
- [ ] List of accordance types (version 1)
 | 
			
		||||
- [ ] List of accordance types (version 2)
 | 
			
		||||
- [ ] Directory of document types
 | 
			
		||||
- [ ] List of certified categories
 | 
			
		||||
- [ ] Adding certificates for products
 | 
			
		||||
- [ ] Link the certificate to the product
 | 
			
		||||
- [ ] Delete certificate
 | 
			
		||||
- [ ] Certificate information
 | 
			
		||||
- [ ] Certificates list
 | 
			
		||||
- [ ] Product statuses list
 | 
			
		||||
- [ ] List of products associated with the certificate
 | 
			
		||||
- [ ] Unbind products from a certificate
 | 
			
		||||
- [ ] Possible certificate rejection reasons
 | 
			
		||||
- [ ] Possible certificate statuses
 | 
			
		||||
- [x] List of accordance types (version 2)
 | 
			
		||||
- [x] Directory of document types
 | 
			
		||||
- [x] List of certified categories
 | 
			
		||||
- [x] Adding certificates for products
 | 
			
		||||
- [x] Link the certificate to the product
 | 
			
		||||
- [x] Delete certificate
 | 
			
		||||
- [x] Certificate information
 | 
			
		||||
- [x] Certificates list
 | 
			
		||||
- [x] Product statuses list
 | 
			
		||||
- [x] List of products associated with the certificate
 | 
			
		||||
- [x] Unbind products from a certificate
 | 
			
		||||
- [x] Possible certificate rejection reasons
 | 
			
		||||
- [x] Possible certificate statuses
 | 
			
		||||
 | 
			
		||||
## Warehouses
 | 
			
		||||
- [x] List of warehouses
 | 
			
		||||
- [x] List of delivery methods for a warehouse
 | 
			
		||||
 | 
			
		||||
## Polygons
 | 
			
		||||
- [ ] Create delivery polygon
 | 
			
		||||
- [ ] Link delivery method to a delivery polygon
 | 
			
		||||
- [ ] Delete polygon
 | 
			
		||||
- [x] Create delivery polygon
 | 
			
		||||
- [x] Link delivery method to a delivery polygon
 | 
			
		||||
- [x] Delete polygon
 | 
			
		||||
 | 
			
		||||
## FBO
 | 
			
		||||
- [x] Shipments list
 | 
			
		||||
- [ ] Shipment details
 | 
			
		||||
- [x] Shipment details
 | 
			
		||||
 | 
			
		||||
## FBS and rFBS products labeling
 | 
			
		||||
- [ ] Validate labeling codes
 | 
			
		||||
- [ ] Check and save product items data
 | 
			
		||||
- [ ] Get product items check statuses
 | 
			
		||||
- [x] Validate labeling codes
 | 
			
		||||
- [x] Check and save product items data
 | 
			
		||||
- [x] Get product items check statuses
 | 
			
		||||
- [x] Pack the order (version 4)
 | 
			
		||||
 | 
			
		||||
## FBS and rFBS
 | 
			
		||||
- [x] List of unprocessed shipments (version 3)
 | 
			
		||||
- [x] Shipments list (version 3)
 | 
			
		||||
- [ ] Get shipment details by identifier (version 3)
 | 
			
		||||
- [ ] Get shipment data by barcode
 | 
			
		||||
- [ ] List of manufacturing countries
 | 
			
		||||
- [ ] Set the manufacturing country
 | 
			
		||||
- [ ] Specify number of boxes for multi-box shipments
 | 
			
		||||
- [ ] Get drop-off point restrictions
 | 
			
		||||
- [ ] Partial pack the order
 | 
			
		||||
- [ ] Create an acceptance and transfer certificate and a waybill
 | 
			
		||||
- [ ] Status of acceptance and transfer certificate and waybill
 | 
			
		||||
- [ ] Available freights list
 | 
			
		||||
- [ ] Get acceptance and transfer certificate and waybill
 | 
			
		||||
- [ ] Generating status of digital acceptance and transfer certificate and waybill
 | 
			
		||||
- [ ] Get digital shipment certificate
 | 
			
		||||
- [ ] Print the labeling
 | 
			
		||||
- [ ] Create a task to generate labeling
 | 
			
		||||
- [ ] Get a labeling file
 | 
			
		||||
- [ ] Package unit labels
 | 
			
		||||
- [ ] Open a dispute over a shipment
 | 
			
		||||
- [ ] Pass the shipment to shipping
 | 
			
		||||
- [ ] Shipment cancellation reasons
 | 
			
		||||
- [ ] Shipments cancellation reasons
 | 
			
		||||
- [ ] Cancel the shipment
 | 
			
		||||
- [ ] Add weight for bulk products in a shipment
 | 
			
		||||
- [ ] Cancel sending some products in the shipment
 | 
			
		||||
- [ ] List of shipment certificates
 | 
			
		||||
- [ ] Sign shipment certificates
 | 
			
		||||
- [ ] List of shipments in the certificate
 | 
			
		||||
- [ ] Change the status to "Delivering"
 | 
			
		||||
- [ ] Add tracking numbers
 | 
			
		||||
- [ ] Change the status to "Last Mile"
 | 
			
		||||
- [ ] Change the status to "Delivered"
 | 
			
		||||
- [ ] Change status to "Sent by seller"
 | 
			
		||||
- [ ] Dates available for delivery reschedule
 | 
			
		||||
- [ ] Reschedule shipment delivery date
 | 
			
		||||
- [ ] ETGB customs declarations
 | 
			
		||||
- [x] Get shipment details by identifier (version 3)
 | 
			
		||||
- [x] Get shipment data by barcode
 | 
			
		||||
- [x] List of manufacturing countries
 | 
			
		||||
- [x] Set the manufacturing country
 | 
			
		||||
- [x] Specify number of boxes for multi-box shipments
 | 
			
		||||
- [x] Get drop-off point restrictions
 | 
			
		||||
- [x] Partial pack the order
 | 
			
		||||
- [x] Create an acceptance and transfer certificate and a waybill
 | 
			
		||||
- [x] Status of acceptance and transfer certificate and waybill
 | 
			
		||||
- [x] Available freights list
 | 
			
		||||
- [x] Get acceptance and transfer certificate and waybill
 | 
			
		||||
- [x] Generating status of digital acceptance and transfer certificate and waybill
 | 
			
		||||
- [x] Get digital shipment certificate
 | 
			
		||||
- [x] Print the labeling
 | 
			
		||||
- [x] Create a task to generate labeling
 | 
			
		||||
- [x] Get a labeling file
 | 
			
		||||
- [x] Package unit labels
 | 
			
		||||
- [x] Open a dispute over a shipment
 | 
			
		||||
- [x] Pass the shipment to shipping
 | 
			
		||||
- [x] Shipment cancellation reasons
 | 
			
		||||
- [x] Shipments cancellation reasons
 | 
			
		||||
- [x] Cancel the shipment
 | 
			
		||||
- [x] Add weight for bulk products in a shipment
 | 
			
		||||
- [x] Cancel sending some products in the shipment
 | 
			
		||||
- [x] List of shipment certificates
 | 
			
		||||
- [x] Sign shipment certificates
 | 
			
		||||
- [x] List of shipments in the certificate
 | 
			
		||||
- [x] Change the status to "Delivering"
 | 
			
		||||
- [x] Add tracking numbers
 | 
			
		||||
- [x] Change the status to "Last Mile"
 | 
			
		||||
- [x] Change the status to "Delivered"
 | 
			
		||||
- [x] Change status to "Sent by seller"
 | 
			
		||||
- [x] Dates available for delivery reschedule
 | 
			
		||||
- [x] Reschedule shipment delivery date
 | 
			
		||||
- [x] ETGB customs declarations
 | 
			
		||||
 | 
			
		||||
## Returns
 | 
			
		||||
- [x] Get information about FBO returns (version 3)
 | 
			
		||||
- [x] Get information about FBS returns
 | 
			
		||||
 | 
			
		||||
## Cancellations
 | 
			
		||||
- [ ] Get information about a rFBS cancellation request
 | 
			
		||||
- [ ] Get a list of rFBS cancellation requests
 | 
			
		||||
- [ ] Approve a rFBS cancellation request
 | 
			
		||||
- [ ] Reject a rFBS cancellation request
 | 
			
		||||
- [x] Get information about a rFBS cancellation request
 | 
			
		||||
- [x] Get a list of rFBS cancellation requests
 | 
			
		||||
- [x] Approve a rFBS cancellation request
 | 
			
		||||
- [x] Reject a rFBS cancellation request
 | 
			
		||||
 | 
			
		||||
## Chats with customers
 | 
			
		||||
- [ ] Chats list
 | 
			
		||||
- [ ] Send message
 | 
			
		||||
- [ ] Send file
 | 
			
		||||
- [ ] Chat history
 | 
			
		||||
- [ ] Update chat
 | 
			
		||||
- [ ] Create a new chat
 | 
			
		||||
- [ ] Mark messages as read
 | 
			
		||||
- [x] Chats list
 | 
			
		||||
- [x] Send message
 | 
			
		||||
- [x] Send file
 | 
			
		||||
- [x] Chat history
 | 
			
		||||
- [x] Update chat
 | 
			
		||||
- [x] Create a new chat
 | 
			
		||||
- [x] Mark messages as read
 | 
			
		||||
 | 
			
		||||
## Invoices
 | 
			
		||||
- [ ] Create or edit proforma invoice link
 | 
			
		||||
- [ ] Get a proforma invoice link
 | 
			
		||||
- [ ] Delete the proforma invoice link
 | 
			
		||||
- [x] Create or edit proforma invoice link
 | 
			
		||||
- [x] Get a proforma invoice link
 | 
			
		||||
- [x] Delete the proforma invoice link
 | 
			
		||||
 | 
			
		||||
## Reports
 | 
			
		||||
- [x] Report details
 | 
			
		||||
@@ -160,9 +159,9 @@
 | 
			
		||||
- [x] Returns report
 | 
			
		||||
- [x] Shipment report
 | 
			
		||||
- [x] Financial report
 | 
			
		||||
- [ ] Issue a report on discounted products
 | 
			
		||||
- [ ] Report on discounted products
 | 
			
		||||
- [ ] List of reports on discounted products
 | 
			
		||||
- [x] Issue a report on discounted products
 | 
			
		||||
- [x] Report on discounted products
 | 
			
		||||
- [x] List of reports on discounted products
 | 
			
		||||
 | 
			
		||||
## Analytics
 | 
			
		||||
- [x] Analytics data
 | 
			
		||||
@@ -170,7 +169,7 @@
 | 
			
		||||
 | 
			
		||||
## Finance
 | 
			
		||||
- [x] Report on sold products
 | 
			
		||||
- [ ] Transactions list (version 3)
 | 
			
		||||
- [x] Transactions list (version 3)
 | 
			
		||||
- [x] Total transactions sum
 | 
			
		||||
 | 
			
		||||
## Seller rating
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,8 @@ Read full [documentation](https://docs.ozon.ru/api/seller/en/#tag/Introduction)
 | 
			
		||||
You can check [list of supported endpoints](ENDPOINTS.md)
 | 
			
		||||
 | 
			
		||||
## How to start
 | 
			
		||||
Get Client-Id and Api-Key in your seller profile [here](https://seller.ozon.ru/app/settings/api-keys?locale=en)
 | 
			
		||||
 | 
			
		||||
Just add dependency to your project and you're ready to go.
 | 
			
		||||
```bash
 | 
			
		||||
go get github.com/diphantxm/ozon-api-client
 | 
			
		||||
@@ -33,7 +35,7 @@ func main() {
 | 
			
		||||
	client := ozon.NewClient("my-client-id", "my-api-key")
 | 
			
		||||
 | 
			
		||||
	// Send request with parameters
 | 
			
		||||
	resp, err := client.GetProductDetails(&ozon.GetProductDetailsParams{
 | 
			
		||||
	resp, err := client.Products().GetProductDetails(&ozon.GetProductDetailsParams{
 | 
			
		||||
		ProductId: 123456789,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil || resp.StatusCode != http.StatusOK {
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,7 @@ func (c Client) newRequest(method string, url string, body interface{}) (*http.R
 | 
			
		||||
	return req, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Client) Request(method string, path string, req, resp interface{}) (*Response, error) {
 | 
			
		||||
func (c Client) Request(method string, path string, req, resp interface{}, options map[string]string) (*Response, error) {
 | 
			
		||||
	httpReq, err := c.newRequest(method, path, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ func TestRequest(t *testing.T) {
 | 
			
		||||
		c := NewMockClient(NewMockHttpHandler(test.statusCode, test.response, test.headers))
 | 
			
		||||
 | 
			
		||||
		respStruct := &TestRequestResponse{}
 | 
			
		||||
		resp, err := c.Request(http.MethodPost, "/", test.params, respStruct)
 | 
			
		||||
		resp, err := c.Request(http.MethodPost, "/", test.params, respStruct, nil)
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Error(err)
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ type GetAnalyticsDataParams struct {
 | 
			
		||||
	DateTo time.Time `json:"date_to"`
 | 
			
		||||
 | 
			
		||||
	// Items Enum: "unknownDimension" "sku" "spu" "day" "week" "month" "year" "category1" "category2" "category3" "category4" "brand" "modelID"
 | 
			
		||||
	Dimension []string `json:"dimension"`
 | 
			
		||||
	Dimension []GetAnalyticsDataDimension `json:"dimension"`
 | 
			
		||||
 | 
			
		||||
	// Filters
 | 
			
		||||
	Filters []struct {
 | 
			
		||||
@@ -27,9 +27,7 @@ type GetAnalyticsDataParams struct {
 | 
			
		||||
		Key string `json:"key"`
 | 
			
		||||
 | 
			
		||||
		// Comparison operation
 | 
			
		||||
		//
 | 
			
		||||
		// Enum: "EQ" "GT" "GTE" "LT" "LTE"
 | 
			
		||||
		Operation string `json:"operation"`
 | 
			
		||||
		Operation GetAnalyticsDataFilterOperation `json:"operation"`
 | 
			
		||||
 | 
			
		||||
		// Value for comparison
 | 
			
		||||
		Value string `json:"value"`
 | 
			
		||||
@@ -41,11 +39,7 @@ type GetAnalyticsDataParams struct {
 | 
			
		||||
	Limit int64 `json:"limit"`
 | 
			
		||||
 | 
			
		||||
	// Specify up to 14 metrics. If there are more, you will get an error with the InvalidArgument code
 | 
			
		||||
	//
 | 
			
		||||
	// Items Enum: "unknown_metric" "hits_view_search" "hits_view_pdp" "hits_view" "hits_tocart_search" "hits_tocart_pdp" "hits_tocart" "session_view_search"
 | 
			
		||||
	// "session_view_pdp" "session_view" "conv_tocart_search" "conv_tocart_pdp" "conv_tocart" "revenue" "returns" "cancellations" "ordered_units" "delivered_units"
 | 
			
		||||
	// "adv_view_pdp" "adv_view_search_category" "adv_view_all" "adv_sum_all" "position_category" "postings" "postings_premium"
 | 
			
		||||
	Metrics []string `json:"metrics"`
 | 
			
		||||
	Metrics []GetAnalyticsDataFilterMetric `json:"metrics"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements that will be skipped in the response. For example, if `offset=10`, the response will start with the 11th element found
 | 
			
		||||
	Offset int64 `json:"offset"`
 | 
			
		||||
@@ -57,12 +51,10 @@ type GetAnalyticsDataParams struct {
 | 
			
		||||
// Report sorting settings
 | 
			
		||||
type GetAnalyticsDataSort struct {
 | 
			
		||||
	// Metric by which the method result will be sorted
 | 
			
		||||
	Key string `json:"key"`
 | 
			
		||||
	Key GetAnalyticsDataFilterMetric `json:"key"`
 | 
			
		||||
 | 
			
		||||
	// Sorting type
 | 
			
		||||
	//   - ASC — in ascending order,
 | 
			
		||||
	//   - DESC — in descending order.
 | 
			
		||||
	Order string `json:"order"`
 | 
			
		||||
	Order Order `json:"order"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetAnalyticsDataResponse struct {
 | 
			
		||||
@@ -99,7 +91,7 @@ func (c Analytics) GetAnalyticsData(params *GetAnalyticsDataParams) (*GetAnalyti
 | 
			
		||||
 | 
			
		||||
	resp := &GetAnalyticsDataResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -112,16 +104,13 @@ type GetStocksOnWarehousesParams struct {
 | 
			
		||||
	// Number of values per page.
 | 
			
		||||
	//
 | 
			
		||||
	// Default is 100
 | 
			
		||||
	Limit int64 `json:"limit"`
 | 
			
		||||
	Limit int64 `json:"limit" default:"100"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements that will be skipped in the response. For example, if `offset=10`, the response will start with the 11th element found
 | 
			
		||||
	Offset int64 `json:"offset"`
 | 
			
		||||
 | 
			
		||||
	// Warehouse type filter:
 | 
			
		||||
	//   - EXPRESS_DARK_STORE — Ozon warehouses with Fresh delivery.
 | 
			
		||||
	//   - NOT_EXPRESS_DARK_STORE — Ozon warehouses without Fresh delivery.
 | 
			
		||||
	//   - ALL — all Ozon warehouses.
 | 
			
		||||
	WarehouseType string `json:"warehouse_type"`
 | 
			
		||||
	WarehouseType WarehouseType `json:"warehouse_type"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetStocksOnWarehousesResponse struct {
 | 
			
		||||
@@ -161,7 +150,7 @@ func (c Analytics) GetStocksOnWarehouses(params *GetStocksOnWarehousesParams) (*
 | 
			
		||||
 | 
			
		||||
	resp := &GetStocksOnWarehousesResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,12 +23,12 @@ func TestGetAnalyticsData(t *testing.T) {
 | 
			
		||||
			&GetAnalyticsDataParams{
 | 
			
		||||
				DateFrom:  core.TimeFromString(t, "2006-01-02", "2020-09-01"),
 | 
			
		||||
				DateTo:    core.TimeFromString(t, "2006-01-02", "2021-10-15"),
 | 
			
		||||
				Dimension: []string{"sku", "day"},
 | 
			
		||||
				Metrics:   []string{"hits_view_search"},
 | 
			
		||||
				Dimension: []GetAnalyticsDataDimension{SKUDimension, DayDimension},
 | 
			
		||||
				Metrics:   []GetAnalyticsDataFilterMetric{AdvViewAll},
 | 
			
		||||
				Sort: []GetAnalyticsDataSort{
 | 
			
		||||
					{
 | 
			
		||||
						Key:   "hits_view_search",
 | 
			
		||||
						Order: "DESC",
 | 
			
		||||
						Key:   HistViewPDP,
 | 
			
		||||
						Order: Descending,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				Limit:  1000,
 | 
			
		||||
@@ -127,5 +127,11 @@ func TestGetStocksOnWarehouses(t *testing.T) {
 | 
			
		||||
		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.Rows) > int(test.params.Limit) {
 | 
			
		||||
				t.Errorf("Length of rows is bigger than limit")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										55
									
								
								ozon/brands.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								ozon/brands.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Brands struct {
 | 
			
		||||
	client *core.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListCertifiedBrandsParams struct {
 | 
			
		||||
	// Number of the page returned in the request
 | 
			
		||||
	Page int32 `json:"page"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements on the page
 | 
			
		||||
	PageSize int32 `json:"page_size"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListCertifiedBrandsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Certified brands details
 | 
			
		||||
		BrandCertification []struct {
 | 
			
		||||
			// Brand name
 | 
			
		||||
			BrandName string `json:"brand_name"`
 | 
			
		||||
 | 
			
		||||
			// Indication that the certificate is required:
 | 
			
		||||
			//   - true if the certificate is required;
 | 
			
		||||
			//   - false if not
 | 
			
		||||
			HasCertificate bool `json:"has_certificate"`
 | 
			
		||||
		} `json:"brand_certification"`
 | 
			
		||||
 | 
			
		||||
		// Total number of brands
 | 
			
		||||
		Total int64 `json:"total"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List of certified brands
 | 
			
		||||
func (c Brands) List(params *ListCertifiedBrandsParams) (*ListCertifiedBrandsResponse, error) {
 | 
			
		||||
	url := "/v1/brand/company-certification/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ListCertifiedBrandsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								ozon/brands_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								ozon/brands_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestListCertifiedBrands(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ListCertifiedBrandsParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ListCertifiedBrandsParams{
 | 
			
		||||
				Page:     0,
 | 
			
		||||
				PageSize: 0,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "brand_certification": [
 | 
			
		||||
					{
 | 
			
		||||
					  "brand_id": 135476863,
 | 
			
		||||
					  "brand_name": "Sea of Spa",
 | 
			
		||||
					  "has_certificate": false
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "total": 1
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ListCertifiedBrandsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Brands().List(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 int64(len(resp.Result.BrandCertification)) != resp.Result.Total {
 | 
			
		||||
				t.Errorf("Length of brands in response is not equal to total field in response")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										207
									
								
								ozon/cancellations.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								ozon/cancellations.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,207 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Cancellations struct {
 | 
			
		||||
	client *core.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetCancellationInfoParams struct {
 | 
			
		||||
	// Cancellation request identifier
 | 
			
		||||
	CancellationId int64 `json:"cancellation_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetCancellationInfoResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result CancellationInfo `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CancellationInfo struct {
 | 
			
		||||
	// Cancellation request identifier
 | 
			
		||||
	CancellationId int64 `json:"cancellation_id"`
 | 
			
		||||
 | 
			
		||||
	// Shipment number
 | 
			
		||||
	PostingNumber string `json:"posting_number"`
 | 
			
		||||
 | 
			
		||||
	// Cancellation reason
 | 
			
		||||
	CancellationReason struct {
 | 
			
		||||
		// Cancellation reason identifier
 | 
			
		||||
		Id int64 `json:"id"`
 | 
			
		||||
 | 
			
		||||
		// Cancellation reason name
 | 
			
		||||
		Name string `json:"name"`
 | 
			
		||||
	} `json:"cancellation_reason"`
 | 
			
		||||
 | 
			
		||||
	// Cancellation request creation date
 | 
			
		||||
	CancelledAt time.Time `json:"cancelled_at"`
 | 
			
		||||
 | 
			
		||||
	// Comment to cancellation submitted by cancellation initiator
 | 
			
		||||
	CancellationReasonMessage string `json:"cancellation_reason_message"`
 | 
			
		||||
 | 
			
		||||
	// Delivery service integration type
 | 
			
		||||
	TPLIntegrationType string `json:"tpl_integration_type"`
 | 
			
		||||
 | 
			
		||||
	// Cancellation request status
 | 
			
		||||
	State struct {
 | 
			
		||||
		// Status identifier
 | 
			
		||||
		Id int64 `json:"id"`
 | 
			
		||||
 | 
			
		||||
		// Status name
 | 
			
		||||
		Name string `json:"name"`
 | 
			
		||||
 | 
			
		||||
		// Request status
 | 
			
		||||
		State string `json:"state"`
 | 
			
		||||
	} `json:"state"`
 | 
			
		||||
 | 
			
		||||
	// Cancellation initiator
 | 
			
		||||
	CancellationInitiator string `json:"cancellation_initiator"`
 | 
			
		||||
 | 
			
		||||
	// Order creation date
 | 
			
		||||
	OrderDate time.Time `json:"order_date"`
 | 
			
		||||
 | 
			
		||||
	// Comment submitted on the cancellation request approval or rejection
 | 
			
		||||
	ApproveComment string `json:"approve_comment"`
 | 
			
		||||
 | 
			
		||||
	// Cancellation request approval or rejection date
 | 
			
		||||
	ApproveDate time.Time `json:"approve_date"`
 | 
			
		||||
 | 
			
		||||
	// Date after which the request will be automatically approved
 | 
			
		||||
	AutoApproveDate time.Time `json:"auto_approve_date"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Method for getting information about a rFBS cancellation request
 | 
			
		||||
func (c Cancellations) GetInfo(params *GetCancellationInfoParams) (*GetCancellationInfoResponse, error) {
 | 
			
		||||
	url := "/v1/delivery-method/list"
 | 
			
		||||
 | 
			
		||||
	resp := &GetCancellationInfoResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListCancellationsParams struct {
 | 
			
		||||
	// Filters
 | 
			
		||||
	Filter ListCancellationsFilter `json:"filter"`
 | 
			
		||||
 | 
			
		||||
	// Number of cancellation requests in the response
 | 
			
		||||
	Limit int32 `json:"limit"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements that will be skipped in the response.
 | 
			
		||||
	// For example, if offset=10, the response will start with the 11th element found
 | 
			
		||||
	Offset int32 `json:"offset"`
 | 
			
		||||
 | 
			
		||||
	// Additional information
 | 
			
		||||
	With ListCancellationWith `json:"with"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListCancellationsFilter struct {
 | 
			
		||||
	// Filter by cancellation initiator
 | 
			
		||||
	CancellationInitiator []string `json:"cancellation_initiator"`
 | 
			
		||||
 | 
			
		||||
	// Filter by shipment number.
 | 
			
		||||
	//
 | 
			
		||||
	// Optional parameter. You can pass several values here
 | 
			
		||||
	PostingNumber string `json:"posting_number"`
 | 
			
		||||
 | 
			
		||||
	// Filter by cancellation request status
 | 
			
		||||
	State string `json:"state"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListCancellationWith struct {
 | 
			
		||||
	// Indication that the counter of requests in different statuses should be displayed in the response
 | 
			
		||||
	Counters bool `json:"counters"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListCancellationsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Cancellation requests list
 | 
			
		||||
	Result []CancellationInfo `json:"result"`
 | 
			
		||||
 | 
			
		||||
	// The total number of requests by the specified filters
 | 
			
		||||
	Total int32 `json:"total"`
 | 
			
		||||
 | 
			
		||||
	// Counter of requests in different statuses
 | 
			
		||||
	Counters struct {
 | 
			
		||||
		// Number of requests for approval
 | 
			
		||||
		OnApproval int64 `json:"on_approval"`
 | 
			
		||||
 | 
			
		||||
		// Number of approved requests
 | 
			
		||||
		Approved int64 `json:"approved"`
 | 
			
		||||
 | 
			
		||||
		// Number of rejected requests
 | 
			
		||||
		Rejected int64 `json:"rejected"`
 | 
			
		||||
	} `json:"counters"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Method for getting a list of rFBS cancellation requests
 | 
			
		||||
func (c Cancellations) List(params *ListCancellationsParams) (*ListCancellationsResponse, error) {
 | 
			
		||||
	url := "/v1/conditional-cancellation/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ListCancellationsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ApproveRejectCancellationsParams struct {
 | 
			
		||||
	// Cancellation request identifier
 | 
			
		||||
	CancellationId int64 `json:"cancellation_id"`
 | 
			
		||||
 | 
			
		||||
	// Comment
 | 
			
		||||
	Comment string `json:"comment"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ApproveRejectCancellationsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The method allows to approve an rFBS cancellation request in the ON_APPROVAL status.
 | 
			
		||||
// The order will be canceled and the money will be returned to the customer
 | 
			
		||||
func (c Cancellations) Approve(params *ApproveRejectCancellationsParams) (*ApproveRejectCancellationsResponse, error) {
 | 
			
		||||
	url := "/v1/conditional-cancellation/approve"
 | 
			
		||||
 | 
			
		||||
	resp := &ApproveRejectCancellationsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The method allows to reject an rFBS cancellation request in the ON_APPROVAL status. Explain your decision in the comment parameter.
 | 
			
		||||
// 
 | 
			
		||||
// The order will remain in the same status and must be delivered to the customer
 | 
			
		||||
func (c Cancellations) Reject(params *ApproveRejectCancellationsParams) (*ApproveRejectCancellationsResponse, error) {
 | 
			
		||||
	url := "/v1/conditional-cancellation/reject"
 | 
			
		||||
 | 
			
		||||
	resp := &ApproveRejectCancellationsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										271
									
								
								ozon/cancellations_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								ozon/cancellations_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,271 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestGetCancellationInfo(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *GetCancellationInfoParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&GetCancellationInfoParams{
 | 
			
		||||
				CancellationId: 90066344,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "cancellation_id": 90066344,
 | 
			
		||||
				  "posting_number": "47134289-0029-1",
 | 
			
		||||
				  "cancellation_reason": {
 | 
			
		||||
					"id": 508,
 | 
			
		||||
					"name": "Покупатель отменил заказ"
 | 
			
		||||
				  },
 | 
			
		||||
				  "cancelled_at": "2022-04-07T06:37:26.871105Z",
 | 
			
		||||
				  "cancellation_reason_message": "Изменение пункта выдачи заказа.",
 | 
			
		||||
				  "tpl_integration_type": "ThirdPartyTracking",
 | 
			
		||||
				  "state": {
 | 
			
		||||
					"id": 2,
 | 
			
		||||
					"name": "Подтверждена",
 | 
			
		||||
					"state": "APPROVED"
 | 
			
		||||
				  },
 | 
			
		||||
				  "cancellation_initiator": "CLIENT",
 | 
			
		||||
				  "order_date": "2022-04-06T17:17:24.517Z",
 | 
			
		||||
				  "approve_comment": "",
 | 
			
		||||
				  "approve_date": "2022-04-07T07:52:45.971824Z",
 | 
			
		||||
				  "auto_approve_date": "2022-04-09T06:37:26.871105Z"
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&GetCancellationInfoParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Cancellations().GetInfo(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 resp.Result.CancellationId != test.params.CancellationId {
 | 
			
		||||
				t.Errorf("Cancellation ids in request and response are not equal")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestListCancellations(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ListCancellationsParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ListCancellationsParams{
 | 
			
		||||
				Filter: ListCancellationsFilter{
 | 
			
		||||
					CancellationInitiator: []string{"CLIENT"},
 | 
			
		||||
					State:                 "ALL",
 | 
			
		||||
				},
 | 
			
		||||
				Limit:  2,
 | 
			
		||||
				Offset: 0,
 | 
			
		||||
				With: ListCancellationWith{
 | 
			
		||||
					Counters: true,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"cancellation_id": 50186754,
 | 
			
		||||
					"posting_number": "41267064-0032-1",
 | 
			
		||||
					"cancellation_reason": {
 | 
			
		||||
					  "id": 508,
 | 
			
		||||
					  "name": "Покупатель отменил заказ"
 | 
			
		||||
					},
 | 
			
		||||
					"cancelled_at": "2021-09-03T07:17:12.116114Z",
 | 
			
		||||
					"cancellation_reason_message": "",
 | 
			
		||||
					"tpl_integration_type": "ThirdPartyTracking",
 | 
			
		||||
					"state": {
 | 
			
		||||
					  "id": 2,
 | 
			
		||||
					  "name": "Подтверждена",
 | 
			
		||||
					  "state": "APPROVED"
 | 
			
		||||
					},
 | 
			
		||||
					"cancellation_initiator": "CLIENT",
 | 
			
		||||
					"order_date": "2021-09-03T07:04:53.220Z",
 | 
			
		||||
					"approve_comment": "",
 | 
			
		||||
					"approve_date": "2021-09-03T09:13:12.614200Z",
 | 
			
		||||
					"auto_approve_date": "2021-09-06T07:17:12.116114Z"
 | 
			
		||||
				  },
 | 
			
		||||
				  {
 | 
			
		||||
					"cancellation_id": 51956491,
 | 
			
		||||
					"posting_number": "14094410-0018-1",
 | 
			
		||||
					"cancellation_reason": {
 | 
			
		||||
					  "id": 507,
 | 
			
		||||
					  "name": "Покупатель передумал"
 | 
			
		||||
					},
 | 
			
		||||
					"cancelled_at": "2021-09-13T15:03:25.155827Z",
 | 
			
		||||
					"cancellation_reason_message": "",
 | 
			
		||||
					"tpl_integration_type": "ThirdPartyTracking",
 | 
			
		||||
					"state": {
 | 
			
		||||
					  "id": 5,
 | 
			
		||||
					  "name": "Автоматически отменена",
 | 
			
		||||
					  "state": "REJECTED"
 | 
			
		||||
					},
 | 
			
		||||
					"cancellation_initiator": "CLIENT",
 | 
			
		||||
					"order_date": "2021-09-13T07:48:50.143Z",
 | 
			
		||||
					"approve_comment": "",
 | 
			
		||||
					"approve_date": null,
 | 
			
		||||
					"auto_approve_date": "2021-09-16T15:03:25.155827Z"
 | 
			
		||||
				  }
 | 
			
		||||
				],
 | 
			
		||||
				"total": 19,
 | 
			
		||||
				"counters": {
 | 
			
		||||
				  "on_approval": 0,
 | 
			
		||||
				  "approved": 14,
 | 
			
		||||
				  "rejected": 5
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ListCancellationsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Cancellations().List(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 TestApproveCancellations(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ApproveRejectCancellationsParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ApproveRejectCancellationsParams{
 | 
			
		||||
				CancellationId: 74393917,
 | 
			
		||||
			},
 | 
			
		||||
			`{}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ApproveRejectCancellationsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Cancellations().Approve(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 TestRejectCancellations(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ApproveRejectCancellationsParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ApproveRejectCancellationsParams{
 | 
			
		||||
				CancellationId: 74393917,
 | 
			
		||||
			},
 | 
			
		||||
			`{}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ApproveRejectCancellationsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Cancellations().Reject(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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										194
									
								
								ozon/categories.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								ozon/categories.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,194 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Categories struct {
 | 
			
		||||
	client *core.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetProductTreeParams struct {
 | 
			
		||||
	// Category identifier
 | 
			
		||||
	CategoryId int64 `json:"category_id"`
 | 
			
		||||
 | 
			
		||||
	// Response language
 | 
			
		||||
	Language Language `json:"language" default:"DEFAULT"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetProductTreeResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Category list
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		// Category identifier
 | 
			
		||||
		CategoryId int64 `json:"category_id"`
 | 
			
		||||
 | 
			
		||||
		// Subcategory tree
 | 
			
		||||
		Children []GetProductTreeResponse `json:"children"`
 | 
			
		||||
 | 
			
		||||
		// Category name
 | 
			
		||||
		Title string `json:"title"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns product categories in the tree view.
 | 
			
		||||
// New products can be created in the last level categories only.
 | 
			
		||||
// This means that you need to match these particular categories with the categories of your site.
 | 
			
		||||
// It is not possible to create categories by user request
 | 
			
		||||
func (c Categories) Tree(params *GetProductTreeParams) (*GetProductTreeResponse, error) {
 | 
			
		||||
	url := "/v2/category/tree"
 | 
			
		||||
 | 
			
		||||
	resp := &GetProductTreeResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetCategoryAttributesParams struct {
 | 
			
		||||
	// Filter by characteristics
 | 
			
		||||
	AttributeType AttributeType `json:"attribute_type" default:"ALL"`
 | 
			
		||||
 | 
			
		||||
	// Category identifier
 | 
			
		||||
	CategoryId []int64 `json:"category_id"`
 | 
			
		||||
 | 
			
		||||
	// Response language
 | 
			
		||||
	Language Language `json:"language" default:"DEFAULT"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetCategoryAttributesResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		// Array of product characteristics
 | 
			
		||||
		Attributes []struct {
 | 
			
		||||
			// Indication that the dictionary attribute values depend on the category:
 | 
			
		||||
			//   - true — the attribute has its own set of values for each category.
 | 
			
		||||
			//   - false — the attribute has the same set of values for all categories
 | 
			
		||||
			CategoryDependent bool `json:"category_dependent"`
 | 
			
		||||
 | 
			
		||||
			// Characteristic description
 | 
			
		||||
			Description string `json:"description"`
 | 
			
		||||
 | 
			
		||||
			// Directory identifier
 | 
			
		||||
			DictionaryId int64 `json:"dictionary_id"`
 | 
			
		||||
 | 
			
		||||
			// Characteristics group identifier
 | 
			
		||||
			GroupId int64 `json:"group_id"`
 | 
			
		||||
 | 
			
		||||
			// Characteristics group name
 | 
			
		||||
			GroupName string `json:"group_name"`
 | 
			
		||||
 | 
			
		||||
			// Document generation task number
 | 
			
		||||
			Id int64 `json:"id"`
 | 
			
		||||
 | 
			
		||||
			// Indicates that the attribute is aspect. An aspect attribute is a characteristic that distinguishes products of the same model.
 | 
			
		||||
			//
 | 
			
		||||
			// For example, clothes and shoes of the same model may have different colors and sizes. That is, color and size are aspect attributes.
 | 
			
		||||
			//
 | 
			
		||||
			// Values description:
 | 
			
		||||
			//   - true — the attribute is aspect and cannot be changed after the products are delivered to the warehouse or sold from the seller's warehouse.
 | 
			
		||||
			//   - false — the attribute is not aspect and can be changed at any time
 | 
			
		||||
			IsAspect bool `json:"is_aspect"`
 | 
			
		||||
 | 
			
		||||
			// Indicates that the characteristic is a set of values:
 | 
			
		||||
			//   - true — the characteristic is a set of values,
 | 
			
		||||
			//   - false — the characteristic consists of a single value
 | 
			
		||||
			IsCollection bool `json:"is_collection"`
 | 
			
		||||
 | 
			
		||||
			// Indicates that the characteristic is mandatory:
 | 
			
		||||
			//   - true — a mandatory characteristic,
 | 
			
		||||
			//   - false — you can leave the characteristic out
 | 
			
		||||
			IsRequired bool `json:"is_required"`
 | 
			
		||||
 | 
			
		||||
			// Name
 | 
			
		||||
			Name string `json:"name"`
 | 
			
		||||
 | 
			
		||||
			// Characteristic type
 | 
			
		||||
			Type string `json:"type"`
 | 
			
		||||
		} `json:"attributes"`
 | 
			
		||||
 | 
			
		||||
		// Category identifier
 | 
			
		||||
		CategoryId int64 `json:"category_id"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Getting characteristics for specified product category.
 | 
			
		||||
//
 | 
			
		||||
// Pass up to 20 category identifiers in the `category_id` list.
 | 
			
		||||
//
 | 
			
		||||
// You can check whether the attribute has a nested directory by the `dictionary_id` parameter.
 | 
			
		||||
// The 0 value means there is no directory. If the value is different, then there are directories.
 | 
			
		||||
// You can get them using the `/v2/category/attribute/values` method
 | 
			
		||||
func (c Categories) Attributes(params *GetCategoryAttributesParams) (*GetCategoryAttributesResponse, error) {
 | 
			
		||||
	url := "/v3/category/attribute"
 | 
			
		||||
 | 
			
		||||
	resp := &GetCategoryAttributesResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetAttributeDictionaryParams struct {
 | 
			
		||||
	// Characteristics identifier
 | 
			
		||||
	AttributeId int64 `json:"attribute_id"`
 | 
			
		||||
 | 
			
		||||
	// Category identifier
 | 
			
		||||
	CategoryId int64 `json:"category_id"`
 | 
			
		||||
 | 
			
		||||
	// Response language
 | 
			
		||||
	// The default language is Russian
 | 
			
		||||
	Language Language `json:"language" default:"DEFAULT"`
 | 
			
		||||
 | 
			
		||||
	LastValueId int64 `json:"last_value_id"`
 | 
			
		||||
 | 
			
		||||
	// Number of values in the response:
 | 
			
		||||
	//   - maximum — 5000
 | 
			
		||||
	//   - minimum — 1
 | 
			
		||||
	Limit int64 `json:"limit"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetAttributeDictionaryResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	HasNext bool `json:"has_next"`
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		Id      int64  `json:"id"`
 | 
			
		||||
		Info    string `json:"info"`
 | 
			
		||||
		Picture string `json:"picture"`
 | 
			
		||||
 | 
			
		||||
		// Product characteristic value
 | 
			
		||||
		Value string `json:"value"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// You can use the `/v3/category/attribute` method to check if an attribute has a nested directory.
 | 
			
		||||
// If there are directories, get them using this method
 | 
			
		||||
func (c Categories) AttributesDictionary(params *GetAttributeDictionaryParams) (*GetAttributeDictionaryResponse, error) {
 | 
			
		||||
	url := "/v2/category/attribute/values"
 | 
			
		||||
 | 
			
		||||
	resp := &GetAttributeDictionaryResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										217
									
								
								ozon/categories_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								ozon/categories_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,217 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestGetProductTree(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *GetProductTreeParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&GetProductTreeParams{
 | 
			
		||||
				CategoryId: 17034410,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"category_id": 17034410,
 | 
			
		||||
					"title": "Развивающие игрушки",
 | 
			
		||||
					"children": []
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&GetProductTreeParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Categories().Tree(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) > 0 {
 | 
			
		||||
				if resp.Result[0].CategoryId != test.params.CategoryId {
 | 
			
		||||
					t.Errorf("First category ids in request and response are not equal")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetCategoryAttributes(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *GetCategoryAttributesParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&GetCategoryAttributesParams{
 | 
			
		||||
				CategoryId: []int64{17034410},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"category_id": 17034410,
 | 
			
		||||
					"attributes": [
 | 
			
		||||
					  {
 | 
			
		||||
						"id": 85,
 | 
			
		||||
						"name": "Бренд",
 | 
			
		||||
						"description": "Укажите наименование бренда, под которым произведен товар. Если товар не имеет бренда, используйте значение \"Нет бренда\"",
 | 
			
		||||
						"type": "String",
 | 
			
		||||
						"is_collection": false,
 | 
			
		||||
						"is_required": true,
 | 
			
		||||
						"group_id": 0,
 | 
			
		||||
						"group_name": "",
 | 
			
		||||
						"dictionary_id": 28732849
 | 
			
		||||
					  }
 | 
			
		||||
					]
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&GetCategoryAttributesParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Categories().Attributes(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) != len(test.params.CategoryId) {
 | 
			
		||||
				t.Errorf("Length of categories in request and response are not equal")
 | 
			
		||||
			}
 | 
			
		||||
			if len(resp.Result) > 0 {
 | 
			
		||||
				if resp.Result[0].CategoryId != test.params.CategoryId[0] {
 | 
			
		||||
					t.Errorf("Category ids in request and response are not equal")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetAttributeDictionary(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *GetAttributeDictionaryParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&GetAttributeDictionaryParams{
 | 
			
		||||
				AttributeId: 10096,
 | 
			
		||||
				CategoryId:  17028968,
 | 
			
		||||
				LastValueId: 0,
 | 
			
		||||
				Limit:       3,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"id": 61571,
 | 
			
		||||
					"value": "белый",
 | 
			
		||||
					"info": "",
 | 
			
		||||
					"picture": ""
 | 
			
		||||
				  },
 | 
			
		||||
				  {
 | 
			
		||||
					"id": 61572,
 | 
			
		||||
					"value": "прозрачный",
 | 
			
		||||
					"info": "",
 | 
			
		||||
					"picture": ""
 | 
			
		||||
				  },
 | 
			
		||||
				  {
 | 
			
		||||
					"id": 61573,
 | 
			
		||||
					"value": "бежевый",
 | 
			
		||||
					"info": "",
 | 
			
		||||
					"picture": ""
 | 
			
		||||
				  }
 | 
			
		||||
				],
 | 
			
		||||
				"has_next": true
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&GetAttributeDictionaryParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Categories().AttributesDictionary(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) > int(test.params.Limit) {
 | 
			
		||||
				t.Errorf("Length of response result is bigger than limit")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										543
									
								
								ozon/certificates.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										543
									
								
								ozon/certificates.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,543 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Certificates struct {
 | 
			
		||||
	client *core.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListOfAccordanceTypesResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Accordance types
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Main accordance types
 | 
			
		||||
		Base []struct {
 | 
			
		||||
			// Accordance type code
 | 
			
		||||
			Code string `json:"code"`
 | 
			
		||||
 | 
			
		||||
			// Accordance type description
 | 
			
		||||
			Title string `json:"title"`
 | 
			
		||||
		} `json:"base"`
 | 
			
		||||
 | 
			
		||||
		// Main accordance types related to dangerous products
 | 
			
		||||
		Hazard []struct {
 | 
			
		||||
			// Accordance type code
 | 
			
		||||
			Code string `json:"code"`
 | 
			
		||||
 | 
			
		||||
			// Accordance type description
 | 
			
		||||
			Title string `json:"title"`
 | 
			
		||||
		} `json:"hazard"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List of accordance types (version 2)
 | 
			
		||||
func (c Certificates) ListOfAccordanceTypes() (*ListOfAccordanceTypesResponse, error) {
 | 
			
		||||
	url := "/v2/product/certificate/accordance-types/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ListOfAccordanceTypesResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodGet, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DirectoryOfDocumentTypesResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// List of certificate types and names
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		// Certificate name
 | 
			
		||||
		Name string `json:"name"`
 | 
			
		||||
 | 
			
		||||
		// Certificate type
 | 
			
		||||
		Value string `json:"value"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Directory of document types
 | 
			
		||||
func (c Certificates) DirectoryOfDocumentTypes() (*DirectoryOfDocumentTypesResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/types"
 | 
			
		||||
 | 
			
		||||
	resp := &DirectoryOfDocumentTypesResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodGet, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListOfCertifiedCategoriesParams struct {
 | 
			
		||||
	// Number of the page returned in the query
 | 
			
		||||
	Page int32 `json:"page"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements on the page
 | 
			
		||||
	PageSize int32 `json:"page_size"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListOfCertifiedCategoriesResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Certified categories details
 | 
			
		||||
		Certification []struct {
 | 
			
		||||
			// Category name
 | 
			
		||||
			CategoryName string `json:"category_name"`
 | 
			
		||||
 | 
			
		||||
			// Indication of a mandatory category
 | 
			
		||||
			IsRequired bool `json:"is_required"`
 | 
			
		||||
		} `json:"certification"`
 | 
			
		||||
 | 
			
		||||
		// Total number of categories
 | 
			
		||||
		Total int64 `json:"total"`
 | 
			
		||||
	} `json:"reult"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List of certified categories
 | 
			
		||||
func (c Certificates) ListOfCertifiedCategories(params *ListOfCertifiedCategoriesParams) (*ListOfCertifiedCategoriesResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/types"
 | 
			
		||||
 | 
			
		||||
	resp := &ListOfCertifiedCategoriesResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LinkCertificateToProductParams struct {
 | 
			
		||||
	// Certificate identifier that was assigned when it was uploaded
 | 
			
		||||
	CertificateId int64 `json:"certificate_id"`
 | 
			
		||||
 | 
			
		||||
	// An array of product identifiers that this certificate applies to
 | 
			
		||||
	ProductId []int64 `json:"product_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LinkCertificateToProductResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// The result of processing the request. true if the request was executed without errors
 | 
			
		||||
	Result bool `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Link the certificate to the product
 | 
			
		||||
func (c Certificates) LinkToProduct(params *LinkCertificateToProductParams) (*LinkCertificateToProductResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/bind"
 | 
			
		||||
 | 
			
		||||
	resp := &LinkCertificateToProductResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DeleteCertificateParams struct {
 | 
			
		||||
	// Certificate identifier
 | 
			
		||||
	CertificateId int32 `json:"certificate_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DeleteCertificateResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Result of deleting the certificate
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Indication that a certificate has been deleted:
 | 
			
		||||
		//   - true — deleted
 | 
			
		||||
		//   - false — not deleted
 | 
			
		||||
		IsDelete bool `json:"is_delete"`
 | 
			
		||||
 | 
			
		||||
		// Description of errors during certificate deletion
 | 
			
		||||
		ErrorMessage string `json:"error_message"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Delete certificate
 | 
			
		||||
func (c Certificates) Delete(params *DeleteCertificateParams) (*DeleteCertificateResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/delete"
 | 
			
		||||
 | 
			
		||||
	resp := &DeleteCertificateResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetCertificateInfoParams struct {
 | 
			
		||||
	// Certificate identifier
 | 
			
		||||
	CertificateNumber string `json:"certificate_number"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetCertificateInfoResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Certificate information
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Identifier
 | 
			
		||||
		CertificateId int32 `json:"certificate_id"`
 | 
			
		||||
 | 
			
		||||
		// Number
 | 
			
		||||
		CertificateNumber string `json:"certificate_number"`
 | 
			
		||||
 | 
			
		||||
		// Name
 | 
			
		||||
		CertificateName string `json:"certificate_name"`
 | 
			
		||||
 | 
			
		||||
		// Type
 | 
			
		||||
		TypeCode string `json:"type_code"`
 | 
			
		||||
 | 
			
		||||
		// Status
 | 
			
		||||
		StatusCode string `json:"status_code"`
 | 
			
		||||
 | 
			
		||||
		// Accordance type
 | 
			
		||||
		AccordanceTypeCode string `json:"accordance_type_code"`
 | 
			
		||||
 | 
			
		||||
		// Certificate rejection reason
 | 
			
		||||
		RejectionReasonCode string `json:"rejectio_reason_code"`
 | 
			
		||||
 | 
			
		||||
		// Moderator's comment
 | 
			
		||||
		VerificationComment string `json:"verification_comment"`
 | 
			
		||||
 | 
			
		||||
		// Issue date
 | 
			
		||||
		IssueDate time.Time `json:"issue_date"`
 | 
			
		||||
 | 
			
		||||
		// Expire date
 | 
			
		||||
		ExpireDate time.Time `json:"expire_date"`
 | 
			
		||||
 | 
			
		||||
		// Number of products associated with a certificate
 | 
			
		||||
		ProductsCount int32 `json:"products_count"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Certificate information
 | 
			
		||||
func (c Certificates) GetInfo(params *GetCertificateInfoParams) (*GetCertificateInfoResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/info"
 | 
			
		||||
 | 
			
		||||
	resp := &GetCertificateInfoResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListCertificatesParams struct {
 | 
			
		||||
	// Product identifier associated with the certificate.
 | 
			
		||||
	// Pass the parameter if you need certificates that certain products are associated with
 | 
			
		||||
	OfferId string `json:"offer_id"`
 | 
			
		||||
 | 
			
		||||
	// Certificate status. Pass the parameter if you need certificates with a certain status
 | 
			
		||||
	Status string `json:"status"`
 | 
			
		||||
 | 
			
		||||
	// Certificate type. Pass the parameter if you need certificates with a certain type
 | 
			
		||||
	Type string `json:"type"`
 | 
			
		||||
 | 
			
		||||
	// Page from which the list should be displayed. The minimum value is 1
 | 
			
		||||
	Page int32 `json:"page"`
 | 
			
		||||
 | 
			
		||||
	// Number of objects on the page. The value is from 1 to 1000
 | 
			
		||||
	PageSize int32 `json:"page_size"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListCertificatesResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Certificates
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Сertificate information
 | 
			
		||||
		Certificates []struct {
 | 
			
		||||
			// Identifier
 | 
			
		||||
			CertificateId int32 `json:"certificate_id"`
 | 
			
		||||
 | 
			
		||||
			// Number
 | 
			
		||||
			CertificateNumber string `json:"certificate_number"`
 | 
			
		||||
 | 
			
		||||
			// Name
 | 
			
		||||
			CertificateName string `json:"certificate_name"`
 | 
			
		||||
 | 
			
		||||
			// Type
 | 
			
		||||
			TypeCode string `json:"type"`
 | 
			
		||||
 | 
			
		||||
			// Status
 | 
			
		||||
			StatusCode string `json:"status_code"`
 | 
			
		||||
 | 
			
		||||
			// Accordance type
 | 
			
		||||
			AccordanceTypecode string `json:"accordance_type_code"`
 | 
			
		||||
 | 
			
		||||
			// Certificate rejection reason
 | 
			
		||||
			RejectionReasonCode string `json:"rejectio_reason_code"`
 | 
			
		||||
 | 
			
		||||
			// Moderator's comment
 | 
			
		||||
			VerificationComment string `json:"verification_comment"`
 | 
			
		||||
 | 
			
		||||
			// Issue date
 | 
			
		||||
			IssueDate time.Time `json:"issue_data"`
 | 
			
		||||
 | 
			
		||||
			// Expire date
 | 
			
		||||
			ExpireDate time.Time `json:"expire_date"`
 | 
			
		||||
 | 
			
		||||
			// Number of products associated with a certificate
 | 
			
		||||
			ProductsCount int32 `json:"products_count"`
 | 
			
		||||
		} `json:"certificates"`
 | 
			
		||||
 | 
			
		||||
		// Number of pages
 | 
			
		||||
		PageCount int32 `json:"page_count"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Certificates list
 | 
			
		||||
func (c Certificates) List(params *ListCertificatesParams) (*ListCertificatesResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ListCertificatesResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProductStatusesResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Product statuses
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		// Product status code when linking it to the certificate
 | 
			
		||||
		Code string `json:"code"`
 | 
			
		||||
 | 
			
		||||
		// Status description
 | 
			
		||||
		Name string `json:"name"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Certificates) ProductStatuses() (*ProductStatusesResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ProductStatusesResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListProductsForCertificateParams struct {
 | 
			
		||||
	// Certificate identifier
 | 
			
		||||
	CertificateId int32 `json:"certificate_id"`
 | 
			
		||||
 | 
			
		||||
	// Status of the product verification when binding to a certificate
 | 
			
		||||
	ProductStatusCode string `json:"product_status_code"`
 | 
			
		||||
 | 
			
		||||
	// Page from which the list should be displayed. The minimum value is 1
 | 
			
		||||
	Page int32 `json:"page"`
 | 
			
		||||
 | 
			
		||||
	// Number of objects on the page. The value is from 1 to 1000
 | 
			
		||||
	PageSize int32 `json:"page_size"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListProductsForCertificateResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// List of products
 | 
			
		||||
		Items []struct {
 | 
			
		||||
			// Product identifier
 | 
			
		||||
			ProductId int64 `json:"product_id"`
 | 
			
		||||
 | 
			
		||||
			// Status of the product processing when binding to a certificate
 | 
			
		||||
			ProductStatusCode string `json:"product_status_code"`
 | 
			
		||||
		} `json:"items"`
 | 
			
		||||
 | 
			
		||||
		// Number of products found
 | 
			
		||||
		Count int64 `json:"count"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A method for getting a list of possible statuses of products when binding them to a certificate
 | 
			
		||||
func (c Certificates) ListProductsForCertificate(params *ListProductsForCertificateParams) (*ListProductsForCertificateResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/products/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ListProductsForCertificateResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UnlinkFromProductParams struct {
 | 
			
		||||
	// Certificate identifier
 | 
			
		||||
	CertificateId int32 `json:"certificate_id"`
 | 
			
		||||
 | 
			
		||||
	// List of product identifiers that you want to unbind from a certificate
 | 
			
		||||
	ProductId []int64 `json:"product_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UnlinkFromProductResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		// Error message when unbinding a product
 | 
			
		||||
		Error string `json:"error"`
 | 
			
		||||
 | 
			
		||||
		// Product identifier
 | 
			
		||||
		ProductId int64 `json:"product_id"`
 | 
			
		||||
 | 
			
		||||
		// Indication that the product was unbound from a certificate:
 | 
			
		||||
		//   - true — it was unbound,
 | 
			
		||||
		//   - false — it is still bound
 | 
			
		||||
		Updated bool `json:"updated"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unbind products from a certificate
 | 
			
		||||
func (c Certificates) UnlinkFromProduct(params *UnlinkFromProductParams) (*UnlinkFromProductResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/unbind"
 | 
			
		||||
 | 
			
		||||
	resp := &UnlinkFromProductResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PossibleRejectReasonsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Certificate rejection reasons
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		// Сode of a certificate rejection reason
 | 
			
		||||
		Code string `json:"code"`
 | 
			
		||||
 | 
			
		||||
		// Description of a certificate rejection reason
 | 
			
		||||
		Name string `json:"name"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Possible certificate rejection reasons
 | 
			
		||||
func (c Certificates) PossibleRejectReasons() (*PossibleRejectReasonsResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/rejection_reasons/list"
 | 
			
		||||
 | 
			
		||||
	resp := &PossibleRejectReasonsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PossibleStatusesResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Possible certificate statuses
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		// Certificate status code
 | 
			
		||||
		Code string `json:"code"`
 | 
			
		||||
 | 
			
		||||
		// Status description
 | 
			
		||||
		Name string `json:"name"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Certificates) PossibleStatuses() (*PossibleStatusesResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/status/list"
 | 
			
		||||
 | 
			
		||||
	resp := &PossibleStatusesResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AddCertificatesForProductsParams struct {
 | 
			
		||||
	// Array of certificates for the product. Valid extensions are jpg, jpeg, png, pdf
 | 
			
		||||
	Files []byte `json:"files"`
 | 
			
		||||
 | 
			
		||||
	// Certificate name. No more than 100 characters
 | 
			
		||||
	Name string `json:"name"`
 | 
			
		||||
 | 
			
		||||
	// Certificate number. No more than 100 characters
 | 
			
		||||
	Number string `json:"number"`
 | 
			
		||||
 | 
			
		||||
	// Certificate type. To get the list of types, use the GET `/v1/product/certificate/types` method
 | 
			
		||||
	TypeCode string `json:"type_code"`
 | 
			
		||||
 | 
			
		||||
	// Accordance type. To get the list of types, use the GET `/v1/product/certificate/accordance-types` method
 | 
			
		||||
	AccordanceTypeCode string `json:"accordance_type_code"`
 | 
			
		||||
 | 
			
		||||
	// Issue date of the certificate
 | 
			
		||||
	IssueDate time.Time `json:"issue_date"`
 | 
			
		||||
 | 
			
		||||
	// Expiration date of the certificate. Can be empty for permanent certificates
 | 
			
		||||
	ExpireDate time.Time `json:"expire_date"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AddCertificatesForProductsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	Id int `json:"id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Adding certificates for products
 | 
			
		||||
func (c Certificates) AddForProducts(params *AddCertificatesForProductsParams) (*AddCertificatesForProductsResponse, error) {
 | 
			
		||||
	url := "/v1/product/certificate/create"
 | 
			
		||||
 | 
			
		||||
	resp := &AddCertificatesForProductsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, map[string]string{
 | 
			
		||||
		"Content-Type": "multipart/form-data",
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										707
									
								
								ozon/certificates_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										707
									
								
								ozon/certificates_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,707 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestListOfAccordanceTypes(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "base": [
 | 
			
		||||
					{
 | 
			
		||||
					  "code": "string",
 | 
			
		||||
					  "title": "string"
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "hazard": [
 | 
			
		||||
					{
 | 
			
		||||
					  "code": "string",
 | 
			
		||||
					  "title": "string"
 | 
			
		||||
					}
 | 
			
		||||
				  ]
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().ListOfAccordanceTypes()
 | 
			
		||||
		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 TestDirectoryOfDocumentTypes(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"name": "Сертификат соответствия",
 | 
			
		||||
					"value": "certificate_of_conformity"
 | 
			
		||||
				  },
 | 
			
		||||
				  {
 | 
			
		||||
					"name": "Декларация",
 | 
			
		||||
					"value": "declaration"
 | 
			
		||||
				  },
 | 
			
		||||
				  {
 | 
			
		||||
					"name": "Свидетельство о гос регистрации",
 | 
			
		||||
					"value": "certificate_of_registration"
 | 
			
		||||
				  },
 | 
			
		||||
				  {
 | 
			
		||||
					"name": "Регистрационное удостоверение",
 | 
			
		||||
					"value": "registration_certificate"
 | 
			
		||||
				  },
 | 
			
		||||
				  {
 | 
			
		||||
					"name": "Отказное письмо",
 | 
			
		||||
					"value": "refused_letter"
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().DirectoryOfDocumentTypes()
 | 
			
		||||
		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 TestListOfCertifiedCategories(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ListOfCertifiedCategoriesParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ListOfCertifiedCategoriesParams{
 | 
			
		||||
				Page:     1,
 | 
			
		||||
				PageSize: 100,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "certification": [
 | 
			
		||||
					{
 | 
			
		||||
					  "is_required": true,
 | 
			
		||||
					  "category_name": "Витаминно-минеральные комплексы для взрослых"
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "total": 1
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ListOfCertifiedCategoriesParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().ListOfCertifiedCategories(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 TestLinkCertificateToProduct(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *LinkCertificateToProductParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&LinkCertificateToProductParams{
 | 
			
		||||
				CertificateId: 50058,
 | 
			
		||||
				ProductId:     []int64{290},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": true
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&LinkCertificateToProductParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().LinkToProduct(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 TestDeleteCertificate(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *DeleteCertificateParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&DeleteCertificateParams{
 | 
			
		||||
				CertificateId: 0,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "is_delete": true,
 | 
			
		||||
				  "error_message": "string"
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&DeleteCertificateParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().Delete(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 TestGetCertificateInfo(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *GetCertificateInfoParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&GetCertificateInfoParams{
 | 
			
		||||
				CertificateNumber: "certificate number",
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "certificate_id": 0,
 | 
			
		||||
				  "certificate_number": "certificate number",
 | 
			
		||||
				  "certificate_name": "string",
 | 
			
		||||
				  "type_code": "string",
 | 
			
		||||
				  "status_code": "string",
 | 
			
		||||
				  "accordance_type_code": "string",
 | 
			
		||||
				  "rejection_reason_code": "string",
 | 
			
		||||
				  "verification_comment": "string",
 | 
			
		||||
				  "issue_date": "2019-08-24T14:15:22Z",
 | 
			
		||||
				  "expire_date": "2019-08-24T14:15:22Z",
 | 
			
		||||
				  "products_count": 0
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&GetCertificateInfoParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().GetInfo(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 resp.Result.CertificateNumber != test.params.CertificateNumber {
 | 
			
		||||
				t.Errorf("Certificate numbers in request and response are not equal")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestListCertificates(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ListCertificatesParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ListCertificatesParams{
 | 
			
		||||
				OfferId:  "id",
 | 
			
		||||
				Status:   "some status",
 | 
			
		||||
				Type:     "some type",
 | 
			
		||||
				Page:     1,
 | 
			
		||||
				PageSize: 1,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "certificates": [
 | 
			
		||||
					{
 | 
			
		||||
					  "certificate_id": 0,
 | 
			
		||||
					  "certificate_number": "string",
 | 
			
		||||
					  "certificate_name": "string",
 | 
			
		||||
					  "type_code": "string",
 | 
			
		||||
					  "status_code": "string",
 | 
			
		||||
					  "accordance_type_code": "string",
 | 
			
		||||
					  "rejection_reason_code": "string",
 | 
			
		||||
					  "verification_comment": "string",
 | 
			
		||||
					  "issue_date": "2019-08-24T14:15:22Z",
 | 
			
		||||
					  "expire_date": "2019-08-24T14:15:22Z",
 | 
			
		||||
					  "products_count": 0
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "page_count": 0
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ListCertificatesParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().List(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 TestProductStatuses(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"code": "string",
 | 
			
		||||
					"name": "string"
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().ProductStatuses()
 | 
			
		||||
		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 TestListProductsForCertificate(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ListProductsForCertificateParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ListProductsForCertificateParams{
 | 
			
		||||
				CertificateId:     0,
 | 
			
		||||
				ProductStatusCode: "status code",
 | 
			
		||||
				Page:              0,
 | 
			
		||||
				PageSize:          0,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "items": [
 | 
			
		||||
					{
 | 
			
		||||
					  "product_id": 0,
 | 
			
		||||
					  "product_status_code": "string"
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "count": 0
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ListProductsForCertificateParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().ListProductsForCertificate(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 TestUnlinkFromProduct(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *UnlinkFromProductParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&UnlinkFromProductParams{
 | 
			
		||||
				CertificateId: 0,
 | 
			
		||||
				ProductId:     []int64{0},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"error": "string",
 | 
			
		||||
					"product_id": 0,
 | 
			
		||||
					"updated": true
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&UnlinkFromProductParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().UnlinkFromProduct(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 TestPossibleRejectReasons(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"code": "string",
 | 
			
		||||
					"name": "string"
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().PossibleRejectReasons()
 | 
			
		||||
		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 TestPossibleStatuses(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"code": "string",
 | 
			
		||||
					"name": "string"
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().PossibleStatuses()
 | 
			
		||||
		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 TestAddCertificatesForProducts(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *AddCertificatesForProductsParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&AddCertificatesForProductsParams{
 | 
			
		||||
				Files:              []byte{10, 15, 2, 0},
 | 
			
		||||
				Name:               "Certificate name",
 | 
			
		||||
				Number:             "10a-d5s9-4asdf2",
 | 
			
		||||
				TypeCode:           "declaration",
 | 
			
		||||
				AccordanceTypeCode: "gost",
 | 
			
		||||
				IssueDate:          time.Now(),
 | 
			
		||||
				ExpireDate:         time.Now(),
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"id": 50058
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&AddCertificatesForProductsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Certificates().AddForProducts(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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										390
									
								
								ozon/chats.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								ozon/chats.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,390 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Chats struct {
 | 
			
		||||
	client *core.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListChatsParams struct {
 | 
			
		||||
	// Chats filter
 | 
			
		||||
	Filter ListChatsFilter `json:"filter"`
 | 
			
		||||
 | 
			
		||||
	// Number of values in the response. Default value is 1
 | 
			
		||||
	Limit int64 `json:"limit" default:"1"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements that will be skipped in the response.
 | 
			
		||||
	// For example, if offset=10, the response will start with the 11th element found
 | 
			
		||||
	Offset int64 `json:"offset"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListChatsFilter struct {
 | 
			
		||||
	// Filter by chat status:
 | 
			
		||||
	//   - All
 | 
			
		||||
	//   - Opened
 | 
			
		||||
	//   - Closed
 | 
			
		||||
	ChatStatus string `json:"chat_status" default:"ALL"`
 | 
			
		||||
 | 
			
		||||
	// Filter by chats with unread messages
 | 
			
		||||
	UnreadOnly bool `json:"unread_only"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListChatsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Chats data
 | 
			
		||||
	Chats []struct {
 | 
			
		||||
		// Chat data
 | 
			
		||||
		Chat struct {
 | 
			
		||||
			// Chat identifier
 | 
			
		||||
			ChatId string `json:"chat_id"`
 | 
			
		||||
 | 
			
		||||
			// Chat status:
 | 
			
		||||
			//   - All
 | 
			
		||||
			//   - Opened
 | 
			
		||||
			//   - Closed
 | 
			
		||||
			ChatStatus string `json:"chat_status"`
 | 
			
		||||
 | 
			
		||||
			// Chat type:
 | 
			
		||||
			//   - Seller_Support — support chat
 | 
			
		||||
			//   - Buyer_Seller — chat with a customer
 | 
			
		||||
			ChatType string `json:"chat_type"`
 | 
			
		||||
 | 
			
		||||
			// Chat creation date
 | 
			
		||||
			CreatedAt time.Time `json:"created_at"`
 | 
			
		||||
		} `json:"chat"`
 | 
			
		||||
 | 
			
		||||
		// Identifier of the first unread chat message
 | 
			
		||||
		FirstUnreadMessageId string `json:"first_unread_message_id"`
 | 
			
		||||
 | 
			
		||||
		// Identifier of the last message in the chat
 | 
			
		||||
		LastMessageId string `json:"last_message_id"`
 | 
			
		||||
 | 
			
		||||
		// Number of unread messages in the chat
 | 
			
		||||
		UnreadCount int64 `json:"unread_count"`
 | 
			
		||||
	} `json:"chats"`
 | 
			
		||||
 | 
			
		||||
	// Total number of chats
 | 
			
		||||
	TotalChatsCount int64 `json:"total_chats_count"`
 | 
			
		||||
 | 
			
		||||
	// Total number of unread messages
 | 
			
		||||
	TotalUnreadCount int64 `json:"total_unread_count"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns information about chats by specified filters
 | 
			
		||||
func (c Chats) List(params *ListChatsParams) (*ListChatsResponse, error) {
 | 
			
		||||
	url := "/v2/chat/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ListChatsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SendMessageParams struct {
 | 
			
		||||
	// Chat identifier
 | 
			
		||||
	ChatId string `json:"chat_id"`
 | 
			
		||||
 | 
			
		||||
	// Message text in the plain text format
 | 
			
		||||
	Text string `json:"text"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SendMessageResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result string `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sends a message to an existing chat by its identifier
 | 
			
		||||
func (c Chats) SendMessage(params *SendMessageParams) (*SendMessageResponse, error) {
 | 
			
		||||
	url := "/v1/chat/send/message"
 | 
			
		||||
 | 
			
		||||
	resp := &SendMessageResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SendFileParams struct {
 | 
			
		||||
	// File as a base64 string
 | 
			
		||||
	Base64Content string `json:"base64_content"`
 | 
			
		||||
 | 
			
		||||
	// Chat identifier
 | 
			
		||||
	ChatId string `json:"chat_id"`
 | 
			
		||||
 | 
			
		||||
	// File name with extension
 | 
			
		||||
	Name string `json:"name"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SendFileResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result string `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sends a file to an existing chat by its identifier
 | 
			
		||||
func (c Chats) SendFile(params *SendFileParams) (*SendFileResponse, error) {
 | 
			
		||||
	url := "/v1/chat/send/file"
 | 
			
		||||
 | 
			
		||||
	resp := &SendFileResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ChatHistoryParams struct {
 | 
			
		||||
	// Chat idenitifier
 | 
			
		||||
	ChatId string `json:"chat_id"`
 | 
			
		||||
 | 
			
		||||
	// Messages sorting direction:
 | 
			
		||||
	//   - Forward—from old messages to new ones.
 | 
			
		||||
	//   - Backward—from new messages to old ones.
 | 
			
		||||
	// The default value is `Backward`. You can set the number of messages in the limit parameter
 | 
			
		||||
	Direction string `json:"direction" default:"Backward"`
 | 
			
		||||
 | 
			
		||||
	// Identifier of the message from which the chat history will be displayed.
 | 
			
		||||
	// Default value is the last visible message
 | 
			
		||||
	FromMessageId string `json:"from_message_id"`
 | 
			
		||||
 | 
			
		||||
	// Number of messages in the response. The default value is 50
 | 
			
		||||
	Limit int64 `json:"limit" default:"50"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ChatHistoryResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Indicates that the response returned only a part of messages
 | 
			
		||||
	HasNext bool `json:"has_next"`
 | 
			
		||||
 | 
			
		||||
	// An array of messages sorted according to the direction parameter in the request body
 | 
			
		||||
	Messages []struct {
 | 
			
		||||
		// Message creation date
 | 
			
		||||
		CreatedAt time.Time `json:"created_at"`
 | 
			
		||||
 | 
			
		||||
		// Array with message content in Markdown format
 | 
			
		||||
		Data []string `json:"data"`
 | 
			
		||||
 | 
			
		||||
		// Indication of the read message
 | 
			
		||||
		IsRead bool `json:"is_read"`
 | 
			
		||||
 | 
			
		||||
		// Message identifier
 | 
			
		||||
		MessageId string `json:"message_id"`
 | 
			
		||||
 | 
			
		||||
		// Chat participant identifier
 | 
			
		||||
		User struct {
 | 
			
		||||
			// Chat participant identifier
 | 
			
		||||
			Id string `json:"id"`
 | 
			
		||||
 | 
			
		||||
			// Chat participant type:
 | 
			
		||||
			//   - customer
 | 
			
		||||
			//   - seller
 | 
			
		||||
			//   - crm—system messages
 | 
			
		||||
			//   - courier
 | 
			
		||||
			//   - support
 | 
			
		||||
			Type string `json:"type"`
 | 
			
		||||
		} `json:"user"`
 | 
			
		||||
	} `json:"messages"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Chat history
 | 
			
		||||
func (c Chats) History(params *ChatHistoryParams) (*ChatHistoryResponse, error) {
 | 
			
		||||
	url := "/v2/chat/history"
 | 
			
		||||
 | 
			
		||||
	resp := &ChatHistoryResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UpdateChatParams struct {
 | 
			
		||||
	// Chat identifier
 | 
			
		||||
	ChatId string `json:"chat_id"`
 | 
			
		||||
 | 
			
		||||
	// Message identifier
 | 
			
		||||
	FromMessageId uint64 `json:"from_message_id"`
 | 
			
		||||
 | 
			
		||||
	// Number of messages in the response
 | 
			
		||||
	Limit int64 `json:"limit"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UpdateChatResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		// An order or a product user wrote about in the chat
 | 
			
		||||
		Context struct {
 | 
			
		||||
			// Product inforamtion
 | 
			
		||||
			Item struct {
 | 
			
		||||
				// Product identifier in the Ozon system, SKU
 | 
			
		||||
				SKU int64 `json:"sku"`
 | 
			
		||||
			} `json:"item"`
 | 
			
		||||
 | 
			
		||||
			// Order information
 | 
			
		||||
			Order struct {
 | 
			
		||||
				// Order number
 | 
			
		||||
				OrderNumber string `json:"order_number"`
 | 
			
		||||
 | 
			
		||||
				// Shipment information
 | 
			
		||||
				Postings []struct {
 | 
			
		||||
					// Delivery scheme:
 | 
			
		||||
					//   - FBO
 | 
			
		||||
					//   - FBS
 | 
			
		||||
					//   - RFBS
 | 
			
		||||
					//   - Crossborder
 | 
			
		||||
					DeliverySchema string `json:"delivery_schema"`
 | 
			
		||||
 | 
			
		||||
					// Shipment number
 | 
			
		||||
					PostingNumber string `json:"posting_number"`
 | 
			
		||||
 | 
			
		||||
					// List of product identifiers in the shipment
 | 
			
		||||
					SKUList []int64 `json:"sku_list"`
 | 
			
		||||
				} `json:"postings"`
 | 
			
		||||
			} `json:"order"`
 | 
			
		||||
		} `json:"context"`
 | 
			
		||||
 | 
			
		||||
		// Creation date and time
 | 
			
		||||
		CreatedAt time.Time `json:"created_at"`
 | 
			
		||||
 | 
			
		||||
		// Information about the file in the chat. Displayed only for `type = file`
 | 
			
		||||
		File struct {
 | 
			
		||||
			// File type
 | 
			
		||||
			Mime string `json:"mime"`
 | 
			
		||||
 | 
			
		||||
			// File name
 | 
			
		||||
			Name string `json:"name"`
 | 
			
		||||
 | 
			
		||||
			// File size in bytes
 | 
			
		||||
			Size int64 `json:"size"`
 | 
			
		||||
 | 
			
		||||
			// File URL
 | 
			
		||||
			URL string `json:"url"`
 | 
			
		||||
		} `json:"file"`
 | 
			
		||||
 | 
			
		||||
		// File identifier
 | 
			
		||||
		Id uint64 `json:"id"`
 | 
			
		||||
 | 
			
		||||
		// Message. Displayed only for `type = text`
 | 
			
		||||
		Text string `json:"text"`
 | 
			
		||||
 | 
			
		||||
		// Message type:
 | 
			
		||||
		//   - text
 | 
			
		||||
		//   - file
 | 
			
		||||
		Type string `json:"type"`
 | 
			
		||||
 | 
			
		||||
		// Chat participant information
 | 
			
		||||
		User struct {
 | 
			
		||||
			// Chat participant identifier
 | 
			
		||||
			Id string `json:"id"`
 | 
			
		||||
 | 
			
		||||
			// Chat participant chat:
 | 
			
		||||
			//   - customer
 | 
			
		||||
			//   - seller
 | 
			
		||||
			//   - crm—system messages
 | 
			
		||||
			//   - courier
 | 
			
		||||
			Type string `json:"type"`
 | 
			
		||||
		} `json:"user"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update chat
 | 
			
		||||
func (c Chats) Update(params *UpdateChatParams) (*UpdateChatResponse, error) {
 | 
			
		||||
	url := "/v1/chat/updates"
 | 
			
		||||
 | 
			
		||||
	resp := &UpdateChatResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CreateNewChatParams struct {
 | 
			
		||||
	// Shipment identifier
 | 
			
		||||
	PostingNumber string `json:"posting_number"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CreateNewChatResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	//Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Chat identifier
 | 
			
		||||
		ChatId string `json:"chat_id"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Creates a new chat on the shipment with the customer. For example, to clarify the address or the product model
 | 
			
		||||
func (c Chats) Create(params *CreateNewChatParams) (*CreateNewChatResponse, error) {
 | 
			
		||||
	url := "/v1/chat/start"
 | 
			
		||||
 | 
			
		||||
	resp := &CreateNewChatResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MarkAsReadParams struct {
 | 
			
		||||
	// Chat identifier
 | 
			
		||||
	Chatid string `json:"chat_id"`
 | 
			
		||||
 | 
			
		||||
	// Message identifier
 | 
			
		||||
	FromMessageId uint64 `json:"from_message_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MarkAsReadResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Number of unread messages in the chat
 | 
			
		||||
	UnreadCount int64 `json:"unread_count"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A method for marking the selected message and messages before it as read
 | 
			
		||||
func (c Chats) MarkAsRead(params *MarkAsReadParams) (*MarkAsReadResponse, error) {
 | 
			
		||||
	url := "/v2/chat/read"
 | 
			
		||||
 | 
			
		||||
	resp := &MarkAsReadResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										409
									
								
								ozon/chats_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										409
									
								
								ozon/chats_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,409 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestListChats(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ListChatsParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ListChatsParams{
 | 
			
		||||
				Filter: ListChatsFilter{
 | 
			
		||||
					ChatStatus: "Opened",
 | 
			
		||||
					UnreadOnly: true,
 | 
			
		||||
				},
 | 
			
		||||
				Limit:  1,
 | 
			
		||||
				Offset: 0,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"chats": [
 | 
			
		||||
				  {
 | 
			
		||||
					"chat": {
 | 
			
		||||
					  "created_at": "2022-07-22T08:07:19.581Z",
 | 
			
		||||
					  "chat_id": "5e767w03-b400-4y1b-a841-75319ca8a5c8",
 | 
			
		||||
					  "chat_status": "Opened",
 | 
			
		||||
					  "chat_type": "Seller_Support"
 | 
			
		||||
					},
 | 
			
		||||
					"first_unread_message_id": "3000000000118021931",
 | 
			
		||||
					"last_message_id": "30000000001280042740",
 | 
			
		||||
					"unread_count": 1
 | 
			
		||||
				  }
 | 
			
		||||
				],
 | 
			
		||||
				"total_chats_count": 25,
 | 
			
		||||
				"total_unread_count": 5
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ListChatsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Chats().List(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.Chats) > 0 {
 | 
			
		||||
				if resp.Chats[0].Chat.ChatStatus == "" {
 | 
			
		||||
					t.Errorf("Chat status cannot be empty")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Chats[0].Chat.ChatType == "" {
 | 
			
		||||
					t.Errorf("Chat type cannot be empty")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSendMessage(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *SendMessageParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&SendMessageParams{
 | 
			
		||||
				ChatId: "99feb3fc-a474-469f-95d5-268b470cc607",
 | 
			
		||||
				Text:   "test",
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": "success"
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&SendMessageParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Chats().SendMessage(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 TestSendFile(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *SendFileParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&SendFileParams{
 | 
			
		||||
				ChatId:        "99feb3fc-a474-469f-95d5-268b470cc607",
 | 
			
		||||
				Name:          "tempor",
 | 
			
		||||
				Base64Content: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=",
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": "success"
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&SendFileParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Chats().SendFile(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 TestChatHistory(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ChatHistoryParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ChatHistoryParams{
 | 
			
		||||
				ChatId:        "18b8e1f9-4ae7-461c-84ea-8e1f54d1a45e",
 | 
			
		||||
				Direction:     "Forward",
 | 
			
		||||
				FromMessageId: "3000000000118032000",
 | 
			
		||||
				Limit:         1,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"has_next": true,
 | 
			
		||||
				"messages": [
 | 
			
		||||
				  {
 | 
			
		||||
					"message_id": "3000000000817031942",
 | 
			
		||||
					"user": {
 | 
			
		||||
					  "id": "115568",
 | 
			
		||||
					  "type": "Сustomer"
 | 
			
		||||
					},
 | 
			
		||||
					"created_at": "2022-07-18T20:58:04.528Z",
 | 
			
		||||
					"is_read": true,
 | 
			
		||||
					"data": [
 | 
			
		||||
					  "Здравствуйте, у меня вопрос по вашему товару \"Стекло защитное для смартфонов\", артикул 11223. Подойдет ли он на данную [ модель ](https://www.ozon.ru/product/smartfon-samsung-galaxy-a03s-4-64-gb-chernyy) телефона?"
 | 
			
		||||
					]
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ChatHistoryParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Chats().History(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 TestUpdateChat(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *UpdateChatParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&UpdateChatParams{
 | 
			
		||||
				ChatId:        "99feb3fc-a474-469f-95d5-268b470cc607",
 | 
			
		||||
				FromMessageId: 0,
 | 
			
		||||
				Limit:         1000,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"id": 3000000000012735500,
 | 
			
		||||
					"user": {
 | 
			
		||||
					  "id": "15",
 | 
			
		||||
					  "type": "seller"
 | 
			
		||||
					},
 | 
			
		||||
					"type": "file",
 | 
			
		||||
					"text": "",
 | 
			
		||||
					"file": {
 | 
			
		||||
					  "url": "https://cdn-stg.ozonru.me/s3/fs-chat-api/108a0370-4dfa-11ec-bd02-06a332735108.png",
 | 
			
		||||
					  "mime": "image/png",
 | 
			
		||||
					  "size": 68,
 | 
			
		||||
					  "name": "tempor"
 | 
			
		||||
					},
 | 
			
		||||
					"created_at": "2021-11-25T14:14:55Z",
 | 
			
		||||
					"context": null
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&UpdateChatParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Chats().Update(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 TestCreateNewChat(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *CreateNewChatParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&CreateNewChatParams{
 | 
			
		||||
				PostingNumber: "47873153-0052-1",
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "chat_id": "5969c331-2e64-44b7-8a0e-ff9526762c62"
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&CreateNewChatParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Chats().Create(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 resp.Result.ChatId == "" {
 | 
			
		||||
				t.Errorf("Chat id cannot be empty")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMarkAsRead(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *MarkAsReadParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&MarkAsReadParams{
 | 
			
		||||
				Chatid:        "99feb3fc-a474-469f-95d5-268b470cc607",
 | 
			
		||||
				FromMessageId: 3000000000118032000,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"unread_count": 0
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&MarkAsReadParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Chats().MarkAsRead(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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										315
									
								
								ozon/common.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								ozon/common.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,315 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
type Order string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Ascending  Order = "ASC"
 | 
			
		||||
	Descending Order = "DESC"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type GetAnalyticsDataFilterOperation string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Equal        GetAnalyticsDataFilterOperation = "EQ"
 | 
			
		||||
	Greater      GetAnalyticsDataFilterOperation = "GT"
 | 
			
		||||
	GreaterEqual GetAnalyticsDataFilterOperation = "GTE"
 | 
			
		||||
	Lesser       GetAnalyticsDataFilterOperation = "LT"
 | 
			
		||||
	LesserEqual  GetAnalyticsDataFilterOperation = "LTE"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type GetAnalyticsDataFilterMetric string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	UnknownMetric         GetAnalyticsDataFilterMetric = "unknown_metric"
 | 
			
		||||
	HitsViewSearch        GetAnalyticsDataFilterMetric = "hits_view_search"
 | 
			
		||||
	HistViewPDP           GetAnalyticsDataFilterMetric = "hits_view_pdp"
 | 
			
		||||
	HitsView              GetAnalyticsDataFilterMetric = "hist_view"
 | 
			
		||||
	HitsToCartSearch      GetAnalyticsDataFilterMetric = "hits_tocart_search"
 | 
			
		||||
	HitsToCartPDP         GetAnalyticsDataFilterMetric = "hits_tocart_pdp"
 | 
			
		||||
	SessionViewSearch     GetAnalyticsDataFilterMetric = "session_view_search"
 | 
			
		||||
	SessionViewPDP        GetAnalyticsDataFilterMetric = "session_view_pdp"
 | 
			
		||||
	SessionView           GetAnalyticsDataFilterMetric = "session_view"
 | 
			
		||||
	ConvToCartSearch      GetAnalyticsDataFilterMetric = "conv_tocart_search"
 | 
			
		||||
	ConvToCartPDP         GetAnalyticsDataFilterMetric = "conv_tocart_pdp"
 | 
			
		||||
	ConvToCart            GetAnalyticsDataFilterMetric = "conv_tocart"
 | 
			
		||||
	Revenue               GetAnalyticsDataFilterMetric = "revenue"
 | 
			
		||||
	ReturnsMetric         GetAnalyticsDataFilterMetric = "returns"
 | 
			
		||||
	CancellationsMetric   GetAnalyticsDataFilterMetric = "cancellations"
 | 
			
		||||
	OrderedUnits          GetAnalyticsDataFilterMetric = "ordered_units"
 | 
			
		||||
	DeliveredUnits        GetAnalyticsDataFilterMetric = "delivered_units"
 | 
			
		||||
	AdvViewPDP            GetAnalyticsDataFilterMetric = "adv_view_pdp"
 | 
			
		||||
	AdvViewSearchCategory GetAnalyticsDataFilterMetric = "adv_view_search_category"
 | 
			
		||||
	AdvViewAll            GetAnalyticsDataFilterMetric = "adv_view_all"
 | 
			
		||||
	AdvSumAll             GetAnalyticsDataFilterMetric = "adv_sum_all"
 | 
			
		||||
	PositionCategory      GetAnalyticsDataFilterMetric = "position_category"
 | 
			
		||||
	PostingsMetric        GetAnalyticsDataFilterMetric = "postings"
 | 
			
		||||
	PostingsPremium       GetAnalyticsDataFilterMetric = "postings_premium"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type WarehouseType string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Ozon warehouses with Fresh delivery
 | 
			
		||||
	ExpressDarkStore WarehouseType = "EXPRESS_DARK_STORE"
 | 
			
		||||
 | 
			
		||||
	// Ozon warehouses without Fresh delivery
 | 
			
		||||
	NotExressDarkStore WarehouseType = "NOT_EXPRESS_DARK_STORE"
 | 
			
		||||
 | 
			
		||||
	// All Ozon warehouses
 | 
			
		||||
	ALLWarehouseType WarehouseType = "ALL"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Language string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Default Language = "DEFAULT"
 | 
			
		||||
	Russian Language = "RU"
 | 
			
		||||
	English Language = "EN"
 | 
			
		||||
	Turkish Language = "TR"
 | 
			
		||||
	Chinese Language = "ZH_HANS"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AttributeType string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	All      AttributeType = "ALL"
 | 
			
		||||
	Required AttributeType = "REQUIRED"
 | 
			
		||||
	Optional AttributeType = "OPTIONAL"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ListDiscountRequestsStatus string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	New            ListDiscountRequestsStatus = "NEW"
 | 
			
		||||
	Seen           ListDiscountRequestsStatus = "SEEN"
 | 
			
		||||
	Approved       ListDiscountRequestsStatus = "APPROVED"
 | 
			
		||||
	PartlyApproved ListDiscountRequestsStatus = "PARTLY_APPROVED"
 | 
			
		||||
	Declined       ListDiscountRequestsStatus = "DECLINED"
 | 
			
		||||
	AutoDeclined   ListDiscountRequestsStatus = "AUTO_DECLINED"
 | 
			
		||||
	DeclinedByUser ListDiscountRequestsStatus = "DECLINED_BY_USER"
 | 
			
		||||
	Coupon         ListDiscountRequestsStatus = "COUPON"
 | 
			
		||||
	Purchased      ListDiscountRequestsStatus = "PURCHASED"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type WorkingDay string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Mon WorkingDay = "1"
 | 
			
		||||
	Tue WorkingDay = "2"
 | 
			
		||||
	Wed WorkingDay = "3"
 | 
			
		||||
	Thu WorkingDay = "4"
 | 
			
		||||
	Fri WorkingDay = "5"
 | 
			
		||||
	Sat WorkingDay = "6"
 | 
			
		||||
	Sun WorkingDay = "7"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type GetAnalyticsDataDimension string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	UnknownDimension   GetAnalyticsDataDimension = "unknownDimension"
 | 
			
		||||
	SKUDimension       GetAnalyticsDataDimension = "sku"
 | 
			
		||||
	SPUDimension       GetAnalyticsDataDimension = "spu"
 | 
			
		||||
	DayDimension       GetAnalyticsDataDimension = "day"
 | 
			
		||||
	WeekDimension      GetAnalyticsDataDimension = "week"
 | 
			
		||||
	MonthDimension     GetAnalyticsDataDimension = "month"
 | 
			
		||||
	YearDimension      GetAnalyticsDataDimension = "year"
 | 
			
		||||
	Category1Dimension GetAnalyticsDataDimension = "category1"
 | 
			
		||||
	Category2Dimension GetAnalyticsDataDimension = "category2"
 | 
			
		||||
	Category3Dimension GetAnalyticsDataDimension = "category3"
 | 
			
		||||
	Category4Dimension GetAnalyticsDataDimension = "category4"
 | 
			
		||||
	BrandDimension     GetAnalyticsDataDimension = "brand"
 | 
			
		||||
	ModelIDDimension   GetAnalyticsDataDimension = "modelID"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SupplyRequestState string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// request draft. Only for supplies via vDC
 | 
			
		||||
	Draft SupplyRequestState = "DRAFT"
 | 
			
		||||
 | 
			
		||||
	// selecting supply options. Only for supplies via vDC
 | 
			
		||||
	SupplyVariantsArranging SupplyRequestState = "SUPPLY_VARIANTS_ARRANGING"
 | 
			
		||||
 | 
			
		||||
	// no supply options, the request is archived. Only for supplies via vDC
 | 
			
		||||
	HasNoSupplyVariantsArchive SupplyRequestState = "HAS_NO_SUPPLY_VARIANTS_ARCHIVE"
 | 
			
		||||
 | 
			
		||||
	// no supply options. Only for supplies via vDC
 | 
			
		||||
	HasNoSupplyVariantsNew SupplyRequestState = "HAS_NO_SUPPLY_VARIANTS_NEW"
 | 
			
		||||
 | 
			
		||||
	// supply being approved. Only for supplies via vDC
 | 
			
		||||
	SupplyVariantsConfirmation SupplyRequestState = "SUPPLY_VARIANTS_CONFIRMATION"
 | 
			
		||||
 | 
			
		||||
	// time reservation
 | 
			
		||||
	TimeslotBooking SupplyRequestState = "TIMESLOT_BOOKING"
 | 
			
		||||
 | 
			
		||||
	// filling in the data
 | 
			
		||||
	DATA_FILLING SupplyRequestState = "DATA_FILLING"
 | 
			
		||||
 | 
			
		||||
	// ready for shipment
 | 
			
		||||
	ReadyToSupply SupplyRequestState = "READY_TO_SUPPLY"
 | 
			
		||||
 | 
			
		||||
	// accepted at the shipping point
 | 
			
		||||
	AcceptedAtSupplyWarehouse SupplyRequestState = "ACCEPTED_AT_SUPPLY_WAREHOUSE"
 | 
			
		||||
 | 
			
		||||
	// on the way
 | 
			
		||||
	InTransit SupplyRequestState = "IN_TRANSIT"
 | 
			
		||||
 | 
			
		||||
	// acceptance at the warehouse
 | 
			
		||||
	AcceptanceAtStorageWarehouse SupplyRequestState = "ACCEPTANCE_AT_STORAGE_WAREHOUSE"
 | 
			
		||||
 | 
			
		||||
	// acts being approved
 | 
			
		||||
	ReportsConfirmationAwaiting SupplyRequestState = "REPORTS_CONFIRMATION_AWAITING"
 | 
			
		||||
 | 
			
		||||
	// dispute
 | 
			
		||||
	ReportRejected SupplyRequestState = "REPORT_REJECTED"
 | 
			
		||||
 | 
			
		||||
	// completed
 | 
			
		||||
	Completed SupplyRequestState = "COMPLETED"
 | 
			
		||||
 | 
			
		||||
	// refused acceptance
 | 
			
		||||
	RejectedAtSupplyWarehouse SupplyRequestState = "REJECTED_AT_SUPPLY_WAREHOUSE"
 | 
			
		||||
 | 
			
		||||
	// cancelled
 | 
			
		||||
	Cancelled SupplyRequestState = "CANCELLED"
 | 
			
		||||
 | 
			
		||||
	// overdue
 | 
			
		||||
	Overdue SupplyRequestState = "OVERDUE"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ShipmentStatus string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// acceptance is in progress
 | 
			
		||||
	AcceptanceInProgress ShipmentStatus = "acceptance_in_progress"
 | 
			
		||||
 | 
			
		||||
	// arbitration
 | 
			
		||||
	Arbitration ShipmentStatus = "arbitration"
 | 
			
		||||
 | 
			
		||||
	// awaiting confirmation
 | 
			
		||||
	AwaitingApprove ShipmentStatus = "awaiting_approve"
 | 
			
		||||
 | 
			
		||||
	// awaiting shipping
 | 
			
		||||
	AwaitingDeliver ShipmentStatus = "awaiting_deliver"
 | 
			
		||||
 | 
			
		||||
	// awaiting packaging
 | 
			
		||||
	AwaitingPackaging ShipmentStatus = "awaiting_packaging"
 | 
			
		||||
 | 
			
		||||
	// created
 | 
			
		||||
	AwaitingVerification ShipmentStatus = "awaiting_verification"
 | 
			
		||||
 | 
			
		||||
	// cancelled
 | 
			
		||||
	CancelledSubstatus ShipmentStatus = "cancelled"
 | 
			
		||||
 | 
			
		||||
	// delivered
 | 
			
		||||
	Delivered ShipmentStatus = "delivered"
 | 
			
		||||
 | 
			
		||||
	// delivery is in progress
 | 
			
		||||
	Delivering ShipmentStatus = "delivering"
 | 
			
		||||
 | 
			
		||||
	// picked up by driver
 | 
			
		||||
	DriverPickup ShipmentStatus = "driver_pickup"
 | 
			
		||||
 | 
			
		||||
	// not accepted at the sorting center
 | 
			
		||||
	NotAccepted ShipmentStatus = "not_accepted"
 | 
			
		||||
 | 
			
		||||
	// sent by the seller
 | 
			
		||||
	SentBySeller ShipmentStatus = "sent_by_seller"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ShipmentSubstatus string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// acceptance in progress
 | 
			
		||||
	PostingAcceptanceInProgress ShipmentStatus = "posting_acceptance_in_progress"
 | 
			
		||||
 | 
			
		||||
	// arbitrage
 | 
			
		||||
	PostingInArbitration ShipmentStatus = "posting_in_arbitration"
 | 
			
		||||
 | 
			
		||||
	// created
 | 
			
		||||
	PostingCreated ShipmentStatus = "posting_created"
 | 
			
		||||
 | 
			
		||||
	// in the freight
 | 
			
		||||
	PostingInCarriage ShipmentStatus = "posting_in_carriage"
 | 
			
		||||
 | 
			
		||||
	// not added to the freight
 | 
			
		||||
	PostingNotInCarriage ShipmentStatus = "posting_not_in_carriage"
 | 
			
		||||
 | 
			
		||||
	// registered
 | 
			
		||||
	PostingRegistered ShipmentStatus = "posting_registered"
 | 
			
		||||
 | 
			
		||||
	// is handed over to the delivery service
 | 
			
		||||
	PostingTransferringToDelivery ShipmentStatus = "posting_transferring_to_delivery"
 | 
			
		||||
 | 
			
		||||
	// waiting for passport data
 | 
			
		||||
	PostingAwaitingPassportData ShipmentStatus = "posting_awaiting_passport_data"
 | 
			
		||||
 | 
			
		||||
	// created
 | 
			
		||||
	PostingCreatedSubstatus ShipmentStatus = "posting_created"
 | 
			
		||||
 | 
			
		||||
	// awaiting registration
 | 
			
		||||
	PostingAwaitingRegistration ShipmentStatus = "posting_awaiting_registration"
 | 
			
		||||
 | 
			
		||||
	// registration error
 | 
			
		||||
	PostingRegistrationError ShipmentStatus = "posting_registration_error"
 | 
			
		||||
 | 
			
		||||
	// created
 | 
			
		||||
	PostingSplitPending ShipmentStatus = "posting_split_pending"
 | 
			
		||||
 | 
			
		||||
	// canceled
 | 
			
		||||
	PostingCancelled ShipmentStatus = "posting_canceled"
 | 
			
		||||
 | 
			
		||||
	// customer delivery arbitrage
 | 
			
		||||
	PostingInClientArbitration ShipmentStatus = "posting_in_client_arbitration"
 | 
			
		||||
 | 
			
		||||
	// delivered
 | 
			
		||||
	PostingDelivered ShipmentStatus = "posting_delivered"
 | 
			
		||||
 | 
			
		||||
	// recieved
 | 
			
		||||
	PostingReceived ShipmentStatus = "posting_received"
 | 
			
		||||
 | 
			
		||||
	// presumably delivered
 | 
			
		||||
	PostingConditionallyDelivered ShipmentStatus = "posting_conditionally_delivered"
 | 
			
		||||
 | 
			
		||||
	// courier on the way
 | 
			
		||||
	PostingInCourierService ShipmentStatus = "posting_in_courier_service"
 | 
			
		||||
 | 
			
		||||
	// at the pick-up point
 | 
			
		||||
	PostingInPickupPoint ShipmentStatus = "posting_in_pickup_point"
 | 
			
		||||
 | 
			
		||||
	// on the way to the city
 | 
			
		||||
	PostingOnWayToCity ShipmentStatus = "posting_on_way_to_city"
 | 
			
		||||
 | 
			
		||||
	// on the way to the pick-up point
 | 
			
		||||
	PostingOnWayToPickupPoint ShipmentStatus = "posting_on_way_to_pickup_point"
 | 
			
		||||
 | 
			
		||||
	// returned to the warehouse
 | 
			
		||||
	PostingReturnedToWarehouse ShipmentStatus = "posting_returned_to_warehouse"
 | 
			
		||||
 | 
			
		||||
	// is handed over to the courier
 | 
			
		||||
	PostingTransferredToCourierService ShipmentStatus = "posting_transferred_to_courier_service"
 | 
			
		||||
 | 
			
		||||
	// handed over to the driver
 | 
			
		||||
	PostingDriverPickup ShipmentStatus = "posting_driver_pick_up"
 | 
			
		||||
 | 
			
		||||
	// not accepted at the sorting center
 | 
			
		||||
	PostingNotInSortCenter ShipmentStatus = "posting_not_in_sort_center"
 | 
			
		||||
 | 
			
		||||
	// sent by the seller
 | 
			
		||||
	SentBySellerSubstatus ShipmentStatus = "sent_by_seller"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TPLIntegrationType string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// delivery by the Ozon logistics
 | 
			
		||||
	OzonTPLType TPLIntegrationType = "ozon"
 | 
			
		||||
 | 
			
		||||
	// delivery by a third-party service, Ozon registers the order
 | 
			
		||||
	AggregatorTPLType TPLIntegrationType = "aggregator"
 | 
			
		||||
 | 
			
		||||
	// delivery by a third-party service, the seller registers the order
 | 
			
		||||
	TrackingTPLType TPLIntegrationType = "3pl_tracking"
 | 
			
		||||
 | 
			
		||||
	// delivery by the seller
 | 
			
		||||
	NonIntegratedTPLType TPLIntegrationType = "non_integrated"
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										342
									
								
								ozon/fbo.go
									
									
									
									
									
								
							
							
						
						
									
										342
									
								
								ozon/fbo.go
									
									
									
									
									
								
							@@ -99,19 +99,7 @@ type GetFBOShipmentsListResponse struct {
 | 
			
		||||
		CreatedAt time.Time `json:"created_at"`
 | 
			
		||||
 | 
			
		||||
		// Financial data
 | 
			
		||||
		FinancialData struct {
 | 
			
		||||
			// Identifier of the cluster, where the shipment is sent from
 | 
			
		||||
			ClusterFrom string `json:"cluster_from"`
 | 
			
		||||
 | 
			
		||||
			// Identifier of the cluster, where the shipment is delivered to
 | 
			
		||||
			ClusterTo string `json:"cluster_to"`
 | 
			
		||||
 | 
			
		||||
			// Services
 | 
			
		||||
			PostingServices MarketplaceServices `json:"posting_services"`
 | 
			
		||||
 | 
			
		||||
			// Products list
 | 
			
		||||
			Products []FinancialDataProduct `json:"products"`
 | 
			
		||||
		} `json:"financial_data"`
 | 
			
		||||
		FinancialData FBOFinancialData `json:"financial_data"`
 | 
			
		||||
 | 
			
		||||
		// Date and time of shipment processing start
 | 
			
		||||
		InProccessAt time.Time `json:"in_process_at"`
 | 
			
		||||
@@ -126,7 +114,14 @@ type GetFBOShipmentsListResponse struct {
 | 
			
		||||
		PostingNumber string `json:"posting_number"`
 | 
			
		||||
 | 
			
		||||
		// Number of products in the shipment
 | 
			
		||||
		Products []struct {
 | 
			
		||||
		Products []FBOPostingProduct `json:"products"`
 | 
			
		||||
 | 
			
		||||
		// Shipment status
 | 
			
		||||
		Status string `json:"status"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FBOPostingProduct struct {
 | 
			
		||||
	// Activation codes for services and digital products
 | 
			
		||||
	DigitalCodes []string `json:"digital_codes"`
 | 
			
		||||
 | 
			
		||||
@@ -147,20 +142,327 @@ type GetFBOShipmentsListResponse struct {
 | 
			
		||||
 | 
			
		||||
	// Product identifier in the Ozon system, SKU
 | 
			
		||||
	SKU int64 `json:"sku"`
 | 
			
		||||
		} `json:"products"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		// Shipment status
 | 
			
		||||
		Status string `json:"status"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
type FBOFinancialData struct {
 | 
			
		||||
	// Identifier of the cluster, where the shipment is sent from
 | 
			
		||||
	ClusterFrom string `json:"cluster_from"`
 | 
			
		||||
 | 
			
		||||
	// Identifier of the cluster, where the shipment is delivered to
 | 
			
		||||
	ClusterTo string `json:"cluster_to"`
 | 
			
		||||
 | 
			
		||||
	// Services
 | 
			
		||||
	PostingServices MarketplaceServices `json:"posting_services"`
 | 
			
		||||
 | 
			
		||||
	// Products list
 | 
			
		||||
	Products []FinancialDataProduct `json:"products"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a list of shipments for a specified period of time. You can additionally filter the shipments by their status
 | 
			
		||||
func (c FBO) GetFBOShipmentsList(params *GetFBOShipmentsListParams) (*GetFBOShipmentsListResponse, error) {
 | 
			
		||||
func (c FBO) GetShipmentsList(params *GetFBOShipmentsListParams) (*GetFBOShipmentsListResponse, error) {
 | 
			
		||||
	url := "/v2/posting/fbo/list"
 | 
			
		||||
 | 
			
		||||
	resp := &GetFBOShipmentsListResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetShipmentDetailsParams struct {
 | 
			
		||||
	// Shipment number
 | 
			
		||||
	PostingNumber string `json:"posting_number"`
 | 
			
		||||
 | 
			
		||||
	// true if the address transliteration from Cyrillic to Latin is enabled
 | 
			
		||||
	Translit bool `json:"translit"`
 | 
			
		||||
 | 
			
		||||
	// Additional fields to add to the response
 | 
			
		||||
	With GetShipmentDetailsWith `json:"with"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetShipmentDetailsWith struct {
 | 
			
		||||
	// Specify true to add analytics data to the response
 | 
			
		||||
	AnalyticsData bool `json:"analytics_data"`
 | 
			
		||||
 | 
			
		||||
	// Specify true to add financial data to the response
 | 
			
		||||
	FinancialData bool `json:"financial_data"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetShipmentDetailsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Additional data
 | 
			
		||||
		AdditionalData []struct {
 | 
			
		||||
			Key   string `json:"key"`
 | 
			
		||||
			Value string `json:"value"`
 | 
			
		||||
		} `json:"additional_data"`
 | 
			
		||||
 | 
			
		||||
		// Analytical data
 | 
			
		||||
		AnalyticsData struct {
 | 
			
		||||
			// Delivery city
 | 
			
		||||
			City string `json:"Delivery city"`
 | 
			
		||||
 | 
			
		||||
			// Delivery method
 | 
			
		||||
			DeliveryType string `json:"delivery_type"`
 | 
			
		||||
 | 
			
		||||
			// Indication that the recipient is a legal person:
 | 
			
		||||
			//   - true — a legal person
 | 
			
		||||
			//   - false — a natural person
 | 
			
		||||
			IsLegal bool `json:"is_legal"`
 | 
			
		||||
 | 
			
		||||
			// Premium subscription
 | 
			
		||||
			IsPremium bool `json:"is_premium"`
 | 
			
		||||
 | 
			
		||||
			// Payment method
 | 
			
		||||
			PaymentTypeGroupName string `json:"payment_type_group_name"`
 | 
			
		||||
 | 
			
		||||
			// Delivery region
 | 
			
		||||
			Region string `json:"region"`
 | 
			
		||||
 | 
			
		||||
			// Warehouse identifier
 | 
			
		||||
			WarehouseId int64 `json:"warehouse_id"`
 | 
			
		||||
 | 
			
		||||
			// Name of the warehouse from which the order is shipped
 | 
			
		||||
			WarehouseName string `json:"warehouse_name"`
 | 
			
		||||
		} `json:"analytics_data"`
 | 
			
		||||
 | 
			
		||||
		// Shipment cancellation reason identifier
 | 
			
		||||
		CancelReasonId int64 `json:"cancel_reason_id"`
 | 
			
		||||
 | 
			
		||||
		// Date and time of shipment creation
 | 
			
		||||
		CreatedAt time.Time `json:"created_at"`
 | 
			
		||||
 | 
			
		||||
		// Financial data
 | 
			
		||||
		FinancialData FBOFinancialData `json:"financial_data"`
 | 
			
		||||
 | 
			
		||||
		// Date and time of shipment processing start
 | 
			
		||||
		InProcessAt time.Time `json:"in_process_at"`
 | 
			
		||||
 | 
			
		||||
		// Identifier of the order to which the shipment belongs
 | 
			
		||||
		OrderId int64 `json:"order_id"`
 | 
			
		||||
 | 
			
		||||
		// Number of the order to which the shipment belongs
 | 
			
		||||
		OrderNumber string `json:"order_number"`
 | 
			
		||||
 | 
			
		||||
		// Shipment number
 | 
			
		||||
		PostingNumber string `json:"posting_number"`
 | 
			
		||||
 | 
			
		||||
		// Number of products in the shipment
 | 
			
		||||
		Products []FBOPostingProduct `json:"products"`
 | 
			
		||||
 | 
			
		||||
		// Shipment status
 | 
			
		||||
		Status string `json:"status"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns information about the shipment by its identifier
 | 
			
		||||
func (c FBO) GetShipmentDetails(params *GetShipmentDetailsParams) (*GetShipmentDetailsResponse, error) {
 | 
			
		||||
	url := "/v2/posting/fbo/get"
 | 
			
		||||
 | 
			
		||||
	resp := &GetShipmentDetailsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListSupplyRequestsParams struct {
 | 
			
		||||
	// Number of the page returned in the request
 | 
			
		||||
	Page int32 `json:"page"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements on the page
 | 
			
		||||
	PageSize int32 `json:"page_size"`
 | 
			
		||||
 | 
			
		||||
	// Filter on status of a supply by request
 | 
			
		||||
	States []SupplyRequestState `json:"states"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListSupplyRequestsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Indicates that the response contains not the entire array of supply requests:
 | 
			
		||||
	//   - true — make a new request with a different page and page_size values to get information on the remaining requests;
 | 
			
		||||
	//   - false — the entire array of requests for the filter specified in the request was returned in the response
 | 
			
		||||
	HasNext bool `json:"has_next"`
 | 
			
		||||
 | 
			
		||||
	// Supply requests list
 | 
			
		||||
	SupplyOrders []SupplyRequestCommonResponse `json:"supply_orders"`
 | 
			
		||||
 | 
			
		||||
	// Total requests number
 | 
			
		||||
	TotalSupplyOrdersCount int32 `json:"total_supply_orders_count"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SupplyRequestCommonResponse struct {
 | 
			
		||||
	// Supply request creation date
 | 
			
		||||
	CreatedAt string `json:"created_at"`
 | 
			
		||||
 | 
			
		||||
	// Local time supply interval
 | 
			
		||||
	LocalTimeslot struct {
 | 
			
		||||
		// Interval start
 | 
			
		||||
		From string `json:"from"`
 | 
			
		||||
 | 
			
		||||
		// Interval end
 | 
			
		||||
		To string `json:"to"`
 | 
			
		||||
	} `json:"local_timeslot"`
 | 
			
		||||
 | 
			
		||||
	// Date from which you want to bring the supply to the warehouse. Only for supplies via vDC
 | 
			
		||||
	PreferredSupplyDataFrom string `json:"preferred_supply_data_from"`
 | 
			
		||||
 | 
			
		||||
	// Date by which you want to bring the supply to the warehouse. Only for supplies via vDC
 | 
			
		||||
	PreferredSupplyDataTo string `json:"preferred_supply_data_to"`
 | 
			
		||||
 | 
			
		||||
	// Status of a supply by request
 | 
			
		||||
	State string `json:"state"`
 | 
			
		||||
 | 
			
		||||
	// Supply request identifier
 | 
			
		||||
	SupplyOrderId int64 `json:"supply_order_id"`
 | 
			
		||||
 | 
			
		||||
	// Supply request number
 | 
			
		||||
	SupplyOrderNumber string `json:"supply_order_number"`
 | 
			
		||||
 | 
			
		||||
	// Supply warehouse
 | 
			
		||||
	SupplyWarehouse struct {
 | 
			
		||||
		// Warehouse address
 | 
			
		||||
		Address string `json:address"`
 | 
			
		||||
 | 
			
		||||
		// Warehouse name
 | 
			
		||||
		Name string `json:"name"`
 | 
			
		||||
 | 
			
		||||
		// Warehouse identifier
 | 
			
		||||
		WarehouseId int64 `json:"warehouse_id"`
 | 
			
		||||
	} `json:"supply_warehouse"`
 | 
			
		||||
 | 
			
		||||
	// time_left_to_prepare_supply
 | 
			
		||||
	TimeLeftToPrepareSupply int64 `json:"time_left_to_prepare_supply"`
 | 
			
		||||
 | 
			
		||||
	// Time in seconds left to select the supply option. Only for supplies via vDC
 | 
			
		||||
	TimeLeftToSelectSupplyVariant int64 `json:"time_left_to_select_supply_variant"`
 | 
			
		||||
 | 
			
		||||
	// total_items_count
 | 
			
		||||
	TotalItemsCount int32 `json:"total_items_count"`
 | 
			
		||||
 | 
			
		||||
	// Total number of items in the request
 | 
			
		||||
	TotalQuantity int32 `json:"total_quantity"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Method for getting a list of supply requests to the Ozon warehouse.
 | 
			
		||||
// Requests with supply both to a specific warehouse and via a virtual
 | 
			
		||||
// distribution center (vDC) are taken into account
 | 
			
		||||
func (c FBO) ListSupplyRequests(params *ListSupplyRequestsParams) (*ListSupplyRequestsResponse, error) {
 | 
			
		||||
	url := "/v1/supply-order/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ListSupplyRequestsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetSupplyRequestInfoParams struct {
 | 
			
		||||
	// Supply request identifier
 | 
			
		||||
	SupplyOrderId int64 `json:"supply_order_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetSupplyRequestInfoResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	SupplyRequestCommonResponse
 | 
			
		||||
 | 
			
		||||
	// Driver and car information
 | 
			
		||||
	VehicleInfo struct {
 | 
			
		||||
		// Driver name
 | 
			
		||||
		DriverName string `json:"driver_name"`
 | 
			
		||||
 | 
			
		||||
		// Driver phone number
 | 
			
		||||
		DriverPhone string `json:"driver_phone"`
 | 
			
		||||
 | 
			
		||||
		// Car model
 | 
			
		||||
		VehicleModel string `json:"vehicle_model"`
 | 
			
		||||
 | 
			
		||||
		// Car number
 | 
			
		||||
		VehicleNumber string `json:"vehicle_number"`
 | 
			
		||||
	} `json:"vehicle_info"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Method for getting detailed information on a supply request.
 | 
			
		||||
// Requests with supply both to a specific warehouse and via a
 | 
			
		||||
// virtual distribution center (vDC) are taken into account
 | 
			
		||||
func (c FBO) GetSupplyRequestInfo(params *GetSupplyRequestInfoParams) (*GetSupplyRequestInfoResponse, error) {
 | 
			
		||||
	url := "/v1/supply-order/get"
 | 
			
		||||
 | 
			
		||||
	resp := &GetSupplyRequestInfoResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListProductsInSupplyRequestParams struct {
 | 
			
		||||
	// Number of the page returned in the query
 | 
			
		||||
	Page int32 `json:"page"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements on the page
 | 
			
		||||
	PageSize int32 `json:"page_size"`
 | 
			
		||||
 | 
			
		||||
	// Supply request identifier
 | 
			
		||||
	SupplyOrderId int64 `json:"supply_order_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListProductsInSupplyRequestResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Indicates that the response contains not the entire array of supply requests:
 | 
			
		||||
	//   - true — make a new request with a different page and page_size values to get the remaining products;
 | 
			
		||||
	//   - false — the entire array of product was returned in the response
 | 
			
		||||
	HasNext bool `json:"has_next"`
 | 
			
		||||
 | 
			
		||||
	// Products list
 | 
			
		||||
	Items []struct {
 | 
			
		||||
		// Link to product image
 | 
			
		||||
		IconPath string `json:"icon_path"`
 | 
			
		||||
 | 
			
		||||
		// Product name
 | 
			
		||||
		Name string `json:"name"`
 | 
			
		||||
 | 
			
		||||
		// Product ID
 | 
			
		||||
		OfferId string `json:"offer_id"`
 | 
			
		||||
 | 
			
		||||
		// Product quantity
 | 
			
		||||
		Quantity int64 `json:"quantity"`
 | 
			
		||||
 | 
			
		||||
		// Product identifier in the Ozon system, SKU
 | 
			
		||||
		SKU int64 `json:"sku"`
 | 
			
		||||
	} `json:"items"`
 | 
			
		||||
 | 
			
		||||
	// Total number of products in the request
 | 
			
		||||
	TotalItemsCount int32 `json:"total_items_count"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List of products in the sullpy request
 | 
			
		||||
func (c FBO) ListProductsInSupplyRequest(params *ListProductsInSupplyRequestParams) (*ListProductsInSupplyRequestResponse, error) {
 | 
			
		||||
	url := "/v1/supply-order/items"
 | 
			
		||||
 | 
			
		||||
	resp := &ListProductsInSupplyRequestResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										341
									
								
								ozon/fbo_test.go
									
									
									
									
									
								
							
							
						
						
									
										341
									
								
								ozon/fbo_test.go
									
									
									
									
									
								
							@@ -133,7 +133,346 @@ func TestGetFBOShipmentsList(t *testing.T) {
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers))
 | 
			
		||||
 | 
			
		||||
		resp, err := c.FBO().GetFBOShipmentsList(test.params)
 | 
			
		||||
		resp, err := c.FBO().GetShipmentsList(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 TestGetShipmentDetails(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *GetShipmentDetailsParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&GetShipmentDetailsParams{
 | 
			
		||||
				PostingNumber: "50520644-0012-7",
 | 
			
		||||
				Translit:      true,
 | 
			
		||||
				With: GetShipmentDetailsWith{
 | 
			
		||||
					AnalyticsData: true,
 | 
			
		||||
					FinancialData: true,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "order_id": 354679434,
 | 
			
		||||
				  "order_number": "50520644-0012",
 | 
			
		||||
				  "posting_number": "50520644-0012-7",
 | 
			
		||||
				  "status": "delivered",
 | 
			
		||||
				  "cancel_reason_id": 0,
 | 
			
		||||
				  "created_at": "2021-09-01T00:34:56.563Z",
 | 
			
		||||
				  "in_process_at": "2021-09-01T00:34:56.103Z",
 | 
			
		||||
				  "products": [
 | 
			
		||||
					{
 | 
			
		||||
					  "sku": 254665483,
 | 
			
		||||
					  "name": "Мочалка натуральная из люфы с деревянной ручкой",
 | 
			
		||||
					  "quantity": 1,
 | 
			
		||||
					  "offer_id": "PS1033",
 | 
			
		||||
					  "price": "137.00",
 | 
			
		||||
					  "digital_codes": [],
 | 
			
		||||
					  "currency_code": "RUB"
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "analytics_data": {
 | 
			
		||||
					"region": "МОСКВА",
 | 
			
		||||
					"city": "Москва",
 | 
			
		||||
					"delivery_type": "Courier",
 | 
			
		||||
					"is_premium": false,
 | 
			
		||||
					"payment_type_group_name": "Карты оплаты",
 | 
			
		||||
					"warehouse_id": 15431806189000,
 | 
			
		||||
					"warehouse_name": "ХОРУГВИНО_РФЦ",
 | 
			
		||||
					"is_legal": false
 | 
			
		||||
				  },
 | 
			
		||||
				  "financial_data": {
 | 
			
		||||
					"products": [
 | 
			
		||||
					  {
 | 
			
		||||
						"commission_amount": 13.7,
 | 
			
		||||
						"commission_percent": 10,
 | 
			
		||||
						"payout": 123.3,
 | 
			
		||||
						"product_id": 254665483,
 | 
			
		||||
						"currency_code": "RUB",
 | 
			
		||||
						"old_price": 198,
 | 
			
		||||
						"price": 137,
 | 
			
		||||
						"total_discount_value": 61,
 | 
			
		||||
						"total_discount_percent": 30.81,
 | 
			
		||||
						"actions": [
 | 
			
		||||
						  "Системная виртуальная скидка селлера"
 | 
			
		||||
						],
 | 
			
		||||
						"picking": null,
 | 
			
		||||
						"quantity": 0,
 | 
			
		||||
						"client_price": "",
 | 
			
		||||
						"item_services": {
 | 
			
		||||
						  "marketplace_service_item_fulfillment": -31.5,
 | 
			
		||||
						  "marketplace_service_item_pickup": 0,
 | 
			
		||||
						  "marketplace_service_item_dropoff_pvz": 0,
 | 
			
		||||
						  "marketplace_service_item_dropoff_sc": 0,
 | 
			
		||||
						  "marketplace_service_item_dropoff_ff": 0,
 | 
			
		||||
						  "marketplace_service_item_direct_flow_trans": -5,
 | 
			
		||||
						  "marketplace_service_item_return_flow_trans": 0,
 | 
			
		||||
						  "marketplace_service_item_deliv_to_customer": -20,
 | 
			
		||||
						  "marketplace_service_item_return_not_deliv_to_customer": 0,
 | 
			
		||||
						  "marketplace_service_item_return_part_goods_customer": 0,
 | 
			
		||||
						  "marketplace_service_item_return_after_deliv_to_customer": 0
 | 
			
		||||
						}
 | 
			
		||||
					  }
 | 
			
		||||
					],
 | 
			
		||||
					"posting_services": {
 | 
			
		||||
					  "marketplace_service_item_fulfillment": 0,
 | 
			
		||||
					  "marketplace_service_item_pickup": 0,
 | 
			
		||||
					  "marketplace_service_item_dropoff_pvz": 0,
 | 
			
		||||
					  "marketplace_service_item_dropoff_sc": 0,
 | 
			
		||||
					  "marketplace_service_item_dropoff_ff": 0,
 | 
			
		||||
					  "marketplace_service_item_direct_flow_trans": 0,
 | 
			
		||||
					  "marketplace_service_item_return_flow_trans": 0,
 | 
			
		||||
					  "marketplace_service_item_deliv_to_customer": 0,
 | 
			
		||||
					  "marketplace_service_item_return_not_deliv_to_customer": 0,
 | 
			
		||||
					  "marketplace_service_item_return_part_goods_customer": 0,
 | 
			
		||||
					  "marketplace_service_item_return_after_deliv_to_customer": 0
 | 
			
		||||
					}
 | 
			
		||||
				  },
 | 
			
		||||
				  "additional_data": []
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&GetShipmentDetailsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.FBO().GetShipmentDetails(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 resp.Result.PostingNumber != test.params.PostingNumber {
 | 
			
		||||
				t.Errorf("Posting numbers in request and response are not equal")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestListSupplyRequests(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ListSupplyRequestsParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ListSupplyRequestsParams{
 | 
			
		||||
				Page:     0,
 | 
			
		||||
				PageSize: 0,
 | 
			
		||||
				States:   []SupplyRequestState{AcceptanceAtStorageWarehouse},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"has_next": true,
 | 
			
		||||
				"supply_orders": [
 | 
			
		||||
				  {
 | 
			
		||||
					"created_at": "string",
 | 
			
		||||
					"local_timeslot": {
 | 
			
		||||
					  "from": "string",
 | 
			
		||||
					  "to": "string"
 | 
			
		||||
					},
 | 
			
		||||
					"preferred_supply_date_from": "string",
 | 
			
		||||
					"preferred_supply_date_to": "string",
 | 
			
		||||
					"state": "string",
 | 
			
		||||
					"supply_order_id": 0,
 | 
			
		||||
					"supply_order_number": "string",
 | 
			
		||||
					"supply_warehouse": {
 | 
			
		||||
					  "address": "string",
 | 
			
		||||
					  "name": "string",
 | 
			
		||||
					  "warehouse_id": 0
 | 
			
		||||
					},
 | 
			
		||||
					"time_left_to_prepare_supply": 0,
 | 
			
		||||
					"time_left_to_select_supply_variant": 0,
 | 
			
		||||
					"total_items_count": 0,
 | 
			
		||||
					"total_quantity": 0
 | 
			
		||||
				  }
 | 
			
		||||
				],
 | 
			
		||||
				"total_supply_orders_count": 0
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ListSupplyRequestsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.FBO().ListSupplyRequests(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 TestGetSupplyRequestInfo(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *GetSupplyRequestInfoParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&GetSupplyRequestInfoParams{
 | 
			
		||||
				SupplyOrderId: 0,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"created_at": "string",
 | 
			
		||||
				"local_timeslot": {
 | 
			
		||||
				  "from": "string",
 | 
			
		||||
				  "to": "string"
 | 
			
		||||
				},
 | 
			
		||||
				"preferred_supply_date_from": "string",
 | 
			
		||||
				"preferred_supply_date_to": "string",
 | 
			
		||||
				"seller_warehouse": {
 | 
			
		||||
				  "address": "string",
 | 
			
		||||
				  "name": "string",
 | 
			
		||||
				  "warehouse_id": 0
 | 
			
		||||
				},
 | 
			
		||||
				"state": "string",
 | 
			
		||||
				"supply_order_id": 0,
 | 
			
		||||
				"supply_order_number": "string",
 | 
			
		||||
				"supply_warehouse": {
 | 
			
		||||
				  "address": "string",
 | 
			
		||||
				  "name": "string",
 | 
			
		||||
				  "warehouse_id": 0
 | 
			
		||||
				},
 | 
			
		||||
				"time_left_to_prepare_supply": 0,
 | 
			
		||||
				"time_left_to_select_supply_variant": 0,
 | 
			
		||||
				"total_items_count": 0,
 | 
			
		||||
				"total_quantity": 0,
 | 
			
		||||
				"vehicle_info": {
 | 
			
		||||
				  "driver_name": "string",
 | 
			
		||||
				  "driver_phone": "string",
 | 
			
		||||
				  "vehicle_model": "string",
 | 
			
		||||
				  "vehicle_number": "string"
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&GetSupplyRequestInfoParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.FBO().GetSupplyRequestInfo(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 TestListProductsInSupplyRequest(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ListProductsInSupplyRequestParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ListProductsInSupplyRequestParams{
 | 
			
		||||
				Page:          0,
 | 
			
		||||
				PageSize:      0,
 | 
			
		||||
				SupplyOrderId: 0,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"has_next": true,
 | 
			
		||||
				"items": [
 | 
			
		||||
				  {
 | 
			
		||||
					"icon_path": "string",
 | 
			
		||||
					"name": "string",
 | 
			
		||||
					"offer_id": "string",
 | 
			
		||||
					"quantity": 0,
 | 
			
		||||
					"sku": 0
 | 
			
		||||
				  }
 | 
			
		||||
				],
 | 
			
		||||
				"total_items_count": 0
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ListProductsInSupplyRequestParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.FBO().ListProductsInSupplyRequest(test.params)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Error(err)
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1899
									
								
								ozon/fbs.go
									
									
									
									
									
								
							
							
						
						
									
										1899
									
								
								ozon/fbs.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2104
									
								
								ozon/fbs_test.go
									
									
									
									
									
								
							
							
						
						
									
										2104
									
								
								ozon/fbs_test.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										143
									
								
								ozon/finance.go
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								ozon/finance.go
									
									
									
									
									
								
							@@ -150,7 +150,7 @@ func (c Finance) ReportOnSoldProducts(params *ReportOnSoldProductsParams) (*Repo
 | 
			
		||||
 | 
			
		||||
	resp := &ReportOnSoldProductsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -238,7 +238,146 @@ func (c Finance) GetTotalTransactionsSum(params *GetTotalTransactionsSumParams)
 | 
			
		||||
 | 
			
		||||
	resp := &GetTotalTransactionsSumResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListTransactionsParams struct{
 | 
			
		||||
	// Filter
 | 
			
		||||
	Filter ListTransactionsFilter `json:"filter"`
 | 
			
		||||
 | 
			
		||||
	// Number of the page returned in the request
 | 
			
		||||
	Page int64 `json:"page"`
 | 
			
		||||
 | 
			
		||||
	// Number of items on the page
 | 
			
		||||
	PageSize int64 `json:"page_size"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListTransactionsFilter struct{
 | 
			
		||||
	// Filter by date
 | 
			
		||||
	Date ListTransactionsFilterDate `json:"date"`
 | 
			
		||||
 | 
			
		||||
	// Operation type
 | 
			
		||||
	OperationType string `json:"operation_type"`
 | 
			
		||||
 | 
			
		||||
	// Shipment number
 | 
			
		||||
	PostingNumber string `json:"posting_number"`
 | 
			
		||||
 | 
			
		||||
	// Transaction type
 | 
			
		||||
	TransactionType string `json:"transaction_type"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListTransactionsFilterDate struct{
 | 
			
		||||
	// Period start.
 | 
			
		||||
	// 
 | 
			
		||||
	// Format: YYYY-MM-DDTHH:mm:ss.sssZ.
 | 
			
		||||
	// Example: 2019-11-25T10:43:06.51
 | 
			
		||||
	From time.Time `json:"from"`
 | 
			
		||||
 | 
			
		||||
	// Period end.
 | 
			
		||||
	// 
 | 
			
		||||
	// Format: YYYY-MM-DDTHH:mm:ss.sssZ.
 | 
			
		||||
	// Example: 2019-11-25T10:43:06.51
 | 
			
		||||
	To time.Time `json:"to"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListTransactionsResponse struct{
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct{
 | 
			
		||||
		// Transactions infromation
 | 
			
		||||
		Operations []struct{
 | 
			
		||||
			// Cost of the products with seller's discounts applied
 | 
			
		||||
			AccrualsForSale float64 `json:"accruals_for_sale"`
 | 
			
		||||
 | 
			
		||||
			// Total transaction sum
 | 
			
		||||
			Amount float64 `json:"amount"`
 | 
			
		||||
 | 
			
		||||
			// Delivery cost for charges by rates that were in effect until February 1, 2021, and for charges for bulky products
 | 
			
		||||
			DeliveryCharge float64 `json:"delivery_charge"`
 | 
			
		||||
 | 
			
		||||
			// Product information
 | 
			
		||||
			Items []struct{
 | 
			
		||||
				// Product name
 | 
			
		||||
				Name string `json:"name"`
 | 
			
		||||
 | 
			
		||||
				// Product identifier in the Ozon system, SKU
 | 
			
		||||
				SKU int64 `json:"sku"`
 | 
			
		||||
			} `json:"items"`
 | 
			
		||||
 | 
			
		||||
			// Operation date
 | 
			
		||||
			OperationDate string `json:"operation_date"`
 | 
			
		||||
 | 
			
		||||
			// Operation identifier
 | 
			
		||||
			OperationId int64 `json:"operation_id"`
 | 
			
		||||
 | 
			
		||||
			// Operation type
 | 
			
		||||
			OperationType string `json:"operation_type"`
 | 
			
		||||
 | 
			
		||||
			// Operation type name
 | 
			
		||||
			OperationTypeName string `json:"operation_type_name"`
 | 
			
		||||
 | 
			
		||||
			// Shipment information
 | 
			
		||||
			Posting struct{
 | 
			
		||||
				// Delivery scheme:
 | 
			
		||||
				//   - FBO — delivery to Ozon warehouse
 | 
			
		||||
				//   - FBS — delivery from seller's warehouse
 | 
			
		||||
				//   - RFBS — delivery service of seller's choice
 | 
			
		||||
				//   - Crossborder — delivery from abroad
 | 
			
		||||
				DeliverySchema string `json:"delivery_schema"`
 | 
			
		||||
 | 
			
		||||
				// Date the product was accepted for processing
 | 
			
		||||
				OrderDate string `json:"order_date"`
 | 
			
		||||
 | 
			
		||||
				// Shipment number
 | 
			
		||||
				PostingNumber string `json:"posting_number"`
 | 
			
		||||
 | 
			
		||||
				// Warehouse identifier
 | 
			
		||||
				WarehouseId int64 `json:"warehouse_id"`
 | 
			
		||||
			} `json:"posting"`
 | 
			
		||||
 | 
			
		||||
			// Returns and cancellation cost for charges by rates that were in effect until February 1, 2021, and for charges for bulky products
 | 
			
		||||
			ReturnDeliveryCharge float64 `json:"return_delivery_charge"`
 | 
			
		||||
 | 
			
		||||
			// Sales commission or sales commission refund
 | 
			
		||||
			SaleCommission float64 `json:"sale_commission"`
 | 
			
		||||
 | 
			
		||||
			// Additional services
 | 
			
		||||
			Services []struct{
 | 
			
		||||
				// Service name
 | 
			
		||||
				Name string `json:"name"`
 | 
			
		||||
 | 
			
		||||
				// Price
 | 
			
		||||
				Price float64 `json:"price"`
 | 
			
		||||
			} `json:"services"`
 | 
			
		||||
 | 
			
		||||
			// Transaction type
 | 
			
		||||
			Type string `json:"type"`
 | 
			
		||||
		} `json:"operations"`
 | 
			
		||||
 | 
			
		||||
		// Number of pages
 | 
			
		||||
		PageCount int64 `json:"page_count"`
 | 
			
		||||
 | 
			
		||||
		// Number of products
 | 
			
		||||
		RowCount int64 `json:"row_count"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns detailed information on all accruals. The maximum period for which you can get information in one request is 1 month.
 | 
			
		||||
// 
 | 
			
		||||
// If you don't specify the posting_number in request, the response contains all shipments for the specified period or shipments of a certain type
 | 
			
		||||
func (c Finance) ListTransactions(params *ListTransactionsParams) (*ListTransactionsResponse, error) {
 | 
			
		||||
	url := "/v3/finance/transaction/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ListTransactionsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -174,3 +174,91 @@ func TestGetTotalTransactionsSum(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestListTransactions(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode   int
 | 
			
		||||
		headers      map[string]string
 | 
			
		||||
		params       *ListTransactionsParams
 | 
			
		||||
		response     string
 | 
			
		||||
		errorMessage string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ListTransactionsParams{
 | 
			
		||||
				Filter: ListTransactionsFilter{
 | 
			
		||||
					Date: ListTransactionsFilterDate{
 | 
			
		||||
						From: core.TimeFromString(t, "2006-01-02T15:04:05Z", "2021-11-01T00:00:00.000Z"),
 | 
			
		||||
						To:   core.TimeFromString(t, "2006-01-02T15:04:05Z", "2021-11-02T00:00:00.000Z"),
 | 
			
		||||
					},
 | 
			
		||||
					TransactionType: "ALL",
 | 
			
		||||
				},
 | 
			
		||||
				Page:     1,
 | 
			
		||||
				PageSize: 1000,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "operations": [
 | 
			
		||||
					{
 | 
			
		||||
					  "operation_id": 11401182187840,
 | 
			
		||||
					  "operation_type": "MarketplaceMarketingActionCostOperation",
 | 
			
		||||
					  "operation_date": "2021-11-01 00:00:00",
 | 
			
		||||
					  "operation_type_name": "Услуги продвижения товаров",
 | 
			
		||||
					  "delivery_charge": 0,
 | 
			
		||||
					  "return_delivery_charge": 0,
 | 
			
		||||
					  "accruals_for_sale": 0,
 | 
			
		||||
					  "sale_commission": 0,
 | 
			
		||||
					  "amount": -6.46,
 | 
			
		||||
					  "type": "services",
 | 
			
		||||
					  "posting": {
 | 
			
		||||
						"delivery_schema": "",
 | 
			
		||||
						"order_date": "",
 | 
			
		||||
						"posting_number": "",
 | 
			
		||||
						"warehouse_id": 0
 | 
			
		||||
					  },
 | 
			
		||||
					  "items": [],
 | 
			
		||||
					  "services": []
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "page_count": 1,
 | 
			
		||||
				  "row_count": 355
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
			"",
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ListTransactionsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"code": 16,
 | 
			
		||||
				"message": "Client-Id and Api-Key headers are required"
 | 
			
		||||
			}`,
 | 
			
		||||
			"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.Finance().ListTransactions(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 resp.Message != test.errorMessage {
 | 
			
		||||
				t.Errorf("got wrong error message: got: %s, expected: %s", resp.Message, test.errorMessage)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										97
									
								
								ozon/invoices.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								ozon/invoices.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Invoices struct {
 | 
			
		||||
	client *core.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CreateUpdateProformaLinkParams struct {
 | 
			
		||||
	// Shipment number
 | 
			
		||||
	PostingNumber string `json:"posting_number"`
 | 
			
		||||
 | 
			
		||||
	// Proforma invoice link
 | 
			
		||||
	URL string `json:"url"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CreateUpdateProformaLinkResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result bool `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create or edit proforma invoice link for VAT refund to Turkey sellers
 | 
			
		||||
func (c Invoices) CreateUpdate(params *CreateUpdateProformaLinkParams) (*CreateUpdateProformaLinkResponse, error) {
 | 
			
		||||
	url := "/v1/invoice/create-or-update"
 | 
			
		||||
 | 
			
		||||
	resp := &CreateUpdateProformaLinkResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetProformaLinkParams struct {
 | 
			
		||||
	// Shipment number
 | 
			
		||||
	PostingNumber string `json:"posting_number"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetProformaLinkResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Proforma invoice link
 | 
			
		||||
		FileURL string `json:"file_url"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get a proforma invoice link
 | 
			
		||||
func (c Invoices) Get(params *GetProformaLinkParams) (*GetProformaLinkResponse, error) {
 | 
			
		||||
	url := "/v1/invoice/get"
 | 
			
		||||
 | 
			
		||||
	resp := &GetProformaLinkResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DeleteProformaLinkParams struct {
 | 
			
		||||
	// Shipment number
 | 
			
		||||
	PostingNumber string `json:"posting_number"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DeleteProformaLinkResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result bool `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Invoices) Delete(params *DeleteProformaLinkParams) (*DeleteProformaLinkResponse, error) {
 | 
			
		||||
	url := "/v1/invoice/delete"
 | 
			
		||||
 | 
			
		||||
	resp := &DeleteProformaLinkResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										149
									
								
								ozon/invoices_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								ozon/invoices_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestCreateUpdateProformaLink(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *CreateUpdateProformaLinkParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&CreateUpdateProformaLinkParams{
 | 
			
		||||
				PostingNumber: "posting number",
 | 
			
		||||
				URL:           "link",
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": true
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&CreateUpdateProformaLinkParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Invoices().CreateUpdate(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 TestGetProformaLink(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *GetProformaLinkParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&GetProformaLinkParams{
 | 
			
		||||
				PostingNumber: "posting number",
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "file_url": "string"
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&GetProformaLinkParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Invoices().Get(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 TestDeleteProformaLink(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *DeleteProformaLinkParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&DeleteProformaLinkParams{
 | 
			
		||||
				PostingNumber: "posting number",
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": true
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&DeleteProformaLinkParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Invoices().Delete(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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								ozon/ozon.go
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								ozon/ozon.go
									
									
									
									
									
								
							@@ -23,6 +23,13 @@ type Client struct {
 | 
			
		||||
	warehouses    *Warehouses
 | 
			
		||||
	returns       *Returns
 | 
			
		||||
	reports       *Reports
 | 
			
		||||
	cancellations *Cancellations
 | 
			
		||||
	categories    *Categories
 | 
			
		||||
	polygons      *Polygons
 | 
			
		||||
	invoices      *Invoices
 | 
			
		||||
	brands        *Brands
 | 
			
		||||
	chats         *Chats
 | 
			
		||||
	certificates  *Certificates
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Client) Analytics() *Analytics {
 | 
			
		||||
@@ -65,6 +72,34 @@ func (c Client) Reports() *Reports {
 | 
			
		||||
	return c.reports
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Client) Cancellations() *Cancellations {
 | 
			
		||||
	return c.cancellations
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Client) Categories() *Categories {
 | 
			
		||||
	return c.categories
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Client) Polygons() *Polygons {
 | 
			
		||||
	return c.polygons
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Client) Invoices() *Invoices {
 | 
			
		||||
	return c.invoices
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Client) Brands() *Brands {
 | 
			
		||||
	return c.brands
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Client) Chats() *Chats {
 | 
			
		||||
	return c.chats
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Client) Certificates() *Certificates {
 | 
			
		||||
	return c.certificates
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewClient(clientId, apiKey string) *Client {
 | 
			
		||||
	coreClient := core.NewClient(DefaultAPIBaseUrl, map[string]string{
 | 
			
		||||
		"Client-Id": clientId,
 | 
			
		||||
@@ -83,6 +118,13 @@ func NewClient(clientId, apiKey string) *Client {
 | 
			
		||||
		warehouses:    &Warehouses{client: coreClient},
 | 
			
		||||
		returns:       &Returns{client: coreClient},
 | 
			
		||||
		reports:       &Reports{client: coreClient},
 | 
			
		||||
		cancellations: &Cancellations{client: coreClient},
 | 
			
		||||
		categories:    &Categories{client: coreClient},
 | 
			
		||||
		polygons:      &Polygons{client: coreClient},
 | 
			
		||||
		invoices:      &Invoices{client: coreClient},
 | 
			
		||||
		brands:        &Brands{client: coreClient},
 | 
			
		||||
		chats:         &Chats{client: coreClient},
 | 
			
		||||
		certificates:  &Certificates{client: coreClient},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -101,5 +143,12 @@ func NewMockClient(handler http.HandlerFunc) *Client {
 | 
			
		||||
		warehouses:    &Warehouses{client: coreClient},
 | 
			
		||||
		returns:       &Returns{client: coreClient},
 | 
			
		||||
		reports:       &Reports{client: coreClient},
 | 
			
		||||
		cancellations: &Cancellations{client: coreClient},
 | 
			
		||||
		categories:    &Categories{client: coreClient},
 | 
			
		||||
		polygons:      &Polygons{client: coreClient},
 | 
			
		||||
		invoices:      &Invoices{client: coreClient},
 | 
			
		||||
		brands:        &Brands{client: coreClient},
 | 
			
		||||
		chats:         &Chats{client: coreClient},
 | 
			
		||||
		certificates:  &Certificates{client: coreClient},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										110
									
								
								ozon/polygons.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								ozon/polygons.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Polygons struct {
 | 
			
		||||
	client *core.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CreateDeliveryPolygonParams struct {
 | 
			
		||||
	// Delivery polygon coordinates in [[[lat long]]] format
 | 
			
		||||
	Coordinates string `json:"coordinates"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CreateDeliveryPolygonResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Polygon identifier
 | 
			
		||||
	PolygonId int64 `json:"polygon_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// You can link a polygon to the delivery method.
 | 
			
		||||
//
 | 
			
		||||
// Create a polygon getting its coordinates on https://geojson.io: mark at least 3 points on the map and connect them
 | 
			
		||||
func (c Polygons) CreateDelivery(params *CreateDeliveryPolygonParams) (*CreateDeliveryPolygonResponse, error) {
 | 
			
		||||
	url := "/v1/polygon/create"
 | 
			
		||||
 | 
			
		||||
	resp := &CreateDeliveryPolygonResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LinkDeliveryMethodToPolygonParams struct {
 | 
			
		||||
	// Delivery method identifier
 | 
			
		||||
	DeliveryMethodId int32 `json:"delivery_method_id"`
 | 
			
		||||
 | 
			
		||||
	// Polygons list
 | 
			
		||||
	Polygons []LinkDeliveryMethodToPolygonPolygon `json:"polygons"`
 | 
			
		||||
 | 
			
		||||
	// Warehouse location
 | 
			
		||||
	WarehouseLocation LinkDeliveryMethodToPolygonWarehouse `json:"warehouse_location"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LinkDeliveryMethodToPolygonPolygon struct {
 | 
			
		||||
	// Polygon identifier
 | 
			
		||||
	PolygonId int64 `json:"polygon_id"`
 | 
			
		||||
 | 
			
		||||
	// Delivery time within polygon in minutes
 | 
			
		||||
	Time int64 `json:"time"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LinkDeliveryMethodToPolygonWarehouse struct {
 | 
			
		||||
	// Warehouse location latitude
 | 
			
		||||
	Latitude string `json:"lat"`
 | 
			
		||||
 | 
			
		||||
	// Warehouse location longitude
 | 
			
		||||
	Longitude string `json:"log"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LinkDeliveryMethodToPolygonResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Link delivery method to a delivery polygon
 | 
			
		||||
func (c Polygons) Link(params *LinkDeliveryMethodToPolygonParams) (*LinkDeliveryMethodToPolygonResponse, error) {
 | 
			
		||||
	url := "/v1/polygon/bind"
 | 
			
		||||
 | 
			
		||||
	resp := &LinkDeliveryMethodToPolygonResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DeletePolygonParams struct {
 | 
			
		||||
	// Polygons identifiers list
 | 
			
		||||
	PolygonIds []int64 `json:"polygon_ids"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DeletePolygonResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Delete polygon
 | 
			
		||||
func (c Polygons) Delete(params *DeletePolygonParams) (*DeletePolygonResponse, error) {
 | 
			
		||||
	url := "/v1/polygon/delete"
 | 
			
		||||
 | 
			
		||||
	resp := &DeletePolygonResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										152
									
								
								ozon/polygons_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								ozon/polygons_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
			
		||||
package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestCreateDeliveryPolygon(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *CreateDeliveryPolygonParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&CreateDeliveryPolygonParams{
 | 
			
		||||
				Coordinates: "[[[30.149574279785153,59.86550435303646],[30.21205902099609,59.846884387977326],[30.255661010742184,59.86240174913176],[30.149574279785153,59.86550435303646]]]",
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"polygonId": "1323"
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&CreateDeliveryPolygonParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Polygons().CreateDelivery(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 TestLinkDeliveryMethodToPolygon(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *LinkDeliveryMethodToPolygonParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&LinkDeliveryMethodToPolygonParams{
 | 
			
		||||
				DeliveryMethodId: 0,
 | 
			
		||||
				Polygons: []LinkDeliveryMethodToPolygonPolygon{
 | 
			
		||||
					{
 | 
			
		||||
						PolygonId: 1323,
 | 
			
		||||
						Time:      30,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				WarehouseLocation: LinkDeliveryMethodToPolygonWarehouse{
 | 
			
		||||
					Latitude:  "58.52391272075821",
 | 
			
		||||
					Longitude: "31.236791610717773",
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			`{}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&LinkDeliveryMethodToPolygonParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Polygons().Link(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 TestDeletePolygon(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *DeletePolygonParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&DeletePolygonParams{
 | 
			
		||||
				PolygonIds: []int64{1323},
 | 
			
		||||
			},
 | 
			
		||||
			`{}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&DeletePolygonParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Polygons().Delete(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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1245
									
								
								ozon/products.go
									
									
									
									
									
								
							
							
						
						
									
										1245
									
								
								ozon/products.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -2,6 +2,7 @@ package ozon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	core "github.com/diphantxm/ozon-api-client"
 | 
			
		||||
)
 | 
			
		||||
@@ -75,7 +76,7 @@ func (c Promotions) GetAvailablePromotions() (*GetAvailablePromotionsResponse, e
 | 
			
		||||
 | 
			
		||||
	resp := &GetAvailablePromotionsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodGet, url, nil, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodGet, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -128,7 +129,547 @@ func (c Promotions) AddToPromotion(params *AddProductToPromotionParams) (*AddPro
 | 
			
		||||
 | 
			
		||||
	resp := &AddProductToPromotionResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodGet, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodGet, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProductsAvailableForPromotionParams struct {
 | 
			
		||||
	// Promotion identifier
 | 
			
		||||
	ActionId float64 `json:"action_id"`
 | 
			
		||||
 | 
			
		||||
	// Number of values in the response. The default value is 100
 | 
			
		||||
	Limit float64 `json:"limit"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements that will be skipped in the response.
 | 
			
		||||
	// For example, if offset=10, the response will start with the 11th element found
 | 
			
		||||
	Offset float64 `json:"offset"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProductsAvailableForPromotionResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Products list
 | 
			
		||||
		Products []PromotionProduct `json:"products"`
 | 
			
		||||
 | 
			
		||||
		// Total number of products that can participate in the promotion
 | 
			
		||||
		Total float64 `json:"total"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PromotionProduct struct {
 | 
			
		||||
	// Product identifier
 | 
			
		||||
	Id float64 `json:"id"`
 | 
			
		||||
 | 
			
		||||
	// Current product price without a discount
 | 
			
		||||
	Price float64 `json:"price"`
 | 
			
		||||
 | 
			
		||||
	// Promotional product price
 | 
			
		||||
	ActionPrice float64 `json:"action_price"`
 | 
			
		||||
 | 
			
		||||
	// Maximum possible promotional product price
 | 
			
		||||
	MaxActionType float64 `json:"max_action_type"`
 | 
			
		||||
 | 
			
		||||
	// Type of adding a product to the promotion: automatically or manually by the seller
 | 
			
		||||
	AddMode string `json:"add_mode"`
 | 
			
		||||
 | 
			
		||||
	// Minimum number of product units in a stock discount type promotion
 | 
			
		||||
	MinStock float64 `json:"min_stock"`
 | 
			
		||||
 | 
			
		||||
	// Number of product units in a stock discount type promotion
 | 
			
		||||
	Stock float64 `json:"stock"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A method for getting a list of products that can participate in the promotion by the promotion identifier
 | 
			
		||||
func (c Promotions) ProductsAvailableForPromotion(params *ProductsAvailableForPromotionParams) (*ProductsAvailableForPromotionResponse, error) {
 | 
			
		||||
	url := "/v1/actions/candidates"
 | 
			
		||||
 | 
			
		||||
	resp := &ProductsAvailableForPromotionResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProductsInPromotionParams struct {
 | 
			
		||||
	// Promotion identifier
 | 
			
		||||
	ActionId float64 `json:"action_id"`
 | 
			
		||||
 | 
			
		||||
	// Number of values in the response. The default value is 100
 | 
			
		||||
	Limit float64 `json:"limit"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements that will be skipped in the response. For example, if offset=10, the response will start with the 11th element found
 | 
			
		||||
	Offset float64 `json:"offset"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProductsInPromotionResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Products list
 | 
			
		||||
		Products []PromotionProduct `json:"products"`
 | 
			
		||||
 | 
			
		||||
		// Total number of products that can participate in the promotion
 | 
			
		||||
		Total float64 `json:"total"`
 | 
			
		||||
	} `json:"reuslt"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A method for getting the list of products participating in the promotion by its identifier
 | 
			
		||||
func (c Promotions) ProductsInPromotion(params *ProductsInPromotionParams) (*ProductsInPromotionResponse, error) {
 | 
			
		||||
	url := "/v1/actions/products"
 | 
			
		||||
 | 
			
		||||
	resp := &ProductsInPromotionResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RemoveProductFromPromotionParams struct {
 | 
			
		||||
	// Promotion identifier
 | 
			
		||||
	ActionId float64 `json:"action_id"`
 | 
			
		||||
 | 
			
		||||
	// List of products identifiers
 | 
			
		||||
	ProductIds []float64 `json:"product_ids"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RemoveProductFromPromotionResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// List of product identifiers that were removed from the promotion
 | 
			
		||||
		ProductIds []float64 `json:"product_ids"`
 | 
			
		||||
 | 
			
		||||
		// List of product identifiers that weren't removed from the promotion
 | 
			
		||||
		Rejected []struct {
 | 
			
		||||
			// Product identifier
 | 
			
		||||
			ProductId float64 `json:"product_id"`
 | 
			
		||||
 | 
			
		||||
			// Reason why the product wasn't removed from the promotion
 | 
			
		||||
			Reason string `json:"reason"`
 | 
			
		||||
		} `json:"rejected"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A method for removing products from the promotion
 | 
			
		||||
func (c Promotions) RemoveProduct(params *RemoveProductFromPromotionParams) (*RemoveProductFromPromotionResponse, error) {
 | 
			
		||||
	url := "/v1/actions/products/deactivate"
 | 
			
		||||
 | 
			
		||||
	resp := &RemoveProductFromPromotionResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListHotSalePromotionsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		// Promotion end date
 | 
			
		||||
		DateEnd string `json:"date_end"`
 | 
			
		||||
 | 
			
		||||
		// Promotion start date
 | 
			
		||||
		DateStart string `json:"date_start"`
 | 
			
		||||
 | 
			
		||||
		// Promotion description
 | 
			
		||||
		Description string `json:"description"`
 | 
			
		||||
 | 
			
		||||
		// Promotion freeze date.
 | 
			
		||||
		//
 | 
			
		||||
		// If the field is filled, the seller can't increase prices, change the list of products,
 | 
			
		||||
		// or decrease the number of product units in the promotion.
 | 
			
		||||
		//
 | 
			
		||||
		// The seller can lower prices and increase the product units number in the promotion
 | 
			
		||||
		FreezeDate string `json:"freeze_date"`
 | 
			
		||||
 | 
			
		||||
		// Hot Sale promotion identifier
 | 
			
		||||
		HotsaleId float64 `json:"hotsale_id"`
 | 
			
		||||
 | 
			
		||||
		// Indication that you participate in this promotion
 | 
			
		||||
		IsParticipating bool `json:"is_participating"`
 | 
			
		||||
 | 
			
		||||
		// Promotion name
 | 
			
		||||
		Title string `json:"title"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List of available Hot Sale promotions
 | 
			
		||||
func (c Promotions) ListHotSalePromotions() (*ListHotSalePromotionsResponse, error) {
 | 
			
		||||
	url := "/v1/actions/hotsales/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ListHotSalePromotionsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProductsAvailableForHotSalePromotionParams struct {
 | 
			
		||||
	// Hot Sale promotion identifier
 | 
			
		||||
	HotSaleId float64 `json:"hotsale_id"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements in the response. Default value is 100
 | 
			
		||||
	Limit float64 `json:"limit"`
 | 
			
		||||
 | 
			
		||||
	// Number of elements that will be skipped in the response. For example, if offset=10, the response will start with the 11th element found
 | 
			
		||||
	Offset float64 `json:"offset"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProductsAvailableForHotSalePromotionResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Products list
 | 
			
		||||
		Products []struct {
 | 
			
		||||
			// Promotional product price
 | 
			
		||||
			ActionPrice float64 `json:"action_price"`
 | 
			
		||||
 | 
			
		||||
			// Date when the product participates in the promotion in the YYYY-MM-DD format
 | 
			
		||||
			DateDayPromo string `json:"date_day_promo"`
 | 
			
		||||
 | 
			
		||||
			// Product identifier
 | 
			
		||||
			Id float64 `json:"id"`
 | 
			
		||||
 | 
			
		||||
			// Indication that product participates in the promotion
 | 
			
		||||
			IsActive bool `json:"is_active"`
 | 
			
		||||
 | 
			
		||||
			// Maximum possible promotional price of the product
 | 
			
		||||
			MaxActionPrice float64 `json:"max_action_type"`
 | 
			
		||||
 | 
			
		||||
			// Minimum number of product units in a stock discount type promotion
 | 
			
		||||
			MinStock float64 `json:"min_stock"`
 | 
			
		||||
 | 
			
		||||
			// Number of product units in a stock discount type promotion
 | 
			
		||||
			Stock float64 `json:"stock"`
 | 
			
		||||
		} `json:"products"`
 | 
			
		||||
 | 
			
		||||
		// Total number of products that are available for the promotion
 | 
			
		||||
		Total float64 `json:"total"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Method for getting a list of products that can participate or are already participating in the Hot Sale promotion
 | 
			
		||||
func (c Promotions) ProductsAvailableForHotSalePromotion(params *ProductsAvailableForHotSalePromotionParams) (*ProductsAvailableForHotSalePromotionResponse, error) {
 | 
			
		||||
	url := "/v1/actions/hotsales/products"
 | 
			
		||||
 | 
			
		||||
	resp := &ProductsAvailableForHotSalePromotionResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AddProductsToHotSaleParams struct {
 | 
			
		||||
	// Hot Sale promotion identifier
 | 
			
		||||
	HotSaleId float64 `json:"hotsale_id"`
 | 
			
		||||
 | 
			
		||||
	// Products to be added to the promotion. The maximum number in one request is 100
 | 
			
		||||
	Products []AddProductsToHotSaleProduct `json:"products"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AddProductsToHotSaleProduct struct {
 | 
			
		||||
	// Promotional product price
 | 
			
		||||
	ActionPrice float64 `json:"action_price"`
 | 
			
		||||
 | 
			
		||||
	// Product identifier
 | 
			
		||||
	ProductId float64 `json:"product_id"`
 | 
			
		||||
 | 
			
		||||
	// Number of product units in a stock discount type promotion
 | 
			
		||||
	Stock float64 `json:"stock"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProductsToHotSaleResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// List of products that haven't been added to the promotion
 | 
			
		||||
		Rejected []struct {
 | 
			
		||||
			//Product identifier
 | 
			
		||||
			ProductId float64 `json:"product_id"`
 | 
			
		||||
 | 
			
		||||
			// Reason why the product hasn't been added to the promotion
 | 
			
		||||
			Reason string `json:"reason"`
 | 
			
		||||
		} `json:"rejected"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Promotions) AddProductsToHotSale(params *AddProductsToHotSaleParams) (*ProductsToHotSaleResponse, error) {
 | 
			
		||||
	url := "/v1/actions/hotsales/activate"
 | 
			
		||||
 | 
			
		||||
	resp := &ProductsToHotSaleResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RemoveProductsToHotSaleParams struct {
 | 
			
		||||
	// Hot Sale promotion identifier
 | 
			
		||||
	HotSaleId float64 `json:"hotsale_id"`
 | 
			
		||||
 | 
			
		||||
	// List of products identifiers. Maximum number of values in one request is 100
 | 
			
		||||
	ProductIds []float64 `json:"product_ids"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove product from the Hot Sale promotion
 | 
			
		||||
func (c Promotions) RemoveProductsToHotSale(params *RemoveProductsToHotSaleParams) (*ProductsToHotSaleResponse, error) {
 | 
			
		||||
	url := "/v1/actions/hotsales/activate"
 | 
			
		||||
 | 
			
		||||
	resp := &ProductsToHotSaleResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListDiscountRequestsParams struct {
 | 
			
		||||
	// Discount request status
 | 
			
		||||
	Status ListDiscountRequestsStatus `json:"status" default:"UNKNOWN"`
 | 
			
		||||
 | 
			
		||||
	// Page number from which you want to download the list of discount requests
 | 
			
		||||
	Page uint64 `json:"page"`
 | 
			
		||||
 | 
			
		||||
	// The maximum number of requests on a page
 | 
			
		||||
	Limit uint64 `json:"limit"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListDiscountRequestsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// List of requests
 | 
			
		||||
	Result []struct {
 | 
			
		||||
		// Request ID
 | 
			
		||||
		Id uint64 `json:"id"`
 | 
			
		||||
 | 
			
		||||
		// Request created date
 | 
			
		||||
		CreatedAt time.Time `json:"created_at"`
 | 
			
		||||
 | 
			
		||||
		// End time of the request
 | 
			
		||||
		EndAt time.Time `json:"end_at"`
 | 
			
		||||
 | 
			
		||||
		// Time to change the decision
 | 
			
		||||
		EditedTill time.Time `json:"edited_till"`
 | 
			
		||||
 | 
			
		||||
		// Request status
 | 
			
		||||
		Status string `json:"status"`
 | 
			
		||||
 | 
			
		||||
		// Customer's name
 | 
			
		||||
		CustomerName string `json:"customer_name"`
 | 
			
		||||
 | 
			
		||||
		// Product identifier in the Ozon system, SKU
 | 
			
		||||
		SKU uint64 `json:"sku"`
 | 
			
		||||
 | 
			
		||||
		// Customer's comment on the request
 | 
			
		||||
		UserComment string `json:"user_comment"`
 | 
			
		||||
 | 
			
		||||
		// Seller's comment on the request
 | 
			
		||||
		SellerComment string `json:"seller_comment"`
 | 
			
		||||
 | 
			
		||||
		// Requested price
 | 
			
		||||
		RequestedPrice float64 `json:"requested_price"`
 | 
			
		||||
 | 
			
		||||
		// Approved price
 | 
			
		||||
		ApprovedPrice float64 `json:"approved_price"`
 | 
			
		||||
 | 
			
		||||
		// Product price before all discounts
 | 
			
		||||
		OriginalPrice float64 `json:"original_price"`
 | 
			
		||||
 | 
			
		||||
		// Discount in rubles
 | 
			
		||||
		Discount float64 `json:"discount"`
 | 
			
		||||
 | 
			
		||||
		// Discount percentage
 | 
			
		||||
		DiscountPercent float64 `json:"discount_percent"`
 | 
			
		||||
 | 
			
		||||
		// Base price at which a product is selling on Ozon, if not eligible for a promotion
 | 
			
		||||
		BasePrice float64 `json:"base_price"`
 | 
			
		||||
 | 
			
		||||
		// The minimum price after auto-application of discounts and promotions
 | 
			
		||||
		MinAutoPrice float64 `json:"min_auto_price"`
 | 
			
		||||
 | 
			
		||||
		// ID of the previous customer request for this product
 | 
			
		||||
		PrevTaskId uint64 `json:"prev_task_id"`
 | 
			
		||||
 | 
			
		||||
		// If product is damaged — true
 | 
			
		||||
		IsDamaged bool `json:"is_damaged"`
 | 
			
		||||
 | 
			
		||||
		// Moderation date: review, approval or decline of the request
 | 
			
		||||
		ModeratedAt time.Time `json:"moderated_at"`
 | 
			
		||||
 | 
			
		||||
		// Discount in rubles approved by the seller. Pass the value 0 if the seller did not approve the request
 | 
			
		||||
		ApprovedDiscount float64 `json:"approved_discount"`
 | 
			
		||||
 | 
			
		||||
		// Discount percentage approved by the seller. Pass the value 0 if the seller did not approve the request
 | 
			
		||||
		ApprovedDiscountPercent float64 `json:"approved_discount_percent"`
 | 
			
		||||
 | 
			
		||||
		// Whether the customer has purchased the product. true if purchased
 | 
			
		||||
		IsPurchased bool `json:"is_purchased"`
 | 
			
		||||
 | 
			
		||||
		// Whether the request was moderated automatically. true if moderation was automatic
 | 
			
		||||
		IsAutoModerated bool `json:"is_auto_moderated"`
 | 
			
		||||
 | 
			
		||||
		// Product identifier in the seller's system
 | 
			
		||||
		OfferId string `json:"offer_id"`
 | 
			
		||||
 | 
			
		||||
		// Email of the user who processed the request
 | 
			
		||||
		Email string `json:"email"`
 | 
			
		||||
 | 
			
		||||
		// Last name of the user who processed the request
 | 
			
		||||
		LastName string `json:"last_name"`
 | 
			
		||||
 | 
			
		||||
		// First name of the user who processed the request
 | 
			
		||||
		FirstName string `json:"first_name"`
 | 
			
		||||
 | 
			
		||||
		// Patronymic of the user who processed the request
 | 
			
		||||
		Patronymic string `json:"patronymic"`
 | 
			
		||||
 | 
			
		||||
		// Approved minimum quantity of products
 | 
			
		||||
		ApprovedQuantityMin uint64 `json:"approved_quantity_min"`
 | 
			
		||||
 | 
			
		||||
		// Approved maximum quantity of products
 | 
			
		||||
		ApprovedQuantityMax uint64 `json:"approved_quantity_max"`
 | 
			
		||||
 | 
			
		||||
		// Requested minimum number of products
 | 
			
		||||
		RequestedQuantityMin uint64 `json:"requested_quantity_min"`
 | 
			
		||||
 | 
			
		||||
		// Requested maximum number of products
 | 
			
		||||
		RequestedQuantityMax uint64 `json:"requested_quantity_max"`
 | 
			
		||||
 | 
			
		||||
		// Requested price with fee
 | 
			
		||||
		RequestedPriceWithFee float64 `json:"requested_price_with_fee"`
 | 
			
		||||
 | 
			
		||||
		// Approved price with fee
 | 
			
		||||
		ApprovedPriceWithFee float64 `json:"approved_price_with_fee"`
 | 
			
		||||
 | 
			
		||||
		// Approved price fee percent
 | 
			
		||||
		ApprovedPriceFeePercent float64 `json:"approved_price_fee_percent"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Method for getting a list of products that customers want to buy with discount
 | 
			
		||||
func (c Promotions) ListDiscountRequests(params *ListDiscountRequestsParams) (*ListDiscountRequestsResponse, error) {
 | 
			
		||||
	url := "/v1/actions/discounts-task/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ListDiscountRequestsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DiscountRequestParams struct {
 | 
			
		||||
	// List of discount requests
 | 
			
		||||
	Tasks []DiscountRequestTask `json:"tasks"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DiscountRequestTask struct {
 | 
			
		||||
	// Request ID
 | 
			
		||||
	Id uint64 `json:"id"`
 | 
			
		||||
 | 
			
		||||
	// Approved price
 | 
			
		||||
	ApprovedPrice float64 `json:"approved_price"`
 | 
			
		||||
 | 
			
		||||
	// Seller's comment on the request
 | 
			
		||||
	SellerComment string `json:"seller_comment"`
 | 
			
		||||
 | 
			
		||||
	// Approved minimum quantity of products
 | 
			
		||||
	ApprovedQuantityMin uint64 `json:"approved_quantity_min"`
 | 
			
		||||
 | 
			
		||||
	// Approved maximum quantity of products
 | 
			
		||||
	ApprovedQuantityMax uint64 `json:"approved_quantity_max"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DiscountRequestResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Errors when creating a request
 | 
			
		||||
		FailDetails []struct {
 | 
			
		||||
			// Request ID
 | 
			
		||||
			TaskId uint64 `json:"task_id"`
 | 
			
		||||
 | 
			
		||||
			// Error message
 | 
			
		||||
			ErrorForUser string `json:"error_for_user"`
 | 
			
		||||
		} `json:"fail_details"`
 | 
			
		||||
 | 
			
		||||
		// The number of requests with a successful status change
 | 
			
		||||
		SuccessCount int32 `json:"success_count"`
 | 
			
		||||
 | 
			
		||||
		// The number of requests that failed to change their status
 | 
			
		||||
		FailCount int32 `json:"fail_count"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// You can approve applications in statuses:
 | 
			
		||||
//   - NEW — new
 | 
			
		||||
//   - SEEN — viewed
 | 
			
		||||
func (c Promotions) ApproveDiscountRequest(params *DiscountRequestParams) (*DiscountRequestResponse, error) {
 | 
			
		||||
	url := "/v1/actions/discounts-task/approve"
 | 
			
		||||
 | 
			
		||||
	resp := &DiscountRequestResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// You can decline applications in statuses:
 | 
			
		||||
//   - NEW—new
 | 
			
		||||
//   - SEEN—viewed
 | 
			
		||||
func (c Promotions) DeclineDiscountRequest(params *DiscountRequestParams) (*DiscountRequestResponse, error) {
 | 
			
		||||
	url := "/v1/actions/discounts-task/decline"
 | 
			
		||||
 | 
			
		||||
	resp := &DiscountRequestResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -64,6 +64,17 @@ func TestGetAvailablePromotions(t *testing.T) {
 | 
			
		||||
		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) > 0 {
 | 
			
		||||
				if resp.Result[0].Id == 0 {
 | 
			
		||||
					t.Errorf("Id cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Result[0].ActionType == "" {
 | 
			
		||||
					t.Errorf("Action type cannot be empty")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -122,5 +133,640 @@ func TestAddToPromotion(t *testing.T) {
 | 
			
		||||
		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.ProductIds) != len(test.params.Products) {
 | 
			
		||||
				t.Errorf("Length of products in response and request must be equal")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestProductsAvailableForPromotion(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ProductsAvailableForPromotionParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ProductsAvailableForPromotionParams{
 | 
			
		||||
				ActionId: 63337,
 | 
			
		||||
				Limit:    10,
 | 
			
		||||
				Offset:   0,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "products": [
 | 
			
		||||
					{
 | 
			
		||||
					  "id": 226,
 | 
			
		||||
					  "price": 250,
 | 
			
		||||
					  "action_price": 0,
 | 
			
		||||
					  "max_action_price": 175,
 | 
			
		||||
					  "add_mode": "NOT_SET",
 | 
			
		||||
					  "stock": 0,
 | 
			
		||||
					  "min_stock": 0
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
					  "id": 1366,
 | 
			
		||||
					  "price": 2300,
 | 
			
		||||
					  "action_price": 630,
 | 
			
		||||
					  "max_action_price": 770,
 | 
			
		||||
					  "add_mode": "MANUAL",
 | 
			
		||||
					  "stock": 0,
 | 
			
		||||
					  "min_stock": 0
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "total": 2
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ProductsAvailableForPromotionParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Promotions().ProductsAvailableForPromotion(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 TestProductsInPromotion(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ProductsInPromotionParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ProductsInPromotionParams{
 | 
			
		||||
				ActionId: 66011,
 | 
			
		||||
				Limit:    10,
 | 
			
		||||
				Offset:   0,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "products": [
 | 
			
		||||
					{
 | 
			
		||||
					  "id": 1383,
 | 
			
		||||
					  "price": 5503,
 | 
			
		||||
					  "action_price": 621,
 | 
			
		||||
					  "max_action_price": 3712.1,
 | 
			
		||||
					  "add_mode": "MANUAL",
 | 
			
		||||
					  "stock": 0,
 | 
			
		||||
					  "min_stock": 0
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "total": 1
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ProductsInPromotionParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Promotions().ProductsInPromotion(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 TestRemoveProduct(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *RemoveProductFromPromotionParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&RemoveProductFromPromotionParams{
 | 
			
		||||
				ActionId:   66011,
 | 
			
		||||
				ProductIds: []float64{14975},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "product_ids": [
 | 
			
		||||
					14975
 | 
			
		||||
				  ],
 | 
			
		||||
				  "rejected": []
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&RemoveProductFromPromotionParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Promotions().RemoveProduct(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.ProductIds) > 0 {
 | 
			
		||||
				if resp.Result.ProductIds[0] != test.params.ProductIds[0] {
 | 
			
		||||
					t.Errorf("Product ids in request and response are not equal")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestListHotSalePromotions(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"date_end": "string",
 | 
			
		||||
					"date_start": "string",
 | 
			
		||||
					"description": "string",
 | 
			
		||||
					"freeze_date": "string",
 | 
			
		||||
					"hotsale_id": 0,
 | 
			
		||||
					"is_participating": true,
 | 
			
		||||
					"title": "string"
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Promotions().ListHotSalePromotions()
 | 
			
		||||
		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 TestProductsAvailableForHotSalePromotion(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ProductsAvailableForHotSalePromotionParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ProductsAvailableForHotSalePromotionParams{
 | 
			
		||||
				HotSaleId: 0,
 | 
			
		||||
				Limit:     0,
 | 
			
		||||
				Offset:    0,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "products": [
 | 
			
		||||
					{
 | 
			
		||||
					  "action_price": 0,
 | 
			
		||||
					  "date_day_promo": "string",
 | 
			
		||||
					  "id": 0,
 | 
			
		||||
					  "is_active": true,
 | 
			
		||||
					  "max_action_price": 0,
 | 
			
		||||
					  "min_stock": 0,
 | 
			
		||||
					  "stock": 0
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "total": 0
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ProductsAvailableForHotSalePromotionParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Promotions().ProductsAvailableForHotSalePromotion(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 TestAddProductsToHotSale(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *AddProductsToHotSaleParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&AddProductsToHotSaleParams{
 | 
			
		||||
				HotSaleId: 1234,
 | 
			
		||||
				Products: []AddProductsToHotSaleProduct{
 | 
			
		||||
					{
 | 
			
		||||
						ActionPrice: 12,
 | 
			
		||||
						ProductId:   111,
 | 
			
		||||
						Stock:       45,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "rejected": [
 | 
			
		||||
					{
 | 
			
		||||
					  "product_id": 0,
 | 
			
		||||
					  "reason": "string"
 | 
			
		||||
					}
 | 
			
		||||
				  ]
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&AddProductsToHotSaleParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Promotions().AddProductsToHotSale(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 TestRemoveProductsToHotSale(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *RemoveProductsToHotSaleParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&RemoveProductsToHotSaleParams{
 | 
			
		||||
				HotSaleId:  12345,
 | 
			
		||||
				ProductIds: []float64{111},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "rejected": [
 | 
			
		||||
					{
 | 
			
		||||
					  "product_id": 0,
 | 
			
		||||
					  "reason": "string"
 | 
			
		||||
					}
 | 
			
		||||
				  ]
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&RemoveProductsToHotSaleParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Promotions().RemoveProductsToHotSale(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 TestListDiscountRequests(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ListDiscountRequestsParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ListDiscountRequestsParams{
 | 
			
		||||
				Status: "UNKNOWN",
 | 
			
		||||
				Page:   0,
 | 
			
		||||
				Limit:  100,
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": [
 | 
			
		||||
				  {
 | 
			
		||||
					"id": 0,
 | 
			
		||||
					"created_at": "2019-08-24T14:15:22Z",
 | 
			
		||||
					"end_at": "2019-08-24T14:15:22Z",
 | 
			
		||||
					"edited_till": "2019-08-24T14:15:22Z",
 | 
			
		||||
					"status": "string",
 | 
			
		||||
					"customer_name": "string",
 | 
			
		||||
					"sku": 0,
 | 
			
		||||
					"user_comment": "string",
 | 
			
		||||
					"seller_comment": "string",
 | 
			
		||||
					"requested_price": 0,
 | 
			
		||||
					"approved_price": 0,
 | 
			
		||||
					"original_price": 0,
 | 
			
		||||
					"discount": 0,
 | 
			
		||||
					"discount_percent": 0,
 | 
			
		||||
					"base_price": 0,
 | 
			
		||||
					"min_auto_price": 0,
 | 
			
		||||
					"prev_task_id": 0,
 | 
			
		||||
					"is_damaged": true,
 | 
			
		||||
					"moderated_at": "2019-08-24T14:15:22Z",
 | 
			
		||||
					"approved_discount": 0,
 | 
			
		||||
					"approved_discount_percent": 0,
 | 
			
		||||
					"is_purchased": true,
 | 
			
		||||
					"is_auto_moderated": true,
 | 
			
		||||
					"offer_id": "string",
 | 
			
		||||
					"email": "string",
 | 
			
		||||
					"last_name": "string",
 | 
			
		||||
					"first_name": "string",
 | 
			
		||||
					"patronymic": "string",
 | 
			
		||||
					"approved_quantity_min": 0,
 | 
			
		||||
					"approved_quantity_max": 0,
 | 
			
		||||
					"requested_quantity_min": 0,
 | 
			
		||||
					"requested_quantity_max": 0,
 | 
			
		||||
					"requested_price_with_fee": 0,
 | 
			
		||||
					"approved_price_with_fee": 0,
 | 
			
		||||
					"approved_price_fee_percent": 0
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ListDiscountRequestsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Promotions().ListDiscountRequests(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 TestApproveDiscountRequest(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *DiscountRequestParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&DiscountRequestParams{
 | 
			
		||||
				Tasks: []DiscountRequestTask{
 | 
			
		||||
					{
 | 
			
		||||
						Id: 123,
 | 
			
		||||
						ApprovedPrice: 11,
 | 
			
		||||
						SellerComment: "string",
 | 
			
		||||
						ApprovedQuantityMin: 1,
 | 
			
		||||
						ApprovedQuantityMax: 2,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "fail_details": [
 | 
			
		||||
					{
 | 
			
		||||
					  "task_id": 1234,
 | 
			
		||||
					  "error_for_user": "string"
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "success_count": 1,
 | 
			
		||||
				  "fail_count": 1
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&DiscountRequestParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Promotions().ApproveDiscountRequest(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 TestDeclineDiscountRequest(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *DiscountRequestParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&DiscountRequestParams{
 | 
			
		||||
				Tasks: []DiscountRequestTask{
 | 
			
		||||
					{
 | 
			
		||||
						Id: 123,
 | 
			
		||||
						ApprovedPrice: 11,
 | 
			
		||||
						SellerComment: "string",
 | 
			
		||||
						ApprovedQuantityMin: 1,
 | 
			
		||||
						ApprovedQuantityMax: 2,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"result": {
 | 
			
		||||
				  "fail_details": [
 | 
			
		||||
					{
 | 
			
		||||
					  "task_id": 1234,
 | 
			
		||||
					  "error_for_user": "string"
 | 
			
		||||
					}
 | 
			
		||||
				  ],
 | 
			
		||||
				  "success_count": 1,
 | 
			
		||||
				  "fail_count": 1
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&DiscountRequestParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Promotions().DeclineDiscountRequest(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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +89,7 @@ func (c Rating) GetCurrentSellerRatingInfo() (*GetCurrentSellerRatingInfoRespons
 | 
			
		||||
 | 
			
		||||
	resp := &GetCurrentSellerRatingInfoResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -178,7 +178,7 @@ func (c Rating) GetSellerRatingInfoForPeriod(params *GetSellerRatingInfoForPerio
 | 
			
		||||
 | 
			
		||||
	resp := &GetSellerRatingInfoPeriodResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,14 @@ func TestGetCurrentRatingInfo(t *testing.T) {
 | 
			
		||||
		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.Groups) > 0 {
 | 
			
		||||
				if len(resp.Groups[0].Items) == 0 {
 | 
			
		||||
					t.Errorf("Length of items in a group cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -146,5 +154,13 @@ func TestGetRatingInfoForPeriod(t *testing.T) {
 | 
			
		||||
		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.Ratings) > 0 {
 | 
			
		||||
				if resp.Ratings[0].Rating == "" {
 | 
			
		||||
					t.Errorf("Rating system cannot be empty")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										110
									
								
								ozon/reports.go
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								ozon/reports.go
									
									
									
									
									
								
							@@ -31,7 +31,7 @@ type GetReportsListParams struct {
 | 
			
		||||
	//   - SELLER_RETURNS — returns report,
 | 
			
		||||
	//   - SELLER_POSTINGS — shipments report,
 | 
			
		||||
	//   - SELLER_FINANCE — financial report
 | 
			
		||||
	ReportType string `json:"report_type"`
 | 
			
		||||
	ReportType string `json:"report_type" default:"ALL"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetReportsListResponse struct {
 | 
			
		||||
@@ -39,6 +39,8 @@ type GetReportsListResponse struct {
 | 
			
		||||
 | 
			
		||||
	// Method result
 | 
			
		||||
	Result struct {
 | 
			
		||||
		// Array with generated reports
 | 
			
		||||
		Reports []struct {
 | 
			
		||||
			// Unique report identifier
 | 
			
		||||
			Code string `json:"code"`
 | 
			
		||||
 | 
			
		||||
@@ -70,10 +72,11 @@ type GetReportsListResponse struct {
 | 
			
		||||
			//   - `success`
 | 
			
		||||
			//   - `failed`
 | 
			
		||||
			Status string `json:"status"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
		} `json:"reports"`
 | 
			
		||||
 | 
			
		||||
		// Total number of reports
 | 
			
		||||
		Total int32 `json:"total"`
 | 
			
		||||
	} `json:"result"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns the list of reports that have been generated before
 | 
			
		||||
@@ -82,7 +85,7 @@ func (c Reports) GetList(params *GetReportsListParams) (*GetReportsListResponse,
 | 
			
		||||
 | 
			
		||||
	resp := &GetReportsListResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -136,11 +139,11 @@ type GetReportDetailsResponse struct {
 | 
			
		||||
 | 
			
		||||
// Returns information about a created report by its identifier
 | 
			
		||||
func (c Reports) GetReportDetails(params *GetReportDetailsParams) (*GetReportDetailsResponse, error) {
 | 
			
		||||
	url := "/v1/report/list"
 | 
			
		||||
	url := "/v1/report/info"
 | 
			
		||||
 | 
			
		||||
	resp := &GetReportDetailsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -217,7 +220,7 @@ func (c Reports) GetFinancial(params *GetFinancialReportParams) (*GetFinancialRe
 | 
			
		||||
 | 
			
		||||
	resp := &GetFinancialReportResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -263,7 +266,7 @@ func (c Reports) GetProducts(params *GetProductsReportParams) (*GetProductsRepor
 | 
			
		||||
 | 
			
		||||
	resp := &GetProductsReportResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -296,7 +299,7 @@ func (c Reports) GetStocks(params *GetStocksReportParams) (*GetStocksReportRespo
 | 
			
		||||
 | 
			
		||||
	resp := &GetStocksReportResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -339,7 +342,7 @@ func (c Reports) GetProductsMovement(params *GetProductsMovementReportParams) (*
 | 
			
		||||
 | 
			
		||||
	resp := &GetProductsMovementReportResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -388,7 +391,7 @@ func (c Reports) GetReturns(params *GetReturnsReportParams) (*GetReturnsReportRe
 | 
			
		||||
 | 
			
		||||
	resp := &GetReturnsReportResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -405,7 +408,7 @@ type GetShipmentReportParams struct {
 | 
			
		||||
	// Response language:
 | 
			
		||||
	//   - RU — Russian
 | 
			
		||||
	//   - EN — English
 | 
			
		||||
	Language string `json:"language"`
 | 
			
		||||
	Language string `json:"language" default:"DEFAULT"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetShipmentReportFilter struct {
 | 
			
		||||
@@ -461,7 +464,90 @@ func (c Reports) GetShipment(params *GetShipmentReportParams) (*GetShipmentRepor
 | 
			
		||||
 | 
			
		||||
	resp := &GetShipmentReportResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type IssueOnDiscountedProductsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Unique report identifier
 | 
			
		||||
	Code string `json:"code"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Generates a report on discounted products in Ozon warehouses.
 | 
			
		||||
// For example, Ozon can discount a product due to damage when delivering.
 | 
			
		||||
//
 | 
			
		||||
// Returns report identifier. To get the report, send the identifier in the request body of a method `/v1/report/discounted/info`
 | 
			
		||||
func (c Reports) IssueOnDiscountedProducts() (*IssueOnDiscountedProductsResponse, error) {
 | 
			
		||||
	url := "/v1/report/discounted/create"
 | 
			
		||||
 | 
			
		||||
	resp := &IssueOnDiscountedProductsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ReportOnDiscountedProductsParams struct {
 | 
			
		||||
	// Unique report identifier
 | 
			
		||||
	Code string `json:"code"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ReportOnDiscountedProductsResponse struct {
 | 
			
		||||
	core.CommonResponse
 | 
			
		||||
 | 
			
		||||
	// Report information
 | 
			
		||||
	Report struct {
 | 
			
		||||
		// Report creation date
 | 
			
		||||
		CreatedAt time.Time `json:"created_at"`
 | 
			
		||||
 | 
			
		||||
		// Link to report file
 | 
			
		||||
		File string `json:"file"`
 | 
			
		||||
 | 
			
		||||
		// Report status:
 | 
			
		||||
		//   - success — created
 | 
			
		||||
		//   - pending — waiting to be processed
 | 
			
		||||
		//   - processing — processed
 | 
			
		||||
		//   - failed — generation error
 | 
			
		||||
		Status string `json:"status"`
 | 
			
		||||
 | 
			
		||||
		// Report generation error code
 | 
			
		||||
		Error string `json:"error"`
 | 
			
		||||
	} `json:"report"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// By report identifier, returns information about the report generated earlier
 | 
			
		||||
func (c Reports) ReportOnDiscountedProducts(params *ReportOnDiscountedProductsParams) (*ReportOnDiscountedProductsResponse, error) {
 | 
			
		||||
	url := "/v1/report/discounted/info"
 | 
			
		||||
 | 
			
		||||
	resp := &ReportOnDiscountedProductsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	response.CopyCommonResponse(&resp.CommonResponse)
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// By report identifier, returns information about the report generated earlier
 | 
			
		||||
func (c Reports) ListReportsOnDiscountedProducts() (*ReportOnDiscountedProductsResponse, error) {
 | 
			
		||||
	url := "/v1/report/discounted/list"
 | 
			
		||||
 | 
			
		||||
	resp := &ReportOnDiscountedProductsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -77,6 +77,15 @@ func TestGetList(t *testing.T) {
 | 
			
		||||
		if resp.StatusCode != test.statusCode {
 | 
			
		||||
			t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if int(resp.Result.Total) != len(resp.Result.Reports) {
 | 
			
		||||
			t.Errorf("Amount of reports (%d) is not equal to total (%d)", len(resp.Result.Reports), resp.Result.Total)
 | 
			
		||||
		}
 | 
			
		||||
		if len(resp.Result.Reports) > 0 {
 | 
			
		||||
			if resp.Result.Reports[0].Status == "" {
 | 
			
		||||
				t.Errorf("Status must be 'success' or 'failed'")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -129,6 +138,12 @@ func TestGetReportDetails(t *testing.T) {
 | 
			
		||||
		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 resp.Result.Status == "" {
 | 
			
		||||
				t.Errorf("Status must be 'success' or 'failed'")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -197,6 +212,14 @@ func TestGetFinancialReport(t *testing.T) {
 | 
			
		||||
		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.CashFlows) > 0 {
 | 
			
		||||
				if resp.Result.CashFlows[0].CurrencyCode == "" {
 | 
			
		||||
					t.Errorf("Currency Code cannot be empty")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -243,6 +266,12 @@ func TestGetProductsReport(t *testing.T) {
 | 
			
		||||
		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 resp.Result.Code == "" {
 | 
			
		||||
				t.Errorf("Code cannot be empty")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -289,6 +318,12 @@ func TestGetStocksReport(t *testing.T) {
 | 
			
		||||
		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 resp.Result.Code == "" {
 | 
			
		||||
				t.Errorf("Code cannot be empty")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -338,6 +373,12 @@ func TestGetProductsMovementReport(t *testing.T) {
 | 
			
		||||
		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 resp.Result.Code == "" {
 | 
			
		||||
				t.Errorf("Code cannot be empty")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -388,6 +429,12 @@ func TestGetReturnsReport(t *testing.T) {
 | 
			
		||||
		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 resp.Result.Code == "" {
 | 
			
		||||
				t.Errorf("Code cannot be empty")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -440,5 +487,157 @@ func TestGetShipmentReport(t *testing.T) {
 | 
			
		||||
		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 resp.Result.Code == "" {
 | 
			
		||||
				t.Errorf("Code cannot be empty")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIssueOnDiscountedProducts(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			`{
 | 
			
		||||
				"code": "d55f4517-8347-4e24-9d93-d6e736c1c07c"
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Reports().IssueOnDiscountedProducts()
 | 
			
		||||
		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 resp.Code == "" {
 | 
			
		||||
				t.Errorf("Code cannot be empty")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestReportOnDiscountedProducts(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		params     *ReportOnDiscountedProductsParams
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			&ReportOnDiscountedProductsParams{
 | 
			
		||||
				Code: "d55f4517-8347-4e24-9d93-d6e736c1c07c",
 | 
			
		||||
			},
 | 
			
		||||
			`{
 | 
			
		||||
				"report": {
 | 
			
		||||
				  "created_at": "2022-10-04T10:07:08.146Z",
 | 
			
		||||
				  "error": "string",
 | 
			
		||||
				  "file": "string",
 | 
			
		||||
				  "status": "string"
 | 
			
		||||
				}
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			&ReportOnDiscountedProductsParams{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Reports().ReportOnDiscountedProducts(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 TestListReportsOnDiscountedProducts(t *testing.T) {
 | 
			
		||||
	t.Parallel()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		statusCode int
 | 
			
		||||
		headers    map[string]string
 | 
			
		||||
		response   string
 | 
			
		||||
	}{
 | 
			
		||||
		// Test Ok
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusOK,
 | 
			
		||||
			map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
			
		||||
			`{
 | 
			
		||||
				"reports": [
 | 
			
		||||
				  {
 | 
			
		||||
					"created_at": "2022-10-04T10:07:08.146Z",
 | 
			
		||||
					"error": "string",
 | 
			
		||||
					"file": "string",
 | 
			
		||||
					"status": "string"
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
			}`,
 | 
			
		||||
		},
 | 
			
		||||
		// Test No Client-Id or Api-Key
 | 
			
		||||
		{
 | 
			
		||||
			http.StatusUnauthorized,
 | 
			
		||||
			map[string]string{},
 | 
			
		||||
			`{
 | 
			
		||||
				"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.Reports().ListReportsOnDiscountedProducts()
 | 
			
		||||
		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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -80,7 +80,7 @@ func (c Returns) GetFBOReturns(params *GetFBOReturnsParams) (*GetFBOReturnsRespo
 | 
			
		||||
 | 
			
		||||
	resp := &GetFBOReturnsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -240,7 +240,7 @@ func (c Returns) GetFBSReturns(params *GetFBSReturnsParams) (*GetFBSReturnsRespo
 | 
			
		||||
 | 
			
		||||
	resp := &GetFBSReturnsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, params, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,15 +32,15 @@ func TestGetFBOReturns(t *testing.T) {
 | 
			
		||||
				"returns": [
 | 
			
		||||
				  {
 | 
			
		||||
					"accepted_from_customer_moment": "2019-08-24T14:15:22Z",
 | 
			
		||||
					"company_id": 0,
 | 
			
		||||
					"company_id": 123456789,
 | 
			
		||||
					"current_place_name": "my-place",
 | 
			
		||||
					"dst_place_name": "that-place",
 | 
			
		||||
					"id": 0,
 | 
			
		||||
					"id": 123456789,
 | 
			
		||||
					"is_opened": true,
 | 
			
		||||
					"posting_number": "some number",
 | 
			
		||||
					"return_reason_name": "ripped",
 | 
			
		||||
					"returned_to_ozon_moment": "2019-08-24T14:15:22Z",
 | 
			
		||||
					"sku": 0,
 | 
			
		||||
					"sku": 123456789,
 | 
			
		||||
					"status_name": "delivering"
 | 
			
		||||
				  }
 | 
			
		||||
				]
 | 
			
		||||
@@ -69,6 +69,20 @@ func TestGetFBOReturns(t *testing.T) {
 | 
			
		||||
		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.Returns) > 0 {
 | 
			
		||||
				if resp.Returns[0].Id == 0 {
 | 
			
		||||
					t.Errorf("Id cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Returns[0].CompanyId == 0 {
 | 
			
		||||
					t.Errorf("Company id cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Returns[0].SKU == 0 {
 | 
			
		||||
					t.Errorf("SKU cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -152,5 +166,25 @@ func TestGetFBSReturns(t *testing.T) {
 | 
			
		||||
		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 int(resp.Result.Count) != len(resp.Result.Returns) {
 | 
			
		||||
				t.Errorf("Count must equal to length of returns")
 | 
			
		||||
			}
 | 
			
		||||
			if len(resp.Result.Returns) > 0 {
 | 
			
		||||
				if resp.Result.Returns[0].Id == 0 {
 | 
			
		||||
					t.Errorf("Id cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Result.Returns[0].ProductId == 0 {
 | 
			
		||||
					t.Errorf("Product id cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Result.Returns[0].SKU == 0 {
 | 
			
		||||
					t.Errorf("SKU cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Result.Returns[0].Status == "" {
 | 
			
		||||
					t.Errorf("Status cannot be empty")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@ type GetListOfWarehousesResponse struct {
 | 
			
		||||
		Status string `json:"status"`
 | 
			
		||||
 | 
			
		||||
		// Warehouse working days
 | 
			
		||||
		WorkingDays []string `json:"working_days"`
 | 
			
		||||
		WorkingDays []WorkingDay `json:"working_days"`
 | 
			
		||||
	} `json:"resulCommonResponse"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -86,7 +86,7 @@ func (c Warehouses) GetListOfWarehouses() (*GetListOfWarehousesResponse, error)
 | 
			
		||||
 | 
			
		||||
	resp := &GetListOfWarehousesResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -174,7 +174,7 @@ func (c Warehouses) GetListOfDeliveryMethods(params *GetListOfDeliveryMethodsPar
 | 
			
		||||
 | 
			
		||||
	resp := &GetListOfDeliveryMethodsResponse{}
 | 
			
		||||
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp)
 | 
			
		||||
	response, err := c.client.Request(http.MethodPost, url, nil, resp, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,17 @@ func TestGetListOfWarehouses(t *testing.T) {
 | 
			
		||||
		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) > 0 {
 | 
			
		||||
				if resp.Result[0].WarehouseId == 0 {
 | 
			
		||||
					t.Errorf("Warehouse id cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Result[0].Name == "" {
 | 
			
		||||
					t.Errorf("Name cannot be empty")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -130,5 +141,22 @@ func TestGetListOfDeliveryMethods(t *testing.T) {
 | 
			
		||||
		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) > 0 {
 | 
			
		||||
				if resp.Result[0].Id == 0 {
 | 
			
		||||
					t.Errorf("Id cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Result[0].Name == "" {
 | 
			
		||||
					t.Errorf("Name cannot be empty")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Result[0].Status == "" {
 | 
			
		||||
					t.Errorf("Status cannot be empty")
 | 
			
		||||
				}
 | 
			
		||||
				if resp.Result[0].WarehouseId == 0 {
 | 
			
		||||
					t.Errorf("Warehouse id cannot be 0")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user