removed endpoint /v2/product/list update to /v3/product/list (#136)

Co-authored-by: ypoqou <benice2me11+ypoqou@gmail.com>
This commit is contained in:
benice2me11
2025-02-14 20:43:09 +03:00
committed by GitHub
parent 77c3cf5462
commit 38e8446187
2 changed files with 69 additions and 16 deletions

View File

@@ -1021,12 +1021,14 @@ func (c Products) CreateOrUpdateProduct(ctx context.Context, params *CreateOrUpd
return resp, nil return resp, nil
} }
// GetListOfProductsParams reflects the new /v3/product/list request body.
// Filter, LastId, and Limit are used the same way as in the v2 version, plus we keep
// offer_id and product_id for backward compatibility if needed.
type GetListOfProductsParams struct { type GetListOfProductsParams struct {
// Filter by product // Filter by product
Filter GetListOfProductsFilter `json:"filter"` Filter GetListOfProductsFilter `json:"filter"`
// Identifier of the last value on the page. Leave this field blank in the first request. // 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 // To get the next values, specify last_id from the response of the previous request
LastId string `json:"last_id"` LastId string `json:"last_id"`
@@ -1034,51 +1036,82 @@ type GetListOfProductsParams struct {
Limit int64 `json:"limit"` Limit int64 `json:"limit"`
} }
// GetListOfProductsFilter holds filtering options for /v3/product/list.
type GetListOfProductsFilter struct { type GetListOfProductsFilter struct {
// Filter by the offer_id parameter. You can pass a list of values in this parameter // Filter by the offer_id parameter. You can pass a list of values in this parameter
OfferId []string `json:"offer_id"` OfferId []string `json:"offer_id,omitempty"`
// Filter by the product_id parameter. You can pass a list of values in this parameter // Filter by the product_id parameter. You can pass a list of values in this parameter
ProductId []int64 `json:"product_id"` ProductId []int64 `json:"product_id,omitempty"`
// Filter by product visibility // Filter by product visibility
Visibility string `json:"visibility"` Visibility string `json:"visibility,omitempty"`
} }
// GetListOfProductsResponse describes the /v3/product/list response body.
type GetListOfProductsResponse struct { type GetListOfProductsResponse struct {
core.CommonResponse core.CommonResponse
// Result // Result object containing list of products and pagination info
Result GetListOfProductsResult `json:"result"` Result GetListOfProductsResult `json:"result"`
} }
// GetListOfProductsResult contains the products, total count, and last_id.
type GetListOfProductsResult struct { type GetListOfProductsResult struct {
// Products list // Products list
Items []GetListOfProductsResultItem `json:"items"` Items []GetListOfProductsResultItem `json:"items"`
// 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"`
// Total number of products // Total number of products
Total int32 `json:"total"` Total int32 `json:"total"`
// Identifier of the last value on the page.
// To get the next values, specify the received value in the next request in the last_id parameter
LastId string `json:"last_id"`
} }
// GetListOfProductsResultItem describes a single product item in the /v3/product/list response.
type GetListOfProductsResultItem struct { type GetListOfProductsResultItem struct {
// Product ID
ProductId int64 `json:"product_id"`
// Product identifier in the seller's system // Product identifier in the seller's system
OfferId string `json:"offer_id"` OfferId string `json:"offer_id"`
// Product ID // Flag indicating presence of FBO stocks
ProductId int64 `json:"product_id"` HasFboStocks bool `json:"has_fbo_stocks"`
// Flag indicating presence of FBS stocks
HasFbsStocks bool `json:"has_fbs_stocks"`
// Product archive status
Archived bool `json:"archived"`
// Whether the product has an active discount
IsDiscounted bool `json:"is_discounted"`
// List of quants with detailed stock information
Quants []ProductQuant `json:"quants"`
} }
// ProductQuant describes a single quant entry with warehouse, available quantity, and reserved.
type ProductQuant struct {
// Warehouse ID where the stock is located
WarehouseId int64 `json:"warehouse_id"`
// Quantity available in the warehouse
Quantity int64 `json:"quantity"`
// Quantity reserved in the warehouse
Reserved int64 `json:"reserved"`
}
// GetListOfProducts calls the new /v3/product/list endpoint.
// When using the filter by offer_id or product_id identifier, other parameters are not required. // When using the filter by offer_id or product_id identifier, other parameters are not required.
// Only one identifiers group can be used at a time, not more than 1000 products. // Only one identifiers group can be used at a time, not more than 1000 products.
// //
// If you do not use identifiers for display, specify limit and last_id in subsequent requests. // If you do not use identifiers for display, specify limit and last_id in subsequent requests.
func (c Products) GetListOfProducts(ctx context.Context, params *GetListOfProductsParams) (*GetListOfProductsResponse, error) { func (c Products) GetListOfProducts(ctx context.Context, params *GetListOfProductsParams) (*GetListOfProductsResponse, error) {
url := "/v2/product/list" url := "/v3/product/list"
resp := &GetListOfProductsResponse{} resp := &GetListOfProductsResponse{}

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"testing" "testing"
"time"
core "github.com/diphantxm/ozon-api-client" core "github.com/diphantxm/ozon-api-client"
) )
@@ -531,13 +532,15 @@ func TestCreateOrUpdateProduct(t *testing.T) {
func TestGetListOfProducts(t *testing.T) { func TestGetListOfProducts(t *testing.T) {
t.Parallel() t.Parallel()
testTimeout := 5 * time.Second
tests := []struct { tests := []struct {
statusCode int statusCode int
headers map[string]string headers map[string]string
params *GetListOfProductsParams params *GetListOfProductsParams
response string response string
}{ }{
// Test Ok // Test OK
{ {
http.StatusOK, http.StatusOK,
map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"}, map[string]string{"Client-Id": "my-client-id", "Api-Key": "my-api-key"},
@@ -555,7 +558,18 @@ func TestGetListOfProducts(t *testing.T) {
"items": [ "items": [
{ {
"product_id": 223681945, "product_id": 223681945,
"offer_id": "136748" "offer_id": "136748",
"has_fbo_stocks": false,
"has_fbs_stocks": true,
"archived": false,
"is_discounted": true,
"quants": [
{
"warehouse_id": 123,
"quantity": 50,
"reserved": 10
}
]
} }
], ],
"total": 1, "total": 1,
@@ -578,7 +592,9 @@ func TestGetListOfProducts(t *testing.T) {
for _, test := range tests { for _, test := range tests {
c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers)) c := NewMockClient(core.NewMockHttpHandler(test.statusCode, test.response, test.headers))
ctx, _ := context.WithTimeout(context.Background(), testTimeout) ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
defer cancel()
resp, err := c.Products().GetListOfProducts(ctx, test.params) resp, err := c.Products().GetListOfProducts(ctx, test.params)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -605,6 +621,10 @@ func TestGetListOfProducts(t *testing.T) {
if resp.Result.Items[0].ProductId == 0 { if resp.Result.Items[0].ProductId == 0 {
t.Errorf("Product id cannot be 0") t.Errorf("Product id cannot be 0")
} }
// Optional: check we successfully parse quants
if len(resp.Result.Items[0].Quants) == 0 {
t.Errorf("Expected some quants, got none")
}
} }
} }
} }