initial
This commit is contained in:
		
							
								
								
									
										19
									
								
								.github/workflows/go.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/go.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					name: tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    branches: [ "master" ]
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					    branches: [ "master" ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  unit:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    - name: Check out code
 | 
				
			||||||
 | 
					      uses: actions/checkout@v3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Unit Tests
 | 
				
			||||||
 | 
					      run: go test -v ./...
 | 
				
			||||||
							
								
								
									
										124
									
								
								client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								client.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
				
			|||||||
 | 
					package core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/http/httptest"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type HttpClient interface {
 | 
				
			||||||
 | 
						Do(req *http.Request) (*http.Response, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Client struct {
 | 
				
			||||||
 | 
						baseUrl string
 | 
				
			||||||
 | 
						ctx     context.Context
 | 
				
			||||||
 | 
						Options map[string]string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						client HttpClient
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewClient(baseUrl string, opts map[string]string) *Client {
 | 
				
			||||||
 | 
						return &Client{
 | 
				
			||||||
 | 
							Options: opts,
 | 
				
			||||||
 | 
							ctx:     context.Background(),
 | 
				
			||||||
 | 
							client:  http.DefaultClient,
 | 
				
			||||||
 | 
							baseUrl: baseUrl,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewMockClient(handler http.HandlerFunc) *Client {
 | 
				
			||||||
 | 
						return &Client{
 | 
				
			||||||
 | 
							ctx:    context.Background(),
 | 
				
			||||||
 | 
							client: NewMockHttpClient(handler),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c Client) newRequest(method string, url string, body interface{}) (*http.Request, error) {
 | 
				
			||||||
 | 
						bodyJson, err := json.Marshal(body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						url = c.baseUrl + url
 | 
				
			||||||
 | 
						req, err := http.NewRequestWithContext(c.ctx, method, url, bytes.NewBuffer(bodyJson))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for k, v := range c.Options {
 | 
				
			||||||
 | 
							req.Header.Add(k, v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return req, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c Client) Request(method string, path string, req, resp interface{}) (*Response, error) {
 | 
				
			||||||
 | 
						httpReq, err := c.newRequest(method, path, req)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rawQuery, err := buildRawQuery(httpReq, req)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						httpReq.URL.RawQuery = rawQuery
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						httpResp, err := c.client.Do(httpReq)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer httpResp.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						body, err := ioutil.ReadAll(httpResp.Body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						response := &Response{}
 | 
				
			||||||
 | 
						response.Data = resp
 | 
				
			||||||
 | 
						response.StatusCode = httpResp.StatusCode
 | 
				
			||||||
 | 
						if httpResp.StatusCode == http.StatusOK {
 | 
				
			||||||
 | 
							err = json.Unmarshal(body, &response)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							err = json.Unmarshal(body, &response.Data)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return response, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MockHttpClient struct {
 | 
				
			||||||
 | 
						handler http.HandlerFunc
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewMockHttpClient(handler http.HandlerFunc) *MockHttpClient {
 | 
				
			||||||
 | 
						return &MockHttpClient{
 | 
				
			||||||
 | 
							handler: handler,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c MockHttpClient) Do(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
 | 
						rr := httptest.NewRecorder()
 | 
				
			||||||
 | 
						c.handler.ServeHTTP(rr, req)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rr.Result(), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewMockHttpHandler(statusCode int, json string, headers map[string]string) http.HandlerFunc {
 | 
				
			||||||
 | 
						return func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							if len(headers) > 0 {
 | 
				
			||||||
 | 
								for key, value := range headers {
 | 
				
			||||||
 | 
									w.Header().Add(key, value)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							w.WriteHeader(statusCode)
 | 
				
			||||||
 | 
							w.Write([]byte(json))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										101
									
								
								core.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								core.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					package core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type CommonResponse struct {
 | 
				
			||||||
 | 
						StatusCode int
 | 
				
			||||||
 | 
						Code       int                    `json:"code"`
 | 
				
			||||||
 | 
						Details    []CommonResponseDetail `json:"details"`
 | 
				
			||||||
 | 
						Message    string                 `json:"message"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type CommonResponseDetail struct {
 | 
				
			||||||
 | 
						TypeUrl string `json:"typeUrl"`
 | 
				
			||||||
 | 
						Value   string `json:"value"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Response struct {
 | 
				
			||||||
 | 
						CommonResponse
 | 
				
			||||||
 | 
						Data interface{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r Response) CopyCommonResponse(rhs *CommonResponse) {
 | 
				
			||||||
 | 
						rhs.Code = r.Code
 | 
				
			||||||
 | 
						rhs.Details = r.Details
 | 
				
			||||||
 | 
						rhs.StatusCode = r.StatusCode
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getDefaultValues(v interface{}) (map[string]string, error) {
 | 
				
			||||||
 | 
						isNil, err := isZero(v)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return make(map[string]string), err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if isNil {
 | 
				
			||||||
 | 
							return make(map[string]string), nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out := make(map[string]string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vType := reflect.TypeOf(v).Elem()
 | 
				
			||||||
 | 
						vValue := reflect.ValueOf(v).Elem()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//re := regexp.MustCompile(`default:*`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < vType.NumField(); i++ {
 | 
				
			||||||
 | 
							field := vType.Field(i)
 | 
				
			||||||
 | 
							tag := field.Tag.Get("json")
 | 
				
			||||||
 | 
							defaultValue := field.Tag.Get("default")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if field.Type.Kind() == reflect.Slice {
 | 
				
			||||||
 | 
								// Attach any slices as query params
 | 
				
			||||||
 | 
								fieldVal := vValue.Field(i)
 | 
				
			||||||
 | 
								for j := 0; j < fieldVal.Len(); j++ {
 | 
				
			||||||
 | 
									out[tag] = fmt.Sprintf("%v", fieldVal.Index(j))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// Add any scalar values as query params
 | 
				
			||||||
 | 
								fieldVal := fmt.Sprintf("%v", vValue.Field(i))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// If no value was set by the user, use the default
 | 
				
			||||||
 | 
								// value specified in the struct tag.
 | 
				
			||||||
 | 
								if fieldVal == "" || fieldVal == "0" {
 | 
				
			||||||
 | 
									if defaultValue == "" {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									fieldVal = defaultValue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								out[tag] = fmt.Sprintf("%v", fieldVal)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return out, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func buildRawQuery(req *http.Request, v interface{}) (string, error) {
 | 
				
			||||||
 | 
						query := req.URL.Query()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						values, err := getDefaultValues(v)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for k, v := range values {
 | 
				
			||||||
 | 
							query.Add(k, v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return query.Encode(), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isZero(v interface{}) (bool, error) {
 | 
				
			||||||
 | 
						t := reflect.TypeOf(v)
 | 
				
			||||||
 | 
						if !t.Comparable() {
 | 
				
			||||||
 | 
							return false, fmt.Errorf("type is not comparable: %v", t)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return v == reflect.Zero(t).Interface(), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								core_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								core_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					package core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type TestTagDefaultValueStruct struct {
 | 
				
			||||||
 | 
						TestString string `json:"test_string" default:"something"`
 | 
				
			||||||
 | 
						TestNumber int    `json:"test_number" default:"12"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestTagDefaultValue(t *testing.T) {
 | 
				
			||||||
 | 
						testStruct := &TestTagDefaultValueStruct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						values, err := getDefaultValues(testStruct)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatalf("error when getting default values from tags: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expected := map[string]string{
 | 
				
			||||||
 | 
							"test_string": "something",
 | 
				
			||||||
 | 
							"test_number": "12",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(values) != len(expected) {
 | 
				
			||||||
 | 
							log.Fatalf("expected equal length of values and expected: expected: %d, got: %d", len(expected), len(values))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for expKey, expValue := range expected {
 | 
				
			||||||
 | 
							if expValue != values[expKey] {
 | 
				
			||||||
 | 
								log.Fatalf("not equal values for key %s", expKey)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										198
									
								
								ozon/fbs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								ozon/fbs.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,198 @@
 | 
				
			|||||||
 | 
					package ozon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						core "github.com/diphantxm/ozon-api-client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ListUnprocessedShipmentsParams struct {
 | 
				
			||||||
 | 
						Direction string                         `json:"dir"`
 | 
				
			||||||
 | 
						Filter    ListUnprocessedShipmentsFilter `json:"filter"`
 | 
				
			||||||
 | 
						Limit     int64                          `json:"limit"`
 | 
				
			||||||
 | 
						Offset    int64                          `json:"offset"`
 | 
				
			||||||
 | 
						With      ListUnprocessedShipmentsWith   `json:"with"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ListUnprocessedShipmentsFilter struct {
 | 
				
			||||||
 | 
						CutoffFrom         string  `json:"cutoff_from"`
 | 
				
			||||||
 | 
						CutoffTo           string  `json:"cutoff_to"`
 | 
				
			||||||
 | 
						DeliveringDateFrom string  `json:"delivering_date_from"`
 | 
				
			||||||
 | 
						DeliveringDateTo   string  `json:"delivering_date_to"`
 | 
				
			||||||
 | 
						DeliveryMethodId   []int64 `json:"deliveryMethodId"`
 | 
				
			||||||
 | 
						ProviderId         []int64 `json:"provider_id"`
 | 
				
			||||||
 | 
						Status             string  `json:"status"`
 | 
				
			||||||
 | 
						WarehouseId        []int64 `json:"warehouse_id"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ListUnprocessedShipmentsWith struct {
 | 
				
			||||||
 | 
						AnalyticsData bool `json:"analytics_data"`
 | 
				
			||||||
 | 
						Barcodes      bool `json:"barcodes"`
 | 
				
			||||||
 | 
						FinancialData bool `json:"financial_data"`
 | 
				
			||||||
 | 
						Translit      bool `json:"translit"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ListUnprocessedShipmentsResponse struct {
 | 
				
			||||||
 | 
						core.CommonResponse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Result ListUnprocessedShipmentsResult `json:"result"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ListUnprocessedShipmentsResult struct {
 | 
				
			||||||
 | 
						Count    int64                             `json:"count"`
 | 
				
			||||||
 | 
						Postings []ListUnprocessedShipmentsPosting `json:"postings"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ListUnprocessedShipmentsPosting struct {
 | 
				
			||||||
 | 
						Addressee struct {
 | 
				
			||||||
 | 
							Name  string `json:"name"`
 | 
				
			||||||
 | 
							Phone string `json:"phone"`
 | 
				
			||||||
 | 
						} `json:"addressee"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AnalyticsData struct {
 | 
				
			||||||
 | 
							City                 string `json:"city"`
 | 
				
			||||||
 | 
							DeliveryDateBegin    string `json:"delivery_date_begin"`
 | 
				
			||||||
 | 
							DeliveryDateEnd      string `json:"delivery_date_end"`
 | 
				
			||||||
 | 
							DeliveryType         string `json:"delivery_type"`
 | 
				
			||||||
 | 
							IsLegal              bool   `json:"is_legal"`
 | 
				
			||||||
 | 
							IsPremium            bool   `json:"is_premium"`
 | 
				
			||||||
 | 
							PaymentTypeGroupName string `json:"payment_type_group_name"`
 | 
				
			||||||
 | 
							Region               string `json:"region"`
 | 
				
			||||||
 | 
							TPLProvider          string `json:"tpl_provider"`
 | 
				
			||||||
 | 
							TPLProviderId        int64  `json:"tpl_provider_id"`
 | 
				
			||||||
 | 
							Warehouse            string `json:"warehouse"`
 | 
				
			||||||
 | 
							WarehouseId          int64  `json:"warehouse_id"`
 | 
				
			||||||
 | 
						} `json:"analytics_data"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Barcodes struct {
 | 
				
			||||||
 | 
							LowerBarcode string `json:"lower_barcode"`
 | 
				
			||||||
 | 
							UpperBarcode string `json:"upper_barcode"`
 | 
				
			||||||
 | 
						} `json:"barcodes"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Cancellation struct {
 | 
				
			||||||
 | 
							AffectCancellationRating bool   `json:"affect_cancellation_rating"`
 | 
				
			||||||
 | 
							CancelReason             string `json:"cancel_reason"`
 | 
				
			||||||
 | 
							CancelReasonId           int64  `json:"cancel_reason_id"`
 | 
				
			||||||
 | 
							CancellationInitiator    string `json:"cancellation_initiator"`
 | 
				
			||||||
 | 
							CancellationType         string `json:"cancellation_type"`
 | 
				
			||||||
 | 
							CancelledAfterShip       bool   `json:"cancellation_after_ship"`
 | 
				
			||||||
 | 
						} `json:"cancellation"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Customer struct {
 | 
				
			||||||
 | 
							Address struct {
 | 
				
			||||||
 | 
								AddressTail     string  `json:"address_tail"`
 | 
				
			||||||
 | 
								City            string  `json:"city"`
 | 
				
			||||||
 | 
								Comment         string  `json:"comment"`
 | 
				
			||||||
 | 
								Country         string  `json:"country"`
 | 
				
			||||||
 | 
								District        string  `json:"district"`
 | 
				
			||||||
 | 
								Latitude        float64 `json:'latitude"`
 | 
				
			||||||
 | 
								Longitude       float64 `json:"longitude"`
 | 
				
			||||||
 | 
								ProviderPVZCode string  `json:"provider_pvz_code"`
 | 
				
			||||||
 | 
								PVZCode         int64   `json:"pvz_code"`
 | 
				
			||||||
 | 
								Region          string  `json:"region"`
 | 
				
			||||||
 | 
								ZIPCode         string  `json:"zip_code"`
 | 
				
			||||||
 | 
							} `json:"customer"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CustomerEmail string `json:"customer_email"`
 | 
				
			||||||
 | 
							CustomerId    int64  `json:"customer_id"`
 | 
				
			||||||
 | 
							Name          string `json:"name"`
 | 
				
			||||||
 | 
							Phone         string `json:"phone"`
 | 
				
			||||||
 | 
						} `json:"customer"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DeliveringDate string `json:"delivering_date"`
 | 
				
			||||||
 | 
						DeliveryMethod struct {
 | 
				
			||||||
 | 
							Id            int64  `json:"id"`
 | 
				
			||||||
 | 
							Name          string `json:"name"`
 | 
				
			||||||
 | 
							TPLProvider   string `json:"tpl_provider"`
 | 
				
			||||||
 | 
							TPLProviderId int64  `json:"tpl_provider_id"`
 | 
				
			||||||
 | 
							Warehouse     string `json:"warehouse"`
 | 
				
			||||||
 | 
							WarehouseId   int64  `json:"warehouse_id"`
 | 
				
			||||||
 | 
						} `json:"delivery_method"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FinancialData struct {
 | 
				
			||||||
 | 
							ClusterFrom     string              `json:"cluster_from"`
 | 
				
			||||||
 | 
							ClusterTo       string              `json:"cluster_to"`
 | 
				
			||||||
 | 
							PostingServices MarketplaceServices `json:"posting_services"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Products []struct {
 | 
				
			||||||
 | 
								Actions                 []string            `json:"actions"`
 | 
				
			||||||
 | 
								ClientPrice             string              `json:"client_price"`
 | 
				
			||||||
 | 
								CommissionAmount        float64             `json:"commission_amount"`
 | 
				
			||||||
 | 
								CommissionPercent       int64               `json:"commission_percent"`
 | 
				
			||||||
 | 
								CommissionsCurrencyCode string              `json:"commissions_currency_code"`
 | 
				
			||||||
 | 
								ItemServices            MarketplaceServices `json:"item_services"`
 | 
				
			||||||
 | 
								CurrencyCode            string              `json:"currency_code"`
 | 
				
			||||||
 | 
								OldPrice                float64             `json:"old_price"`
 | 
				
			||||||
 | 
								Payout                  float64             `json:"payout"`
 | 
				
			||||||
 | 
								Picking                 struct {
 | 
				
			||||||
 | 
									Amount float64 `json:"amount"`
 | 
				
			||||||
 | 
									Moment string  `json:"moment"`
 | 
				
			||||||
 | 
									Tag    string  `json:"tag"`
 | 
				
			||||||
 | 
								} `json:"picking"`
 | 
				
			||||||
 | 
								Price                float64 `json:"price"`
 | 
				
			||||||
 | 
								ProductId            int64   `json:"product_id"`
 | 
				
			||||||
 | 
								Quantity             int64   `json:"quantity"`
 | 
				
			||||||
 | 
								TotalDiscountPercent float64 `json:"total_discount_percent"`
 | 
				
			||||||
 | 
								TotalDiscountValue   float64 `json:"total_discount_value"`
 | 
				
			||||||
 | 
							} `json:"products"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InProccessAt        string `json:"in_process_at"`
 | 
				
			||||||
 | 
						IsExpress           bool   `json:"is_express"`
 | 
				
			||||||
 | 
						IsMultibox          bool   `json:"is_multibox"`
 | 
				
			||||||
 | 
						MultiBoxQuantity    int32  `json:"multi_box_qty"`
 | 
				
			||||||
 | 
						OrderId             int64  `json:"order_id"`
 | 
				
			||||||
 | 
						OrderNumber         string `json:"order_number"`
 | 
				
			||||||
 | 
						ParentPostingNumber string `json:"parent_posting_number"`
 | 
				
			||||||
 | 
						PostingNumber       string `json:"posting_number"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Products struct {
 | 
				
			||||||
 | 
							MandatoryMark []string `json:"mandatory_mark"`
 | 
				
			||||||
 | 
							Name          string   `json:"name"`
 | 
				
			||||||
 | 
							OfferId       string   `json:"offer_id"`
 | 
				
			||||||
 | 
							CurrencyCode  string   `json:"currency_code"`
 | 
				
			||||||
 | 
							Price         string   `json:"price"`
 | 
				
			||||||
 | 
							Quantity      int32    `json:"quantity"`
 | 
				
			||||||
 | 
							SKU           int64    `json:"sku"`
 | 
				
			||||||
 | 
						} `json:"products"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Requirements struct {
 | 
				
			||||||
 | 
							ProductsRequiringGTD           []string `json:"products_requiring_gtd"`
 | 
				
			||||||
 | 
							ProductsRequiringCountry       []string `json:"products_requiring_country"`
 | 
				
			||||||
 | 
							ProductsRequiringMandatoryMark []string `json:"products_requiring_mandatory_mark"`
 | 
				
			||||||
 | 
							ProductsRequiringRNPT          []string `json:"products_requiring_rnpt"`
 | 
				
			||||||
 | 
						} `json:"requirements"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ShipmentDate       string `json:"shipment_date"`
 | 
				
			||||||
 | 
						Status             string `json:"status"`
 | 
				
			||||||
 | 
						TPLIntegrationType string `json:"tpl_integration_type"`
 | 
				
			||||||
 | 
						TrackingNumber     string `json:"tracking_number"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MarketplaceServices struct {
 | 
				
			||||||
 | 
						DeliveryToCustomer            float64 `json:"marketplace_service_item_deliv_to_customer"`
 | 
				
			||||||
 | 
						DirectFlowTrans               float64 `json:"marketplace_service_item_direct_flow_trans"`
 | 
				
			||||||
 | 
						DropoffFF                     float64 `json:"marketplace_service_item_item_dropoff_ff"`
 | 
				
			||||||
 | 
						DropoffPVZ                    float64 `json:"marketplace_service_item_dropoff_pvz"`
 | 
				
			||||||
 | 
						DropoffSC                     float64 `json:"marketplace_service_item_dropoff_sc"`
 | 
				
			||||||
 | 
						Fulfillment                   float64 `json:"marketplace_service_item_fulfillment"`
 | 
				
			||||||
 | 
						Pickup                        float64 `json:"marketplace_service_item_pickup"`
 | 
				
			||||||
 | 
						ReturnAfterDeliveryToCustomer float64 `json:"marketplace_service_item_return_after_deliv_to_customer"`
 | 
				
			||||||
 | 
						ReturnFlowTrans               float64 `json:"marketplace_service_item_return_flow_trans"`
 | 
				
			||||||
 | 
						ReturnNotDeliveryToCustomer   float64 `json:"marketplace_service_item_return_not_deliv_to_customer"`
 | 
				
			||||||
 | 
						ReturnPartGoodsCustomer       float64 `json:"marketplace_service_item_return_part_goods_customer"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c Client) ListUnprocessedShipments(params *ListUnprocessedShipmentsParams) (*ListUnprocessedShipmentsResponse, error) {
 | 
				
			||||||
 | 
						url := "/v3/posting/fbs/unfulfilled/list"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp := &ListUnprocessedShipmentsResponse{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						response.CopyCommonResponse(&resp.CommonResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return resp, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										165
									
								
								ozon/fbs_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								ozon/fbs_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					package ozon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						core "github.com/diphantxm/ozon-api-client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestListUnprocessedShipments(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							statusCode int
 | 
				
			||||||
 | 
							headers    map[string]string
 | 
				
			||||||
 | 
							params     *ListUnprocessedShipmentsParams
 | 
				
			||||||
 | 
							response   string
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								200,
 | 
				
			||||||
 | 
								map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
				
			||||||
 | 
								&ListUnprocessedShipmentsParams{
 | 
				
			||||||
 | 
									Direction: "ASC",
 | 
				
			||||||
 | 
									Filter: ListUnprocessedShipmentsFilter{
 | 
				
			||||||
 | 
										CutoffFrom: "2021-08-24T14:15:22Z",
 | 
				
			||||||
 | 
										CutoffTo:   "2021-08-31T14:15:22Z",
 | 
				
			||||||
 | 
										Status:     "awaiting_packaging",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Limit: 100,
 | 
				
			||||||
 | 
									With: ListUnprocessedShipmentsWith{
 | 
				
			||||||
 | 
										AnalyticsData: true,
 | 
				
			||||||
 | 
										Barcodes:      true,
 | 
				
			||||||
 | 
										FinancialData: true,
 | 
				
			||||||
 | 
										Translit:      true,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								`{
 | 
				
			||||||
 | 
									"result": {
 | 
				
			||||||
 | 
									  "postings": [
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
										  "posting_number": "23713478-0018-3",
 | 
				
			||||||
 | 
										  "order_id": 559293114,
 | 
				
			||||||
 | 
										  "order_number": "33713378-0051",
 | 
				
			||||||
 | 
										  "status": "awaiting_packaging",
 | 
				
			||||||
 | 
										  "delivery_method": {
 | 
				
			||||||
 | 
											"id": 15110442724000,
 | 
				
			||||||
 | 
											"name": "Ozon Логистика курьеру, Москва",
 | 
				
			||||||
 | 
											"warehouse_id": 15110442724000,
 | 
				
			||||||
 | 
											"warehouse": "Склад на Ленина",
 | 
				
			||||||
 | 
											"tpl_provider_id": 24,
 | 
				
			||||||
 | 
											"tpl_provider": "Ozon Логистика"
 | 
				
			||||||
 | 
										  },
 | 
				
			||||||
 | 
										  "tracking_number": "",
 | 
				
			||||||
 | 
										  "tpl_integration_type": "ozon",
 | 
				
			||||||
 | 
										  "in_process_at": "2021-08-25T10:48:38Z",
 | 
				
			||||||
 | 
										  "shipment_date": "2021-08-26T10:00:00Z",
 | 
				
			||||||
 | 
										  "delivering_date": null,
 | 
				
			||||||
 | 
										  "cancellation": {
 | 
				
			||||||
 | 
											"cancel_reason_id": 0,
 | 
				
			||||||
 | 
											"cancel_reason": "",
 | 
				
			||||||
 | 
											"cancellation_type": "",
 | 
				
			||||||
 | 
											"cancelled_after_ship": false,
 | 
				
			||||||
 | 
											"affect_cancellation_rating": false,
 | 
				
			||||||
 | 
											"cancellation_initiator": ""
 | 
				
			||||||
 | 
										  },
 | 
				
			||||||
 | 
										  "customer": null,
 | 
				
			||||||
 | 
										  "products": [
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
											  "currency_code": "RUB",
 | 
				
			||||||
 | 
											  "price": "1259",
 | 
				
			||||||
 | 
											  "offer_id": "УТ-0001365",
 | 
				
			||||||
 | 
											  "name": "Мяч, цвет: черный, 5 кг",
 | 
				
			||||||
 | 
											  "sku": 140048123,
 | 
				
			||||||
 | 
											  "quantity": 1,
 | 
				
			||||||
 | 
											  "mandatory_mark": []
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										  ],
 | 
				
			||||||
 | 
										  "addressee": null,
 | 
				
			||||||
 | 
										  "barcodes": {
 | 
				
			||||||
 | 
											"upper_barcode": "%101%806044518",
 | 
				
			||||||
 | 
											"lower_barcode": "23024930500000"
 | 
				
			||||||
 | 
										  },
 | 
				
			||||||
 | 
										  "analytics_data": {
 | 
				
			||||||
 | 
											"region": "Санкт-Петербург",
 | 
				
			||||||
 | 
											"city": "Санкт-Петербург",
 | 
				
			||||||
 | 
											"delivery_type": "PVZ",
 | 
				
			||||||
 | 
											"is_premium": false,
 | 
				
			||||||
 | 
											"payment_type_group_name": "Карты оплаты",
 | 
				
			||||||
 | 
											"warehouse_id": 15110442724000,
 | 
				
			||||||
 | 
											"warehouse": "Склад на Ленина",
 | 
				
			||||||
 | 
											"tpl_provider_id": 24,
 | 
				
			||||||
 | 
											"tpl_provider": "Ozon Логистика",
 | 
				
			||||||
 | 
											"delivery_date_begin": "2022-08-28T14:00:00Z",
 | 
				
			||||||
 | 
											"delivery_date_end": "2022-08-28T18:00:00Z",
 | 
				
			||||||
 | 
											"is_legal": false
 | 
				
			||||||
 | 
										  },
 | 
				
			||||||
 | 
										  "financial_data": {
 | 
				
			||||||
 | 
											"products": [
 | 
				
			||||||
 | 
											  {
 | 
				
			||||||
 | 
												"commission_amount": 0,
 | 
				
			||||||
 | 
												"commission_percent": 0,
 | 
				
			||||||
 | 
												"payout": 0,
 | 
				
			||||||
 | 
												"product_id": 140048123,
 | 
				
			||||||
 | 
												"old_price": 1888,
 | 
				
			||||||
 | 
												"price": 1259,
 | 
				
			||||||
 | 
												"total_discount_value": 629,
 | 
				
			||||||
 | 
												"total_discount_percent": 33.32,
 | 
				
			||||||
 | 
												"actions": [
 | 
				
			||||||
 | 
												  "Системная виртуальная скидка селлера"
 | 
				
			||||||
 | 
												],
 | 
				
			||||||
 | 
												"picking": null,
 | 
				
			||||||
 | 
												"quantity": 1,
 | 
				
			||||||
 | 
												"client_price": "",
 | 
				
			||||||
 | 
												"item_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
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											  }
 | 
				
			||||||
 | 
											],
 | 
				
			||||||
 | 
											"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
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										  },
 | 
				
			||||||
 | 
										  "is_express": false,
 | 
				
			||||||
 | 
										  "requirements": {
 | 
				
			||||||
 | 
											"products_requiring_gtd": [],
 | 
				
			||||||
 | 
											"products_requiring_country": []
 | 
				
			||||||
 | 
										  }
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									  ],
 | 
				
			||||||
 | 
									  "count": 55
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}`,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							resp, err := c.ListUnprocessedShipments(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)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								ozon/ozon.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								ozon/ozon.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					package ozon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						core "github.com/diphantxm/ozon-api-client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						DefaultAPIBaseUrl = "https://api-seller.ozon.ru"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Client struct {
 | 
				
			||||||
 | 
						client *core.Client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewClient(clientId, apiKey string) *Client {
 | 
				
			||||||
 | 
						return &Client{
 | 
				
			||||||
 | 
							client: core.NewClient(DefaultAPIBaseUrl, map[string]string{
 | 
				
			||||||
 | 
								"Client-Id": clientId,
 | 
				
			||||||
 | 
								"Api-Key":   apiKey,
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewMockClient(handler http.HandlerFunc) *Client {
 | 
				
			||||||
 | 
						return &Client{
 | 
				
			||||||
 | 
							client: core.NewMockClient(handler),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										217
									
								
								ozon/products.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								ozon/products.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,217 @@
 | 
				
			|||||||
 | 
					package ozon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						core "github.com/diphantxm/ozon-api-client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetStocksInfoParams struct {
 | 
				
			||||||
 | 
						// Identifier of the last value on the page. Leave this field blank in the first request.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// To get the next values, specify last_id from the response of the previous request.
 | 
				
			||||||
 | 
						LastId string `json:"last_id,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Number of values per page. Minimum is 1, maximum is 1000
 | 
				
			||||||
 | 
						Limit int64 `json:"limit,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Filter by product
 | 
				
			||||||
 | 
						Filter GetStocksInfoFilter `json:"filter,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetStocksInfoFilter struct {
 | 
				
			||||||
 | 
						// Filter by the offer_id parameter. It is possible to pass a list of values
 | 
				
			||||||
 | 
						OfferId string `json:"offer_id,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Filter by the product_id parameter. It is possible to pass a list of values
 | 
				
			||||||
 | 
						ProductId int64 `json:"product_id,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Filter by product visibility
 | 
				
			||||||
 | 
						Visibility string `json:"visibility,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetStocksInfoResponse struct {
 | 
				
			||||||
 | 
						core.CommonResponse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Method Result
 | 
				
			||||||
 | 
						Result GetStocksInfoResponseResult `json:"result,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetStocksInfoResponseResult struct {
 | 
				
			||||||
 | 
						// Identifier of the last value on the page
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// To get the next values, specify the recieved value in the next request in the last_id parameter
 | 
				
			||||||
 | 
						LastId string `json:"last_id,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The number of unique products for which information about stocks is displayed
 | 
				
			||||||
 | 
						Total int32 `json:"total,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Product details
 | 
				
			||||||
 | 
						Items []GetStocksInfoResponseItem `json:"items,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetStocksInfoResponseItem struct {
 | 
				
			||||||
 | 
						// Product identifier in the seller's system
 | 
				
			||||||
 | 
						OfferId string `json:"offer_id,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Product identifier
 | 
				
			||||||
 | 
						ProductId int64 `json:"product_id,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Stock details
 | 
				
			||||||
 | 
						Stocks []GetStocksInfoResponseStock `json:"stocks,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetStocksInfoResponseStock struct {
 | 
				
			||||||
 | 
						// In a warehouse
 | 
				
			||||||
 | 
						Present int32 `json:"present,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Reserved
 | 
				
			||||||
 | 
						Reserved int32 `json:"reserved,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Warehouse type
 | 
				
			||||||
 | 
						Type string `json:"type,omitempty" default:"ALL"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c Client) GetStocksInfo(params *GetStocksInfoParams) (*GetStocksInfoResponse, error) {
 | 
				
			||||||
 | 
						url := "/v3/product/info/stocks"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp := &GetStocksInfoResponse{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						response.CopyCommonResponse(&resp.CommonResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return resp, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsParams struct {
 | 
				
			||||||
 | 
						OfferId   string `json:"offer_id"`
 | 
				
			||||||
 | 
						ProductId int64  `json:"product_id"`
 | 
				
			||||||
 | 
						SKU       int64  `json:"sku"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsResponse struct {
 | 
				
			||||||
 | 
						core.CommonResponse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Result GetProductDetailsResponseResult `json:"Result"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsResponseResult struct {
 | 
				
			||||||
 | 
						Barcode             string                                    `json:"barcode"`
 | 
				
			||||||
 | 
						Barcodes            []string                                  `json:"barcodes"`
 | 
				
			||||||
 | 
						BuyboxPrice         string                                    `json:"buybox_price"`
 | 
				
			||||||
 | 
						CategoryId          int64                                     `json:"category_id"`
 | 
				
			||||||
 | 
						ColorImage          string                                    `json:"color_image"`
 | 
				
			||||||
 | 
						Commissions         []GetProductDetailsResponseCommission     `json:"commissions"`
 | 
				
			||||||
 | 
						CreatedAt           string                                    `json:"created_at"`
 | 
				
			||||||
 | 
						FBOSKU              int64                                     `json:"fbo_sku"`
 | 
				
			||||||
 | 
						FBSSKU              int64                                     `json:"fbs_sku"`
 | 
				
			||||||
 | 
						Id                  int64                                     `json:"id"`
 | 
				
			||||||
 | 
						Images              []string                                  `json:"images"`
 | 
				
			||||||
 | 
						PrimaryImage        string                                    `json:"primary_image"`
 | 
				
			||||||
 | 
						Images360           []string                                  `json:"images360"`
 | 
				
			||||||
 | 
						HasDiscountedItem   bool                                      `json:"has_discounted_item"`
 | 
				
			||||||
 | 
						IsDiscounted        bool                                      `json:"is_discounted"`
 | 
				
			||||||
 | 
						DiscountedStocks    GetProductDetailsResponseDiscountedStocks `json:"discounted_stocks"`
 | 
				
			||||||
 | 
						IsKGT               bool                                      `json:"is_kgt"`
 | 
				
			||||||
 | 
						IsPrepayment        bool                                      `json:"is_prepayment"`
 | 
				
			||||||
 | 
						IsPrepaymentAllowed bool                                      `json:"is_prepayment_allowed"`
 | 
				
			||||||
 | 
						CurrencyCode        string                                    `json:"currency_code"`
 | 
				
			||||||
 | 
						MarketingPrice      string                                    `json:"marketing_price"`
 | 
				
			||||||
 | 
						MinOzonPrice        string                                    `json:"min_ozon_price"`
 | 
				
			||||||
 | 
						MinPrice            string                                    `json:"min_price"`
 | 
				
			||||||
 | 
						Name                string                                    `json:"name"`
 | 
				
			||||||
 | 
						OfferId             string                                    `json:"offer_id"`
 | 
				
			||||||
 | 
						OldPrice            string                                    `json:"old_price"`
 | 
				
			||||||
 | 
						PremiumPrice        string                                    `json:"premium_price"`
 | 
				
			||||||
 | 
						Price               string                                    `json:"price"`
 | 
				
			||||||
 | 
						PriceIndex          string                                    `json:"price_idnex"`
 | 
				
			||||||
 | 
						RecommendedPrice    string                                    `json:"recommended_price"`
 | 
				
			||||||
 | 
						Status              GetProductDetailsResponseStatus           `json:"status"`
 | 
				
			||||||
 | 
						Sources             []GetProductDetailsResponseSource         `json:"sources"`
 | 
				
			||||||
 | 
						Stocks              GetProductDetailsResponseStocks           `json:"stocks"`
 | 
				
			||||||
 | 
						UpdatedAt           string                                    `json:"updated_at"`
 | 
				
			||||||
 | 
						VAT                 string                                    `json:"vat"`
 | 
				
			||||||
 | 
						VisibilityDetails   GetProductDetailsResponseDetails          `json:"visibility_details"`
 | 
				
			||||||
 | 
						Visible             bool                                      `json:"visible"`
 | 
				
			||||||
 | 
						VolumeWeight        float64                                   `json:"volume_weights"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsResponseCommission struct {
 | 
				
			||||||
 | 
						DeliveryAmount float64 `json:"deliveryAmount"`
 | 
				
			||||||
 | 
						MinValue       float64 `json:"minValue"`
 | 
				
			||||||
 | 
						Percent        float64 `json:"percent"`
 | 
				
			||||||
 | 
						ReturnAmount   float64 `json:"returnAmount"`
 | 
				
			||||||
 | 
						SaleSchema     string  `json:"saleSchema"`
 | 
				
			||||||
 | 
						Value          float64 `json:"value"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsResponseDiscountedStocks struct {
 | 
				
			||||||
 | 
						Coming   int32 `json:"coming"`
 | 
				
			||||||
 | 
						Present  int32 `json:"present"`
 | 
				
			||||||
 | 
						Reserved int32 `json:"reserved"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsResponseStatus struct {
 | 
				
			||||||
 | 
						State            string                               `json:"state"`
 | 
				
			||||||
 | 
						StateFailed      string                               `json:"state_failed"`
 | 
				
			||||||
 | 
						ModerateStatus   string                               `json:"moderate_status"`
 | 
				
			||||||
 | 
						DeclineReasons   []string                             `json:"decline_reasons"`
 | 
				
			||||||
 | 
						ValidationsState string                               `json:"validation_state"`
 | 
				
			||||||
 | 
						StateName        string                               `json:"state_name"`
 | 
				
			||||||
 | 
						StateDescription string                               `json:"state_description"`
 | 
				
			||||||
 | 
						IsFailed         bool                                 `json:"is_failed"`
 | 
				
			||||||
 | 
						IsCreated        bool                                 `json:"is_created"`
 | 
				
			||||||
 | 
						StateTooltip     string                               `json:"state_tooltip"`
 | 
				
			||||||
 | 
						ItemErrors       []GetProductDetailsResponseItemError `json:"item_errors"`
 | 
				
			||||||
 | 
						StateUpdatedAt   string                               `json:"state_updated_at"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsResponseItemError struct {
 | 
				
			||||||
 | 
						Code                        string                                               `json:"code"`
 | 
				
			||||||
 | 
						State                       string                                               `json:"state"`
 | 
				
			||||||
 | 
						Level                       string                                               `json:"level"`
 | 
				
			||||||
 | 
						Description                 string                                               `json:"description"`
 | 
				
			||||||
 | 
						Field                       string                                               `json:"field"`
 | 
				
			||||||
 | 
						AttributeId                 int64                                                `json:"attribute_id"`
 | 
				
			||||||
 | 
						AttributeName               string                                               `json:"attribute_name"`
 | 
				
			||||||
 | 
						OptionalDescriptionElements GetProductDetailsResponseOptionalDescriptionElements `json:"optional_description_elements"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsResponseOptionalDescriptionElements struct {
 | 
				
			||||||
 | 
						PropertyName string `json:"property_name"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsResponseSource struct {
 | 
				
			||||||
 | 
						IsEnabled bool   `json:"is_enabled"`
 | 
				
			||||||
 | 
						SKU       int64  `json:"sku"`
 | 
				
			||||||
 | 
						Source    string `json:"source"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsResponseStocks struct {
 | 
				
			||||||
 | 
						Coming   int32 `json:"coming"`
 | 
				
			||||||
 | 
						Present  int32 `json:"present"`
 | 
				
			||||||
 | 
						Reserved int32 `json:"reserved"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductDetailsResponseDetails struct {
 | 
				
			||||||
 | 
						ActiveProduct bool `json:"active_product"`
 | 
				
			||||||
 | 
						HasPrice      bool `json:"has_price"`
 | 
				
			||||||
 | 
						HasStock      bool `json:"has_stock"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c Client) GetProductDetails(params *GetProductDetailsParams) (*GetProductDetailsResponse, error) {
 | 
				
			||||||
 | 
						url := "/v2/product/info"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp := &GetProductDetailsResponse{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						response, err := c.client.Request(http.MethodPost, url, params, resp)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						response.CopyCommonResponse(&resp.CommonResponse)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return resp, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										261
									
								
								ozon/products_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								ozon/products_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,261 @@
 | 
				
			|||||||
 | 
					package ozon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						core "github.com/diphantxm/ozon-api-client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGetStocksInfo(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							statusCode int
 | 
				
			||||||
 | 
							headers    map[string]string
 | 
				
			||||||
 | 
							params     *GetStocksInfoParams
 | 
				
			||||||
 | 
							response   string
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								http.StatusOK,
 | 
				
			||||||
 | 
								map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
				
			||||||
 | 
								&GetStocksInfoParams{
 | 
				
			||||||
 | 
									Limit:  100,
 | 
				
			||||||
 | 
									LastId: "",
 | 
				
			||||||
 | 
									Filter: GetStocksInfoFilter{
 | 
				
			||||||
 | 
										OfferId:    "136834",
 | 
				
			||||||
 | 
										ProductId:  214887921,
 | 
				
			||||||
 | 
										Visibility: "ALL",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								`{
 | 
				
			||||||
 | 
									"result": {
 | 
				
			||||||
 | 
									  "items": [
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
										  "product_id": 214887921,
 | 
				
			||||||
 | 
										  "offer_id": "136834",
 | 
				
			||||||
 | 
										  "stocks": [
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
											  "type": "fbs",
 | 
				
			||||||
 | 
											  "present": 170,
 | 
				
			||||||
 | 
											  "reserved": 0
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
											  "type": "fbo",
 | 
				
			||||||
 | 
											  "present": 0,
 | 
				
			||||||
 | 
											  "reserved": 0
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										  ]
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									  ],
 | 
				
			||||||
 | 
									  "total": 1,
 | 
				
			||||||
 | 
									  "last_id": "anVsbA=="
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}`,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								400,
 | 
				
			||||||
 | 
								map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
				
			||||||
 | 
								&GetStocksInfoParams{
 | 
				
			||||||
 | 
									Limit:  100,
 | 
				
			||||||
 | 
									LastId: "",
 | 
				
			||||||
 | 
									Filter: GetStocksInfoFilter{
 | 
				
			||||||
 | 
										OfferId:    "136834",
 | 
				
			||||||
 | 
										ProductId:  214887921,
 | 
				
			||||||
 | 
										Visibility: "ALL",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								`{
 | 
				
			||||||
 | 
									"code": 0,
 | 
				
			||||||
 | 
									"details": [
 | 
				
			||||||
 | 
									  {
 | 
				
			||||||
 | 
										"typeUrl": "string",
 | 
				
			||||||
 | 
										"value": "string"
 | 
				
			||||||
 | 
									  }
 | 
				
			||||||
 | 
									],
 | 
				
			||||||
 | 
									"message": "string"
 | 
				
			||||||
 | 
								}`,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							resp, err := c.GetStocksInfo(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 TestGetProductDetails(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							statusCode int
 | 
				
			||||||
 | 
							headers    map[string]string
 | 
				
			||||||
 | 
							params     *GetProductDetailsParams
 | 
				
			||||||
 | 
							response   string
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								http.StatusOK,
 | 
				
			||||||
 | 
								map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
				
			||||||
 | 
								&GetProductDetailsParams{
 | 
				
			||||||
 | 
									ProductId: 137208233,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								`{
 | 
				
			||||||
 | 
									"result": {
 | 
				
			||||||
 | 
									  "id": 137208233,
 | 
				
			||||||
 | 
									  "name": "Комплект защитных плёнок для X3 NFC. Темный хлопок",
 | 
				
			||||||
 | 
									  "offer_id": "143210586",
 | 
				
			||||||
 | 
									  "barcode": "",
 | 
				
			||||||
 | 
									  "barcodes": [
 | 
				
			||||||
 | 
										"2335900005",
 | 
				
			||||||
 | 
										"7533900005"
 | 
				
			||||||
 | 
									  ],
 | 
				
			||||||
 | 
									  "buybox_price": "",
 | 
				
			||||||
 | 
									  "category_id": 17038062,
 | 
				
			||||||
 | 
									  "created_at": "2021-10-21T15:48:03.529178Z",
 | 
				
			||||||
 | 
									  "images": [
 | 
				
			||||||
 | 
										"https://cdn1.ozone.ru/s3/multimedia-5/6088931525.jpg",
 | 
				
			||||||
 | 
										"https://cdn1.ozone.ru/s3/multimedia-p/6088915813.jpg"
 | 
				
			||||||
 | 
									  ],
 | 
				
			||||||
 | 
									  "has_discounted_item": true,
 | 
				
			||||||
 | 
									  "is_discounted": true,
 | 
				
			||||||
 | 
									  "discounted_stocks": {
 | 
				
			||||||
 | 
										"coming": 0,
 | 
				
			||||||
 | 
										"present": 0,
 | 
				
			||||||
 | 
										"reserved": 0
 | 
				
			||||||
 | 
									  },
 | 
				
			||||||
 | 
									  "currency_code": "RUB",
 | 
				
			||||||
 | 
									  "marketing_price": "",
 | 
				
			||||||
 | 
									  "min_price": "",
 | 
				
			||||||
 | 
									  "old_price": "",
 | 
				
			||||||
 | 
									  "premium_price": "",
 | 
				
			||||||
 | 
									  "price": "590.0000",
 | 
				
			||||||
 | 
									  "recommended_price": "",
 | 
				
			||||||
 | 
									  "sources": [
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
										  "is_enabled": true,
 | 
				
			||||||
 | 
										  "sku": 522759607,
 | 
				
			||||||
 | 
										  "source": "fbo"
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
										  "is_enabled": true,
 | 
				
			||||||
 | 
										  "sku": 522759608,
 | 
				
			||||||
 | 
										  "source": "fbs"
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									  ],
 | 
				
			||||||
 | 
									  "stocks": {
 | 
				
			||||||
 | 
										"coming": 0,
 | 
				
			||||||
 | 
										"present": 0,
 | 
				
			||||||
 | 
										"reserved": 0
 | 
				
			||||||
 | 
									  },
 | 
				
			||||||
 | 
									  "errors": [],
 | 
				
			||||||
 | 
									  "updated_at": "2023-02-09T06:46:44.152Z",
 | 
				
			||||||
 | 
									  "vat": "0.0",
 | 
				
			||||||
 | 
									  "visible": false,
 | 
				
			||||||
 | 
									  "visibility_details": {
 | 
				
			||||||
 | 
										"has_price": true,
 | 
				
			||||||
 | 
										"has_stock": false,
 | 
				
			||||||
 | 
										"active_product": false
 | 
				
			||||||
 | 
									  },
 | 
				
			||||||
 | 
									  "price_index": "0.00",
 | 
				
			||||||
 | 
									  "commissions": [],
 | 
				
			||||||
 | 
									  "volume_weight": 0.1,
 | 
				
			||||||
 | 
									  "is_prepayment": false,
 | 
				
			||||||
 | 
									  "is_prepayment_allowed": true,
 | 
				
			||||||
 | 
									  "images360": [],
 | 
				
			||||||
 | 
									  "is_kgt": false,
 | 
				
			||||||
 | 
									  "color_image": "",
 | 
				
			||||||
 | 
									  "primary_image": "https://cdn1.ozone.ru/s3/multimedia-p/6088931545.jpg",
 | 
				
			||||||
 | 
									  "status": {
 | 
				
			||||||
 | 
										"state": "imported",
 | 
				
			||||||
 | 
										"state_failed": "imported",
 | 
				
			||||||
 | 
										"moderate_status": "",
 | 
				
			||||||
 | 
										"decline_reasons": [],
 | 
				
			||||||
 | 
										"validation_state": "pending",
 | 
				
			||||||
 | 
										"state_name": "Не продается",
 | 
				
			||||||
 | 
										"state_description": "Не создан",
 | 
				
			||||||
 | 
										"is_failed": true,
 | 
				
			||||||
 | 
										"is_created": false,
 | 
				
			||||||
 | 
										"state_tooltip": "",
 | 
				
			||||||
 | 
										"item_errors": [
 | 
				
			||||||
 | 
										  {
 | 
				
			||||||
 | 
											"code": "error_attribute_values_empty",
 | 
				
			||||||
 | 
											"field": "attribute",
 | 
				
			||||||
 | 
											"attribute_id": 9048,
 | 
				
			||||||
 | 
											"state": "imported",
 | 
				
			||||||
 | 
											"level": "error",
 | 
				
			||||||
 | 
											"description": "Не заполнен обязательный атрибут. Иногда мы обновляем обязательные атрибуты или добавляем новые. Отредактируйте товар или загрузите новый XLS-шаблон с актуальными атрибутами. ",
 | 
				
			||||||
 | 
											"optional_description_elements": {},
 | 
				
			||||||
 | 
											"attribute_name": "Название модели"
 | 
				
			||||||
 | 
										  },
 | 
				
			||||||
 | 
										  {
 | 
				
			||||||
 | 
											"code": "error_attribute_values_empty",
 | 
				
			||||||
 | 
											"field": "attribute",
 | 
				
			||||||
 | 
											"attribute_id": 5076,
 | 
				
			||||||
 | 
											"state": "imported",
 | 
				
			||||||
 | 
											"level": "error",
 | 
				
			||||||
 | 
											"description": "Не заполнен обязательный атрибут. Иногда мы обновляем обязательные атрибуты или добавляем новые. Отредактируйте товар или загрузите новый XLS-шаблон с актуальными атрибутами. ",
 | 
				
			||||||
 | 
											"optional_description_elements": {},
 | 
				
			||||||
 | 
											"attribute_name": "Рекомендовано для"
 | 
				
			||||||
 | 
										  },
 | 
				
			||||||
 | 
										  {
 | 
				
			||||||
 | 
											"code": "error_attribute_values_empty",
 | 
				
			||||||
 | 
											"field": "attribute",
 | 
				
			||||||
 | 
											"attribute_id": 8229,
 | 
				
			||||||
 | 
											"state": "imported",
 | 
				
			||||||
 | 
											"level": "error",
 | 
				
			||||||
 | 
											"description": "Не заполнен обязательный атрибут. Иногда мы обновляем обязательные атрибуты или добавляем новые. Отредактируйте товар или загрузите новый XLS-шаблон с актуальными атрибутами. ",
 | 
				
			||||||
 | 
											"optional_description_elements": {},
 | 
				
			||||||
 | 
											"attribute_name": "Тип"
 | 
				
			||||||
 | 
										  },
 | 
				
			||||||
 | 
										  {
 | 
				
			||||||
 | 
											"code": "error_attribute_values_empty",
 | 
				
			||||||
 | 
											"field": "attribute",
 | 
				
			||||||
 | 
											"attribute_id": 85,
 | 
				
			||||||
 | 
											"state": "imported",
 | 
				
			||||||
 | 
											"level": "error",
 | 
				
			||||||
 | 
											"description": "Не заполнен обязательный атрибут. Иногда мы обновляем обязательные атрибуты или добавляем новые. Отредактируйте товар или загрузите новый XLS-шаблон с актуальными атрибутами. ",
 | 
				
			||||||
 | 
											"optional_description_elements": {},
 | 
				
			||||||
 | 
											"attribute_name": "Бренд"
 | 
				
			||||||
 | 
										  }
 | 
				
			||||||
 | 
										],
 | 
				
			||||||
 | 
										"state_updated_at": "2021-10-21T15:48:03.927309Z"
 | 
				
			||||||
 | 
									  }
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								  }`,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								400,
 | 
				
			||||||
 | 
								map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
 | 
				
			||||||
 | 
								&GetProductDetailsParams{
 | 
				
			||||||
 | 
									ProductId: 137208233,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								`{
 | 
				
			||||||
 | 
									"code": 0,
 | 
				
			||||||
 | 
									"details": [
 | 
				
			||||||
 | 
									  {
 | 
				
			||||||
 | 
										"typeUrl": "string",
 | 
				
			||||||
 | 
										"value": "string"
 | 
				
			||||||
 | 
									  }
 | 
				
			||||||
 | 
									],
 | 
				
			||||||
 | 
									"message": "string"
 | 
				
			||||||
 | 
								}`,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							resp, err := c.GetProductDetails(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)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user