diff --git a/ozon/fbs.go b/ozon/fbs.go index 2b6b02f..69f3373 100644 --- a/ozon/fbs.go +++ b/ozon/fbs.go @@ -2902,3 +2902,96 @@ func (c FBS) CreateOrGetProductExemplar(ctx context.Context, params *CreateOrGet return resp, nil } + +type GetCarriageParams struct { + CarriageId int64 `json:"carriage_id"` +} + +type GetCarriageResponse struct { + core.CommonResponse + + // Acceptance certificate type for FBS sellers + ActType string `json:"act_type"` + + // Pass identifiers for the freight + ArrivalPassIds []string `json:"arrival_pass_ids"` + + // List of available actions on the freight + AvailableActions []string `json:"available_actions"` + + // Cancel availability + CancelAvailability GetCarriageCancelAvailability `json:"cancel_availability"` + + // Freight identifier + CarriageId int64 `json:"carriage_id"` + + // Company identifier + CompanyId int64 `json:"company_id"` + + // Number of package units + ContainersCount int32 `json:"containers_count"` + + // Date and time of freight creation + CreatedAt time.Time `json:"created_at"` + + // Delivery method identifier + DeliveryMethodId int64 `json:"delivery_method_id"` + + // Shipping date + DepartureDate string `json:"departure_date"` + + // First mile type + FirstMileType string `json:"first_mile_type"` + + // true if there are shipments subject to shipping that are not in the current freight + HasPostingsForNextCarriage bool `json:"has_postings_for_next_carriage"` + + // Delivery service integration type + IntegrationType string `json:"integration_type"` + + // true if you already printed shipping labels + IsContainerLabelPrinted bool `json:"is_container_label_printed"` + + // true if the freight is partial + IsPartial bool `json:"is_partial"` + + // Serial number of the partial freight + PartialNum int64 `json:"partial_num"` + + // The number of retries to create a freight + RetryCount int32 `json:"retry_count"` + + // Freight status + Status string `json:"status"` + + // Delivery method identifier + TPLProviderId int64 `json:"tpl_provider_id"` + + // Date and time when the freight was last updated + UpdatedAt time.Time `json:"updated_at"` + + // Warehouse identifier + WarehouseId int64 `json:"warehouse_id"` +} + +type GetCarriageCancelAvailability struct { + // true if the freight can be cancelled + IsCancelAvailable bool `json:"is_cancel_available"` + + // Reason why freight can't be cancelled + Reason string `json:"reason"` +} + +func (c FBS) GetCarriage(ctx context.Context, params *GetCarriageParams) (*GetCarriageResponse, error) { + url := "/v1/carriage/get" + + resp := &GetCarriageResponse{} + + response, err := c.client.Request(ctx, http.MethodPost, url, params, resp, nil) + if err != nil { + return nil, err + } + response.CopyCommonResponse(&resp.CommonResponse) + + return resp, nil +} diff --git a/ozon/fbs_test.go b/ozon/fbs_test.go index a8c4671..e663a4c 100644 --- a/ozon/fbs_test.go +++ b/ozon/fbs_test.go @@ -2919,3 +2919,84 @@ func TestCreateOrGetProductExemplar(t *testing.T) { } } } + +func TestGetCarriage(t *testing.T) { + t.Parallel() + + tests := []struct { + statusCode int + headers map[string]string + params *GetCarriageParams + response string + }{ + // Test Ok + { + http.StatusOK, + map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"}, + &GetCarriageParams{ + CarriageId: 15, + }, + `{ + "act_type": "string", + "arrival_pass_ids": [ + "string" + ], + "available_actions": [ + "string" + ], + "cancel_availability": { + "is_cancel_available": true, + "reason": "string" + }, + "carriage_id": 15, + "company_id": 0, + "containers_count": 0, + "created_at": "2019-08-24T14:15:22Z", + "delivery_method_id": 0, + "departure_date": "string", + "first_mile_type": "string", + "has_postings_for_next_carriage": true, + "integration_type": "string", + "is_container_label_printed": true, + "is_partial": true, + "partial_num": 0, + "retry_count": 0, + "status": "string", + "tpl_provider_id": 0, + "updated_at": "2019-08-24T14:15:22Z", + "warehouse_id": 0 + }`, + }, + // Test No Client-Id or Api-Key + { + http.StatusUnauthorized, + map[string]string{}, + &GetCarriageParams{}, + `{ + "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)) + + ctx, _ := context.WithTimeout(context.Background(), testTimeout) + resp, err := c.FBS().GetCarriage(ctx, test.params) + if err != nil { + t.Error(err) + continue + } + + compareJsonResponse(t, test.response, &GetCarriageResponse{}) + + if resp.StatusCode != test.statusCode { + t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode) + } + + if resp.CarriageId != test.params.CarriageId { + t.Errorf("carriage id in request and response should be equal") + } + } +} diff --git a/ozon/ozon.go b/ozon/ozon.go index 5ee6c8a..55899a2 100644 --- a/ozon/ozon.go +++ b/ozon/ozon.go @@ -41,6 +41,7 @@ type Client struct { certificates *Certificates strategies *Strategies barcodes *Barcodes + passes *Passes } func (c Client) Analytics() *Analytics { @@ -119,6 +120,10 @@ func (c Client) Barcodes() *Barcodes { return c.barcodes } +func (c Client) Passes() *Passes { + return c.passes +} + type ClientOption func(c *ClientOptions) func WithHttpClient(httpClient core.HttpClient) ClientOption { @@ -182,6 +187,7 @@ func NewClient(opts ...ClientOption) *Client { certificates: &Certificates{client: coreClient}, strategies: &Strategies{client: coreClient}, barcodes: &Barcodes{client: coreClient}, + passes: &Passes{client: coreClient}, } } @@ -209,5 +215,6 @@ func NewMockClient(handler http.HandlerFunc) *Client { certificates: &Certificates{client: coreClient}, strategies: &Strategies{client: coreClient}, barcodes: &Barcodes{client: coreClient}, + passes: &Passes{client: coreClient}, } } diff --git a/ozon/pass.go b/ozon/pass.go new file mode 100644 index 0000000..63e41d5 --- /dev/null +++ b/ozon/pass.go @@ -0,0 +1,302 @@ +package ozon + +import ( + "context" + "net/http" + "time" + + core "github.com/diphantxm/ozon-api-client" +) + +type Passes struct { + client *core.Client +} + +type ListPassesParams struct { + // Cursor for the next data sample + Cursor string `json:"curson"` + + // Filters + Filter ListPassesFilter `json:"filter"` + + // Limit on number of entries in a reply. Default value is 1000. Maximum value is 1000 + Limit int32 `json:"limit"` +} + +type ListPassesFilter struct { + // Filter by pass identifier + ArrivalPassIds []string `json:"arrival_pass_ids"` + + // Filter by purpose of arrival: + // + // FBS_DELIVERY—delivery. + // FBS_RETURN—take out returns. + // If the parameter isn't specified, both purposes are considered. + // + // The specified purpose must be in the list of reasons for passes + ArrivalReason string `json:"arrival_reason"` + + // Filter by drop-off points identifier + DropoffPointIds []int64 `json:"dropoff_point_ids"` + + // true to get only active pass requests + OnlyActivePasses bool `json:"only_active_passes"` + + // Filter by seller's warehouses identifier + WarehouseIds []int64 `json:"warehouse_ids"` +} + +type ListPassesResponse struct { + core.CommonResponse + + // List of passes + ArrivalPasses []ListPassesArrivalPass `json:"arrival_passes"` + + // Cursor for the next data sample. If the parameter is empty, there is no more data + Cursor string `json:"cursor"` +} + +type ListPassesArrivalPass struct { + // Pass identifier + ArrivalPassId int64 `json:"arrival_pass_id"` + + // Arrival purpose + ArrivalReasons []string `json:"arrival_reasons"` + + // Date and time of arrival in UTC format + ArrivalTime time.Time `json:"arrival_time"` + + // Driver full name + DriverName string `json:"driver_name"` + + // Driver phone number + DriverPhone string `json:"driver_phone"` + + // Drop-off point identifier + DropoffPointId int64 `json:"dropoff_point_id"` + + // true if the request is active + IsActive bool `json:"is_active"` + + // Car license plate + VehicleLicensePlate string `json:"vehicle_license_plate"` + + // Car model + VehicleModel string `json:"vehicle_model"` + + // Warehouse identifier + WarehouseId int64 `json:"warehouse_id"` +} + +func (c Passes) List(ctx context.Context, params *ListPassesParams) (*ListPassesResponse, error) { + url := "/v1/pass/list" + + resp := &ListPassesResponse{} + + response, err := c.client.Request(ctx, http.MethodPost, url, params, resp, nil) + if err != nil { + return nil, err + } + response.CopyCommonResponse(&resp.CommonResponse) + + return resp, nil +} + +type CreateCarriageParams struct { + // List of passes + ArrivalPasses []CarriageArrivalPass `json:"arrival_passes"` + + // Freight identifier + CarriageId int64 `json:"carriage_id"` +} + +type CarriageArrivalPass struct { + // Driver full name + DriverName string `json:"driver_name"` + + // Driver phone number + DriverPhone string `json:"driver_phone"` + + // Car license plate + VehicleLicensePlate string `json:"vehicle_license_plate"` + + // Car model + VehicleModel string `json:"vehicle_model"` + + // true if you will export returns. Default is false + WithReturns bool `json:"with_returns"` +} + +type CreateCarriageResponse struct { + core.CommonResponse + + // Pass identifiers + ArrivalPassIds []string `json:"arrival_pass_ids"` +} + +func (c Passes) CreateCarriage(ctx context.Context, params *CreateCarriageParams) (*CreateCarriageResponse, error) { + url := "/v1/carriage/pass/create" + + resp := &CreateCarriageResponse{} + + response, err := c.client.Request(ctx, http.MethodPost, url, params, resp, nil) + if err != nil { + return nil, err + } + response.CopyCommonResponse(&resp.CommonResponse) + + return resp, nil +} + +type UpdateCarriageParams struct { + ArrivalPasses []UpdateCarriageArrivalPass `json:"arrival_passes"` + + CarriageId int64 `json:"carriage_id"` +} + +type UpdateCarriageArrivalPass struct { + CarriageArrivalPass + + Id int64 `json:"id"` +} + +type UpdateCarriageResponse struct { + core.CommonResponse +} + +func (c Passes) UpdateCarriage(ctx context.Context, params *UpdateCarriageParams) (*UpdateCarriageResponse, error) { + url := "/v1/carriage/pass/update" + + resp := &UpdateCarriageResponse{} + + response, err := c.client.Request(ctx, http.MethodPost, url, params, resp, nil) + if err != nil { + return nil, err + } + response.CopyCommonResponse(&resp.CommonResponse) + + return resp, nil +} + +type DeleteCarriageParams struct { + // Pass identifiers + ArrivalPassIds []int64 `json:"arrival_pass_ids"` + + // Freight identifier + CarriageId int64 `json:"carriage_id"` +} + +type DeleteCarriageResponse struct { + core.CommonResponse +} + +func (c Passes) DeleteCarriage(ctx context.Context, params *DeleteCarriageParams) (*DeleteCarriageResponse, error) { + url := "/v1/carriage/pass/delete" + + resp := &DeleteCarriageResponse{} + + response, err := c.client.Request(ctx, http.MethodPost, url, params, resp, nil) + if err != nil { + return nil, err + } + response.CopyCommonResponse(&resp.CommonResponse) + + return resp, nil +} + +type CreateReturnParams struct { + // Array of passes + ArrivalPasses []ReturnArrivalPass `json:"arrival_passes"` +} + +type ReturnArrivalPass struct { + // Date and time of arrival in UTC format. At that time, the pass will become valid + ArrivalTime time.Time `json:"arrival_time"` + + // Driver full name + DriverName string `json:"driver_name"` + + // Driver phone number + DriverPhone string `json:"driver_phone"` + + // Car license plate + VehicleLicensePlate string `json:"vehicle_license_plate"` + + // Car model + VehicleModel string `json:"vehicle_model"` + + // Drop-off point identifier for which the pass is issued + DropoffPointId int64 `json:"dropoff_point_id"` + + // Warehouse identifier + WarehouseId int64 `json:"warehouse_id"` +} + +type CreateReturnResponse struct { + core.CommonResponse + + // Pass identifiers + ArrivalPassIds []string `json:"arrival_pass_ids"` +} + +func (c Passes) CreateReturn(ctx context.Context, params *CreateReturnParams) (*CreateReturnResponse, error) { + url := "/v1/return/pass/create" + + resp := &CreateReturnResponse{} + + response, err := c.client.Request(ctx, http.MethodPost, url, params, resp, nil) + if err != nil { + return nil, err + } + response.CopyCommonResponse(&resp.CommonResponse) + + return resp, nil +} + +type UpdateReturnParams struct { + ArrivalPasses []ReturnArrivalPass `json:"arrival_passes"` +} + +type UpdateReturnResponse struct { + core.CommonResponse + + // Pass identifiers + ArrivalPassIds []string `json:"arrival_pass_ids"` +} + +func (c Passes) UpdateReturn(ctx context.Context, params *UpdateReturnParams) (*UpdateReturnResponse, error) { + url := "/v1/return/pass/update" + + resp := &UpdateReturnResponse{} + + response, err := c.client.Request(ctx, http.MethodPost, url, params, resp, nil) + if err != nil { + return nil, err + } + response.CopyCommonResponse(&resp.CommonResponse) + + return resp, nil +} + +type DeleteReturnParams struct { + // Pass identifiers + ArrivalPassIds []int64 `json:"arrival_pass_ids"` +} + +type DeleteReturnResponse struct { + core.CommonResponse +} + +func (c Passes) DeleteReturn(ctx context.Context, params *DeleteReturnParams) (*DeleteReturnResponse, error) { + url := "/v1/return/pass/delete" + + resp := &DeleteReturnResponse{} + + response, err := c.client.Request(ctx, http.MethodPost, url, params, resp, nil) + if err != nil { + return nil, err + } + response.CopyCommonResponse(&resp.CommonResponse) + + return resp, nil +} diff --git a/ozon/pass_test.go b/ozon/pass_test.go new file mode 100644 index 0000000..bc9d65e --- /dev/null +++ b/ozon/pass_test.go @@ -0,0 +1,431 @@ +package ozon + +import ( + "context" + "net/http" + "testing" + "time" + + core "github.com/diphantxm/ozon-api-client" +) + +func TestListPasses(t *testing.T) { + t.Parallel() + + tests := []struct { + statusCode int + headers map[string]string + params *ListPassesParams + response string + }{ + // Test Ok + { + http.StatusOK, + map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"}, + &ListPassesParams{ + Cursor: "", + Filter: ListPassesFilter{ + ArrivalPassIds: []string{"string"}, + ArrivalReason: "string", + DropoffPointIds: []int64{123}, + OnlyActivePasses: true, + WarehouseIds: []int64{456}, + }, + }, + `{ + "arrival_passes": [ + { + "arrival_pass_id": 0, + "arrival_reasons": [ + "string" + ], + "arrival_time": "2019-08-24T14:15:22Z", + "driver_name": "string", + "driver_phone": "string", + "dropoff_point_id": 123, + "is_active": true, + "vehicle_license_plate": "string", + "vehicle_model": "string", + "warehouse_id": 456 + } + ], + "cursor": "string" + }`, + }, + // Test No Client-Id or Api-Key + { + http.StatusUnauthorized, + map[string]string{}, + &ListPassesParams{}, + `{ + "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)) + + ctx, _ := context.WithTimeout(context.Background(), testTimeout) + resp, err := c.Passes().List(ctx, test.params) + if err != nil { + t.Error(err) + continue + } + + compareJsonResponse(t, test.response, &ListPassesResponse{}) + + if resp.StatusCode != test.statusCode { + t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode) + } + + if len(resp.ArrivalPasses) != 0 { + if resp.ArrivalPasses[0].WarehouseId != test.params.Filter.WarehouseIds[0] { + t.Errorf("warehouse id in request and response should be equal") + } + + if resp.ArrivalPasses[0].DropoffPointId != test.params.Filter.DropoffPointIds[0] { + t.Errorf("dropoff point id in request and response should be equal") + } + } + } +} + +func TestCreateArrivalPass(t *testing.T) { + t.Parallel() + + tests := []struct { + statusCode int + headers map[string]string + params *CreateCarriageParams + response string + }{ + // Test Ok + { + http.StatusOK, + map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"}, + &CreateCarriageParams{ + ArrivalPasses: []CarriageArrivalPass{ + { + DriverName: "string", + DriverPhone: "string", + VehicleLicensePlate: "string", + VehicleModel: "string", + WithReturns: true, + }, + }, + CarriageId: 14, + }, + `{ + "arrival_pass_ids": [ + "154" + ] + }`, + }, + // Test No Client-Id or Api-Key + { + http.StatusUnauthorized, + map[string]string{}, + &CreateCarriageParams{}, + `{ + "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)) + + ctx, _ := context.WithTimeout(context.Background(), testTimeout) + resp, err := c.Passes().CreateCarriage(ctx, test.params) + if err != nil { + t.Error(err) + continue + } + + compareJsonResponse(t, test.response, &CreateCarriageResponse{}) + + if resp.StatusCode != test.statusCode { + t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode) + } + } +} + +func TestUpdateArrivalPass(t *testing.T) { + t.Parallel() + + tests := []struct { + statusCode int + headers map[string]string + params *UpdateCarriageParams + response string + }{ + // Test Ok + { + http.StatusOK, + map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"}, + &UpdateCarriageParams{ + ArrivalPasses: []UpdateCarriageArrivalPass{ + { + Id: 11, + CarriageArrivalPass: CarriageArrivalPass{ + DriverName: "string", + DriverPhone: "string", + VehicleLicensePlate: "string", + VehicleModel: "string", + WithReturns: true, + }, + }, + }, + CarriageId: 14, + }, + `{}`, + }, + // Test No Client-Id or Api-Key + { + http.StatusUnauthorized, + map[string]string{}, + &UpdateCarriageParams{}, + `{ + "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)) + + ctx, _ := context.WithTimeout(context.Background(), testTimeout) + resp, err := c.Passes().UpdateCarriage(ctx, test.params) + if err != nil { + t.Error(err) + continue + } + + compareJsonResponse(t, test.response, &UpdateCarriageResponse{}) + + if resp.StatusCode != test.statusCode { + t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode) + } + } +} + +func TestDeleteArrivalPass(t *testing.T) { + t.Parallel() + + tests := []struct { + statusCode int + headers map[string]string + params *DeleteCarriageParams + response string + }{ + // Test Ok + { + http.StatusOK, + map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"}, + &DeleteCarriageParams{ + ArrivalPassIds: []int64{123}, + CarriageId: 14, + }, + `{}`, + }, + // Test No Client-Id or Api-Key + { + http.StatusUnauthorized, + map[string]string{}, + &DeleteCarriageParams{}, + `{ + "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)) + + ctx, _ := context.WithTimeout(context.Background(), testTimeout) + resp, err := c.Passes().DeleteCarriage(ctx, test.params) + if err != nil { + t.Error(err) + continue + } + + compareJsonResponse(t, test.response, &DeleteCarriageResponse{}) + + if resp.StatusCode != test.statusCode { + t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode) + } + } +} + +func TestCreateReturn(t *testing.T) { + t.Parallel() + + tests := []struct { + statusCode int + headers map[string]string + params *CreateReturnParams + response string + }{ + // Test Ok + { + http.StatusOK, + map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"}, + &CreateReturnParams{ + ArrivalPasses: []ReturnArrivalPass{ + { + ArrivalTime: time.Now(), + DriverName: "string", + DriverPhone: "string", + VehicleLicensePlate: "string", + VehicleModel: "string", + DropoffPointId: 11, + WarehouseId: 5, + }, + }, + }, + `{ + "arrival_pass_ids": [ + "1111" + ] + }`, + }, + // Test No Client-Id or Api-Key + { + http.StatusUnauthorized, + map[string]string{}, + &CreateReturnParams{}, + `{ + "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)) + + ctx, _ := context.WithTimeout(context.Background(), testTimeout) + resp, err := c.Passes().CreateReturn(ctx, test.params) + if err != nil { + t.Error(err) + continue + } + + compareJsonResponse(t, test.response, &CreateReturnResponse{}) + + if resp.StatusCode != test.statusCode { + t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode) + } + } +} + +func TestUpdateReturn(t *testing.T) { + t.Parallel() + + tests := []struct { + statusCode int + headers map[string]string + params *UpdateReturnParams + response string + }{ + // Test Ok + { + http.StatusOK, + map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"}, + &UpdateReturnParams{ + ArrivalPasses: []ReturnArrivalPass{ + { + ArrivalTime: time.Now(), + DriverName: "string", + DriverPhone: "string", + VehicleLicensePlate: "string", + VehicleModel: "string", + DropoffPointId: 11, + WarehouseId: 5, + }, + }, + }, + `{}`, + }, + // Test No Client-Id or Api-Key + { + http.StatusUnauthorized, + map[string]string{}, + &UpdateReturnParams{}, + `{ + "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)) + + ctx, _ := context.WithTimeout(context.Background(), testTimeout) + resp, err := c.Passes().UpdateReturn(ctx, test.params) + if err != nil { + t.Error(err) + continue + } + + compareJsonResponse(t, test.response, &UpdateReturnResponse{}) + + if resp.StatusCode != test.statusCode { + t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode) + } + } +} + +func TestDeleteReturn(t *testing.T) { + t.Parallel() + + tests := []struct { + statusCode int + headers map[string]string + params *DeleteReturnParams + response string + }{ + // Test Ok + { + http.StatusOK, + map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"}, + &DeleteReturnParams{ + ArrivalPassIds: []int64{456}, + }, + `{}`, + }, + // Test No Client-Id or Api-Key + { + http.StatusUnauthorized, + map[string]string{}, + &DeleteReturnParams{}, + `{ + "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)) + + ctx, _ := context.WithTimeout(context.Background(), testTimeout) + resp, err := c.Passes().DeleteReturn(ctx, test.params) + if err != nil { + t.Error(err) + continue + } + + compareJsonResponse(t, test.response, &DeleteReturnResponse{}) + + if resp.StatusCode != test.statusCode { + t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode) + } + } +} diff --git a/ozon/returns.go b/ozon/returns.go index 973aa9c..7205753 100644 --- a/ozon/returns.go +++ b/ozon/returns.go @@ -872,3 +872,82 @@ func (c Returns) GetGiveoutInfo(ctx context.Context, params *GetGiveoutInfoParam return resp, nil } + +type GetFBSQuantityReturnsParams struct { + Filter GetFBSQuantityReturnsFilter `json:"filter"` + + // Split the method response + Pagination GetFBSQuantityReturnsPagination `json:"pagination"` +} + +type GetFBSQuantityReturnsFilter struct { + // Filter by drop-off point identifier + PlaceId int64 `json:"place_id"` +} + +type GetFBSQuantityReturnsPagination struct { + // Identifier of the last drop-off point on the page. Leave this field blank in the first request. + // + // To get the next values, specify id of the last drop-off point from the response of the previous request + LastId int64 `json:"last_id"` + + // Number of drop-off points per page. Maximum is 500 + Limit int32 `json:"limit"` +} + +type GetFBSQuantityReturnsResponse struct { + core.CommonResponse + + // Seller identifier + CompanyId int64 `json:"company_id"` + + DropoffPoints []GetFBSQuantityDropoffPoint `json:"drop_off_points"` + + // true if there are any other points where sellers have orders waiting + HasNext bool `json:"has_next"` +} + +type GetFBSQuantityDropoffPoint struct { + // Drop-off point address + Address string `json:"address"` + + // Drop-off point identifier + Id int64 `json:"id"` + + // Drop-off point name + Name string `json:"name"` + + // Pass information + PassInfo GetFBSQuantityDropoffPointPassInfo `json:"pass_info"` + + // The warehouse identifier to which the shipment will arrive + PlaceId int64 `json:"place_id"` + + // Quantity of returns at the drop-off point + ReturnsCount int32 `json:"returns_count"` + + // Seller's warehouses identifiers + WarehouseIds []string `json:"warehouses_ids"` +} + +type GetFBSQuantityDropoffPointPassInfo struct { + // Quantity of drop-off point passes + Count int32 `json:"count"` + + // true if you need a pass to the drop-off point + IsRequired bool `json:"is_required"` +} + +func (c Returns) FBSQuantity(ctx context.Context, params *GetFBSQuantityReturnsParams) (*GetFBSQuantityReturnsResponse, error) { + url := "/v1/returns/company/fbs/info" + + resp := &GetFBSQuantityReturnsResponse{} + + response, err := c.client.Request(ctx, http.MethodPost, url, nil, resp, nil) + if err != nil { + return nil, err + } + response.CopyCommonResponse(&resp.CommonResponse) + + return resp, nil +} diff --git a/ozon/returns_test.go b/ozon/returns_test.go index 2db5ace..4623cbe 100644 --- a/ozon/returns_test.go +++ b/ozon/returns_test.go @@ -986,3 +986,76 @@ func TestGetGiveoutInfo(t *testing.T) { } } } + +func TestFBSQuantity(t *testing.T) { + t.Parallel() + + tests := []struct { + statusCode int + headers map[string]string + params *GetFBSQuantityReturnsParams + response string + }{ + // Test Ok + { + http.StatusOK, + map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"}, + &GetFBSQuantityReturnsParams{ + Filter: GetFBSQuantityReturnsFilter{ + PlaceId: 1, + }, + Pagination: GetFBSQuantityReturnsPagination{ + LastId: 2, + Limit: 3, + }, + }, + `{ + "company_id": 0, + "drop_off_points": [ + { + "address": "string", + "id": 0, + "name": "string", + "pass_info": { + "count": 0, + "is_required": true + }, + "place_id": 0, + "returns_count": 0, + "warehouses_ids": [ + "string" + ] + } + ], + "has_next": true + }`, + }, + // Test No Client-Id or Api-Key + { + http.StatusUnauthorized, + map[string]string{}, + &GetFBSQuantityReturnsParams{}, + `{ + "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)) + + ctx, _ := context.WithTimeout(context.Background(), testTimeout) + resp, err := c.Returns().FBSQuantity(ctx, test.params) + if err != nil { + t.Error(err) + continue + } + + compareJsonResponse(t, test.response, &GetFBSQuantityReturnsResponse{}) + + if resp.StatusCode != test.statusCode { + t.Errorf("got wrong status code: got: %d, expected: %d", resp.StatusCode, test.statusCode) + } + } +}