Add Wildberries product fetching and rate limiting functionality
This commit is contained in:
		
							
								
								
									
										6
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					FROM alpine:latest
 | 
				
			||||||
 | 
					WORKDIR /app
 | 
				
			||||||
 | 
					COPY main .
 | 
				
			||||||
 | 
					COPY ".env" .
 | 
				
			||||||
 | 
					RUN apk add gcompat
 | 
				
			||||||
 | 
					CMD ["./main"]
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
					// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
				
			||||||
// versions:
 | 
					// versions:
 | 
				
			||||||
// 	protoc-gen-go v1.36.6
 | 
					// 	protoc-gen-go v1.36.6
 | 
				
			||||||
// 	protoc        v6.31.0
 | 
					// 	protoc        v6.31.1
 | 
				
			||||||
// source: marketplace/marketplace.proto
 | 
					// source: marketplace/marketplace.proto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package marketplace
 | 
					package marketplace
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 | 
					// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 | 
				
			||||||
// versions:
 | 
					// versions:
 | 
				
			||||||
// - protoc-gen-go-grpc v1.5.1
 | 
					// - protoc-gen-go-grpc v1.5.1
 | 
				
			||||||
// - protoc             v6.31.0
 | 
					// - protoc             v6.31.1
 | 
				
			||||||
// source: marketplace/marketplace.proto
 | 
					// source: marketplace/marketplace.proto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package marketplace
 | 
					package marketplace
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
					// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
				
			||||||
// versions:
 | 
					// versions:
 | 
				
			||||||
// 	protoc-gen-go v1.36.6
 | 
					// 	protoc-gen-go v1.36.6
 | 
				
			||||||
// 	protoc        v6.31.0
 | 
					// 	protoc        v6.31.1
 | 
				
			||||||
// source: ozon/products.proto
 | 
					// source: ozon/products.proto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package products
 | 
					package products
 | 
				
			||||||
@@ -110,6 +110,94 @@ func (x *GetListOfProductsResponse) GetProducts() []*Product {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductPriceRequest struct {
 | 
				
			||||||
 | 
						state         protoimpl.MessageState `protogen:"open.v1"`
 | 
				
			||||||
 | 
						MarketplaceId int64                  `protobuf:"varint,1,opt,name=marketplace_id,json=marketplaceId,proto3" json:"marketplace_id,omitempty"`
 | 
				
			||||||
 | 
						unknownFields protoimpl.UnknownFields
 | 
				
			||||||
 | 
						sizeCache     protoimpl.SizeCache
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductPriceRequest) Reset() {
 | 
				
			||||||
 | 
						*x = GetProductPriceRequest{}
 | 
				
			||||||
 | 
						mi := &file_ozon_products_proto_msgTypes[2]
 | 
				
			||||||
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductPriceRequest) String() string {
 | 
				
			||||||
 | 
						return protoimpl.X.MessageStringOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (*GetProductPriceRequest) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductPriceRequest) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
 | 
						mi := &file_ozon_products_proto_msgTypes[2]
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
 | 
								ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ms
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mi.MessageOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: Use GetProductPriceRequest.ProtoReflect.Descriptor instead.
 | 
				
			||||||
 | 
					func (*GetProductPriceRequest) Descriptor() ([]byte, []int) {
 | 
				
			||||||
 | 
						return file_ozon_products_proto_rawDescGZIP(), []int{2}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductPriceRequest) GetMarketplaceId() int64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.MarketplaceId
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductPriceResponse struct {
 | 
				
			||||||
 | 
						state         protoimpl.MessageState `protogen:"open.v1"`
 | 
				
			||||||
 | 
						ProductPrices []*ProductPrice        `protobuf:"bytes,1,rep,name=product_prices,json=productPrices,proto3" json:"product_prices,omitempty"`
 | 
				
			||||||
 | 
						unknownFields protoimpl.UnknownFields
 | 
				
			||||||
 | 
						sizeCache     protoimpl.SizeCache
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductPriceResponse) Reset() {
 | 
				
			||||||
 | 
						*x = GetProductPriceResponse{}
 | 
				
			||||||
 | 
						mi := &file_ozon_products_proto_msgTypes[3]
 | 
				
			||||||
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductPriceResponse) String() string {
 | 
				
			||||||
 | 
						return protoimpl.X.MessageStringOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (*GetProductPriceResponse) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductPriceResponse) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
 | 
						mi := &file_ozon_products_proto_msgTypes[3]
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
 | 
								ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ms
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mi.MessageOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: Use GetProductPriceResponse.ProtoReflect.Descriptor instead.
 | 
				
			||||||
 | 
					func (*GetProductPriceResponse) Descriptor() ([]byte, []int) {
 | 
				
			||||||
 | 
						return file_ozon_products_proto_rawDescGZIP(), []int{3}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductPriceResponse) GetProductPrices() []*ProductPrice {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.ProductPrices
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Product struct {
 | 
					type Product struct {
 | 
				
			||||||
	state         protoimpl.MessageState `protogen:"open.v1"`
 | 
						state         protoimpl.MessageState `protogen:"open.v1"`
 | 
				
			||||||
	Id            int64                  `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
 | 
						Id            int64                  `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
 | 
				
			||||||
@@ -123,7 +211,7 @@ type Product struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (x *Product) Reset() {
 | 
					func (x *Product) Reset() {
 | 
				
			||||||
	*x = Product{}
 | 
						*x = Product{}
 | 
				
			||||||
	mi := &file_ozon_products_proto_msgTypes[2]
 | 
						mi := &file_ozon_products_proto_msgTypes[4]
 | 
				
			||||||
	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
	ms.StoreMessageInfo(mi)
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -135,7 +223,7 @@ func (x *Product) String() string {
 | 
				
			|||||||
func (*Product) ProtoMessage() {}
 | 
					func (*Product) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *Product) ProtoReflect() protoreflect.Message {
 | 
					func (x *Product) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
	mi := &file_ozon_products_proto_msgTypes[2]
 | 
						mi := &file_ozon_products_proto_msgTypes[4]
 | 
				
			||||||
	if x != nil {
 | 
						if x != nil {
 | 
				
			||||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
		if ms.LoadMessageInfo() == nil {
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
@@ -148,7 +236,7 @@ func (x *Product) ProtoReflect() protoreflect.Message {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Deprecated: Use Product.ProtoReflect.Descriptor instead.
 | 
					// Deprecated: Use Product.ProtoReflect.Descriptor instead.
 | 
				
			||||||
func (*Product) Descriptor() ([]byte, []int) {
 | 
					func (*Product) Descriptor() ([]byte, []int) {
 | 
				
			||||||
	return file_ozon_products_proto_rawDescGZIP(), []int{2}
 | 
						return file_ozon_products_proto_rawDescGZIP(), []int{4}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *Product) GetId() int64 {
 | 
					func (x *Product) GetId() int64 {
 | 
				
			||||||
@@ -186,6 +274,74 @@ func (x *Product) GetStatuses() *Product_Status {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ProductPrice struct {
 | 
				
			||||||
 | 
						state         protoimpl.MessageState    `protogen:"open.v1"`
 | 
				
			||||||
 | 
						Acquiring     uint32                    `protobuf:"varint,1,opt,name=acquiring,proto3" json:"acquiring,omitempty"`
 | 
				
			||||||
 | 
						Commissions   *ProductPrice_Commissions `protobuf:"bytes,2,opt,name=commissions,proto3" json:"commissions,omitempty"`
 | 
				
			||||||
 | 
						OfferId       string                    `protobuf:"bytes,4,opt,name=offer_id,json=offerId,proto3" json:"offer_id,omitempty"`
 | 
				
			||||||
 | 
						ProductId     uint32                    `protobuf:"varint,7,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"`
 | 
				
			||||||
 | 
						unknownFields protoimpl.UnknownFields
 | 
				
			||||||
 | 
						sizeCache     protoimpl.SizeCache
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice) Reset() {
 | 
				
			||||||
 | 
						*x = ProductPrice{}
 | 
				
			||||||
 | 
						mi := &file_ozon_products_proto_msgTypes[5]
 | 
				
			||||||
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice) String() string {
 | 
				
			||||||
 | 
						return protoimpl.X.MessageStringOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (*ProductPrice) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
 | 
						mi := &file_ozon_products_proto_msgTypes[5]
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
 | 
								ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ms
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mi.MessageOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: Use ProductPrice.ProtoReflect.Descriptor instead.
 | 
				
			||||||
 | 
					func (*ProductPrice) Descriptor() ([]byte, []int) {
 | 
				
			||||||
 | 
						return file_ozon_products_proto_rawDescGZIP(), []int{5}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice) GetAcquiring() uint32 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.Acquiring
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice) GetCommissions() *ProductPrice_Commissions {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.Commissions
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice) GetOfferId() string {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.OfferId
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice) GetProductId() uint32 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.ProductId
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Product_Status struct {
 | 
					type Product_Status struct {
 | 
				
			||||||
	state         protoimpl.MessageState `protogen:"open.v1"`
 | 
						state         protoimpl.MessageState `protogen:"open.v1"`
 | 
				
			||||||
	StatusName    string                 `protobuf:"bytes,1,opt,name=status_name,json=statusName,proto3" json:"status_name,omitempty"`
 | 
						StatusName    string                 `protobuf:"bytes,1,opt,name=status_name,json=statusName,proto3" json:"status_name,omitempty"`
 | 
				
			||||||
@@ -195,7 +351,7 @@ type Product_Status struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (x *Product_Status) Reset() {
 | 
					func (x *Product_Status) Reset() {
 | 
				
			||||||
	*x = Product_Status{}
 | 
						*x = Product_Status{}
 | 
				
			||||||
	mi := &file_ozon_products_proto_msgTypes[3]
 | 
						mi := &file_ozon_products_proto_msgTypes[6]
 | 
				
			||||||
	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
	ms.StoreMessageInfo(mi)
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -207,7 +363,7 @@ func (x *Product_Status) String() string {
 | 
				
			|||||||
func (*Product_Status) ProtoMessage() {}
 | 
					func (*Product_Status) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *Product_Status) ProtoReflect() protoreflect.Message {
 | 
					func (x *Product_Status) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
	mi := &file_ozon_products_proto_msgTypes[3]
 | 
						mi := &file_ozon_products_proto_msgTypes[6]
 | 
				
			||||||
	if x != nil {
 | 
						if x != nil {
 | 
				
			||||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
		if ms.LoadMessageInfo() == nil {
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
@@ -220,7 +376,7 @@ func (x *Product_Status) ProtoReflect() protoreflect.Message {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Deprecated: Use Product_Status.ProtoReflect.Descriptor instead.
 | 
					// Deprecated: Use Product_Status.ProtoReflect.Descriptor instead.
 | 
				
			||||||
func (*Product_Status) Descriptor() ([]byte, []int) {
 | 
					func (*Product_Status) Descriptor() ([]byte, []int) {
 | 
				
			||||||
	return file_ozon_products_proto_rawDescGZIP(), []int{2, 0}
 | 
						return file_ozon_products_proto_rawDescGZIP(), []int{4, 0}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *Product_Status) GetStatusName() string {
 | 
					func (x *Product_Status) GetStatusName() string {
 | 
				
			||||||
@@ -240,7 +396,7 @@ type Product_Stocks struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (x *Product_Stocks) Reset() {
 | 
					func (x *Product_Stocks) Reset() {
 | 
				
			||||||
	*x = Product_Stocks{}
 | 
						*x = Product_Stocks{}
 | 
				
			||||||
	mi := &file_ozon_products_proto_msgTypes[4]
 | 
						mi := &file_ozon_products_proto_msgTypes[7]
 | 
				
			||||||
	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
	ms.StoreMessageInfo(mi)
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -252,7 +408,7 @@ func (x *Product_Stocks) String() string {
 | 
				
			|||||||
func (*Product_Stocks) ProtoMessage() {}
 | 
					func (*Product_Stocks) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *Product_Stocks) ProtoReflect() protoreflect.Message {
 | 
					func (x *Product_Stocks) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
	mi := &file_ozon_products_proto_msgTypes[4]
 | 
						mi := &file_ozon_products_proto_msgTypes[7]
 | 
				
			||||||
	if x != nil {
 | 
						if x != nil {
 | 
				
			||||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
		if ms.LoadMessageInfo() == nil {
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
@@ -265,7 +421,7 @@ func (x *Product_Stocks) ProtoReflect() protoreflect.Message {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Deprecated: Use Product_Stocks.ProtoReflect.Descriptor instead.
 | 
					// Deprecated: Use Product_Stocks.ProtoReflect.Descriptor instead.
 | 
				
			||||||
func (*Product_Stocks) Descriptor() ([]byte, []int) {
 | 
					func (*Product_Stocks) Descriptor() ([]byte, []int) {
 | 
				
			||||||
	return file_ozon_products_proto_rawDescGZIP(), []int{2, 1}
 | 
						return file_ozon_products_proto_rawDescGZIP(), []int{4, 1}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *Product_Stocks) GetStocks() []*Product_Stock {
 | 
					func (x *Product_Stocks) GetStocks() []*Product_Stock {
 | 
				
			||||||
@@ -294,7 +450,7 @@ type Product_Stock struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (x *Product_Stock) Reset() {
 | 
					func (x *Product_Stock) Reset() {
 | 
				
			||||||
	*x = Product_Stock{}
 | 
						*x = Product_Stock{}
 | 
				
			||||||
	mi := &file_ozon_products_proto_msgTypes[5]
 | 
						mi := &file_ozon_products_proto_msgTypes[8]
 | 
				
			||||||
	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
	ms.StoreMessageInfo(mi)
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -306,7 +462,7 @@ func (x *Product_Stock) String() string {
 | 
				
			|||||||
func (*Product_Stock) ProtoMessage() {}
 | 
					func (*Product_Stock) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *Product_Stock) ProtoReflect() protoreflect.Message {
 | 
					func (x *Product_Stock) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
	mi := &file_ozon_products_proto_msgTypes[5]
 | 
						mi := &file_ozon_products_proto_msgTypes[8]
 | 
				
			||||||
	if x != nil {
 | 
						if x != nil {
 | 
				
			||||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
		if ms.LoadMessageInfo() == nil {
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
@@ -319,7 +475,7 @@ func (x *Product_Stock) ProtoReflect() protoreflect.Message {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Deprecated: Use Product_Stock.ProtoReflect.Descriptor instead.
 | 
					// Deprecated: Use Product_Stock.ProtoReflect.Descriptor instead.
 | 
				
			||||||
func (*Product_Stock) Descriptor() ([]byte, []int) {
 | 
					func (*Product_Stock) Descriptor() ([]byte, []int) {
 | 
				
			||||||
	return file_ozon_products_proto_rawDescGZIP(), []int{2, 2}
 | 
						return file_ozon_products_proto_rawDescGZIP(), []int{4, 2}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *Product_Stock) GetPresent() int64 {
 | 
					func (x *Product_Stock) GetPresent() int64 {
 | 
				
			||||||
@@ -350,6 +506,138 @@ func (x *Product_Stock) GetSource() string {
 | 
				
			|||||||
	return ""
 | 
						return ""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ProductPrice_Commissions struct {
 | 
				
			||||||
 | 
						state                       protoimpl.MessageState `protogen:"open.v1"`
 | 
				
			||||||
 | 
						FboDelivToCustomerAmount    float64                `protobuf:"fixed64,1,opt,name=fbo_deliv_to_customer_amount,json=fboDelivToCustomerAmount,proto3" json:"fbo_deliv_to_customer_amount,omitempty"`
 | 
				
			||||||
 | 
						FboDirectFlowTransMaxAmount float64                `protobuf:"fixed64,2,opt,name=fbo_direct_flow_trans_max_amount,json=fboDirectFlowTransMaxAmount,proto3" json:"fbo_direct_flow_trans_max_amount,omitempty"`
 | 
				
			||||||
 | 
						FboDirectFlowTransMinAmount float64                `protobuf:"fixed64,3,opt,name=fbo_direct_flow_trans_min_amount,json=fboDirectFlowTransMinAmount,proto3" json:"fbo_direct_flow_trans_min_amount,omitempty"`
 | 
				
			||||||
 | 
						FboReturnFlowAmount         float64                `protobuf:"fixed64,4,opt,name=fbo_return_flow_amount,json=fboReturnFlowAmount,proto3" json:"fbo_return_flow_amount,omitempty"`
 | 
				
			||||||
 | 
						FbsDelivToCustomerAmount    float64                `protobuf:"fixed64,5,opt,name=fbs_deliv_to_customer_amount,json=fbsDelivToCustomerAmount,proto3" json:"fbs_deliv_to_customer_amount,omitempty"`
 | 
				
			||||||
 | 
						FbsDirectFlowTransMaxAmount float64                `protobuf:"fixed64,6,opt,name=fbs_direct_flow_trans_max_amount,json=fbsDirectFlowTransMaxAmount,proto3" json:"fbs_direct_flow_trans_max_amount,omitempty"`
 | 
				
			||||||
 | 
						FbsDirectFlowTransMinAmount float64                `protobuf:"fixed64,7,opt,name=fbs_direct_flow_trans_min_amount,json=fbsDirectFlowTransMinAmount,proto3" json:"fbs_direct_flow_trans_min_amount,omitempty"`
 | 
				
			||||||
 | 
						FbsFirstMileMaxAmount       float64                `protobuf:"fixed64,8,opt,name=fbs_first_mile_max_amount,json=fbsFirstMileMaxAmount,proto3" json:"fbs_first_mile_max_amount,omitempty"`
 | 
				
			||||||
 | 
						FbsFirstMileMinAmount       float64                `protobuf:"fixed64,9,opt,name=fbs_first_mile_min_amount,json=fbsFirstMileMinAmount,proto3" json:"fbs_first_mile_min_amount,omitempty"`
 | 
				
			||||||
 | 
						FbsReturnFlowAmount         float64                `protobuf:"fixed64,10,opt,name=fbs_return_flow_amount,json=fbsReturnFlowAmount,proto3" json:"fbs_return_flow_amount,omitempty"`
 | 
				
			||||||
 | 
						SalesPercentFbo             float64                `protobuf:"fixed64,11,opt,name=sales_percent_fbo,json=salesPercentFbo,proto3" json:"sales_percent_fbo,omitempty"`
 | 
				
			||||||
 | 
						SalesPercentFbs             float64                `protobuf:"fixed64,12,opt,name=sales_percent_fbs,json=salesPercentFbs,proto3" json:"sales_percent_fbs,omitempty"`
 | 
				
			||||||
 | 
						unknownFields               protoimpl.UnknownFields
 | 
				
			||||||
 | 
						sizeCache                   protoimpl.SizeCache
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) Reset() {
 | 
				
			||||||
 | 
						*x = ProductPrice_Commissions{}
 | 
				
			||||||
 | 
						mi := &file_ozon_products_proto_msgTypes[9]
 | 
				
			||||||
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) String() string {
 | 
				
			||||||
 | 
						return protoimpl.X.MessageStringOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (*ProductPrice_Commissions) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
 | 
						mi := &file_ozon_products_proto_msgTypes[9]
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
 | 
								ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ms
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mi.MessageOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: Use ProductPrice_Commissions.ProtoReflect.Descriptor instead.
 | 
				
			||||||
 | 
					func (*ProductPrice_Commissions) Descriptor() ([]byte, []int) {
 | 
				
			||||||
 | 
						return file_ozon_products_proto_rawDescGZIP(), []int{5, 0}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetFboDelivToCustomerAmount() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.FboDelivToCustomerAmount
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetFboDirectFlowTransMaxAmount() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.FboDirectFlowTransMaxAmount
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetFboDirectFlowTransMinAmount() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.FboDirectFlowTransMinAmount
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetFboReturnFlowAmount() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.FboReturnFlowAmount
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetFbsDelivToCustomerAmount() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.FbsDelivToCustomerAmount
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetFbsDirectFlowTransMaxAmount() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.FbsDirectFlowTransMaxAmount
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetFbsDirectFlowTransMinAmount() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.FbsDirectFlowTransMinAmount
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetFbsFirstMileMaxAmount() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.FbsFirstMileMaxAmount
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetFbsFirstMileMinAmount() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.FbsFirstMileMinAmount
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetFbsReturnFlowAmount() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.FbsReturnFlowAmount
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetSalesPercentFbo() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.SalesPercentFbo
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *ProductPrice_Commissions) GetSalesPercentFbs() float64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.SalesPercentFbs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var File_ozon_products_proto protoreflect.FileDescriptor
 | 
					var File_ozon_products_proto protoreflect.FileDescriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const file_ozon_products_proto_rawDesc = "" +
 | 
					const file_ozon_products_proto_rawDesc = "" +
 | 
				
			||||||
@@ -358,7 +646,11 @@ const file_ozon_products_proto_rawDesc = "" +
 | 
				
			|||||||
	"\x18GetListOfProductsRequest\x12%\n" +
 | 
						"\x18GetListOfProductsRequest\x12%\n" +
 | 
				
			||||||
	"\x0emarketplace_id\x18\x01 \x01(\x03R\rmarketplaceId\"O\n" +
 | 
						"\x0emarketplace_id\x18\x01 \x01(\x03R\rmarketplaceId\"O\n" +
 | 
				
			||||||
	"\x19GetListOfProductsResponse\x122\n" +
 | 
						"\x19GetListOfProductsResponse\x122\n" +
 | 
				
			||||||
	"\bproducts\x18\x01 \x03(\v2\x16.ozon.products.ProductR\bproducts\"\xb3\x03\n" +
 | 
						"\bproducts\x18\x01 \x03(\v2\x16.ozon.products.ProductR\bproducts\"?\n" +
 | 
				
			||||||
 | 
						"\x16GetProductPriceRequest\x12%\n" +
 | 
				
			||||||
 | 
						"\x0emarketplace_id\x18\x01 \x01(\x03R\rmarketplaceId\"]\n" +
 | 
				
			||||||
 | 
						"\x17GetProductPriceResponse\x12B\n" +
 | 
				
			||||||
 | 
						"\x0eproduct_prices\x18\x01 \x03(\v2\x1b.ozon.products.ProductPriceR\rproductPrices\"\xb3\x03\n" +
 | 
				
			||||||
	"\aProduct\x12\x0e\n" +
 | 
						"\aProduct\x12\x0e\n" +
 | 
				
			||||||
	"\x02id\x18\x01 \x01(\x03R\x02id\x12\x19\n" +
 | 
						"\x02id\x18\x01 \x01(\x03R\x02id\x12\x19\n" +
 | 
				
			||||||
	"\boffer_id\x18\x02 \x01(\tR\aofferId\x125\n" +
 | 
						"\boffer_id\x18\x02 \x01(\tR\aofferId\x125\n" +
 | 
				
			||||||
@@ -375,9 +667,30 @@ const file_ozon_products_proto_rawDesc = "" +
 | 
				
			|||||||
	"\apresent\x18\x01 \x01(\x03R\apresent\x12\x1a\n" +
 | 
						"\apresent\x18\x01 \x01(\x03R\apresent\x12\x1a\n" +
 | 
				
			||||||
	"\breserved\x18\x02 \x01(\x03R\breserved\x12\x10\n" +
 | 
						"\breserved\x18\x02 \x01(\x03R\breserved\x12\x10\n" +
 | 
				
			||||||
	"\x03SKU\x18\x03 \x01(\x03R\x03SKU\x12\x16\n" +
 | 
						"\x03SKU\x18\x03 \x01(\x03R\x03SKU\x12\x16\n" +
 | 
				
			||||||
	"\x06source\x18\x04 \x01(\tR\x06source2{\n" +
 | 
						"\x06source\x18\x04 \x01(\tR\x06source\"\x93\a\n" +
 | 
				
			||||||
 | 
						"\fProductPrice\x12\x1c\n" +
 | 
				
			||||||
 | 
						"\tacquiring\x18\x01 \x01(\rR\tacquiring\x12I\n" +
 | 
				
			||||||
 | 
						"\vcommissions\x18\x02 \x01(\v2'.ozon.products.ProductPrice.CommissionsR\vcommissions\x12\x19\n" +
 | 
				
			||||||
 | 
						"\boffer_id\x18\x04 \x01(\tR\aofferId\x12\x1d\n" +
 | 
				
			||||||
 | 
						"\n" +
 | 
				
			||||||
 | 
						"product_id\x18\a \x01(\rR\tproductId\x1a\xdf\x05\n" +
 | 
				
			||||||
 | 
						"\vCommissions\x12>\n" +
 | 
				
			||||||
 | 
						"\x1cfbo_deliv_to_customer_amount\x18\x01 \x01(\x01R\x18fboDelivToCustomerAmount\x12E\n" +
 | 
				
			||||||
 | 
						" fbo_direct_flow_trans_max_amount\x18\x02 \x01(\x01R\x1bfboDirectFlowTransMaxAmount\x12E\n" +
 | 
				
			||||||
 | 
						" fbo_direct_flow_trans_min_amount\x18\x03 \x01(\x01R\x1bfboDirectFlowTransMinAmount\x123\n" +
 | 
				
			||||||
 | 
						"\x16fbo_return_flow_amount\x18\x04 \x01(\x01R\x13fboReturnFlowAmount\x12>\n" +
 | 
				
			||||||
 | 
						"\x1cfbs_deliv_to_customer_amount\x18\x05 \x01(\x01R\x18fbsDelivToCustomerAmount\x12E\n" +
 | 
				
			||||||
 | 
						" fbs_direct_flow_trans_max_amount\x18\x06 \x01(\x01R\x1bfbsDirectFlowTransMaxAmount\x12E\n" +
 | 
				
			||||||
 | 
						" fbs_direct_flow_trans_min_amount\x18\a \x01(\x01R\x1bfbsDirectFlowTransMinAmount\x128\n" +
 | 
				
			||||||
 | 
						"\x19fbs_first_mile_max_amount\x18\b \x01(\x01R\x15fbsFirstMileMaxAmount\x128\n" +
 | 
				
			||||||
 | 
						"\x19fbs_first_mile_min_amount\x18\t \x01(\x01R\x15fbsFirstMileMinAmount\x123\n" +
 | 
				
			||||||
 | 
						"\x16fbs_return_flow_amount\x18\n" +
 | 
				
			||||||
 | 
						" \x01(\x01R\x13fbsReturnFlowAmount\x12*\n" +
 | 
				
			||||||
 | 
						"\x11sales_percent_fbo\x18\v \x01(\x01R\x0fsalesPercentFbo\x12*\n" +
 | 
				
			||||||
 | 
						"\x11sales_percent_fbs\x18\f \x01(\x01R\x0fsalesPercentFbs2\xdf\x01\n" +
 | 
				
			||||||
	"\x0fProductsService\x12h\n" +
 | 
						"\x0fProductsService\x12h\n" +
 | 
				
			||||||
	"\x11GetListOfProducts\x12'.ozon.products.GetListOfProductsRequest\x1a(.ozon.products.GetListOfProductsResponse0\x01B\x11Z\x0f./ozon/productsb\x06proto3"
 | 
						"\x11GetListOfProducts\x12'.ozon.products.GetListOfProductsRequest\x1a(.ozon.products.GetListOfProductsResponse0\x01\x12b\n" +
 | 
				
			||||||
 | 
						"\x0fGetProductPrice\x12%.ozon.products.GetProductPriceRequest\x1a&.ozon.products.GetProductPriceResponse0\x01B\x11Z\x0f./ozon/productsb\x06proto3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	file_ozon_products_proto_rawDescOnce sync.Once
 | 
						file_ozon_products_proto_rawDescOnce sync.Once
 | 
				
			||||||
@@ -391,27 +704,35 @@ func file_ozon_products_proto_rawDescGZIP() []byte {
 | 
				
			|||||||
	return file_ozon_products_proto_rawDescData
 | 
						return file_ozon_products_proto_rawDescData
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var file_ozon_products_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
 | 
					var file_ozon_products_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
 | 
				
			||||||
var file_ozon_products_proto_goTypes = []any{
 | 
					var file_ozon_products_proto_goTypes = []any{
 | 
				
			||||||
	(*GetListOfProductsRequest)(nil),  // 0: ozon.products.GetListOfProductsRequest
 | 
						(*GetListOfProductsRequest)(nil),  // 0: ozon.products.GetListOfProductsRequest
 | 
				
			||||||
	(*GetListOfProductsResponse)(nil), // 1: ozon.products.GetListOfProductsResponse
 | 
						(*GetListOfProductsResponse)(nil), // 1: ozon.products.GetListOfProductsResponse
 | 
				
			||||||
	(*Product)(nil),                   // 2: ozon.products.Product
 | 
						(*GetProductPriceRequest)(nil),    // 2: ozon.products.GetProductPriceRequest
 | 
				
			||||||
	(*Product_Status)(nil),            // 3: ozon.products.Product.Status
 | 
						(*GetProductPriceResponse)(nil),   // 3: ozon.products.GetProductPriceResponse
 | 
				
			||||||
	(*Product_Stocks)(nil),            // 4: ozon.products.Product.Stocks
 | 
						(*Product)(nil),                   // 4: ozon.products.Product
 | 
				
			||||||
	(*Product_Stock)(nil),             // 5: ozon.products.Product.Stock
 | 
						(*ProductPrice)(nil),              // 5: ozon.products.ProductPrice
 | 
				
			||||||
 | 
						(*Product_Status)(nil),            // 6: ozon.products.Product.Status
 | 
				
			||||||
 | 
						(*Product_Stocks)(nil),            // 7: ozon.products.Product.Stocks
 | 
				
			||||||
 | 
						(*Product_Stock)(nil),             // 8: ozon.products.Product.Stock
 | 
				
			||||||
 | 
						(*ProductPrice_Commissions)(nil),  // 9: ozon.products.ProductPrice.Commissions
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
var file_ozon_products_proto_depIdxs = []int32{
 | 
					var file_ozon_products_proto_depIdxs = []int32{
 | 
				
			||||||
	2, // 0: ozon.products.GetListOfProductsResponse.products:type_name -> ozon.products.Product
 | 
						4, // 0: ozon.products.GetListOfProductsResponse.products:type_name -> ozon.products.Product
 | 
				
			||||||
	4, // 1: ozon.products.Product.stocks:type_name -> ozon.products.Product.Stocks
 | 
						5, // 1: ozon.products.GetProductPriceResponse.product_prices:type_name -> ozon.products.ProductPrice
 | 
				
			||||||
	3, // 2: ozon.products.Product.statuses:type_name -> ozon.products.Product.Status
 | 
						7, // 2: ozon.products.Product.stocks:type_name -> ozon.products.Product.Stocks
 | 
				
			||||||
	5, // 3: ozon.products.Product.Stocks.stocks:type_name -> ozon.products.Product.Stock
 | 
						6, // 3: ozon.products.Product.statuses:type_name -> ozon.products.Product.Status
 | 
				
			||||||
	0, // 4: ozon.products.ProductsService.GetListOfProducts:input_type -> ozon.products.GetListOfProductsRequest
 | 
						9, // 4: ozon.products.ProductPrice.commissions:type_name -> ozon.products.ProductPrice.Commissions
 | 
				
			||||||
	1, // 5: ozon.products.ProductsService.GetListOfProducts:output_type -> ozon.products.GetListOfProductsResponse
 | 
						8, // 5: ozon.products.Product.Stocks.stocks:type_name -> ozon.products.Product.Stock
 | 
				
			||||||
	5, // [5:6] is the sub-list for method output_type
 | 
						0, // 6: ozon.products.ProductsService.GetListOfProducts:input_type -> ozon.products.GetListOfProductsRequest
 | 
				
			||||||
	4, // [4:5] is the sub-list for method input_type
 | 
						2, // 7: ozon.products.ProductsService.GetProductPrice:input_type -> ozon.products.GetProductPriceRequest
 | 
				
			||||||
	4, // [4:4] is the sub-list for extension type_name
 | 
						1, // 8: ozon.products.ProductsService.GetListOfProducts:output_type -> ozon.products.GetListOfProductsResponse
 | 
				
			||||||
	4, // [4:4] is the sub-list for extension extendee
 | 
						3, // 9: ozon.products.ProductsService.GetProductPrice:output_type -> ozon.products.GetProductPriceResponse
 | 
				
			||||||
	0, // [0:4] is the sub-list for field type_name
 | 
						8, // [8:10] is the sub-list for method output_type
 | 
				
			||||||
 | 
						6, // [6:8] is the sub-list for method input_type
 | 
				
			||||||
 | 
						6, // [6:6] is the sub-list for extension type_name
 | 
				
			||||||
 | 
						6, // [6:6] is the sub-list for extension extendee
 | 
				
			||||||
 | 
						0, // [0:6] is the sub-list for field type_name
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() { file_ozon_products_proto_init() }
 | 
					func init() { file_ozon_products_proto_init() }
 | 
				
			||||||
@@ -425,7 +746,7 @@ func file_ozon_products_proto_init() {
 | 
				
			|||||||
			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 | 
								GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 | 
				
			||||||
			RawDescriptor: unsafe.Slice(unsafe.StringData(file_ozon_products_proto_rawDesc), len(file_ozon_products_proto_rawDesc)),
 | 
								RawDescriptor: unsafe.Slice(unsafe.StringData(file_ozon_products_proto_rawDesc), len(file_ozon_products_proto_rawDesc)),
 | 
				
			||||||
			NumEnums:      0,
 | 
								NumEnums:      0,
 | 
				
			||||||
			NumMessages:   6,
 | 
								NumMessages:   10,
 | 
				
			||||||
			NumExtensions: 0,
 | 
								NumExtensions: 0,
 | 
				
			||||||
			NumServices:   1,
 | 
								NumServices:   1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 | 
					// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 | 
				
			||||||
// versions:
 | 
					// versions:
 | 
				
			||||||
// - protoc-gen-go-grpc v1.5.1
 | 
					// - protoc-gen-go-grpc v1.5.1
 | 
				
			||||||
// - protoc             v6.31.0
 | 
					// - protoc             v6.31.1
 | 
				
			||||||
// source: ozon/products.proto
 | 
					// source: ozon/products.proto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package products
 | 
					package products
 | 
				
			||||||
@@ -20,6 +20,7 @@ const _ = grpc.SupportPackageIsVersion9
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	ProductsService_GetListOfProducts_FullMethodName = "/ozon.products.ProductsService/GetListOfProducts"
 | 
						ProductsService_GetListOfProducts_FullMethodName = "/ozon.products.ProductsService/GetListOfProducts"
 | 
				
			||||||
 | 
						ProductsService_GetProductPrice_FullMethodName   = "/ozon.products.ProductsService/GetProductPrice"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ProductsServiceClient is the client API for ProductsService service.
 | 
					// ProductsServiceClient is the client API for ProductsService service.
 | 
				
			||||||
@@ -28,6 +29,7 @@ const (
 | 
				
			|||||||
type ProductsServiceClient interface {
 | 
					type ProductsServiceClient interface {
 | 
				
			||||||
	// Retrieves a list of products based on the provided request.
 | 
						// Retrieves a list of products based on the provided request.
 | 
				
			||||||
	GetListOfProducts(ctx context.Context, in *GetListOfProductsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetListOfProductsResponse], error)
 | 
						GetListOfProducts(ctx context.Context, in *GetListOfProductsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetListOfProductsResponse], error)
 | 
				
			||||||
 | 
						GetProductPrice(ctx context.Context, in *GetProductPriceRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetProductPriceResponse], error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type productsServiceClient struct {
 | 
					type productsServiceClient struct {
 | 
				
			||||||
@@ -57,12 +59,32 @@ func (c *productsServiceClient) GetListOfProducts(ctx context.Context, in *GetLi
 | 
				
			|||||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
 | 
					// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
 | 
				
			||||||
type ProductsService_GetListOfProductsClient = grpc.ServerStreamingClient[GetListOfProductsResponse]
 | 
					type ProductsService_GetListOfProductsClient = grpc.ServerStreamingClient[GetListOfProductsResponse]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *productsServiceClient) GetProductPrice(ctx context.Context, in *GetProductPriceRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetProductPriceResponse], error) {
 | 
				
			||||||
 | 
						cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
 | 
				
			||||||
 | 
						stream, err := c.cc.NewStream(ctx, &ProductsService_ServiceDesc.Streams[1], ProductsService_GetProductPrice_FullMethodName, cOpts...)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						x := &grpc.GenericClientStream[GetProductPriceRequest, GetProductPriceResponse]{ClientStream: stream}
 | 
				
			||||||
 | 
						if err := x.ClientStream.SendMsg(in); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := x.ClientStream.CloseSend(); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return x, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
 | 
				
			||||||
 | 
					type ProductsService_GetProductPriceClient = grpc.ServerStreamingClient[GetProductPriceResponse]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ProductsServiceServer is the server API for ProductsService service.
 | 
					// ProductsServiceServer is the server API for ProductsService service.
 | 
				
			||||||
// All implementations must embed UnimplementedProductsServiceServer
 | 
					// All implementations must embed UnimplementedProductsServiceServer
 | 
				
			||||||
// for forward compatibility.
 | 
					// for forward compatibility.
 | 
				
			||||||
type ProductsServiceServer interface {
 | 
					type ProductsServiceServer interface {
 | 
				
			||||||
	// Retrieves a list of products based on the provided request.
 | 
						// Retrieves a list of products based on the provided request.
 | 
				
			||||||
	GetListOfProducts(*GetListOfProductsRequest, grpc.ServerStreamingServer[GetListOfProductsResponse]) error
 | 
						GetListOfProducts(*GetListOfProductsRequest, grpc.ServerStreamingServer[GetListOfProductsResponse]) error
 | 
				
			||||||
 | 
						GetProductPrice(*GetProductPriceRequest, grpc.ServerStreamingServer[GetProductPriceResponse]) error
 | 
				
			||||||
	mustEmbedUnimplementedProductsServiceServer()
 | 
						mustEmbedUnimplementedProductsServiceServer()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -76,6 +98,9 @@ type UnimplementedProductsServiceServer struct{}
 | 
				
			|||||||
func (UnimplementedProductsServiceServer) GetListOfProducts(*GetListOfProductsRequest, grpc.ServerStreamingServer[GetListOfProductsResponse]) error {
 | 
					func (UnimplementedProductsServiceServer) GetListOfProducts(*GetListOfProductsRequest, grpc.ServerStreamingServer[GetListOfProductsResponse]) error {
 | 
				
			||||||
	return status.Errorf(codes.Unimplemented, "method GetListOfProducts not implemented")
 | 
						return status.Errorf(codes.Unimplemented, "method GetListOfProducts not implemented")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					func (UnimplementedProductsServiceServer) GetProductPrice(*GetProductPriceRequest, grpc.ServerStreamingServer[GetProductPriceResponse]) error {
 | 
				
			||||||
 | 
						return status.Errorf(codes.Unimplemented, "method GetProductPrice not implemented")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
func (UnimplementedProductsServiceServer) mustEmbedUnimplementedProductsServiceServer() {}
 | 
					func (UnimplementedProductsServiceServer) mustEmbedUnimplementedProductsServiceServer() {}
 | 
				
			||||||
func (UnimplementedProductsServiceServer) testEmbeddedByValue()                         {}
 | 
					func (UnimplementedProductsServiceServer) testEmbeddedByValue()                         {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -108,6 +133,17 @@ func _ProductsService_GetListOfProducts_Handler(srv interface{}, stream grpc.Ser
 | 
				
			|||||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
 | 
					// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
 | 
				
			||||||
type ProductsService_GetListOfProductsServer = grpc.ServerStreamingServer[GetListOfProductsResponse]
 | 
					type ProductsService_GetListOfProductsServer = grpc.ServerStreamingServer[GetListOfProductsResponse]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func _ProductsService_GetProductPrice_Handler(srv interface{}, stream grpc.ServerStream) error {
 | 
				
			||||||
 | 
						m := new(GetProductPriceRequest)
 | 
				
			||||||
 | 
						if err := stream.RecvMsg(m); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return srv.(ProductsServiceServer).GetProductPrice(m, &grpc.GenericServerStream[GetProductPriceRequest, GetProductPriceResponse]{ServerStream: stream})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
 | 
				
			||||||
 | 
					type ProductsService_GetProductPriceServer = grpc.ServerStreamingServer[GetProductPriceResponse]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ProductsService_ServiceDesc is the grpc.ServiceDesc for ProductsService service.
 | 
					// ProductsService_ServiceDesc is the grpc.ServiceDesc for ProductsService service.
 | 
				
			||||||
// It's only intended for direct use with grpc.RegisterService,
 | 
					// It's only intended for direct use with grpc.RegisterService,
 | 
				
			||||||
// and not to be introspected or modified (even as a copy)
 | 
					// and not to be introspected or modified (even as a copy)
 | 
				
			||||||
@@ -121,6 +157,11 @@ var ProductsService_ServiceDesc = grpc.ServiceDesc{
 | 
				
			|||||||
			Handler:       _ProductsService_GetListOfProducts_Handler,
 | 
								Handler:       _ProductsService_GetListOfProducts_Handler,
 | 
				
			||||||
			ServerStreams: true,
 | 
								ServerStreams: true,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								StreamName:    "GetProductPrice",
 | 
				
			||||||
 | 
								Handler:       _ProductsService_GetProductPrice_Handler,
 | 
				
			||||||
 | 
								ServerStreams: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	Metadata: "ozon/products.proto",
 | 
						Metadata: "ozon/products.proto",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
					// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
				
			||||||
// versions:
 | 
					// versions:
 | 
				
			||||||
// 	protoc-gen-go v1.36.6
 | 
					// 	protoc-gen-go v1.36.6
 | 
				
			||||||
// 	protoc        v6.31.0
 | 
					// 	protoc        v6.31.1
 | 
				
			||||||
// source: wb/products.proto
 | 
					// source: wb/products.proto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package products
 | 
					package products
 | 
				
			||||||
@@ -10,6 +10,7 @@ import (
 | 
				
			|||||||
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 | 
						protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 | 
				
			||||||
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 | 
						protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 | 
				
			||||||
	reflect "reflect"
 | 
						reflect "reflect"
 | 
				
			||||||
 | 
						sync "sync"
 | 
				
			||||||
	unsafe "unsafe"
 | 
						unsafe "unsafe"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,20 +21,255 @@ const (
 | 
				
			|||||||
	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 | 
						_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductsRequest struct {
 | 
				
			||||||
 | 
						state         protoimpl.MessageState `protogen:"open.v1"`
 | 
				
			||||||
 | 
						MarketplaceId int64                  `protobuf:"varint,1,opt,name=marketplace_id,json=marketplaceId,proto3" json:"marketplace_id,omitempty"`
 | 
				
			||||||
 | 
						unknownFields protoimpl.UnknownFields
 | 
				
			||||||
 | 
						sizeCache     protoimpl.SizeCache
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductsRequest) Reset() {
 | 
				
			||||||
 | 
						*x = GetProductsRequest{}
 | 
				
			||||||
 | 
						mi := &file_wb_products_proto_msgTypes[0]
 | 
				
			||||||
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductsRequest) String() string {
 | 
				
			||||||
 | 
						return protoimpl.X.MessageStringOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (*GetProductsRequest) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductsRequest) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
 | 
						mi := &file_wb_products_proto_msgTypes[0]
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
 | 
								ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ms
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mi.MessageOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: Use GetProductsRequest.ProtoReflect.Descriptor instead.
 | 
				
			||||||
 | 
					func (*GetProductsRequest) Descriptor() ([]byte, []int) {
 | 
				
			||||||
 | 
						return file_wb_products_proto_rawDescGZIP(), []int{0}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductsRequest) GetMarketplaceId() int64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.MarketplaceId
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Product struct {
 | 
				
			||||||
 | 
						state         protoimpl.MessageState `protogen:"open.v1"`
 | 
				
			||||||
 | 
						NmID          int64                  `protobuf:"varint,1,opt,name=nmID,proto3" json:"nmID,omitempty"`
 | 
				
			||||||
 | 
						SubjectID     int64                  `protobuf:"varint,2,opt,name=subjectID,proto3" json:"subjectID,omitempty"`
 | 
				
			||||||
 | 
						VendorCode    string                 `protobuf:"bytes,3,opt,name=vendor_code,json=vendorCode,proto3" json:"vendor_code,omitempty"`
 | 
				
			||||||
 | 
						Sizes         []*Product_Size        `protobuf:"bytes,4,rep,name=sizes,proto3" json:"sizes,omitempty"`
 | 
				
			||||||
 | 
						unknownFields protoimpl.UnknownFields
 | 
				
			||||||
 | 
						sizeCache     protoimpl.SizeCache
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product) Reset() {
 | 
				
			||||||
 | 
						*x = Product{}
 | 
				
			||||||
 | 
						mi := &file_wb_products_proto_msgTypes[1]
 | 
				
			||||||
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product) String() string {
 | 
				
			||||||
 | 
						return protoimpl.X.MessageStringOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (*Product) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
 | 
						mi := &file_wb_products_proto_msgTypes[1]
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
 | 
								ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ms
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mi.MessageOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: Use Product.ProtoReflect.Descriptor instead.
 | 
				
			||||||
 | 
					func (*Product) Descriptor() ([]byte, []int) {
 | 
				
			||||||
 | 
						return file_wb_products_proto_rawDescGZIP(), []int{1}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product) GetNmID() int64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.NmID
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product) GetSubjectID() int64 {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.SubjectID
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product) GetVendorCode() string {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.VendorCode
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product) GetSizes() []*Product_Size {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.Sizes
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GetProductsResponse struct {
 | 
				
			||||||
 | 
						state         protoimpl.MessageState `protogen:"open.v1"`
 | 
				
			||||||
 | 
						Products      []*Product             `protobuf:"bytes,1,rep,name=products,proto3" json:"products,omitempty"`
 | 
				
			||||||
 | 
						unknownFields protoimpl.UnknownFields
 | 
				
			||||||
 | 
						sizeCache     protoimpl.SizeCache
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductsResponse) Reset() {
 | 
				
			||||||
 | 
						*x = GetProductsResponse{}
 | 
				
			||||||
 | 
						mi := &file_wb_products_proto_msgTypes[2]
 | 
				
			||||||
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductsResponse) String() string {
 | 
				
			||||||
 | 
						return protoimpl.X.MessageStringOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (*GetProductsResponse) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductsResponse) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
 | 
						mi := &file_wb_products_proto_msgTypes[2]
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
 | 
								ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ms
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mi.MessageOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: Use GetProductsResponse.ProtoReflect.Descriptor instead.
 | 
				
			||||||
 | 
					func (*GetProductsResponse) Descriptor() ([]byte, []int) {
 | 
				
			||||||
 | 
						return file_wb_products_proto_rawDescGZIP(), []int{2}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *GetProductsResponse) GetProducts() []*Product {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.Products
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Product_Size struct {
 | 
				
			||||||
 | 
						state         protoimpl.MessageState `protogen:"open.v1"`
 | 
				
			||||||
 | 
						Skus          []string               `protobuf:"bytes,1,rep,name=skus,proto3" json:"skus,omitempty"`
 | 
				
			||||||
 | 
						unknownFields protoimpl.UnknownFields
 | 
				
			||||||
 | 
						sizeCache     protoimpl.SizeCache
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product_Size) Reset() {
 | 
				
			||||||
 | 
						*x = Product_Size{}
 | 
				
			||||||
 | 
						mi := &file_wb_products_proto_msgTypes[3]
 | 
				
			||||||
 | 
						ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
						ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product_Size) String() string {
 | 
				
			||||||
 | 
						return protoimpl.X.MessageStringOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (*Product_Size) ProtoMessage() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product_Size) ProtoReflect() protoreflect.Message {
 | 
				
			||||||
 | 
						mi := &file_wb_products_proto_msgTypes[3]
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
				
			||||||
 | 
							if ms.LoadMessageInfo() == nil {
 | 
				
			||||||
 | 
								ms.StoreMessageInfo(mi)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ms
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return mi.MessageOf(x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Deprecated: Use Product_Size.ProtoReflect.Descriptor instead.
 | 
				
			||||||
 | 
					func (*Product_Size) Descriptor() ([]byte, []int) {
 | 
				
			||||||
 | 
						return file_wb_products_proto_rawDescGZIP(), []int{1, 0}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (x *Product_Size) GetSkus() []string {
 | 
				
			||||||
 | 
						if x != nil {
 | 
				
			||||||
 | 
							return x.Skus
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var File_wb_products_proto protoreflect.FileDescriptor
 | 
					var File_wb_products_proto protoreflect.FileDescriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const file_wb_products_proto_rawDesc = "" +
 | 
					const file_wb_products_proto_rawDesc = "" +
 | 
				
			||||||
	"\n" +
 | 
						"\n" +
 | 
				
			||||||
	"\x11wb/products.proto\x12\vwb.products2\x11\n" +
 | 
						"\x11wb/products.proto\x12\vwb.products\";\n" +
 | 
				
			||||||
	"\x0fProductsServiceB\x0fZ\r./wb/productsb\x06proto3"
 | 
						"\x12GetProductsRequest\x12%\n" +
 | 
				
			||||||
 | 
						"\x0emarketplace_id\x18\x01 \x01(\x03R\rmarketplaceId\"\xa9\x01\n" +
 | 
				
			||||||
 | 
						"\aProduct\x12\x12\n" +
 | 
				
			||||||
 | 
						"\x04nmID\x18\x01 \x01(\x03R\x04nmID\x12\x1c\n" +
 | 
				
			||||||
 | 
						"\tsubjectID\x18\x02 \x01(\x03R\tsubjectID\x12\x1f\n" +
 | 
				
			||||||
 | 
						"\vvendor_code\x18\x03 \x01(\tR\n" +
 | 
				
			||||||
 | 
						"vendorCode\x12/\n" +
 | 
				
			||||||
 | 
						"\x05sizes\x18\x04 \x03(\v2\x19.wb.products.Product.SizeR\x05sizes\x1a\x1a\n" +
 | 
				
			||||||
 | 
						"\x04Size\x12\x12\n" +
 | 
				
			||||||
 | 
						"\x04skus\x18\x01 \x03(\tR\x04skus\"G\n" +
 | 
				
			||||||
 | 
						"\x13GetProductsResponse\x120\n" +
 | 
				
			||||||
 | 
						"\bproducts\x18\x01 \x03(\v2\x14.wb.products.ProductR\bproducts2e\n" +
 | 
				
			||||||
 | 
						"\x0fProductsService\x12R\n" +
 | 
				
			||||||
 | 
						"\vGetProducts\x12\x1f.wb.products.GetProductsRequest\x1a .wb.products.GetProductsResponse0\x01B\x0fZ\r./wb/productsb\x06proto3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var file_wb_products_proto_goTypes = []any{}
 | 
					var (
 | 
				
			||||||
 | 
						file_wb_products_proto_rawDescOnce sync.Once
 | 
				
			||||||
 | 
						file_wb_products_proto_rawDescData []byte
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func file_wb_products_proto_rawDescGZIP() []byte {
 | 
				
			||||||
 | 
						file_wb_products_proto_rawDescOnce.Do(func() {
 | 
				
			||||||
 | 
							file_wb_products_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_wb_products_proto_rawDesc), len(file_wb_products_proto_rawDesc)))
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return file_wb_products_proto_rawDescData
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var file_wb_products_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
 | 
				
			||||||
 | 
					var file_wb_products_proto_goTypes = []any{
 | 
				
			||||||
 | 
						(*GetProductsRequest)(nil),  // 0: wb.products.GetProductsRequest
 | 
				
			||||||
 | 
						(*Product)(nil),             // 1: wb.products.Product
 | 
				
			||||||
 | 
						(*GetProductsResponse)(nil), // 2: wb.products.GetProductsResponse
 | 
				
			||||||
 | 
						(*Product_Size)(nil),        // 3: wb.products.Product.Size
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
var file_wb_products_proto_depIdxs = []int32{
 | 
					var file_wb_products_proto_depIdxs = []int32{
 | 
				
			||||||
	0, // [0:0] is the sub-list for method output_type
 | 
						3, // 0: wb.products.Product.sizes:type_name -> wb.products.Product.Size
 | 
				
			||||||
	0, // [0:0] is the sub-list for method input_type
 | 
						1, // 1: wb.products.GetProductsResponse.products:type_name -> wb.products.Product
 | 
				
			||||||
	0, // [0:0] is the sub-list for extension type_name
 | 
						0, // 2: wb.products.ProductsService.GetProducts:input_type -> wb.products.GetProductsRequest
 | 
				
			||||||
	0, // [0:0] is the sub-list for extension extendee
 | 
						2, // 3: wb.products.ProductsService.GetProducts:output_type -> wb.products.GetProductsResponse
 | 
				
			||||||
	0, // [0:0] is the sub-list for field type_name
 | 
						3, // [3:4] is the sub-list for method output_type
 | 
				
			||||||
 | 
						2, // [2:3] is the sub-list for method input_type
 | 
				
			||||||
 | 
						2, // [2:2] is the sub-list for extension type_name
 | 
				
			||||||
 | 
						2, // [2:2] is the sub-list for extension extendee
 | 
				
			||||||
 | 
						0, // [0:2] is the sub-list for field type_name
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() { file_wb_products_proto_init() }
 | 
					func init() { file_wb_products_proto_init() }
 | 
				
			||||||
@@ -47,12 +283,13 @@ func file_wb_products_proto_init() {
 | 
				
			|||||||
			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 | 
								GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 | 
				
			||||||
			RawDescriptor: unsafe.Slice(unsafe.StringData(file_wb_products_proto_rawDesc), len(file_wb_products_proto_rawDesc)),
 | 
								RawDescriptor: unsafe.Slice(unsafe.StringData(file_wb_products_proto_rawDesc), len(file_wb_products_proto_rawDesc)),
 | 
				
			||||||
			NumEnums:      0,
 | 
								NumEnums:      0,
 | 
				
			||||||
			NumMessages:   0,
 | 
								NumMessages:   4,
 | 
				
			||||||
			NumExtensions: 0,
 | 
								NumExtensions: 0,
 | 
				
			||||||
			NumServices:   1,
 | 
								NumServices:   1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		GoTypes:           file_wb_products_proto_goTypes,
 | 
							GoTypes:           file_wb_products_proto_goTypes,
 | 
				
			||||||
		DependencyIndexes: file_wb_products_proto_depIdxs,
 | 
							DependencyIndexes: file_wb_products_proto_depIdxs,
 | 
				
			||||||
 | 
							MessageInfos:      file_wb_products_proto_msgTypes,
 | 
				
			||||||
	}.Build()
 | 
						}.Build()
 | 
				
			||||||
	File_wb_products_proto = out.File
 | 
						File_wb_products_proto = out.File
 | 
				
			||||||
	file_wb_products_proto_goTypes = nil
 | 
						file_wb_products_proto_goTypes = nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,16 @@
 | 
				
			|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 | 
					// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 | 
				
			||||||
// versions:
 | 
					// versions:
 | 
				
			||||||
// - protoc-gen-go-grpc v1.5.1
 | 
					// - protoc-gen-go-grpc v1.5.1
 | 
				
			||||||
// - protoc             v6.31.0
 | 
					// - protoc             v6.31.1
 | 
				
			||||||
// source: wb/products.proto
 | 
					// source: wb/products.proto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package products
 | 
					package products
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						context "context"
 | 
				
			||||||
	grpc "google.golang.org/grpc"
 | 
						grpc "google.golang.org/grpc"
 | 
				
			||||||
 | 
						codes "google.golang.org/grpc/codes"
 | 
				
			||||||
 | 
						status "google.golang.org/grpc/status"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This is a compile-time assertion to ensure that this generated file
 | 
					// This is a compile-time assertion to ensure that this generated file
 | 
				
			||||||
@@ -15,10 +18,15 @@ import (
 | 
				
			|||||||
// Requires gRPC-Go v1.64.0 or later.
 | 
					// Requires gRPC-Go v1.64.0 or later.
 | 
				
			||||||
const _ = grpc.SupportPackageIsVersion9
 | 
					const _ = grpc.SupportPackageIsVersion9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ProductsService_GetProducts_FullMethodName = "/wb.products.ProductsService/GetProducts"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ProductsServiceClient is the client API for ProductsService service.
 | 
					// ProductsServiceClient is the client API for ProductsService service.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
 | 
					// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
 | 
				
			||||||
type ProductsServiceClient interface {
 | 
					type ProductsServiceClient interface {
 | 
				
			||||||
 | 
						GetProducts(ctx context.Context, in *GetProductsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetProductsResponse], error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type productsServiceClient struct {
 | 
					type productsServiceClient struct {
 | 
				
			||||||
@@ -29,10 +37,30 @@ func NewProductsServiceClient(cc grpc.ClientConnInterface) ProductsServiceClient
 | 
				
			|||||||
	return &productsServiceClient{cc}
 | 
						return &productsServiceClient{cc}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *productsServiceClient) GetProducts(ctx context.Context, in *GetProductsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetProductsResponse], error) {
 | 
				
			||||||
 | 
						cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
 | 
				
			||||||
 | 
						stream, err := c.cc.NewStream(ctx, &ProductsService_ServiceDesc.Streams[0], ProductsService_GetProducts_FullMethodName, cOpts...)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						x := &grpc.GenericClientStream[GetProductsRequest, GetProductsResponse]{ClientStream: stream}
 | 
				
			||||||
 | 
						if err := x.ClientStream.SendMsg(in); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := x.ClientStream.CloseSend(); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return x, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
 | 
				
			||||||
 | 
					type ProductsService_GetProductsClient = grpc.ServerStreamingClient[GetProductsResponse]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ProductsServiceServer is the server API for ProductsService service.
 | 
					// ProductsServiceServer is the server API for ProductsService service.
 | 
				
			||||||
// All implementations must embed UnimplementedProductsServiceServer
 | 
					// All implementations must embed UnimplementedProductsServiceServer
 | 
				
			||||||
// for forward compatibility.
 | 
					// for forward compatibility.
 | 
				
			||||||
type ProductsServiceServer interface {
 | 
					type ProductsServiceServer interface {
 | 
				
			||||||
 | 
						GetProducts(*GetProductsRequest, grpc.ServerStreamingServer[GetProductsResponse]) error
 | 
				
			||||||
	mustEmbedUnimplementedProductsServiceServer()
 | 
						mustEmbedUnimplementedProductsServiceServer()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -43,6 +71,9 @@ type ProductsServiceServer interface {
 | 
				
			|||||||
// pointer dereference when methods are called.
 | 
					// pointer dereference when methods are called.
 | 
				
			||||||
type UnimplementedProductsServiceServer struct{}
 | 
					type UnimplementedProductsServiceServer struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (UnimplementedProductsServiceServer) GetProducts(*GetProductsRequest, grpc.ServerStreamingServer[GetProductsResponse]) error {
 | 
				
			||||||
 | 
						return status.Errorf(codes.Unimplemented, "method GetProducts not implemented")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
func (UnimplementedProductsServiceServer) mustEmbedUnimplementedProductsServiceServer() {}
 | 
					func (UnimplementedProductsServiceServer) mustEmbedUnimplementedProductsServiceServer() {}
 | 
				
			||||||
func (UnimplementedProductsServiceServer) testEmbeddedByValue()                         {}
 | 
					func (UnimplementedProductsServiceServer) testEmbeddedByValue()                         {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,6 +95,17 @@ func RegisterProductsServiceServer(s grpc.ServiceRegistrar, srv ProductsServiceS
 | 
				
			|||||||
	s.RegisterService(&ProductsService_ServiceDesc, srv)
 | 
						s.RegisterService(&ProductsService_ServiceDesc, srv)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func _ProductsService_GetProducts_Handler(srv interface{}, stream grpc.ServerStream) error {
 | 
				
			||||||
 | 
						m := new(GetProductsRequest)
 | 
				
			||||||
 | 
						if err := stream.RecvMsg(m); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return srv.(ProductsServiceServer).GetProducts(m, &grpc.GenericServerStream[GetProductsRequest, GetProductsResponse]{ServerStream: stream})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
 | 
				
			||||||
 | 
					type ProductsService_GetProductsServer = grpc.ServerStreamingServer[GetProductsResponse]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ProductsService_ServiceDesc is the grpc.ServiceDesc for ProductsService service.
 | 
					// ProductsService_ServiceDesc is the grpc.ServiceDesc for ProductsService service.
 | 
				
			||||||
// It's only intended for direct use with grpc.RegisterService,
 | 
					// It's only intended for direct use with grpc.RegisterService,
 | 
				
			||||||
// and not to be introspected or modified (even as a copy)
 | 
					// and not to be introspected or modified (even as a copy)
 | 
				
			||||||
@@ -71,6 +113,12 @@ var ProductsService_ServiceDesc = grpc.ServiceDesc{
 | 
				
			|||||||
	ServiceName: "wb.products.ProductsService",
 | 
						ServiceName: "wb.products.ProductsService",
 | 
				
			||||||
	HandlerType: (*ProductsServiceServer)(nil),
 | 
						HandlerType: (*ProductsServiceServer)(nil),
 | 
				
			||||||
	Methods:     []grpc.MethodDesc{},
 | 
						Methods:     []grpc.MethodDesc{},
 | 
				
			||||||
	Streams:     []grpc.StreamDesc{},
 | 
						Streams: []grpc.StreamDesc{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								StreamName:    "GetProducts",
 | 
				
			||||||
 | 
								Handler:       _ProductsService_GetProducts_Handler,
 | 
				
			||||||
 | 
								ServerStreams: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	Metadata: "wb/products.proto",
 | 
						Metadata: "wb/products.proto",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
					// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
				
			||||||
// versions:
 | 
					// versions:
 | 
				
			||||||
// 	protoc-gen-go v1.36.6
 | 
					// 	protoc-gen-go v1.36.6
 | 
				
			||||||
// 	protoc        v6.31.0
 | 
					// 	protoc        v6.31.1
 | 
				
			||||||
// source: yandexmarket/products.proto
 | 
					// source: yandexmarket/products.proto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package products
 | 
					package products
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 | 
					// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 | 
				
			||||||
// versions:
 | 
					// versions:
 | 
				
			||||||
// - protoc-gen-go-grpc v1.5.1
 | 
					// - protoc-gen-go-grpc v1.5.1
 | 
				
			||||||
// - protoc             v6.31.0
 | 
					// - protoc             v6.31.1
 | 
				
			||||||
// source: yandexmarket/products.proto
 | 
					// source: yandexmarket/products.proto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package products
 | 
					package products
 | 
				
			||||||
 
 | 
				
			|||||||
 Submodule api/proto/v1 updated: c6df89a7a3...2c4ca98d2d
									
								
							@@ -8,9 +8,12 @@ import (
 | 
				
			|||||||
	"google.golang.org/grpc"
 | 
						"google.golang.org/grpc"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"sipro-mps/internal/config"
 | 
				
			||||||
	"sipro-mps/internal/marketplace"
 | 
						"sipro-mps/internal/marketplace"
 | 
				
			||||||
	ozon "sipro-mps/internal/ozon/products"
 | 
						ozon "sipro-mps/internal/ozon/products"
 | 
				
			||||||
	"sipro-mps/internal/redis"
 | 
						"sipro-mps/internal/redis"
 | 
				
			||||||
 | 
						"sipro-mps/internal/tasks/client"
 | 
				
			||||||
 | 
						wb "sipro-mps/internal/wb/products"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func logMessage(level string, format string, a ...interface{}) {
 | 
					func logMessage(level string, format string, a ...interface{}) {
 | 
				
			||||||
@@ -50,7 +53,11 @@ func createGrpcServer(pool *pgxpool.Pool) {
 | 
				
			|||||||
		fmt.Printf("failed to register Ozon Products gRPC server: %v\n", err)
 | 
							fmt.Printf("failed to register Ozon Products gRPC server: %v\n", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						_, err = wb.RegisterAdapterGRPC(grpcServer, *repo)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							fmt.Printf("failed to register Wildberries Products gRPC server: %v\n", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	fmt.Println("gRPC server registered successfully.")
 | 
						fmt.Println("gRPC server registered successfully.")
 | 
				
			||||||
	// Start serving gRPC requests
 | 
						// Start serving gRPC requests
 | 
				
			||||||
	fmt.Println("gRPC server is starting on port 8080...")
 | 
						fmt.Println("gRPC server is starting on port 8080...")
 | 
				
			||||||
@@ -61,26 +68,64 @@ func createGrpcServer(pool *pgxpool.Pool) {
 | 
				
			|||||||
	fmt.Println("gRPC server created.")
 | 
						fmt.Println("gRPC server created.")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func initDotenv() error {
 | 
				
			||||||
	// Initializing the dotenv file
 | 
					 | 
				
			||||||
	err := godotenv.Load()
 | 
						err := godotenv.Load()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logMessage("error", "Error loading .env file: %v", err)
 | 
							return fmt.Errorf("error loading .env file: %w", err)
 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	logMessage("info", "Dotenv file loaded successfully. 🌱")
 | 
						logMessage("info", "Dotenv file loaded successfully. 🌱")
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func initRedisClient(ctx context.Context) error {
 | 
				
			||||||
 | 
						err := redis.InitClient(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("error initializing Redis client: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						//defer redis.CloseClient()
 | 
				
			||||||
 | 
						logMessage("info", "Redis client initialized successfully. 🟥")
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func initRedisLocker() error {
 | 
				
			||||||
 | 
						err := redis.InitLocker()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("error initializing Redis locker: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						logMessage("info", "Redis locker initialized successfully. 🟥")
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
						err := initDotenv()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							logMessage("error", "Failed to load .env file: %v", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						logMessage("info", "Starting the SIPRO Marketplace Server... 🚀1")
 | 
				
			||||||
	ctx := context.Background()
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Initializing the Redis client
 | 
						// Initializing the Redis client
 | 
				
			||||||
	err = redis.InitClient(ctx)
 | 
						err = initRedisClient(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logMessage("error", "Failed to initialize Redis client: %v", err)
 | 
							logMessage("error", "Failed to initialize Redis client: %v", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer redis.CloseClient()
 | 
						defer redis.CloseClient()
 | 
				
			||||||
	logMessage("info", "Redis client initialized successfully. 🟥")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Initializing the Redis locker
 | 
				
			||||||
 | 
						err = initRedisLocker()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							logMessage("error", "Failed to initialize Redis locker: %v", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer redis.CloseLocker()
 | 
				
			||||||
 | 
						cfg, err := config.LoadConfig()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							logMessage("error", "Failed to load configuration: %v", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						client.InitClient(*cfg.Redis)
 | 
				
			||||||
	// Initializing pgx connection
 | 
						// Initializing pgx connection
 | 
				
			||||||
	dbpool, err := pgxpool.New(ctx, os.Getenv("POSTGRES_URL"))
 | 
						dbpool, err := pgxpool.New(ctx, os.Getenv("POSTGRES_URL"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -88,11 +133,6 @@ func main() {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer dbpool.Close()
 | 
						defer dbpool.Close()
 | 
				
			||||||
	logMessage("info", "Connected to PostgreSQL successfully. 🐘")
 | 
					
 | 
				
			||||||
	createGrpcServer(dbpool)
 | 
						createGrpcServer(dbpool)
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
//for _, item := range items {
 | 
					 | 
				
			||||||
//	//logMessage("info", "Product ID: %s, Name: %s, Price: %d", item.Price, item.Name, item.Price)
 | 
					 | 
				
			||||||
//}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								cmd/tasks_server/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								cmd/tasks_server/main.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"github.com/jackc/pgx/v5/pgxpool"
 | 
				
			||||||
 | 
						"sipro-mps/internal/config"
 | 
				
			||||||
 | 
						"sipro-mps/internal/redis"
 | 
				
			||||||
 | 
						"sipro-mps/internal/tasks/server"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
						cfg, err := config.LoadConfig()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
						err = redis.InitClient(ctx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer redis.CloseClient()
 | 
				
			||||||
 | 
						err = redis.InitLocker()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer redis.CloseLocker()
 | 
				
			||||||
 | 
						dbpool, err := pgxpool.New(ctx, cfg.Database.URL)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srv := server.NewAsynqServer(cfg.Redis, dbpool)
 | 
				
			||||||
 | 
						srv.Run()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										51
									
								
								cmd/test/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								cmd/test/main.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/go-faster/errors"
 | 
				
			||||||
 | 
						"github.com/hibiken/asynq"
 | 
				
			||||||
 | 
						"github.com/joho/godotenv"
 | 
				
			||||||
 | 
						"github.com/redis/rueidis"
 | 
				
			||||||
 | 
						"sipro-mps/internal/config"
 | 
				
			||||||
 | 
						"sipro-mps/internal/redis"
 | 
				
			||||||
 | 
						"sipro-mps/internal/tasks"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
						godotenv.Load()
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						redis.InitClient(ctx)
 | 
				
			||||||
 | 
						c := *redis.Client
 | 
				
			||||||
 | 
						key := fmt.Sprintf("wb:products:%d", "test")
 | 
				
			||||||
 | 
						v, err := c.Do(ctx, c.B().Get().Key(key).Build()).ToString()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if errors.As(err, &rueidis.Nil) {
 | 
				
			||||||
 | 
								fmt.Println("Key does not exist in Redis:", key)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fmt.Println("Value from Redis:", v)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
						cfg, err := config.LoadConfig()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						client := asynq.NewClient(asynq.RedisClientOpt{Addr: cfg.Redis.Host + ":" + cfg.Redis.Port, Password: cfg.Redis.Password})
 | 
				
			||||||
 | 
						defer func(client *asynq.Client) {
 | 
				
			||||||
 | 
							err := client.Close()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								panic(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}(client)
 | 
				
			||||||
 | 
						task, err := tasks.NewFetchProductsTask(1130)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						info, err := client.Enqueue(task)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						println("Task enqueued successfully:", info.ID, "with queue name:", info.Queue, "and payload size:", len(info.Payload), "bytes")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					version: '3.8'
 | 
				
			||||||
 | 
					services:
 | 
				
			||||||
 | 
					  app:
 | 
				
			||||||
 | 
					    image: git.denco.store/fakz9/sipro-marketplaces:latest
 | 
				
			||||||
 | 
					    depends_on:
 | 
				
			||||||
 | 
					      - redis
 | 
				
			||||||
 | 
					    networks:
 | 
				
			||||||
 | 
					      - appnet
 | 
				
			||||||
 | 
					  redis:
 | 
				
			||||||
 | 
					    image: redis
 | 
				
			||||||
 | 
					    networks:
 | 
				
			||||||
 | 
					      - appnet
 | 
				
			||||||
 | 
					networks:
 | 
				
			||||||
 | 
					  appnet:
 | 
				
			||||||
 | 
					    driver: bridge
 | 
				
			||||||
							
								
								
									
										39
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								go.mod
									
									
									
									
									
								
							@@ -4,24 +4,55 @@ go 1.24
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	git.denco.store/fakz9/ozon-api-client v1.18.1-0.20250526003754-c6c303092505
 | 
						git.denco.store/fakz9/ozon-api-client v1.18.1-0.20250526003754-c6c303092505
 | 
				
			||||||
 | 
						github.com/go-faster/errors v0.7.1
 | 
				
			||||||
 | 
						github.com/go-faster/jx v1.1.0
 | 
				
			||||||
 | 
						github.com/golang-jwt/jwt/v5 v5.2.2
 | 
				
			||||||
 | 
						github.com/google/uuid v1.6.0
 | 
				
			||||||
 | 
						github.com/hibiken/asynq v0.25.1
 | 
				
			||||||
	github.com/jackc/pgx/v5 v5.7.5
 | 
						github.com/jackc/pgx/v5 v5.7.5
 | 
				
			||||||
	github.com/joho/godotenv v1.5.1
 | 
						github.com/joho/godotenv v1.5.1
 | 
				
			||||||
	github.com/lib/pq v1.10.9
 | 
						github.com/lib/pq v1.10.9
 | 
				
			||||||
 | 
						github.com/ogen-go/ogen v1.14.0
 | 
				
			||||||
	github.com/redis/rueidis v1.0.60
 | 
						github.com/redis/rueidis v1.0.60
 | 
				
			||||||
	github.com/samber/lo v1.50.0
 | 
						github.com/samber/lo v1.50.0
 | 
				
			||||||
	github.com/tidwall/gjson v1.18.0
 | 
						github.com/tidwall/gjson v1.18.0
 | 
				
			||||||
 | 
						go.opentelemetry.io/otel v1.36.0
 | 
				
			||||||
 | 
						go.opentelemetry.io/otel/metric v1.36.0
 | 
				
			||||||
 | 
						go.opentelemetry.io/otel/trace v1.36.0
 | 
				
			||||||
	google.golang.org/grpc v1.72.2
 | 
						google.golang.org/grpc v1.72.2
 | 
				
			||||||
	google.golang.org/protobuf v1.36.5
 | 
						google.golang.org/protobuf v1.36.5
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
 | 
						github.com/cespare/xxhash/v2 v2.3.0 // indirect
 | 
				
			||||||
 | 
						github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 | 
				
			||||||
 | 
						github.com/dlclark/regexp2 v1.11.5 // indirect
 | 
				
			||||||
 | 
						github.com/fatih/color v1.18.0 // indirect
 | 
				
			||||||
 | 
						github.com/ghodss/yaml v1.0.0 // indirect
 | 
				
			||||||
 | 
						github.com/go-faster/yaml v0.4.6 // indirect
 | 
				
			||||||
 | 
						github.com/go-logr/logr v1.4.2 // indirect
 | 
				
			||||||
 | 
						github.com/go-logr/stdr v1.2.2 // indirect
 | 
				
			||||||
	github.com/jackc/pgpassfile v1.0.0 // indirect
 | 
						github.com/jackc/pgpassfile v1.0.0 // indirect
 | 
				
			||||||
	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
 | 
						github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
 | 
				
			||||||
 | 
						github.com/jackc/puddle/v2 v2.2.2 // indirect
 | 
				
			||||||
 | 
						github.com/mattn/go-colorable v0.1.13 // indirect
 | 
				
			||||||
 | 
						github.com/mattn/go-isatty v0.0.20 // indirect
 | 
				
			||||||
 | 
						github.com/redis/go-redis/v9 v9.7.0 // indirect
 | 
				
			||||||
 | 
						github.com/robfig/cron/v3 v3.0.1 // indirect
 | 
				
			||||||
 | 
						github.com/segmentio/asm v1.2.0 // indirect
 | 
				
			||||||
 | 
						github.com/spf13/cast v1.7.0 // indirect
 | 
				
			||||||
	github.com/tidwall/match v1.1.1 // indirect
 | 
						github.com/tidwall/match v1.1.1 // indirect
 | 
				
			||||||
	github.com/tidwall/pretty v1.2.1 // indirect
 | 
						github.com/tidwall/pretty v1.2.1 // indirect
 | 
				
			||||||
	golang.org/x/crypto v0.37.0 // indirect
 | 
						go.opentelemetry.io/auto/sdk v1.1.0 // indirect
 | 
				
			||||||
	golang.org/x/net v0.38.0 // indirect
 | 
						go.uber.org/multierr v1.11.0 // indirect
 | 
				
			||||||
	golang.org/x/sys v0.32.0 // indirect
 | 
						go.uber.org/zap v1.27.0 // indirect
 | 
				
			||||||
	golang.org/x/text v0.24.0 // indirect
 | 
						golang.org/x/crypto v0.38.0 // indirect
 | 
				
			||||||
 | 
						golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect
 | 
				
			||||||
 | 
						golang.org/x/net v0.40.0 // indirect
 | 
				
			||||||
 | 
						golang.org/x/sync v0.14.0 // indirect
 | 
				
			||||||
 | 
						golang.org/x/sys v0.33.0 // indirect
 | 
				
			||||||
 | 
						golang.org/x/text v0.25.0 // indirect
 | 
				
			||||||
 | 
						golang.org/x/time v0.8.0 // indirect
 | 
				
			||||||
	google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
 | 
						google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
 | 
				
			||||||
 | 
						gopkg.in/yaml.v2 v2.4.0 // indirect
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										104
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								go.sum
									
									
									
									
									
								
							@@ -1,18 +1,45 @@
 | 
				
			|||||||
git.denco.store/fakz9/ozon-api-client v1.18.1-0.20250526003754-c6c303092505 h1:5mviYMLXLIvsFEXLR0IlGuqMNzkB8X/yrmxZHYk0n84=
 | 
					git.denco.store/fakz9/ozon-api-client v1.18.1-0.20250526003754-c6c303092505 h1:5mviYMLXLIvsFEXLR0IlGuqMNzkB8X/yrmxZHYk0n84=
 | 
				
			||||||
git.denco.store/fakz9/ozon-api-client v1.18.1-0.20250526003754-c6c303092505/go.mod h1:1uPm278HN7mDkP507KHsLpnW+R9vWGEzp9BSMycjVbQ=
 | 
					git.denco.store/fakz9/ozon-api-client v1.18.1-0.20250526003754-c6c303092505/go.mod h1:1uPm278HN7mDkP507KHsLpnW+R9vWGEzp9BSMycjVbQ=
 | 
				
			||||||
 | 
					github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
 | 
				
			||||||
 | 
					github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
 | 
				
			||||||
 | 
					github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
 | 
				
			||||||
 | 
					github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
 | 
				
			||||||
 | 
					github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 | 
				
			||||||
 | 
					github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
					github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
				
			||||||
 | 
					github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 | 
				
			||||||
 | 
					github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
 | 
				
			||||||
 | 
					github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
 | 
				
			||||||
 | 
					github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
 | 
				
			||||||
 | 
					github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
 | 
				
			||||||
 | 
					github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
 | 
				
			||||||
 | 
					github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
 | 
				
			||||||
 | 
					github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 | 
				
			||||||
 | 
					github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 | 
				
			||||||
 | 
					github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 | 
				
			||||||
 | 
					github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
 | 
				
			||||||
 | 
					github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
 | 
				
			||||||
 | 
					github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg=
 | 
				
			||||||
 | 
					github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb3skg=
 | 
				
			||||||
 | 
					github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I=
 | 
				
			||||||
 | 
					github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk=
 | 
				
			||||||
 | 
					github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 | 
				
			||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
 | 
					github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
 | 
				
			||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 | 
					github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 | 
				
			||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 | 
					github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 | 
				
			||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 | 
					github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 | 
				
			||||||
 | 
					github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
 | 
				
			||||||
 | 
					github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 | 
				
			||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
 | 
					github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
 | 
				
			||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 | 
					github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 | 
				
			||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
 | 
					github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
 | 
				
			||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
 | 
					github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
 | 
				
			||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 | 
					github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 | 
				
			||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
					github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
				
			||||||
 | 
					github.com/hibiken/asynq v0.25.1 h1:phj028N0nm15n8O2ims+IvJ2gz4k2auvermngh9JhTw=
 | 
				
			||||||
 | 
					github.com/hibiken/asynq v0.25.1/go.mod h1:pazWNOLBu0FEynQRBvHA26qdIKRSmfdIfUm4HdsLmXg=
 | 
				
			||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 | 
					github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 | 
				
			||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
 | 
					github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
 | 
				
			||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
 | 
					github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
 | 
				
			||||||
@@ -23,16 +50,37 @@ github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo
 | 
				
			|||||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 | 
					github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 | 
				
			||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
 | 
					github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
 | 
				
			||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 | 
					github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 | 
				
			||||||
 | 
					github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 | 
				
			||||||
 | 
					github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 | 
				
			||||||
 | 
					github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 | 
				
			||||||
 | 
					github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 | 
				
			||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
 | 
					github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
 | 
				
			||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 | 
					github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 | 
				
			||||||
 | 
					github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
 | 
				
			||||||
 | 
					github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
 | 
				
			||||||
 | 
					github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 | 
				
			||||||
 | 
					github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 | 
				
			||||||
 | 
					github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 | 
				
			||||||
 | 
					github.com/ogen-go/ogen v1.14.0 h1:TU1Nj4z9UBsAfTkf+IhuNNp7igdFQKqkk9+6/y4XuWg=
 | 
				
			||||||
 | 
					github.com/ogen-go/ogen v1.14.0/go.mod h1:Iw1vkqkx6SU7I9th5ceP+fVPJ6Wge4e3kAVzAxJEpPE=
 | 
				
			||||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
 | 
					github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
 | 
				
			||||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
 | 
					github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
 | 
				
			||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
					github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
				
			||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
					github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
				
			||||||
 | 
					github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
 | 
				
			||||||
 | 
					github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
 | 
				
			||||||
github.com/redis/rueidis v1.0.60 h1:MGZX8uNdw7iyWz22JhjA/9iXzddfCUE/EMK4VxKoKpA=
 | 
					github.com/redis/rueidis v1.0.60 h1:MGZX8uNdw7iyWz22JhjA/9iXzddfCUE/EMK4VxKoKpA=
 | 
				
			||||||
github.com/redis/rueidis v1.0.60/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA=
 | 
					github.com/redis/rueidis v1.0.60/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA=
 | 
				
			||||||
 | 
					github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
 | 
				
			||||||
 | 
					github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 | 
				
			||||||
 | 
					github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
 | 
				
			||||||
 | 
					github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
 | 
				
			||||||
github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY=
 | 
					github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY=
 | 
				
			||||||
github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc=
 | 
					github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc=
 | 
				
			||||||
 | 
					github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
 | 
				
			||||||
 | 
					github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
 | 
				
			||||||
 | 
					github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
 | 
				
			||||||
 | 
					github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
 | 
				
			||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
					github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
				
			||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 | 
					github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 | 
				
			||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
					github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
				
			||||||
@@ -47,26 +95,38 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
 | 
				
			|||||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 | 
					github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 | 
				
			||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
 | 
					go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
 | 
				
			||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
 | 
					go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
 | 
				
			||||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
 | 
					go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
 | 
				
			||||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
 | 
					go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
 | 
				
			||||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
 | 
					go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
 | 
				
			||||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
 | 
					go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
 | 
				
			||||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
 | 
					go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
 | 
				
			||||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
 | 
					go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
 | 
				
			||||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
 | 
					go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
 | 
				
			||||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
 | 
					go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
 | 
				
			||||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
 | 
					go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
 | 
				
			||||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
 | 
					go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
 | 
				
			||||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
 | 
					go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 | 
				
			||||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
 | 
					go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 | 
				
			||||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
 | 
					go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 | 
				
			||||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
 | 
					go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 | 
				
			||||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
 | 
					go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
 | 
				
			||||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 | 
					go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 | 
				
			||||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
 | 
					golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
 | 
				
			||||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 | 
					golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
 | 
				
			||||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
 | 
					golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY=
 | 
				
			||||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
 | 
					golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
 | 
				
			||||||
 | 
					golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
 | 
				
			||||||
 | 
					golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
 | 
				
			||||||
 | 
					golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
 | 
				
			||||||
 | 
					golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 | 
				
			||||||
 | 
					golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
 | 
				
			||||||
 | 
					golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
 | 
				
			||||||
 | 
					golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
 | 
				
			||||||
 | 
					golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 | 
				
			||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
 | 
					google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
 | 
				
			||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
 | 
					google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
 | 
				
			||||||
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
 | 
					google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
 | 
				
			||||||
@@ -74,6 +134,10 @@ google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3i
 | 
				
			|||||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
 | 
					google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
 | 
				
			||||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 | 
					google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 | 
				
			||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
					gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
				
			||||||
 | 
					gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 | 
				
			||||||
 | 
					gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 | 
				
			||||||
 | 
					gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 | 
				
			||||||
 | 
					gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 | 
				
			||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
					gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
				
			||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 | 
					gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 | 
				
			||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
					gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,18 @@
 | 
				
			|||||||
package config
 | 
					package config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "github.com/joho/godotenv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	DB    string
 | 
						Redis    *RedisConfig
 | 
				
			||||||
	HTTP  string
 | 
						Database *DatabaseConfig
 | 
				
			||||||
	GRPC  string
 | 
					 | 
				
			||||||
	Kafka string
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Load() Config {
 | 
					func LoadConfig() (*Config, error) {
 | 
				
			||||||
	return Config{
 | 
						err := godotenv.Load()
 | 
				
			||||||
		DB:    "dbname=test password=GjitkYf[eq user=postgres sslmode=disable",
 | 
						if err != nil {
 | 
				
			||||||
		HTTP:  ":8080",
 | 
							return nil, err
 | 
				
			||||||
		GRPC:  ":50051",
 | 
					 | 
				
			||||||
		Kafka: "localhost:9092",
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						redisConfig := LoadRedisConfig()
 | 
				
			||||||
 | 
						databaseConfig := LoadDatabaseConfig()
 | 
				
			||||||
 | 
						return &Config{Redis: redisConfig, Database: databaseConfig}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								internal/config/database.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								internal/config/database.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					package config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DatabaseConfig struct {
 | 
				
			||||||
 | 
						Host     string
 | 
				
			||||||
 | 
						Port     string
 | 
				
			||||||
 | 
						Login    string
 | 
				
			||||||
 | 
						Password string
 | 
				
			||||||
 | 
						Database string
 | 
				
			||||||
 | 
						URL      string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LoadDatabaseConfig() *DatabaseConfig {
 | 
				
			||||||
 | 
						return &DatabaseConfig{
 | 
				
			||||||
 | 
							Host:     os.Getenv("POSTGRES_HOST"),
 | 
				
			||||||
 | 
							Port:     os.Getenv("POSTGRES_PORT"),
 | 
				
			||||||
 | 
							Login:    os.Getenv("POSTGRES_LOGIN"),
 | 
				
			||||||
 | 
							Password: os.Getenv("POSTGRES_PASSWORD"),
 | 
				
			||||||
 | 
							Database: os.Getenv("POSTGRES_DATABASE"),
 | 
				
			||||||
 | 
							URL:      os.Getenv("POSTGRES_URL"),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								internal/config/redis.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								internal/config/redis.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					package config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type RedisConfig struct {
 | 
				
			||||||
 | 
						Host     string
 | 
				
			||||||
 | 
						Port     string
 | 
				
			||||||
 | 
						Password string
 | 
				
			||||||
 | 
						Addr     string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LoadRedisConfig() *RedisConfig {
 | 
				
			||||||
 | 
						host := os.Getenv("REDIS_HOST")
 | 
				
			||||||
 | 
						port := os.Getenv("REDIS_PORT")
 | 
				
			||||||
 | 
						password := os.Getenv("REDIS_PASSWORD")
 | 
				
			||||||
 | 
						addr := os.Getenv("REDIS_ADDR")
 | 
				
			||||||
 | 
						return &RedisConfig{
 | 
				
			||||||
 | 
							Host:     host,
 | 
				
			||||||
 | 
							Port:     port,
 | 
				
			||||||
 | 
							Password: password,
 | 
				
			||||||
 | 
							Addr:     addr,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -14,4 +14,5 @@ type Marketplace struct {
 | 
				
			|||||||
	Name            string
 | 
						Name            string
 | 
				
			||||||
	AuthData        pgtype.Text
 | 
						AuthData        pgtype.Text
 | 
				
			||||||
	WarehouseID     pgtype.Text
 | 
						WarehouseID     pgtype.Text
 | 
				
			||||||
 | 
						AuthDataJson    []byte
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getMarketplaceByID = `-- name: GetMarketplaceByID :one
 | 
					const getMarketplaceByID = `-- name: GetMarketplaceByID :one
 | 
				
			||||||
SELECT id, base_marketplace, name, auth_data, warehouse_id FROM marketplaces
 | 
					SELECT id, base_marketplace, name, auth_data, warehouse_id, auth_data_json FROM marketplaces
 | 
				
			||||||
WHERE id = $1 LIMIT 1
 | 
					WHERE id = $1 LIMIT 1
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,6 +23,7 @@ func (q *Queries) GetMarketplaceByID(ctx context.Context, id int32) (Marketplace
 | 
				
			|||||||
		&i.Name,
 | 
							&i.Name,
 | 
				
			||||||
		&i.AuthData,
 | 
							&i.AuthData,
 | 
				
			||||||
		&i.WarehouseID,
 | 
							&i.WarehouseID,
 | 
				
			||||||
 | 
							&i.AuthDataJson,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	return i, err
 | 
						return i, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,5 +5,10 @@ create table marketplaces
 | 
				
			|||||||
    base_marketplace integer not null,
 | 
					    base_marketplace integer not null,
 | 
				
			||||||
    name             varchar not null,
 | 
					    name             varchar not null,
 | 
				
			||||||
    auth_data        varchar,
 | 
					    auth_data        varchar,
 | 
				
			||||||
    warehouse_id                 varchar
 | 
					    warehouse_id     varchar,
 | 
				
			||||||
 | 
					    auth_data_json   jsonb generated always as (
 | 
				
			||||||
 | 
					        CASE
 | 
				
			||||||
 | 
					            WHEN ((auth_data)::text IS JSON) THEN (auth_data)::jsonb
 | 
				
			||||||
 | 
					            ELSE NULL::jsonb
 | 
				
			||||||
 | 
					            END) stored
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
@@ -5,4 +5,5 @@ type Marketplace struct {
 | 
				
			|||||||
	BaseMarketplace int    `json:"base_marketplace"`
 | 
						BaseMarketplace int    `json:"base_marketplace"`
 | 
				
			||||||
	AuthData        string `json:"auth_data"`
 | 
						AuthData        string `json:"auth_data"`
 | 
				
			||||||
	WarehouseID     string `json:"warehouse_id"`
 | 
						WarehouseID     string `json:"warehouse_id"`
 | 
				
			||||||
 | 
						AuthDataJson    []byte `json:"auth_data_json,omitempty"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,5 +24,6 @@ func (r *dbRepository) GetMarketplaceByID(ctx context.Context, id int) (*Marketp
 | 
				
			|||||||
		BaseMarketplace: int(marketplace.BaseMarketplace),
 | 
							BaseMarketplace: int(marketplace.BaseMarketplace),
 | 
				
			||||||
		AuthData:        marketplace.AuthData.String,
 | 
							AuthData:        marketplace.AuthData.String,
 | 
				
			||||||
		WarehouseID:     marketplace.WarehouseID.String,
 | 
							WarehouseID:     marketplace.WarehouseID.String,
 | 
				
			||||||
 | 
							AuthDataJson:    marketplace.AuthDataJson,
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ import (
 | 
				
			|||||||
	proto "sipro-mps/api/generated/v1/ozon/products"
 | 
						proto "sipro-mps/api/generated/v1/ozon/products"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//go:generate go run github.com/jmattheis/goverter/cmd/goverter gen  -g 'ignoreUnexported yes' .
 | 
					//go:generate go run github.com/jmattheis/goverter/cmd/goverter gen  -global "ignoreUnexported yes" .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// goverter:converter
 | 
					// goverter:converter
 | 
				
			||||||
// goverter:extend Int632ToInt64
 | 
					// goverter:extend Int632ToInt64
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,9 +5,8 @@ package generated
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	ozon "git.denco.store/fakz9/ozon-api-client/ozon"
 | 
						ozon "git.denco.store/fakz9/ozon-api-client/ozon"
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	products "sipro-mps/api/generated/v1/ozon/products"
 | 
						products "sipro-mps/api/generated/v1/ozon/products"
 | 
				
			||||||
	ozon "git.denco.store/fakz9/ozon-api-client/ozon"
 | 
						mapping "sipro-mps/internal/ozon/products/mapping"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ConverterImpl struct{}
 | 
					type ConverterImpl struct{}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,7 +85,7 @@ func (a *apiRepository) GetAllProducts(ctx context.Context, marketplaceId int) (
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	items := []OzonProduct{}
 | 
						var items []OzonProduct
 | 
				
			||||||
	productIdsChan := make(chan []int64)
 | 
						productIdsChan := make(chan []int64)
 | 
				
			||||||
	producsChan := make(chan []OzonProduct)
 | 
						producsChan := make(chan []OzonProduct)
 | 
				
			||||||
	errChan := make(chan error)
 | 
						errChan := make(chan error)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,7 @@ func (t *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, error
 | 
				
			|||||||
	waitTime, err := rateLimiterScript.Exec(ctx, *redis.Client, []string{clientId}, []string{
 | 
						waitTime, err := rateLimiterScript.Exec(ctx, *redis.Client, []string{clientId}, []string{
 | 
				
			||||||
		fmt.Sprintf("%d", now),
 | 
							fmt.Sprintf("%d", now),
 | 
				
			||||||
		fmt.Sprintf("%d", int64(windowSize)),
 | 
							fmt.Sprintf("%d", int64(windowSize)),
 | 
				
			||||||
		fmt.Sprintf("%d", 50),
 | 
							fmt.Sprintf("%d", rps),
 | 
				
			||||||
	}).ToInt64()
 | 
						}).ToInt64()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("failed to execute rate limit script: %w", err)
 | 
							return nil, fmt.Errorf("failed to execute rate limit script: %w", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ var Client *rueidis.Client
 | 
				
			|||||||
func InitClient(ctx context.Context) error {
 | 
					func InitClient(ctx context.Context) error {
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	host := os.Getenv("REDIS_HOST")
 | 
						host := os.Getenv("REDIS_HOST")
 | 
				
			||||||
 | 
						//host := "redis"
 | 
				
			||||||
	port := os.Getenv("REDIS_PORT")
 | 
						port := os.Getenv("REDIS_PORT")
 | 
				
			||||||
	password := os.Getenv("REDIS_PASSWORD")
 | 
						password := os.Getenv("REDIS_PASSWORD")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								internal/redis/lock.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								internal/redis/lock.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					package redis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/redis/rueidis"
 | 
				
			||||||
 | 
						"github.com/redis/rueidis/rueidislock"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var Locker *rueidislock.Locker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func InitLocker() error {
 | 
				
			||||||
 | 
						redisAddr := os.Getenv("REDIS_ADDR")
 | 
				
			||||||
 | 
						password := os.Getenv("REDIS_PASSWORD")
 | 
				
			||||||
 | 
						locker, err := rueidislock.NewLocker(rueidislock.LockerOption{
 | 
				
			||||||
 | 
							ClientOption: rueidis.ClientOption{InitAddress: []string{redisAddr}, Password: password},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						Locker = &locker
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func CloseLocker() {
 | 
				
			||||||
 | 
						if Locker != nil {
 | 
				
			||||||
 | 
							(*Locker).Close()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						Locker = nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								internal/tasks/client/client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								internal/tasks/client/client.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					package client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/hibiken/asynq"
 | 
				
			||||||
 | 
						"sipro-mps/internal/config"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var Client *asynq.Client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// InitClient initializes the Asynq client with the provided Redis configuration.
 | 
				
			||||||
 | 
					func InitClient(redisConfig config.RedisConfig) {
 | 
				
			||||||
 | 
						client := asynq.NewClient(asynq.RedisClientOpt{
 | 
				
			||||||
 | 
							Addr:     redisConfig.Addr,
 | 
				
			||||||
 | 
							Password: redisConfig.Password,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						Client = client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func CloseClient() {
 | 
				
			||||||
 | 
						if Client != nil {
 | 
				
			||||||
 | 
							if err := Client.Close(); err != nil {
 | 
				
			||||||
 | 
								panic(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								internal/tasks/server/server.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								internal/tasks/server/server.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					package server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/hibiken/asynq"
 | 
				
			||||||
 | 
						"github.com/jackc/pgx/v5/pgxpool"
 | 
				
			||||||
 | 
						"sipro-mps/internal/config"
 | 
				
			||||||
 | 
						"sipro-mps/internal/tasks/types"
 | 
				
			||||||
 | 
						"sipro-mps/internal/tasks/wb"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AsynqServer struct {
 | 
				
			||||||
 | 
						redisConfig *config.RedisConfig
 | 
				
			||||||
 | 
						dbpool      *pgxpool.Pool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewAsynqServer(redisConfig *config.RedisConfig, dbpool *pgxpool.Pool) *AsynqServer {
 | 
				
			||||||
 | 
						return &AsynqServer{
 | 
				
			||||||
 | 
							redisConfig: redisConfig,
 | 
				
			||||||
 | 
							dbpool:      dbpool,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (s *AsynqServer) createMux() *asynq.ServeMux {
 | 
				
			||||||
 | 
						mux := asynq.NewServeMux()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Register task handlers here
 | 
				
			||||||
 | 
						mux.Handle(types.TypeWbFetchProducts, &wb.FetchProductsProcessor{Dbpool: s.dbpool})
 | 
				
			||||||
 | 
						return mux
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *AsynqServer) Run() {
 | 
				
			||||||
 | 
						srv := asynq.NewServer(
 | 
				
			||||||
 | 
							asynq.RedisClientOpt{Addr: s.redisConfig.Addr, Password: s.redisConfig.Password},
 | 
				
			||||||
 | 
							asynq.Config{Concurrency: 10},
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						mux := s.createMux()
 | 
				
			||||||
 | 
						if err := srv.Run(mux); err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								internal/tasks/types/common.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								internal/tasks/types/common.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					package types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						TypeWbFetchProducts = "wb:fetch_products"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										19
									
								
								internal/tasks/types/wb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								internal/tasks/types/wb.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					package types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"github.com/hibiken/asynq"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type FetchProductsTask struct {
 | 
				
			||||||
 | 
						MarketplaceId int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewFetchProductsTask(marketplaceId int) (*asynq.Task, error) {
 | 
				
			||||||
 | 
						payload, err := json.Marshal(&FetchProductsTask{MarketplaceId: marketplaceId})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return asynq.NewTask(TypeWbFetchProducts, payload, asynq.MaxRetry(2), asynq.Timeout(20*time.Minute)), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										65
									
								
								internal/tasks/wb/wb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								internal/tasks/wb/wb.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					package wb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/hibiken/asynq"
 | 
				
			||||||
 | 
						"github.com/jackc/pgx/v5/pgxpool"
 | 
				
			||||||
 | 
						"github.com/samber/lo"
 | 
				
			||||||
 | 
						pb "sipro-mps/api/generated/v1/wb/products"
 | 
				
			||||||
 | 
						mp_repo "sipro-mps/internal/marketplace"
 | 
				
			||||||
 | 
						"sipro-mps/internal/redis"
 | 
				
			||||||
 | 
						"sipro-mps/internal/tasks/types"
 | 
				
			||||||
 | 
						wb_products_repo "sipro-mps/internal/wb/products"
 | 
				
			||||||
 | 
						conv "sipro-mps/internal/wb/products/mapping/generated"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type FetchProductsProcessor struct {
 | 
				
			||||||
 | 
						Dbpool *pgxpool.Pool
 | 
				
			||||||
 | 
						wbRepo wb_products_repo.Repository
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *FetchProductsProcessor) ProcessTask(ctx context.Context, task *asynq.Task) error {
 | 
				
			||||||
 | 
						var payload types.FetchProductsTask
 | 
				
			||||||
 | 
						if err := json.Unmarshal(task.Payload(), &payload); err != nil {
 | 
				
			||||||
 | 
							return asynq.SkipRetry
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						marketplaceRepo := mp_repo.NewDBRepository(p.Dbpool)
 | 
				
			||||||
 | 
						repo := wb_products_repo.NewAPIRepository(marketplaceRepo)
 | 
				
			||||||
 | 
						_, sellerId, err := repo.ParseMarketplace(ctx, payload.MarketplaceId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("failed to parse marketplace %d: %w", payload.MarketplaceId, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						locker := *redis.Locker
 | 
				
			||||||
 | 
						_, cancel, err := locker.TryWithContext(ctx, fmt.Sprintf("wb:products:marketplace:%s:lock", sellerId))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							fmt.Printf("Failed to acquire lock for marketplace %s: %v\n", sellerId, err)
 | 
				
			||||||
 | 
							return asynq.SkipRetry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fmt.Println("Working on marketplace", payload.MarketplaceId, "with seller ID", sellerId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						redisKey := fmt.Sprintf("wb:products:%s", sellerId)
 | 
				
			||||||
 | 
						productsRaw, err := repo.GetAllProducts(ctx, payload.MarketplaceId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("failed to fetch products for marketplace %d: %w", payload.MarketplaceId, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						converter := conv.ConverterImpl{}
 | 
				
			||||||
 | 
						products := lo.Map(productsRaw, func(item wb_products_repo.WbProduct, _ int) *pb.Product {
 | 
				
			||||||
 | 
							return converter.ToProto(&item)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						redisClient := *redis.Client
 | 
				
			||||||
 | 
						productsJson, err := json.Marshal(products)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("failed to marshal products: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = redisClient.Do(ctx, redisClient.B().Set().Key(redisKey).Value(string(productsJson)).Build()).Error()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										59
									
								
								internal/wb/common.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								internal/wb/common.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					package wb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/golang-jwt/jwt/v5"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"sipro-mps/internal/marketplace"
 | 
				
			||||||
 | 
						wbclient "sipro-mps/pkg/api/wb/client"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type WbAuthData struct {
 | 
				
			||||||
 | 
						Token string `json:"token"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewWbAuthData(token string) WbAuthData {
 | 
				
			||||||
 | 
						return WbAuthData{
 | 
				
			||||||
 | 
							Token: token,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func DecodeWildberriesJwt(token []byte) (WbAuthData, jwt.MapClaims, error) {
 | 
				
			||||||
 | 
						var authData WbAuthData
 | 
				
			||||||
 | 
						err := json.Unmarshal(token, &authData)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return authData, nil, fmt.Errorf("failed to unmarshal JWT: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						claims := jwt.MapClaims{}
 | 
				
			||||||
 | 
						_, _, err = jwt.NewParser().ParseUnverified(authData.Token, claims)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return authData, nil, fmt.Errorf("invalid JWT: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return authData, claims, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetClientFromMarketplace(mp *marketplace.Marketplace) (*wbclient.Client, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						authData, claims, err := DecodeWildberriesJwt(mp.AuthDataJson)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("failed to decode Wildberries JWT")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						exp := claims["exp"].(float64)
 | 
				
			||||||
 | 
						// chec if token is expired, for now unix date
 | 
				
			||||||
 | 
						now := float64(time.Now().Unix())
 | 
				
			||||||
 | 
						if exp < now {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("token is expired")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						securityHandler := NewWildberriesSecurityHandler(authData.Token)
 | 
				
			||||||
 | 
						httpClient := &http.Client{
 | 
				
			||||||
 | 
							Transport: NewRateLimitTransport(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						client, err := wbclient.NewClient("https://content-api.wildberries.ru", securityHandler, wbclient.WithClient(httpClient))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("failed to create Wildberries client: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return client, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										63
									
								
								internal/wb/products/adapter_grpc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								internal/wb/products/adapter_grpc.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					package products
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/samber/lo"
 | 
				
			||||||
 | 
						"google.golang.org/grpc"
 | 
				
			||||||
 | 
						pb "sipro-mps/api/generated/v1/wb/products"
 | 
				
			||||||
 | 
						"sipro-mps/internal/marketplace"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AdapterGRPC struct {
 | 
				
			||||||
 | 
						pb.UnimplementedProductsServiceServer
 | 
				
			||||||
 | 
						repo Repository
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewAdapterGRPC(repo Repository) *AdapterGRPC {
 | 
				
			||||||
 | 
						return &AdapterGRPC{
 | 
				
			||||||
 | 
							repo: repo,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func RegisterAdapterGRPC(server *grpc.Server, marketplacesRepository marketplace.Repository) (*Repository, error) {
 | 
				
			||||||
 | 
						repo := NewAPIRepository(marketplacesRepository)
 | 
				
			||||||
 | 
						adapter := NewAdapterGRPC(repo)
 | 
				
			||||||
 | 
						pb.RegisterProductsServiceServer(server, adapter)
 | 
				
			||||||
 | 
						return &repo, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (a *AdapterGRPC) GetProducts(req *pb.GetProductsRequest, stream pb.ProductsService_GetProductsServer) error {
 | 
				
			||||||
 | 
						ctx := stream.Context()
 | 
				
			||||||
 | 
						resultChan := make(chan []pb.Product)
 | 
				
			||||||
 | 
						errChan := make(chan error)
 | 
				
			||||||
 | 
						go a.repo.StreamAllProductsCache(ctx, int(req.MarketplaceId), resultChan, errChan)
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							select {
 | 
				
			||||||
 | 
							case <-ctx.Done():
 | 
				
			||||||
 | 
								fmt.Println("context done")
 | 
				
			||||||
 | 
								return ctx.Err()
 | 
				
			||||||
 | 
							case products, ok := <-resultChan:
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									fmt.Println("result channel closed")
 | 
				
			||||||
 | 
									return nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								resp := &pb.GetProductsResponse{
 | 
				
			||||||
 | 
									Products: lo.Map(products, func(p pb.Product, _ int) *pb.Product {
 | 
				
			||||||
 | 
										return &p
 | 
				
			||||||
 | 
									}),
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if err := stream.Send(resp); err != nil {
 | 
				
			||||||
 | 
									fmt.Println("error sending response", err)
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case err, ok := <-errChan:
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									return nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if ok && err != nil {
 | 
				
			||||||
 | 
									fmt.Println("error in channel", err)
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								internal/wb/products/entities.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								internal/wb/products/entities.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					package products
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						pb "sipro-mps/api/generated/v1/wb/products"
 | 
				
			||||||
 | 
						"sipro-mps/pkg/api/wb/client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type WbProduct = api.ContentV2GetCardsListPostOKCardsItem
 | 
				
			||||||
 | 
					type PbProduct = pb.Product
 | 
				
			||||||
							
								
								
									
										28
									
								
								internal/wb/products/mapping/converter.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								internal/wb/products/mapping/converter.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					package mapping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import wbclient "sipro-mps/pkg/api/wb/client"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// import (
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	proto "sipro-mps/api/generated/v1/wb/products"
 | 
				
			||||||
 | 
					//	internal "sipro-mps/internal/wb/products"
 | 
				
			||||||
 | 
					//	wbclient "sipro-mps/pkg/api/wb/client"
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// )
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// //go:generate go run github.com/jmattheis/goverter/cmd/goverter gen  -global "ignoreUnexported yes" .
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// // goverter:converter
 | 
				
			||||||
 | 
					// // goverter:extend  OptIntToInt64 OptStringToString
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	type Converter interface {
 | 
				
			||||||
 | 
					//		// goverter:ignore state sizeCache unknownFields
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//		ToProto(details *internal.WbProduct) *proto.Product
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
 | 
					func OptIntToInt64(i wbclient.OptInt) int64 {
 | 
				
			||||||
 | 
						return int64(i.Value)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func OptStringToString(s wbclient.OptString) string {
 | 
				
			||||||
 | 
						return s.Value
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								internal/wb/products/mapping/generated/generated.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								internal/wb/products/mapping/generated/generated.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
 | 
				
			||||||
 | 
					//go:build !goverter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package generated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						products "sipro-mps/api/generated/v1/wb/products"
 | 
				
			||||||
 | 
						mapping "sipro-mps/internal/wb/products/mapping"
 | 
				
			||||||
 | 
						client "sipro-mps/pkg/api/wb/client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ConverterImpl struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *ConverterImpl) ToProto(source *client.ContentV2GetCardsListPostOKCardsItem) *products.Product {
 | 
				
			||||||
 | 
						var pProductsProduct *products.Product
 | 
				
			||||||
 | 
						if source != nil {
 | 
				
			||||||
 | 
							var productsProduct products.Product
 | 
				
			||||||
 | 
							productsProduct.NmID = mapping.OptIntToInt64((*source).NmID)
 | 
				
			||||||
 | 
							productsProduct.SubjectID = mapping.OptIntToInt64((*source).SubjectID)
 | 
				
			||||||
 | 
							productsProduct.VendorCode = mapping.OptStringToString((*source).VendorCode)
 | 
				
			||||||
 | 
							if (*source).Sizes != nil {
 | 
				
			||||||
 | 
								productsProduct.Sizes = make([]*products.Product_Size, len((*source).Sizes))
 | 
				
			||||||
 | 
								for i := 0; i < len((*source).Sizes); i++ {
 | 
				
			||||||
 | 
									productsProduct.Sizes[i] = c.apiContentV2GetCardsListPostOKCardsItemSizesItemToPProductsProduct_Size((*source).Sizes[i])
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							pProductsProduct = &productsProduct
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return pProductsProduct
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (c *ConverterImpl) apiContentV2GetCardsListPostOKCardsItemSizesItemToPProductsProduct_Size(source client.ContentV2GetCardsListPostOKCardsItemSizesItem) *products.Product_Size {
 | 
				
			||||||
 | 
						var productsProduct_Size products.Product_Size
 | 
				
			||||||
 | 
						if source.Skus != nil {
 | 
				
			||||||
 | 
							productsProduct_Size.Skus = make([]string, len(source.Skus))
 | 
				
			||||||
 | 
							for i := 0; i < len(source.Skus); i++ {
 | 
				
			||||||
 | 
								productsProduct_Size.Skus[i] = source.Skus[i]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &productsProduct_Size
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										13
									
								
								internal/wb/products/repository.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								internal/wb/products/repository.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					package products
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"sipro-mps/internal/marketplace"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Repository interface {
 | 
				
			||||||
 | 
						GetAllProducts(ctx context.Context, marketplaceId int) ([]WbProduct, error)
 | 
				
			||||||
 | 
						StreamAllProducts(ctx context.Context, marketplaceId int, resultChan chan<- []WbProduct, errChan chan<- error)
 | 
				
			||||||
 | 
						StreamAllProductsCache(ctx context.Context, marketplaceId int, resultChan chan<- []PbProduct, errChan chan<- error)
 | 
				
			||||||
 | 
						ParseMarketplace(ctx context.Context, marketplaceId int) (*marketplace.Marketplace, string, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										224
									
								
								internal/wb/products/repository_api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								internal/wb/products/repository_api.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,224 @@
 | 
				
			|||||||
 | 
					package products
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/go-faster/errors"
 | 
				
			||||||
 | 
						"github.com/redis/rueidis"
 | 
				
			||||||
 | 
						"github.com/samber/lo"
 | 
				
			||||||
 | 
						pb "sipro-mps/api/generated/v1/wb/products"
 | 
				
			||||||
 | 
						"sipro-mps/internal/marketplace"
 | 
				
			||||||
 | 
						"sipro-mps/internal/redis"
 | 
				
			||||||
 | 
						"sipro-mps/internal/tasks/client"
 | 
				
			||||||
 | 
						"sipro-mps/internal/tasks/types"
 | 
				
			||||||
 | 
						"sipro-mps/internal/wb"
 | 
				
			||||||
 | 
						"sipro-mps/internal/wb/products/mapping/generated"
 | 
				
			||||||
 | 
						wbapi "sipro-mps/pkg/api/wb/client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						maxRetries            = 5
 | 
				
			||||||
 | 
						maxProductsPerRequest = 100
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type apiRepository struct {
 | 
				
			||||||
 | 
						marketplaceRepository marketplace.Repository
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a apiRepository) ParseMarketplace(ctx context.Context, marketplaceId int) (*marketplace.Marketplace, string, error) {
 | 
				
			||||||
 | 
						marketplaceByID, err := a.marketplaceRepository.GetMarketplaceByID(ctx, marketplaceId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, claims, err := wb.DecodeWildberriesJwt(marketplaceByID.AuthDataJson)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sellerId := claims["sid"].(string)
 | 
				
			||||||
 | 
						return marketplaceByID, sellerId, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func fetchProducts(
 | 
				
			||||||
 | 
						ctx context.Context,
 | 
				
			||||||
 | 
						client *wbapi.Client,
 | 
				
			||||||
 | 
						sellerId string,
 | 
				
			||||||
 | 
						resultChan chan<- []WbProduct,
 | 
				
			||||||
 | 
						errChan chan<- error,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
						defer close(resultChan)
 | 
				
			||||||
 | 
						defer close(errChan)
 | 
				
			||||||
 | 
						request := wbapi.ContentV2GetCardsListPostReq{}
 | 
				
			||||||
 | 
						request.Settings.SetTo(wbapi.ContentV2GetCardsListPostReqSettings{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						request.Settings.Value.Cursor.SetTo(wbapi.ContentV2GetCardsListPostReqSettingsCursor{})
 | 
				
			||||||
 | 
						request.Settings.Value.Cursor.Value.Limit.SetTo(maxProductsPerRequest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						request.Settings.Value.Filter.SetTo(wbapi.ContentV2GetCardsListPostReqSettingsFilter{})
 | 
				
			||||||
 | 
						request.Settings.Value.Filter.Value.WithPhoto.SetTo(-1)
 | 
				
			||||||
 | 
						currentRetry := 0
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							response, err := client.ContentV2GetCardsListPost(ctx, &request, wbapi.ContentV2GetCardsListPostParams{Locale: wbapi.NewOptString("ru")})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								currentRetry++
 | 
				
			||||||
 | 
								if currentRetry >= maxRetries {
 | 
				
			||||||
 | 
									errChan <- fmt.Errorf("fetching product IDs: %w", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							currentRetry = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch r := response.(type) {
 | 
				
			||||||
 | 
							case *wbapi.ContentV2GetCardsListPostOKHeaders:
 | 
				
			||||||
 | 
								err = wb.SyncRateLimitRemaining(ctx, sellerId, r.XRatelimitRemaining.Value)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									errChan <- fmt.Errorf("syncing rate limit: %w", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								resultChan <- r.Response.Cards
 | 
				
			||||||
 | 
								if r.Response.Cursor.Value.Total.Value < maxProductsPerRequest {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								request.Settings.Value.Cursor.Value.UpdatedAt.SetTo(r.Response.Cursor.Value.UpdatedAt.Value)
 | 
				
			||||||
 | 
								request.Settings.Value.Cursor.Value.NmID.SetTo(r.Response.Cursor.Value.NmID.Value)
 | 
				
			||||||
 | 
							case *wbapi.R429Headers:
 | 
				
			||||||
 | 
								err = wb.SetRateLimitRetry(ctx, sellerId, r.XRatelimitRetry.Value, r.XRatelimitLimit.Value, r.XRatelimitReset.Value)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									errChan <- fmt.Errorf("setting rate limit retry: %w", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								errChan <- fmt.Errorf("unexpected response type: %T", r)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a apiRepository) StreamAllProductsCache(ctx context.Context, marketplaceId int, resultChan chan<- []pb.Product, errChan chan<- error) {
 | 
				
			||||||
 | 
						defer close(resultChan)
 | 
				
			||||||
 | 
						defer close(errChan)
 | 
				
			||||||
 | 
						_, sellerId, err := a.ParseMarketplace(ctx, marketplaceId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							errChan <- err
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c := *redis.Client
 | 
				
			||||||
 | 
						key := fmt.Sprintf("wb:products:%s", sellerId)
 | 
				
			||||||
 | 
						jsonString, err := c.Do(ctx, c.B().Get().Key(key).Build()).ToString()
 | 
				
			||||||
 | 
						if err == nil && jsonString != "null" {
 | 
				
			||||||
 | 
							var result []pb.Product
 | 
				
			||||||
 | 
							err = json.Unmarshal([]byte(jsonString), &result)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								errChan <- fmt.Errorf("unmarshalling products from cache: %w", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							task, err := types.NewFetchProductsTask(marketplaceId)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								errChan <- fmt.Errorf("creating fetch products task: %w", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_, err = client.Client.Enqueue(task)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								errChan <- fmt.Errorf("enqueueing fetch products task: %w", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							resultChan <- result
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !errors.As(err, &rueidis.Nil) && err != nil {
 | 
				
			||||||
 | 
							errChan <- fmt.Errorf("fetching products from cache: %w", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						converter := generated.ConverterImpl{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						innerResultChan := make(chan []WbProduct)
 | 
				
			||||||
 | 
						innerErrChan := make(chan error)
 | 
				
			||||||
 | 
						go a.StreamAllProducts(ctx, marketplaceId, innerResultChan, innerErrChan)
 | 
				
			||||||
 | 
						var allProducts []pb.Product
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							jsonData, err := json.Marshal(allProducts)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								errChan <- fmt.Errorf("marshalling products to cache: %w", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err = c.Do(ctx, c.B().Set().Key(key).Value(string(jsonData)).Build()).Error()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								errChan <- fmt.Errorf("setting products to cache: %w", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							select {
 | 
				
			||||||
 | 
							case err, ok := <-innerErrChan:
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								errChan <- fmt.Errorf("streaming products: %w", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							case products, ok := <-innerResultChan:
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								pbProducts := lo.Map(products, func(p WbProduct, _ int) pb.Product {
 | 
				
			||||||
 | 
									return *converter.ToProto(&p)
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								allProducts = append(allProducts, pbProducts...)
 | 
				
			||||||
 | 
								resultChan <- pbProducts
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (a apiRepository) GetAllProducts(ctx context.Context, marketplaceId int) ([]WbProduct, error) {
 | 
				
			||||||
 | 
						marketplaceByID, sellerId, err := a.ParseMarketplace(ctx, marketplaceId)
 | 
				
			||||||
 | 
						fromMarketplace, err := wb.GetClientFromMarketplace(marketplaceByID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						resultChan := make(chan []WbProduct)
 | 
				
			||||||
 | 
						errChan := make(chan error)
 | 
				
			||||||
 | 
						go fetchProducts(ctx, fromMarketplace, sellerId, resultChan, errChan)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var products []WbProduct
 | 
				
			||||||
 | 
						isWaiting := true
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							if !isWaiting {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							select {
 | 
				
			||||||
 | 
							case err, ok := <-errChan:
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									isWaiting = false
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							case newProducts, ok := <-resultChan:
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									isWaiting = false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								products = append(products, newProducts...)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return products, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a apiRepository) StreamAllProducts(ctx context.Context, marketplaceId int, resultChan chan<- []WbProduct, errChan chan<- error) {
 | 
				
			||||||
 | 
						marketplaceByID, sellerId, err := a.ParseMarketplace(ctx, marketplaceId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							errChan <- err
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fromMarketplace, err := wb.GetClientFromMarketplace(marketplaceByID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							errChan <- err
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						go fetchProducts(ctx, fromMarketplace, sellerId, resultChan, errChan)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewAPIRepository(marketplaceRepository marketplace.Repository) Repository {
 | 
				
			||||||
 | 
						return &apiRepository{
 | 
				
			||||||
 | 
							marketplaceRepository: marketplaceRepository,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										170
									
								
								internal/wb/rate_limiter.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								internal/wb/rate_limiter.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,170 @@
 | 
				
			|||||||
 | 
					package wb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/redis/rueidis"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"sipro-mps/internal/redis"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						defaultBucketCapacity = 10            // max burst size
 | 
				
			||||||
 | 
						refillRate            = 100.0 / 60000 // 300 requests per minute → 1 token per 200ms
 | 
				
			||||||
 | 
						tokenTTLMillis        = 60000         // Redis key TTL: 60s
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var tokenBucketScript = rueidis.NewLuaScript(`
 | 
				
			||||||
 | 
					local key = KEYS[1]
 | 
				
			||||||
 | 
					local now = tonumber(ARGV[1])
 | 
				
			||||||
 | 
					local default_capacity = tonumber(ARGV[2])
 | 
				
			||||||
 | 
					local refill_rate = tonumber(ARGV[3])
 | 
				
			||||||
 | 
					local ttl = tonumber(ARGV[4])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Retry lock
 | 
				
			||||||
 | 
					local retry_key = key .. ":retry_until"
 | 
				
			||||||
 | 
					local retry_until = tonumber(redis.call("GET", retry_key))
 | 
				
			||||||
 | 
					if retry_until and now < retry_until then
 | 
				
			||||||
 | 
						return retry_until - now
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Token Bucket
 | 
				
			||||||
 | 
					local capacity_key = key .. ":capacity"
 | 
				
			||||||
 | 
					local token_key = key .. ":tokens"
 | 
				
			||||||
 | 
					local time_key = key .. ":last_refill"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local capacity = tonumber(redis.call("GET", capacity_key)) or default_capacity
 | 
				
			||||||
 | 
					local tokens = tonumber(redis.call("GET", token_key))
 | 
				
			||||||
 | 
					local last_refill = tonumber(redis.call("GET", time_key))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if tokens == nil then tokens = capacity end
 | 
				
			||||||
 | 
					if last_refill == nil then last_refill = now end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local elapsed = now - last_refill
 | 
				
			||||||
 | 
					local refill = elapsed * refill_rate
 | 
				
			||||||
 | 
					tokens = math.min(capacity, tokens + refill)
 | 
				
			||||||
 | 
					last_refill = now
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if tokens >= 1 then
 | 
				
			||||||
 | 
						tokens = tokens - 1
 | 
				
			||||||
 | 
						redis.call("SET", token_key, tokens)
 | 
				
			||||||
 | 
						redis.call("SET", time_key, last_refill)
 | 
				
			||||||
 | 
						redis.call("PEXPIRE", token_key, ttl)
 | 
				
			||||||
 | 
						redis.call("PEXPIRE", time_key, ttl)
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						local wait_time = math.ceil((1 - tokens) / refill_rate)
 | 
				
			||||||
 | 
						return wait_time
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type RateLimitTransport struct {
 | 
				
			||||||
 | 
						http.RoundTripper
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
 | 
						ctx := req.Context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokenString := req.Header.Get("Authorization")
 | 
				
			||||||
 | 
						authData := NewWbAuthData(tokenString)
 | 
				
			||||||
 | 
						authDataBytes, err := json.Marshal(authData)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("failed to marshal Wildberries auth data: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, claims, err := DecodeWildberriesJwt(authDataBytes)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("failed to decode Wildberries JWT: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sellerId := claims["sid"].(string)
 | 
				
			||||||
 | 
						if sellerId == "" {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("sellerId is required in JWT claims")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						now := time.Now().UnixMilli()
 | 
				
			||||||
 | 
						client := *redis.Client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						waitTime, err := tokenBucketScript.Exec(ctx, client, []string{sellerId}, []string{
 | 
				
			||||||
 | 
							fmt.Sprintf("%d", now),
 | 
				
			||||||
 | 
							fmt.Sprintf("%d", defaultBucketCapacity),
 | 
				
			||||||
 | 
							fmt.Sprintf("%f", refillRate),
 | 
				
			||||||
 | 
							fmt.Sprintf("%d", tokenTTLMillis),
 | 
				
			||||||
 | 
						}).ToInt64()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("rate limit script error: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if waitTime > 0 {
 | 
				
			||||||
 | 
							select {
 | 
				
			||||||
 | 
							case <-time.After(time.Duration(waitTime) * time.Millisecond):
 | 
				
			||||||
 | 
							case <-ctx.Done():
 | 
				
			||||||
 | 
								return nil, ctx.Err()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return t.RoundTripper.RoundTrip(req)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func SyncRateLimitRemaining(ctx context.Context, sellerId string, remaining int) error {
 | 
				
			||||||
 | 
						if sellerId == "" || remaining < 0 {
 | 
				
			||||||
 | 
							return fmt.Errorf("invalid sellerId or remaining")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						now := time.Now().UnixMilli()
 | 
				
			||||||
 | 
						client := *redis.Client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmds := []rueidis.Completed{
 | 
				
			||||||
 | 
							client.B().Set().Key(sellerId + ":capacity").Value(fmt.Sprintf("%d", defaultBucketCapacity)).Ex(time.Minute).Build(),
 | 
				
			||||||
 | 
							client.B().Set().Key(sellerId + ":tokens").Value(fmt.Sprintf("%d", remaining)).Ex(time.Minute).Build(),
 | 
				
			||||||
 | 
							client.B().Set().Key(sellerId + ":last_refill").Value(fmt.Sprintf("%d", now)).Ex(time.Minute).Build(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						results := client.DoMulti(ctx, cmds...)
 | 
				
			||||||
 | 
						for _, res := range results {
 | 
				
			||||||
 | 
							if res.Error() != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("failed to sync rate limit: %w", res.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func SetRateLimitRetry(ctx context.Context, sellerId string, retrySeconds int, limit int, resetSeconds int) error {
 | 
				
			||||||
 | 
						if sellerId == "" {
 | 
				
			||||||
 | 
							return fmt.Errorf("sellerId is required")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						now := time.Now()
 | 
				
			||||||
 | 
						retryUntil := now.Add(time.Duration(retrySeconds) * time.Second).UnixMilli()
 | 
				
			||||||
 | 
						client := *redis.Client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmds := []rueidis.Completed{
 | 
				
			||||||
 | 
							client.B().Set().
 | 
				
			||||||
 | 
								Key(sellerId + ":retry_until").
 | 
				
			||||||
 | 
								Value(fmt.Sprintf("%d", retryUntil)).
 | 
				
			||||||
 | 
								Px(time.Duration(retrySeconds+5) * time.Second).Build(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if limit > 0 {
 | 
				
			||||||
 | 
							cmds = append(cmds, client.B().Set().
 | 
				
			||||||
 | 
								Key(sellerId+":capacity").
 | 
				
			||||||
 | 
								Value(fmt.Sprintf("%d", limit)).
 | 
				
			||||||
 | 
								Ex(time.Hour).Build())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resetSeconds > 0 {
 | 
				
			||||||
 | 
							resetAt := now.Add(time.Duration(resetSeconds) * time.Second)
 | 
				
			||||||
 | 
							fmt.Printf("Seller %s rate limit resets at %v (limit: %d)\n", sellerId, resetAt, limit)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						results := client.DoMulti(ctx, cmds...)
 | 
				
			||||||
 | 
						for _, res := range results {
 | 
				
			||||||
 | 
							if res.Error() != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("failed to set retry info: %w", res.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewRateLimitTransport() *RateLimitTransport {
 | 
				
			||||||
 | 
						return &RateLimitTransport{RoundTripper: http.DefaultTransport}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								internal/wb/security_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								internal/wb/security_handler.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					package wb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						wbclient "sipro-mps/pkg/api/wb/client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type WildberriesSecurityHandler struct {
 | 
				
			||||||
 | 
						ApiKey string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sh WildberriesSecurityHandler) HeaderApiKey(ctx context.Context, operationName wbclient.OperationName, client *wbclient.Client) (wbclient.HeaderApiKey, error) {
 | 
				
			||||||
 | 
						return wbclient.HeaderApiKey{
 | 
				
			||||||
 | 
							APIKey: sh.ApiKey,
 | 
				
			||||||
 | 
							Roles:  nil,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func NewWildberriesSecurityHandler(apiKey string) WildberriesSecurityHandler {
 | 
				
			||||||
 | 
						return WildberriesSecurityHandler{
 | 
				
			||||||
 | 
							ApiKey: apiKey,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								internal/wb/types.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								internal/wb/types.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					package wb
 | 
				
			||||||
							
								
								
									
										5572
									
								
								pkg/api/wb/02-products.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5572
									
								
								pkg/api/wb/02-products.yaml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										283
									
								
								pkg/api/wb/client/oas_cfg_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								pkg/api/wb/client/oas_cfg_gen.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,283 @@
 | 
				
			|||||||
 | 
					// Code generated by ogen, DO NOT EDIT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"go.opentelemetry.io/otel"
 | 
				
			||||||
 | 
						"go.opentelemetry.io/otel/metric"
 | 
				
			||||||
 | 
						"go.opentelemetry.io/otel/trace"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ht "github.com/ogen-go/ogen/http"
 | 
				
			||||||
 | 
						"github.com/ogen-go/ogen/middleware"
 | 
				
			||||||
 | 
						"github.com/ogen-go/ogen/ogenerrors"
 | 
				
			||||||
 | 
						"github.com/ogen-go/ogen/otelogen"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						// Allocate option closure once.
 | 
				
			||||||
 | 
						clientSpanKind = trace.WithSpanKind(trace.SpanKindClient)
 | 
				
			||||||
 | 
						// Allocate option closure once.
 | 
				
			||||||
 | 
						serverSpanKind = trace.WithSpanKind(trace.SpanKindServer)
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type (
 | 
				
			||||||
 | 
						optionFunc[C any] func(*C)
 | 
				
			||||||
 | 
						otelOptionFunc    func(*otelConfig)
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type otelConfig struct {
 | 
				
			||||||
 | 
						TracerProvider trace.TracerProvider
 | 
				
			||||||
 | 
						Tracer         trace.Tracer
 | 
				
			||||||
 | 
						MeterProvider  metric.MeterProvider
 | 
				
			||||||
 | 
						Meter          metric.Meter
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (cfg *otelConfig) initOTEL() {
 | 
				
			||||||
 | 
						if cfg.TracerProvider == nil {
 | 
				
			||||||
 | 
							cfg.TracerProvider = otel.GetTracerProvider()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if cfg.MeterProvider == nil {
 | 
				
			||||||
 | 
							cfg.MeterProvider = otel.GetMeterProvider()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name,
 | 
				
			||||||
 | 
							trace.WithInstrumentationVersion(otelogen.SemVersion()),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name,
 | 
				
			||||||
 | 
							metric.WithInstrumentationVersion(otelogen.SemVersion()),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ErrorHandler is error handler.
 | 
				
			||||||
 | 
					type ErrorHandler = ogenerrors.ErrorHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type serverConfig struct {
 | 
				
			||||||
 | 
						otelConfig
 | 
				
			||||||
 | 
						NotFound           http.HandlerFunc
 | 
				
			||||||
 | 
						MethodNotAllowed   func(w http.ResponseWriter, r *http.Request, allowed string)
 | 
				
			||||||
 | 
						ErrorHandler       ErrorHandler
 | 
				
			||||||
 | 
						Prefix             string
 | 
				
			||||||
 | 
						Middleware         Middleware
 | 
				
			||||||
 | 
						MaxMultipartMemory int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ServerOption is server config option.
 | 
				
			||||||
 | 
					type ServerOption interface {
 | 
				
			||||||
 | 
						applyServer(*serverConfig)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ ServerOption = (optionFunc[serverConfig])(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (o optionFunc[C]) applyServer(c *C) {
 | 
				
			||||||
 | 
						o(c)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ ServerOption = (otelOptionFunc)(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (o otelOptionFunc) applyServer(c *serverConfig) {
 | 
				
			||||||
 | 
						o(&c.otelConfig)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newServerConfig(opts ...ServerOption) serverConfig {
 | 
				
			||||||
 | 
						cfg := serverConfig{
 | 
				
			||||||
 | 
							NotFound: http.NotFound,
 | 
				
			||||||
 | 
							MethodNotAllowed: func(w http.ResponseWriter, r *http.Request, allowed string) {
 | 
				
			||||||
 | 
								status := http.StatusMethodNotAllowed
 | 
				
			||||||
 | 
								if r.Method == "OPTIONS" {
 | 
				
			||||||
 | 
									w.Header().Set("Access-Control-Allow-Methods", allowed)
 | 
				
			||||||
 | 
									w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
 | 
				
			||||||
 | 
									status = http.StatusNoContent
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									w.Header().Set("Allow", allowed)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								w.WriteHeader(status)
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							ErrorHandler:       ogenerrors.DefaultErrorHandler,
 | 
				
			||||||
 | 
							Middleware:         nil,
 | 
				
			||||||
 | 
							MaxMultipartMemory: 32 << 20, // 32 MB
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, opt := range opts {
 | 
				
			||||||
 | 
							opt.applyServer(&cfg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cfg.initOTEL()
 | 
				
			||||||
 | 
						return cfg
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type baseServer struct {
 | 
				
			||||||
 | 
						cfg      serverConfig
 | 
				
			||||||
 | 
						requests metric.Int64Counter
 | 
				
			||||||
 | 
						errors   metric.Int64Counter
 | 
				
			||||||
 | 
						duration metric.Float64Histogram
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s baseServer) notFound(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
						s.cfg.NotFound(w, r)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s baseServer) notAllowed(w http.ResponseWriter, r *http.Request, allowed string) {
 | 
				
			||||||
 | 
						s.cfg.MethodNotAllowed(w, r, allowed)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (cfg serverConfig) baseServer() (s baseServer, err error) {
 | 
				
			||||||
 | 
						s = baseServer{cfg: cfg}
 | 
				
			||||||
 | 
						if s.requests, err = otelogen.ServerRequestCountCounter(s.cfg.Meter); err != nil {
 | 
				
			||||||
 | 
							return s, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if s.errors, err = otelogen.ServerErrorsCountCounter(s.cfg.Meter); err != nil {
 | 
				
			||||||
 | 
							return s, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if s.duration, err = otelogen.ServerDurationHistogram(s.cfg.Meter); err != nil {
 | 
				
			||||||
 | 
							return s, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type clientConfig struct {
 | 
				
			||||||
 | 
						otelConfig
 | 
				
			||||||
 | 
						Client ht.Client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ClientOption is client config option.
 | 
				
			||||||
 | 
					type ClientOption interface {
 | 
				
			||||||
 | 
						applyClient(*clientConfig)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ ClientOption = (optionFunc[clientConfig])(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (o optionFunc[C]) applyClient(c *C) {
 | 
				
			||||||
 | 
						o(c)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ ClientOption = (otelOptionFunc)(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (o otelOptionFunc) applyClient(c *clientConfig) {
 | 
				
			||||||
 | 
						o(&c.otelConfig)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newClientConfig(opts ...ClientOption) clientConfig {
 | 
				
			||||||
 | 
						cfg := clientConfig{
 | 
				
			||||||
 | 
							Client: http.DefaultClient,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, opt := range opts {
 | 
				
			||||||
 | 
							opt.applyClient(&cfg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cfg.initOTEL()
 | 
				
			||||||
 | 
						return cfg
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type baseClient struct {
 | 
				
			||||||
 | 
						cfg      clientConfig
 | 
				
			||||||
 | 
						requests metric.Int64Counter
 | 
				
			||||||
 | 
						errors   metric.Int64Counter
 | 
				
			||||||
 | 
						duration metric.Float64Histogram
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (cfg clientConfig) baseClient() (c baseClient, err error) {
 | 
				
			||||||
 | 
						c = baseClient{cfg: cfg}
 | 
				
			||||||
 | 
						if c.requests, err = otelogen.ClientRequestCountCounter(c.cfg.Meter); err != nil {
 | 
				
			||||||
 | 
							return c, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.errors, err = otelogen.ClientErrorsCountCounter(c.cfg.Meter); err != nil {
 | 
				
			||||||
 | 
							return c, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c.duration, err = otelogen.ClientDurationHistogram(c.cfg.Meter); err != nil {
 | 
				
			||||||
 | 
							return c, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return c, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Option is config option.
 | 
				
			||||||
 | 
					type Option interface {
 | 
				
			||||||
 | 
						ServerOption
 | 
				
			||||||
 | 
						ClientOption
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WithTracerProvider specifies a tracer provider to use for creating a tracer.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If none is specified, the global provider is used.
 | 
				
			||||||
 | 
					func WithTracerProvider(provider trace.TracerProvider) Option {
 | 
				
			||||||
 | 
						return otelOptionFunc(func(cfg *otelConfig) {
 | 
				
			||||||
 | 
							if provider != nil {
 | 
				
			||||||
 | 
								cfg.TracerProvider = provider
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WithMeterProvider specifies a meter provider to use for creating a meter.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If none is specified, the otel.GetMeterProvider() is used.
 | 
				
			||||||
 | 
					func WithMeterProvider(provider metric.MeterProvider) Option {
 | 
				
			||||||
 | 
						return otelOptionFunc(func(cfg *otelConfig) {
 | 
				
			||||||
 | 
							if provider != nil {
 | 
				
			||||||
 | 
								cfg.MeterProvider = provider
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WithClient specifies http client to use.
 | 
				
			||||||
 | 
					func WithClient(client ht.Client) ClientOption {
 | 
				
			||||||
 | 
						return optionFunc[clientConfig](func(cfg *clientConfig) {
 | 
				
			||||||
 | 
							if client != nil {
 | 
				
			||||||
 | 
								cfg.Client = client
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WithNotFound specifies Not Found handler to use.
 | 
				
			||||||
 | 
					func WithNotFound(notFound http.HandlerFunc) ServerOption {
 | 
				
			||||||
 | 
						return optionFunc[serverConfig](func(cfg *serverConfig) {
 | 
				
			||||||
 | 
							if notFound != nil {
 | 
				
			||||||
 | 
								cfg.NotFound = notFound
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WithMethodNotAllowed specifies Method Not Allowed handler to use.
 | 
				
			||||||
 | 
					func WithMethodNotAllowed(methodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string)) ServerOption {
 | 
				
			||||||
 | 
						return optionFunc[serverConfig](func(cfg *serverConfig) {
 | 
				
			||||||
 | 
							if methodNotAllowed != nil {
 | 
				
			||||||
 | 
								cfg.MethodNotAllowed = methodNotAllowed
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WithErrorHandler specifies error handler to use.
 | 
				
			||||||
 | 
					func WithErrorHandler(h ErrorHandler) ServerOption {
 | 
				
			||||||
 | 
						return optionFunc[serverConfig](func(cfg *serverConfig) {
 | 
				
			||||||
 | 
							if h != nil {
 | 
				
			||||||
 | 
								cfg.ErrorHandler = h
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WithPathPrefix specifies server path prefix.
 | 
				
			||||||
 | 
					func WithPathPrefix(prefix string) ServerOption {
 | 
				
			||||||
 | 
						return optionFunc[serverConfig](func(cfg *serverConfig) {
 | 
				
			||||||
 | 
							cfg.Prefix = prefix
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WithMiddleware specifies middlewares to use.
 | 
				
			||||||
 | 
					func WithMiddleware(m ...Middleware) ServerOption {
 | 
				
			||||||
 | 
						return optionFunc[serverConfig](func(cfg *serverConfig) {
 | 
				
			||||||
 | 
							switch len(m) {
 | 
				
			||||||
 | 
							case 0:
 | 
				
			||||||
 | 
								cfg.Middleware = nil
 | 
				
			||||||
 | 
							case 1:
 | 
				
			||||||
 | 
								cfg.Middleware = m[0]
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								cfg.Middleware = middleware.ChainMiddlewares(m...)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WithMaxMultipartMemory specifies limit of memory for storing file parts.
 | 
				
			||||||
 | 
					// File parts which can't be stored in memory will be stored on disk in temporary files.
 | 
				
			||||||
 | 
					func WithMaxMultipartMemory(max int64) ServerOption {
 | 
				
			||||||
 | 
						return optionFunc[serverConfig](func(cfg *serverConfig) {
 | 
				
			||||||
 | 
							if max > 0 {
 | 
				
			||||||
 | 
								cfg.MaxMultipartMemory = max
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6749
									
								
								pkg/api/wb/client/oas_client_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6749
									
								
								pkg/api/wb/client/oas_client_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										8243
									
								
								pkg/api/wb/client/oas_handlers_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8243
									
								
								pkg/api/wb/client/oas_handlers_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										166
									
								
								pkg/api/wb/client/oas_interfaces_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								pkg/api/wb/client/oas_interfaces_gen.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,166 @@
 | 
				
			|||||||
 | 
					// Code generated by ogen, DO NOT EDIT.
 | 
				
			||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV2BufferGoodsTaskGetRes interface {
 | 
				
			||||||
 | 
						aPIV2BufferGoodsTaskGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV2BufferTasksGetRes interface {
 | 
				
			||||||
 | 
						aPIV2BufferTasksGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV2HistoryGoodsTaskGetRes interface {
 | 
				
			||||||
 | 
						aPIV2HistoryGoodsTaskGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV2HistoryTasksGetRes interface {
 | 
				
			||||||
 | 
						aPIV2HistoryTasksGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV2ListGoodsFilterGetRes interface {
 | 
				
			||||||
 | 
						aPIV2ListGoodsFilterGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV2ListGoodsSizeNmGetRes interface {
 | 
				
			||||||
 | 
						aPIV2ListGoodsSizeNmGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV2QuarantineGoodsGetRes interface {
 | 
				
			||||||
 | 
						aPIV2QuarantineGoodsGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV2UploadTaskClubDiscountPostRes interface {
 | 
				
			||||||
 | 
						aPIV2UploadTaskClubDiscountPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV2UploadTaskPostRes interface {
 | 
				
			||||||
 | 
						aPIV2UploadTaskPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV2UploadTaskSizePostRes interface {
 | 
				
			||||||
 | 
						aPIV2UploadTaskSizePostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV3OfficesGetRes interface {
 | 
				
			||||||
 | 
						aPIV3OfficesGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV3StocksWarehouseIdDeleteRes interface {
 | 
				
			||||||
 | 
						aPIV3StocksWarehouseIdDeleteRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV3StocksWarehouseIdPostRes interface {
 | 
				
			||||||
 | 
						aPIV3StocksWarehouseIdPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV3StocksWarehouseIdPutRes interface {
 | 
				
			||||||
 | 
						aPIV3StocksWarehouseIdPutRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV3WarehousesGetRes interface {
 | 
				
			||||||
 | 
						aPIV3WarehousesGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV3WarehousesPostRes interface {
 | 
				
			||||||
 | 
						aPIV3WarehousesPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV3WarehousesWarehouseIdDeleteRes interface {
 | 
				
			||||||
 | 
						aPIV3WarehousesWarehouseIdDeleteRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type APIV3WarehousesWarehouseIdPutRes interface {
 | 
				
			||||||
 | 
						aPIV3WarehousesWarehouseIdPutRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2BarcodesPostRes interface {
 | 
				
			||||||
 | 
						contentV2BarcodesPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2CardsDeleteTrashPostRes interface {
 | 
				
			||||||
 | 
						contentV2CardsDeleteTrashPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2CardsErrorListGetRes interface {
 | 
				
			||||||
 | 
						contentV2CardsErrorListGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2CardsLimitsGetRes interface {
 | 
				
			||||||
 | 
						contentV2CardsLimitsGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2CardsRecoverPostRes interface {
 | 
				
			||||||
 | 
						contentV2CardsRecoverPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2CardsUpdatePostRes interface {
 | 
				
			||||||
 | 
						contentV2CardsUpdatePostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2CardsUploadAddPostRes interface {
 | 
				
			||||||
 | 
						contentV2CardsUploadAddPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2CardsUploadPostRes interface {
 | 
				
			||||||
 | 
						contentV2CardsUploadPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2DirectoryColorsGetRes interface {
 | 
				
			||||||
 | 
						contentV2DirectoryColorsGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2DirectoryCountriesGetRes interface {
 | 
				
			||||||
 | 
						contentV2DirectoryCountriesGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2DirectoryKindsGetRes interface {
 | 
				
			||||||
 | 
						contentV2DirectoryKindsGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2DirectorySeasonsGetRes interface {
 | 
				
			||||||
 | 
						contentV2DirectorySeasonsGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2DirectoryTnvedGetRes interface {
 | 
				
			||||||
 | 
						contentV2DirectoryTnvedGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2DirectoryVatGetRes interface {
 | 
				
			||||||
 | 
						contentV2DirectoryVatGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2GetCardsListPostRes interface {
 | 
				
			||||||
 | 
						contentV2GetCardsListPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2GetCardsTrashPostRes interface {
 | 
				
			||||||
 | 
						contentV2GetCardsTrashPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2ObjectAllGetRes interface {
 | 
				
			||||||
 | 
						contentV2ObjectAllGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2ObjectCharcsSubjectIdGetRes interface {
 | 
				
			||||||
 | 
						contentV2ObjectCharcsSubjectIdGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2ObjectParentAllGetRes interface {
 | 
				
			||||||
 | 
						contentV2ObjectParentAllGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2TagNomenclatureLinkPostRes interface {
 | 
				
			||||||
 | 
						contentV2TagNomenclatureLinkPostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV2TagsGetRes interface {
 | 
				
			||||||
 | 
						contentV2TagsGetRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV3MediaFilePostRes interface {
 | 
				
			||||||
 | 
						contentV3MediaFilePostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContentV3MediaSavePostRes interface {
 | 
				
			||||||
 | 
						contentV3MediaSavePostRes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19793
									
								
								pkg/api/wb/client/oas_json_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19793
									
								
								pkg/api/wb/client/oas_json_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										42
									
								
								pkg/api/wb/client/oas_labeler_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								pkg/api/wb/client/oas_labeler_gen.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					// Code generated by ogen, DO NOT EDIT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"go.opentelemetry.io/otel/attribute"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Labeler is used to allow adding custom attributes to the server request metrics.
 | 
				
			||||||
 | 
					type Labeler struct {
 | 
				
			||||||
 | 
						attrs []attribute.KeyValue
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Add attributes to the Labeler.
 | 
				
			||||||
 | 
					func (l *Labeler) Add(attrs ...attribute.KeyValue) {
 | 
				
			||||||
 | 
						l.attrs = append(l.attrs, attrs...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AttributeSet returns the attributes added to the Labeler as an attribute.Set.
 | 
				
			||||||
 | 
					func (l *Labeler) AttributeSet() attribute.Set {
 | 
				
			||||||
 | 
						return attribute.NewSet(l.attrs...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type labelerContextKey struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LabelerFromContext retrieves the Labeler from the provided context, if present.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If no Labeler was found in the provided context a new, empty Labeler is returned and the second
 | 
				
			||||||
 | 
					// return value is false. In this case it is safe to use the Labeler but any attributes added to
 | 
				
			||||||
 | 
					// it will not be used.
 | 
				
			||||||
 | 
					func LabelerFromContext(ctx context.Context) (*Labeler, bool) {
 | 
				
			||||||
 | 
						if l, ok := ctx.Value(labelerContextKey{}).(*Labeler); ok {
 | 
				
			||||||
 | 
							return l, true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &Labeler{}, false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func contextWithLabeler(ctx context.Context, l *Labeler) context.Context {
 | 
				
			||||||
 | 
						return context.WithValue(ctx, labelerContextKey{}, l)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								pkg/api/wb/client/oas_middleware_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								pkg/api/wb/client/oas_middleware_gen.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					// Code generated by ogen, DO NOT EDIT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/ogen-go/ogen/middleware"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Middleware is middleware type.
 | 
				
			||||||
 | 
					type Middleware = middleware.Middleware
 | 
				
			||||||
							
								
								
									
										50
									
								
								pkg/api/wb/client/oas_operations_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								pkg/api/wb/client/oas_operations_gen.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					// Code generated by ogen, DO NOT EDIT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// OperationName is the ogen operation name
 | 
				
			||||||
 | 
					type OperationName = string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						APIV2BufferGoodsTaskGetOperation           OperationName = "APIV2BufferGoodsTaskGet"
 | 
				
			||||||
 | 
						APIV2BufferTasksGetOperation               OperationName = "APIV2BufferTasksGet"
 | 
				
			||||||
 | 
						APIV2HistoryGoodsTaskGetOperation          OperationName = "APIV2HistoryGoodsTaskGet"
 | 
				
			||||||
 | 
						APIV2HistoryTasksGetOperation              OperationName = "APIV2HistoryTasksGet"
 | 
				
			||||||
 | 
						APIV2ListGoodsFilterGetOperation           OperationName = "APIV2ListGoodsFilterGet"
 | 
				
			||||||
 | 
						APIV2ListGoodsSizeNmGetOperation           OperationName = "APIV2ListGoodsSizeNmGet"
 | 
				
			||||||
 | 
						APIV2QuarantineGoodsGetOperation           OperationName = "APIV2QuarantineGoodsGet"
 | 
				
			||||||
 | 
						APIV2UploadTaskClubDiscountPostOperation   OperationName = "APIV2UploadTaskClubDiscountPost"
 | 
				
			||||||
 | 
						APIV2UploadTaskPostOperation               OperationName = "APIV2UploadTaskPost"
 | 
				
			||||||
 | 
						APIV2UploadTaskSizePostOperation           OperationName = "APIV2UploadTaskSizePost"
 | 
				
			||||||
 | 
						APIV3OfficesGetOperation                   OperationName = "APIV3OfficesGet"
 | 
				
			||||||
 | 
						APIV3StocksWarehouseIdDeleteOperation      OperationName = "APIV3StocksWarehouseIdDelete"
 | 
				
			||||||
 | 
						APIV3StocksWarehouseIdPostOperation        OperationName = "APIV3StocksWarehouseIdPost"
 | 
				
			||||||
 | 
						APIV3StocksWarehouseIdPutOperation         OperationName = "APIV3StocksWarehouseIdPut"
 | 
				
			||||||
 | 
						APIV3WarehousesGetOperation                OperationName = "APIV3WarehousesGet"
 | 
				
			||||||
 | 
						APIV3WarehousesPostOperation               OperationName = "APIV3WarehousesPost"
 | 
				
			||||||
 | 
						APIV3WarehousesWarehouseIdDeleteOperation  OperationName = "APIV3WarehousesWarehouseIdDelete"
 | 
				
			||||||
 | 
						APIV3WarehousesWarehouseIdPutOperation     OperationName = "APIV3WarehousesWarehouseIdPut"
 | 
				
			||||||
 | 
						ContentV2BarcodesPostOperation             OperationName = "ContentV2BarcodesPost"
 | 
				
			||||||
 | 
						ContentV2CardsDeleteTrashPostOperation     OperationName = "ContentV2CardsDeleteTrashPost"
 | 
				
			||||||
 | 
						ContentV2CardsErrorListGetOperation        OperationName = "ContentV2CardsErrorListGet"
 | 
				
			||||||
 | 
						ContentV2CardsLimitsGetOperation           OperationName = "ContentV2CardsLimitsGet"
 | 
				
			||||||
 | 
						ContentV2CardsRecoverPostOperation         OperationName = "ContentV2CardsRecoverPost"
 | 
				
			||||||
 | 
						ContentV2CardsUpdatePostOperation          OperationName = "ContentV2CardsUpdatePost"
 | 
				
			||||||
 | 
						ContentV2CardsUploadAddPostOperation       OperationName = "ContentV2CardsUploadAddPost"
 | 
				
			||||||
 | 
						ContentV2CardsUploadPostOperation          OperationName = "ContentV2CardsUploadPost"
 | 
				
			||||||
 | 
						ContentV2DirectoryColorsGetOperation       OperationName = "ContentV2DirectoryColorsGet"
 | 
				
			||||||
 | 
						ContentV2DirectoryCountriesGetOperation    OperationName = "ContentV2DirectoryCountriesGet"
 | 
				
			||||||
 | 
						ContentV2DirectoryKindsGetOperation        OperationName = "ContentV2DirectoryKindsGet"
 | 
				
			||||||
 | 
						ContentV2DirectorySeasonsGetOperation      OperationName = "ContentV2DirectorySeasonsGet"
 | 
				
			||||||
 | 
						ContentV2DirectoryTnvedGetOperation        OperationName = "ContentV2DirectoryTnvedGet"
 | 
				
			||||||
 | 
						ContentV2DirectoryVatGetOperation          OperationName = "ContentV2DirectoryVatGet"
 | 
				
			||||||
 | 
						ContentV2GetCardsListPostOperation         OperationName = "ContentV2GetCardsListPost"
 | 
				
			||||||
 | 
						ContentV2GetCardsTrashPostOperation        OperationName = "ContentV2GetCardsTrashPost"
 | 
				
			||||||
 | 
						ContentV2ObjectAllGetOperation             OperationName = "ContentV2ObjectAllGet"
 | 
				
			||||||
 | 
						ContentV2ObjectCharcsSubjectIdGetOperation OperationName = "ContentV2ObjectCharcsSubjectIdGet"
 | 
				
			||||||
 | 
						ContentV2ObjectParentAllGetOperation       OperationName = "ContentV2ObjectParentAllGet"
 | 
				
			||||||
 | 
						ContentV2TagNomenclatureLinkPostOperation  OperationName = "ContentV2TagNomenclatureLinkPost"
 | 
				
			||||||
 | 
						ContentV2TagsGetOperation                  OperationName = "ContentV2TagsGet"
 | 
				
			||||||
 | 
						ContentV3MediaFilePostOperation            OperationName = "ContentV3MediaFilePost"
 | 
				
			||||||
 | 
						ContentV3MediaSavePostOperation            OperationName = "ContentV3MediaSavePost"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										2634
									
								
								pkg/api/wb/client/oas_parameters_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2634
									
								
								pkg/api/wb/client/oas_parameters_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1360
									
								
								pkg/api/wb/client/oas_request_decoders_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1360
									
								
								pkg/api/wb/client/oas_request_decoders_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										315
									
								
								pkg/api/wb/client/oas_request_encoders_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								pkg/api/wb/client/oas_request_encoders_gen.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,315 @@
 | 
				
			|||||||
 | 
					// Code generated by ogen, DO NOT EDIT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"mime"
 | 
				
			||||||
 | 
						"mime/multipart"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/go-faster/errors"
 | 
				
			||||||
 | 
						"github.com/go-faster/jx"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ht "github.com/ogen-go/ogen/http"
 | 
				
			||||||
 | 
						"github.com/ogen-go/ogen/uri"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeAPIV2UploadTaskClubDiscountPostRequest(
 | 
				
			||||||
 | 
						req *APIV2UploadTaskClubDiscountPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeAPIV2UploadTaskPostRequest(
 | 
				
			||||||
 | 
						req *APIV2UploadTaskPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeAPIV2UploadTaskSizePostRequest(
 | 
				
			||||||
 | 
						req *APIV2UploadTaskSizePostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeAPIV3StocksWarehouseIdDeleteRequest(
 | 
				
			||||||
 | 
						req *APIV3StocksWarehouseIdDeleteReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeAPIV3StocksWarehouseIdPostRequest(
 | 
				
			||||||
 | 
						req *APIV3StocksWarehouseIdPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeAPIV3StocksWarehouseIdPutRequest(
 | 
				
			||||||
 | 
						req OptAPIV3StocksWarehouseIdPutReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						if !req.Set {
 | 
				
			||||||
 | 
							// Keep request with empty body if value is not set.
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if req.Set {
 | 
				
			||||||
 | 
								req.Encode(e)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeAPIV3WarehousesPostRequest(
 | 
				
			||||||
 | 
						req *APIV3WarehousesPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeAPIV3WarehousesWarehouseIdPutRequest(
 | 
				
			||||||
 | 
						req *APIV3WarehousesWarehouseIdPutReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV2BarcodesPostRequest(
 | 
				
			||||||
 | 
						req *ContentV2BarcodesPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV2CardsDeleteTrashPostRequest(
 | 
				
			||||||
 | 
						req *ContentV2CardsDeleteTrashPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV2CardsRecoverPostRequest(
 | 
				
			||||||
 | 
						req *ContentV2CardsRecoverPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV2CardsUpdatePostRequest(
 | 
				
			||||||
 | 
						req []ContentV2CardsUpdatePostReqItem,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if req != nil {
 | 
				
			||||||
 | 
								e.ArrStart()
 | 
				
			||||||
 | 
								for _, elem := range req {
 | 
				
			||||||
 | 
									elem.Encode(e)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								e.ArrEnd()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV2CardsUploadAddPostRequest(
 | 
				
			||||||
 | 
						req OptContentV2CardsUploadAddPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						if !req.Set {
 | 
				
			||||||
 | 
							// Keep request with empty body if value is not set.
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if req.Set {
 | 
				
			||||||
 | 
								req.Encode(e)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV2CardsUploadPostRequest(
 | 
				
			||||||
 | 
						req []ContentV2CardsUploadPostReqItem,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if req != nil {
 | 
				
			||||||
 | 
								e.ArrStart()
 | 
				
			||||||
 | 
								for _, elem := range req {
 | 
				
			||||||
 | 
									elem.Encode(e)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								e.ArrEnd()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV2GetCardsListPostRequest(
 | 
				
			||||||
 | 
						req *ContentV2GetCardsListPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV2GetCardsTrashPostRequest(
 | 
				
			||||||
 | 
						req *ContentV2GetCardsTrashPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV2TagNomenclatureLinkPostRequest(
 | 
				
			||||||
 | 
						req *ContentV2TagNomenclatureLinkPostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV3MediaFilePostRequest(
 | 
				
			||||||
 | 
						req *ContentV3MediaFilePostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "multipart/form-data"
 | 
				
			||||||
 | 
						request := req
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						q := uri.NewFormEncoder(map[string]string{})
 | 
				
			||||||
 | 
						body, boundary := ht.CreateMultipartBody(func(w *multipart.Writer) error {
 | 
				
			||||||
 | 
							if val, ok := request.Uploadfile.Get(); ok {
 | 
				
			||||||
 | 
								if err := val.WriteMultipart("uploadfile", w); err != nil {
 | 
				
			||||||
 | 
									return errors.Wrap(err, "write \"uploadfile\"")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err := q.WriteMultipart(w); err != nil {
 | 
				
			||||||
 | 
								return errors.Wrap(err, "write multipart")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						ht.SetCloserBody(r, body, mime.FormatMediaType(contentType, map[string]string{"boundary": boundary}))
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeContentV3MediaSavePostRequest(
 | 
				
			||||||
 | 
						req *ContentV3MediaSavePostReq,
 | 
				
			||||||
 | 
						r *http.Request,
 | 
				
			||||||
 | 
					) error {
 | 
				
			||||||
 | 
						const contentType = "application/json"
 | 
				
			||||||
 | 
						e := new(jx.Encoder)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							req.Encode(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encoded := e.Bytes()
 | 
				
			||||||
 | 
						ht.SetBody(r, bytes.NewReader(encoded), contentType)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12994
									
								
								pkg/api/wb/client/oas_response_decoders_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12994
									
								
								pkg/api/wb/client/oas_response_decoders_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5052
									
								
								pkg/api/wb/client/oas_response_encoders_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5052
									
								
								pkg/api/wb/client/oas_response_encoders_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2379
									
								
								pkg/api/wb/client/oas_router_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2379
									
								
								pkg/api/wb/client/oas_router_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										10053
									
								
								pkg/api/wb/client/oas_schemas_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10053
									
								
								pkg/api/wb/client/oas_schemas_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										111
									
								
								pkg/api/wb/client/oas_security_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								pkg/api/wb/client/oas_security_gen.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
				
			|||||||
 | 
					// Code generated by ogen, DO NOT EDIT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/go-faster/errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ogen-go/ogen/ogenerrors"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SecurityHandler is handler for security parameters.
 | 
				
			||||||
 | 
					type SecurityHandler interface {
 | 
				
			||||||
 | 
						// HandleHeaderApiKey handles HeaderApiKey security.
 | 
				
			||||||
 | 
						HandleHeaderApiKey(ctx context.Context, operationName OperationName, t HeaderApiKey) (context.Context, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func findAuthorization(h http.Header, prefix string) (string, bool) {
 | 
				
			||||||
 | 
						v, ok := h["Authorization"]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return "", false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, vv := range v {
 | 
				
			||||||
 | 
							scheme, value, ok := strings.Cut(vv, " ")
 | 
				
			||||||
 | 
							if !ok || !strings.EqualFold(scheme, prefix) {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return value, true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return "", false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var operationRolesHeaderApiKey = map[string][]string{
 | 
				
			||||||
 | 
						APIV2BufferGoodsTaskGetOperation:           []string{},
 | 
				
			||||||
 | 
						APIV2BufferTasksGetOperation:               []string{},
 | 
				
			||||||
 | 
						APIV2HistoryGoodsTaskGetOperation:          []string{},
 | 
				
			||||||
 | 
						APIV2HistoryTasksGetOperation:              []string{},
 | 
				
			||||||
 | 
						APIV2ListGoodsFilterGetOperation:           []string{},
 | 
				
			||||||
 | 
						APIV2ListGoodsSizeNmGetOperation:           []string{},
 | 
				
			||||||
 | 
						APIV2QuarantineGoodsGetOperation:           []string{},
 | 
				
			||||||
 | 
						APIV2UploadTaskClubDiscountPostOperation:   []string{},
 | 
				
			||||||
 | 
						APIV2UploadTaskPostOperation:               []string{},
 | 
				
			||||||
 | 
						APIV2UploadTaskSizePostOperation:           []string{},
 | 
				
			||||||
 | 
						APIV3OfficesGetOperation:                   []string{},
 | 
				
			||||||
 | 
						APIV3StocksWarehouseIdDeleteOperation:      []string{},
 | 
				
			||||||
 | 
						APIV3StocksWarehouseIdPostOperation:        []string{},
 | 
				
			||||||
 | 
						APIV3StocksWarehouseIdPutOperation:         []string{},
 | 
				
			||||||
 | 
						APIV3WarehousesGetOperation:                []string{},
 | 
				
			||||||
 | 
						APIV3WarehousesPostOperation:               []string{},
 | 
				
			||||||
 | 
						APIV3WarehousesWarehouseIdDeleteOperation:  []string{},
 | 
				
			||||||
 | 
						APIV3WarehousesWarehouseIdPutOperation:     []string{},
 | 
				
			||||||
 | 
						ContentV2BarcodesPostOperation:             []string{},
 | 
				
			||||||
 | 
						ContentV2CardsDeleteTrashPostOperation:     []string{},
 | 
				
			||||||
 | 
						ContentV2CardsErrorListGetOperation:        []string{},
 | 
				
			||||||
 | 
						ContentV2CardsLimitsGetOperation:           []string{},
 | 
				
			||||||
 | 
						ContentV2CardsRecoverPostOperation:         []string{},
 | 
				
			||||||
 | 
						ContentV2CardsUpdatePostOperation:          []string{},
 | 
				
			||||||
 | 
						ContentV2CardsUploadAddPostOperation:       []string{},
 | 
				
			||||||
 | 
						ContentV2CardsUploadPostOperation:          []string{},
 | 
				
			||||||
 | 
						ContentV2DirectoryColorsGetOperation:       []string{},
 | 
				
			||||||
 | 
						ContentV2DirectoryCountriesGetOperation:    []string{},
 | 
				
			||||||
 | 
						ContentV2DirectoryKindsGetOperation:        []string{},
 | 
				
			||||||
 | 
						ContentV2DirectorySeasonsGetOperation:      []string{},
 | 
				
			||||||
 | 
						ContentV2DirectoryTnvedGetOperation:        []string{},
 | 
				
			||||||
 | 
						ContentV2DirectoryVatGetOperation:          []string{},
 | 
				
			||||||
 | 
						ContentV2GetCardsListPostOperation:         []string{},
 | 
				
			||||||
 | 
						ContentV2GetCardsTrashPostOperation:        []string{},
 | 
				
			||||||
 | 
						ContentV2ObjectAllGetOperation:             []string{},
 | 
				
			||||||
 | 
						ContentV2ObjectCharcsSubjectIdGetOperation: []string{},
 | 
				
			||||||
 | 
						ContentV2ObjectParentAllGetOperation:       []string{},
 | 
				
			||||||
 | 
						ContentV2TagNomenclatureLinkPostOperation:  []string{},
 | 
				
			||||||
 | 
						ContentV2TagsGetOperation:                  []string{},
 | 
				
			||||||
 | 
						ContentV3MediaFilePostOperation:            []string{},
 | 
				
			||||||
 | 
						ContentV3MediaSavePostOperation:            []string{},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *Server) securityHeaderApiKey(ctx context.Context, operationName OperationName, req *http.Request) (context.Context, bool, error) {
 | 
				
			||||||
 | 
						var t HeaderApiKey
 | 
				
			||||||
 | 
						const parameterName = "Authorization"
 | 
				
			||||||
 | 
						value := req.Header.Get(parameterName)
 | 
				
			||||||
 | 
						if value == "" {
 | 
				
			||||||
 | 
							return ctx, false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.APIKey = value
 | 
				
			||||||
 | 
						t.Roles = operationRolesHeaderApiKey[operationName]
 | 
				
			||||||
 | 
						rctx, err := s.sec.HandleHeaderApiKey(ctx, operationName, t)
 | 
				
			||||||
 | 
						if errors.Is(err, ogenerrors.ErrSkipServerSecurity) {
 | 
				
			||||||
 | 
							return nil, false, nil
 | 
				
			||||||
 | 
						} else if err != nil {
 | 
				
			||||||
 | 
							return nil, false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rctx, true, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SecuritySource is provider of security values (tokens, passwords, etc.).
 | 
				
			||||||
 | 
					type SecuritySource interface {
 | 
				
			||||||
 | 
						// HeaderApiKey provides HeaderApiKey security value.
 | 
				
			||||||
 | 
						HeaderApiKey(ctx context.Context, operationName OperationName, client *Client) (HeaderApiKey, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *Client) securityHeaderApiKey(ctx context.Context, operationName OperationName, req *http.Request) error {
 | 
				
			||||||
 | 
						t, err := s.sec.HeaderApiKey(ctx, operationName, s)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return errors.Wrap(err, "security source \"HeaderApiKey\"")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						req.Header.Set("Authorization", t.APIKey)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										951
									
								
								pkg/api/wb/client/oas_server_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										951
									
								
								pkg/api/wb/client/oas_server_gen.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,951 @@
 | 
				
			|||||||
 | 
					// Code generated by ogen, DO NOT EDIT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Handler handles operations described by OpenAPI v3 specification.
 | 
				
			||||||
 | 
					type Handler interface {
 | 
				
			||||||
 | 
						// APIV2BufferGoodsTaskGet implements GET /api/v2/buffer/goods/task operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет информацию о товарах и ошибках в
 | 
				
			||||||
 | 
						// товарах из загрузки в обработке.
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Необработанная загрузка — это загрузка скидок для <a
 | 
				
			||||||
 | 
						// href="/openapi/promotion#tag/Kalendar-akcij">календаря акций</a>. Такие
 | 
				
			||||||
 | 
						// скидки применятся к товарам только в момент начала
 | 
				
			||||||
 | 
						// акции.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 10 запросов за 6 <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
 | 
				
			||||||
 | 
						// на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /api/v2/buffer/goods/task
 | 
				
			||||||
 | 
						APIV2BufferGoodsTaskGet(ctx context.Context, params APIV2BufferGoodsTaskGetParams) (APIV2BufferGoodsTaskGetRes, error)
 | 
				
			||||||
 | 
						// APIV2BufferTasksGet implements GET /api/v2/buffer/tasks operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет информацию про загрузку скидок в
 | 
				
			||||||
 | 
						// обработке.
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Необработанная загрузка — это загрузка скидок для <a
 | 
				
			||||||
 | 
						// href="/openapi/promotion#tag/Kalendar-akcij">календаря акций</a>. Такие
 | 
				
			||||||
 | 
						// скидки применятся к товарам только в момент начала
 | 
				
			||||||
 | 
						// акции.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 10 запросов за 6 <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
 | 
				
			||||||
 | 
						// на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /api/v2/buffer/tasks
 | 
				
			||||||
 | 
						APIV2BufferTasksGet(ctx context.Context, params APIV2BufferTasksGetParams) (APIV2BufferTasksGetRes, error)
 | 
				
			||||||
 | 
						// APIV2HistoryGoodsTaskGet implements GET /api/v2/history/goods/task operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет информацию о товарах и об
 | 
				
			||||||
 | 
						// ошибках в товарах в обработанной загрузке.
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Обработанная загрузка — это загрузка цен и скидок
 | 
				
			||||||
 | 
						// для <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task/post">товаров</a> и <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1size/post">размеров товаров</a>, а также скидок <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1club-discount/post">WB Клуба</a>.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 10 запросов за 6 <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
 | 
				
			||||||
 | 
						// на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /api/v2/history/goods/task
 | 
				
			||||||
 | 
						APIV2HistoryGoodsTaskGet(ctx context.Context, params APIV2HistoryGoodsTaskGetParams) (APIV2HistoryGoodsTaskGetRes, error)
 | 
				
			||||||
 | 
						// APIV2HistoryTasksGet implements GET /api/v2/history/tasks operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет информацию об обработанной
 | 
				
			||||||
 | 
						// загрузке цен и скидок.
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Обработанная загрузка — это загрузка цен и скидок
 | 
				
			||||||
 | 
						// для <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task/post">товаров</a> и <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1size/post">размеров товаров</a>, а также скидок <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1club-discount/post">WB Клуба</a>.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 10 запросов за 6 <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
 | 
				
			||||||
 | 
						// на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /api/v2/history/tasks
 | 
				
			||||||
 | 
						APIV2HistoryTasksGet(ctx context.Context, params APIV2HistoryTasksGetParams) (APIV2HistoryTasksGetRes, error)
 | 
				
			||||||
 | 
						// APIV2ListGoodsFilterGet implements GET /api/v2/list/goods/filter operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет информацию о товарах по их
 | 
				
			||||||
 | 
						// артикулам: цены, валюту, общие скидки и скидки для [WB
 | 
				
			||||||
 | 
						// Клуба](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1club-discount/post).
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Чтобы получить информацию обо всех товарах продавца,
 | 
				
			||||||
 | 
						// оставьте артикул пустым, установите `limit=1000`, в
 | 
				
			||||||
 | 
						// параметре `offset` установите смещение по количеству
 | 
				
			||||||
 | 
						// записей. Количество нужно рассчитать по формуле: `offset`
 | 
				
			||||||
 | 
						// плюс `limit` из предыдущего запроса. Повторяйте запрос,
 | 
				
			||||||
 | 
						// пока вы не получите ответ с пустым массивом.<br> Чтобы
 | 
				
			||||||
 | 
						// получить информацию о размерах товара, используйте
 | 
				
			||||||
 | 
						// [отдельный
 | 
				
			||||||
 | 
						// метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1list~1goods~1size~1nm/get).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 10 запросов за 6 <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
 | 
				
			||||||
 | 
						// на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /api/v2/list/goods/filter
 | 
				
			||||||
 | 
						APIV2ListGoodsFilterGet(ctx context.Context, params APIV2ListGoodsFilterGetParams) (APIV2ListGoodsFilterGetRes, error)
 | 
				
			||||||
 | 
						// APIV2ListGoodsSizeNmGet implements GET /api/v2/list/goods/size/nm operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет информацию обо всех размерах
 | 
				
			||||||
 | 
						// одного товарам: цены, валюту, общие скидки и скидки
 | 
				
			||||||
 | 
						// для [WB
 | 
				
			||||||
 | 
						// Клуба](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1club-discount/post).
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Работает только для товаров из категорий, где можно
 | 
				
			||||||
 | 
						// устанавливать цены отдельно для разных размеров. Для
 | 
				
			||||||
 | 
						// таких товаров `editableSizePrice: true`.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Чтобы получить информацию о самом товаре,
 | 
				
			||||||
 | 
						// используйте [отдельный
 | 
				
			||||||
 | 
						// метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1list~1goods~1filter/get).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 10 запросов за 6 <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
 | 
				
			||||||
 | 
						// на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /api/v2/list/goods/size/nm
 | 
				
			||||||
 | 
						APIV2ListGoodsSizeNmGet(ctx context.Context, params APIV2ListGoodsSizeNmGetParams) (APIV2ListGoodsSizeNmGetRes, error)
 | 
				
			||||||
 | 
						// APIV2QuarantineGoodsGet implements GET /api/v2/quarantine/goods operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет информацию о товарах в карантине.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Если новая цена товара со скидкой будет минимум в 3
 | 
				
			||||||
 | 
						// раза меньше старой, товар попадёт [в
 | 
				
			||||||
 | 
						// карантин](https://seller.wildberries.ru/discount-and-prices/quarantine) и будет
 | 
				
			||||||
 | 
						// продаваться по старой цене. Ошибка об этом будет в
 | 
				
			||||||
 | 
						// ответах методов [состояний
 | 
				
			||||||
 | 
						// загрузок](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1tasks/get).
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Вы можете изменить цену или скидку с помощью API либо
 | 
				
			||||||
 | 
						// вывести товар из карантина [в личном
 | 
				
			||||||
 | 
						// кабинете](https://seller.wildberries.ru/discount-and-prices/quarantine).
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Для товаров с [поразмерной установкой
 | 
				
			||||||
 | 
						// цен](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1size/post)
 | 
				
			||||||
 | 
						// карантин не применяется.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 10 запросов за 6 <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
 | 
				
			||||||
 | 
						// на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /api/v2/quarantine/goods
 | 
				
			||||||
 | 
						APIV2QuarantineGoodsGet(ctx context.Context, params APIV2QuarantineGoodsGetParams) (APIV2QuarantineGoodsGetRes, error)
 | 
				
			||||||
 | 
						// APIV2UploadTaskClubDiscountPost implements POST /api/v2/upload/task/club-discount operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Устанавливает скидки для товаров в рамках подписки [WB
 | 
				
			||||||
 | 
						// Клуб](https://seller.wildberries.ru/help-center/article/A-337).
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Получить информацию о процессе установки цен и
 | 
				
			||||||
 | 
						// скидок можно с помощью методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1tasks/get">состояния</a> и <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1goods~1task/get">детализации</a> обработанной загрузки.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 10 запросов за 6 <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
 | 
				
			||||||
 | 
						// на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /api/v2/upload/task/club-discount
 | 
				
			||||||
 | 
						APIV2UploadTaskClubDiscountPost(ctx context.Context, req *APIV2UploadTaskClubDiscountPostReq) (APIV2UploadTaskClubDiscountPostRes, error)
 | 
				
			||||||
 | 
						// APIV2UploadTaskPost implements POST /api/v2/upload/task operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод устанавливает цены и скидки для товаров.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Чтобы установить цены и скидки для размеров товара,
 | 
				
			||||||
 | 
						// используйте [отдельный
 | 
				
			||||||
 | 
						// метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1size/post).
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Получить информацию о процессе установки цен и
 | 
				
			||||||
 | 
						// скидок можно с помощью методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1tasks/get">состояния</a> и <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1goods~1task/get">детализации</a> обработанной загрузки.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 10 запросов за 6 <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
 | 
				
			||||||
 | 
						// на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /api/v2/upload/task
 | 
				
			||||||
 | 
						APIV2UploadTaskPost(ctx context.Context, req *APIV2UploadTaskPostReq) (APIV2UploadTaskPostRes, error)
 | 
				
			||||||
 | 
						// APIV2UploadTaskSizePost implements POST /api/v2/upload/task/size operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод устанавливает цены отдельно для размеров
 | 
				
			||||||
 | 
						// товаров.
 | 
				
			||||||
 | 
						// Работает только для товаров из категорий, где можно
 | 
				
			||||||
 | 
						// устанавливать цены отдельно для разных размеров. Для
 | 
				
			||||||
 | 
						// [таких
 | 
				
			||||||
 | 
						// товаров](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1list~1goods~1size~1nm/get) `editableSizePrice: true`.
 | 
				
			||||||
 | 
						// Чтобы установить цены и скидки для самих товаров,
 | 
				
			||||||
 | 
						// используйте [отдельный
 | 
				
			||||||
 | 
						// метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task/post).
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Получить информацию о процессе установки цен и
 | 
				
			||||||
 | 
						// скидок можно с помощью методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1tasks/get">состояния</a> и <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1goods~1task/get">детализации</a> обработанной загрузки.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 10 запросов за 6 <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
 | 
				
			||||||
 | 
						// на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /api/v2/upload/task/size
 | 
				
			||||||
 | 
						APIV2UploadTaskSizePost(ctx context.Context, req *APIV2UploadTaskSizePostReq) (APIV2UploadTaskSizePostRes, error)
 | 
				
			||||||
 | 
						// APIV3OfficesGet implements GET /api/v3/offices operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет список всех складов WB для
 | 
				
			||||||
 | 
						// привязки к складам продавца. Предназначен для
 | 
				
			||||||
 | 
						// определения складов WB, чтобы сдавать готовые заказы
 | 
				
			||||||
 | 
						// по схеме [FBS](/openapi/orders-fbs#tag/Zakazy-FBS) (Fulfillment by Seller).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 300 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
 | 
				
			||||||
 | 
						// один аккаунт продавца.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Один запрос с кодом ответа <code>409</code> учитывается как 5
 | 
				
			||||||
 | 
						// запросов
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /api/v3/offices
 | 
				
			||||||
 | 
						APIV3OfficesGet(ctx context.Context) (APIV3OfficesGetRes, error)
 | 
				
			||||||
 | 
						// APIV3StocksWarehouseIdDelete implements DELETE /api/v3/stocks/{warehouseId} operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод удаляет запись об остатках товаров продавца из
 | 
				
			||||||
 | 
						// [списка
 | 
				
			||||||
 | 
						// остатков](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post).
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// <strong>Действие необратимо</strong>. Удаленный остаток
 | 
				
			||||||
 | 
						// будет необходимо загрузить повторно для
 | 
				
			||||||
 | 
						// возобновления продаж.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 300 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
 | 
				
			||||||
 | 
						// один аккаунт продавца.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Один запрос с кодом ответа <code>409</code> учитывается как 5
 | 
				
			||||||
 | 
						// запросов
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// DELETE /api/v3/stocks/{warehouseId}
 | 
				
			||||||
 | 
						APIV3StocksWarehouseIdDelete(ctx context.Context, req *APIV3StocksWarehouseIdDeleteReq, params APIV3StocksWarehouseIdDeleteParams) (APIV3StocksWarehouseIdDeleteRes, error)
 | 
				
			||||||
 | 
						// APIV3StocksWarehouseIdPost implements POST /api/v3/stocks/{warehouseId} operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет данные об остатках товаров на
 | 
				
			||||||
 | 
						// [складах продавца](/openapi/work-with-products#tag/Sklady-prodavca).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 300 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
 | 
				
			||||||
 | 
						// один аккаунт продавца.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Один запрос с кодом ответа <code>409</code> учитывается как 5
 | 
				
			||||||
 | 
						// запросов
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /api/v3/stocks/{warehouseId}
 | 
				
			||||||
 | 
						APIV3StocksWarehouseIdPost(ctx context.Context, req *APIV3StocksWarehouseIdPostReq, params APIV3StocksWarehouseIdPostParams) (APIV3StocksWarehouseIdPostRes, error)
 | 
				
			||||||
 | 
						// APIV3StocksWarehouseIdPut implements PUT /api/v3/stocks/{warehouseId} operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод обновляет количество остатков товаров
 | 
				
			||||||
 | 
						// продавца [в
 | 
				
			||||||
 | 
						// списке](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post).
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Названия параметров запроса не валидируются. При
 | 
				
			||||||
 | 
						// отправке некорректных названий вы получите успешный
 | 
				
			||||||
 | 
						// ответ (<code>204</code>), но остатки не обновятся.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 300 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
 | 
				
			||||||
 | 
						// один аккаунт продавца.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Один запрос с кодом ответа <code>409</code> учитывается как 5
 | 
				
			||||||
 | 
						// запросов
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// PUT /api/v3/stocks/{warehouseId}
 | 
				
			||||||
 | 
						APIV3StocksWarehouseIdPut(ctx context.Context, req OptAPIV3StocksWarehouseIdPutReq, params APIV3StocksWarehouseIdPutParams) (APIV3StocksWarehouseIdPutRes, error)
 | 
				
			||||||
 | 
						// APIV3WarehousesGet implements GET /api/v3/warehouses operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет список всех складов продавца.
 | 
				
			||||||
 | 
						// Может использоваться для получения [остатков
 | 
				
			||||||
 | 
						// товаров](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 300 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
 | 
				
			||||||
 | 
						// один аккаунт продавца.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Один запрос с кодом ответа <code>409</code> учитывается как 5
 | 
				
			||||||
 | 
						// запросов
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /api/v3/warehouses
 | 
				
			||||||
 | 
						APIV3WarehousesGet(ctx context.Context) (APIV3WarehousesGetRes, error)
 | 
				
			||||||
 | 
						// APIV3WarehousesPost implements POST /api/v3/warehouses operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод создаёт склад продавца для работы с [остатками
 | 
				
			||||||
 | 
						// товаров](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post). Нужно привязать к складу продавца [склад WB](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1offices/get) для работы по схеме [FBS](/openapi/orders-fbs#tag/Zakazy-FBS) (Fulfillment by Seller).
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Нельзя привязывать склад WB, который уже используется
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 300 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
 | 
				
			||||||
 | 
						// один аккаунт продавца.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Один запрос с кодом ответа <code>409</code> учитывается как 5
 | 
				
			||||||
 | 
						// запросов
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /api/v3/warehouses
 | 
				
			||||||
 | 
						APIV3WarehousesPost(ctx context.Context, req *APIV3WarehousesPostReq) (APIV3WarehousesPostRes, error)
 | 
				
			||||||
 | 
						// APIV3WarehousesWarehouseIdDelete implements DELETE /api/v3/warehouses/{warehouseId} operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод удаляет склад продавца из [списка
 | 
				
			||||||
 | 
						// складов](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1warehouses/get).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 300 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
 | 
				
			||||||
 | 
						// один аккаунт продавца.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Один запрос с кодом ответа <code>409</code> учитывается как 5
 | 
				
			||||||
 | 
						// запросов
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// DELETE /api/v3/warehouses/{warehouseId}
 | 
				
			||||||
 | 
						APIV3WarehousesWarehouseIdDelete(ctx context.Context, params APIV3WarehousesWarehouseIdDeleteParams) (APIV3WarehousesWarehouseIdDeleteRes, error)
 | 
				
			||||||
 | 
						// APIV3WarehousesWarehouseIdPut implements PUT /api/v3/warehouses/{warehouseId} operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод обновляет данные склада продавца в [списке
 | 
				
			||||||
 | 
						// складов](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1warehouses/get).
 | 
				
			||||||
 | 
						// Данные о привязанном [складе
 | 
				
			||||||
 | 
						// WB](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1offices/get) можно
 | 
				
			||||||
 | 
						// изменить один раз в сутки.
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Нельзя привязывать склад WB, который уже используется
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 300 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
 | 
				
			||||||
 | 
						// один аккаунт продавца.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Один запрос с кодом ответа <code>409</code> учитывается как 5
 | 
				
			||||||
 | 
						// запросов
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// PUT /api/v3/warehouses/{warehouseId}
 | 
				
			||||||
 | 
						APIV3WarehousesWarehouseIdPut(ctx context.Context, req *APIV3WarehousesWarehouseIdPutReq, params APIV3WarehousesWarehouseIdPutParams) (APIV3WarehousesWarehouseIdPutRes, error)
 | 
				
			||||||
 | 
						// ContentV2BarcodesPost implements POST /content/v2/barcodes operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод генерирует массив уникальных баркодов для
 | 
				
			||||||
 | 
						// создания размера в [карточке
 | 
				
			||||||
 | 
						// товара](/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post). Можно использовать, если у вас нет собственных баркодов.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v2/barcodes
 | 
				
			||||||
 | 
						ContentV2BarcodesPost(ctx context.Context, req *ContentV2BarcodesPostReq) (ContentV2BarcodesPostRes, error)
 | 
				
			||||||
 | 
						// ContentV2CardsDeleteTrashPost implements POST /content/v2/cards/delete/trash operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод переносит [карточки товаров в
 | 
				
			||||||
 | 
						// корзину](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post). При этом карточки товаров не удаляются, их можно [восстановить](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1recover/post).
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// После переноса в корзину карточке товара
 | 
				
			||||||
 | 
						// присваивается новый <code>imtID</code>.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// Карточки товаров удаляются автоматически, если лежат
 | 
				
			||||||
 | 
						// в корзине больше 30 дней. Очистка корзины происходит
 | 
				
			||||||
 | 
						// каждую ночь по московскому времени.<br>
 | 
				
			||||||
 | 
						// Карточки товаров можно удалить в любое время в
 | 
				
			||||||
 | 
						// [личном кабинете](https://seller.wildberries.ru/new-goods/basket-cards).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v2/cards/delete/trash
 | 
				
			||||||
 | 
						ContentV2CardsDeleteTrashPost(ctx context.Context, req *ContentV2CardsDeleteTrashPostReq) (ContentV2CardsDeleteTrashPostRes, error)
 | 
				
			||||||
 | 
						// ContentV2CardsErrorListGet implements GET /content/v2/cards/error/list operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет список карточек товаров, при
 | 
				
			||||||
 | 
						// создании или редактировании которых произошли
 | 
				
			||||||
 | 
						// ошибки, с описанием этих ошибок.
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Чтобы убрать карточку товара из списка, нужно
 | 
				
			||||||
 | 
						// повторно сделать запрос на <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создание</a> или редактирование карточки товара с исправленными ошибками.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/cards/error/list
 | 
				
			||||||
 | 
						ContentV2CardsErrorListGet(ctx context.Context, params ContentV2CardsErrorListGetParams) (ContentV2CardsErrorListGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2CardsLimitsGet implements GET /content/v2/cards/limits operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Возвращает бесплатные и платные лимиты продавца на
 | 
				
			||||||
 | 
						// [создание карточек
 | 
				
			||||||
 | 
						// товаров](/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post).<br><br>
 | 
				
			||||||
 | 
						// Формула для получения количества карточек, которые
 | 
				
			||||||
 | 
						// можно создать:
 | 
				
			||||||
 | 
						// > (`freeLimits` + `paidLimits`) - количество созданных карточек
 | 
				
			||||||
 | 
						// Созданными считаются карточки, которые можно
 | 
				
			||||||
 | 
						// получить через методы [список карточек
 | 
				
			||||||
 | 
						// товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1list/post) и [список карточек товаров в корзине](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/cards/limits
 | 
				
			||||||
 | 
						ContentV2CardsLimitsGet(ctx context.Context) (ContentV2CardsLimitsGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2CardsRecoverPost implements POST /content/v2/cards/recover operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод восстанавливает [карточки товаров из
 | 
				
			||||||
 | 
						// корзины](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post).
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Карточка товара сохраняет тот же <code>imtID</code>, что был
 | 
				
			||||||
 | 
						// присвоен ей при <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1delete~1trash/post">перемещении в корзину</a>.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v2/cards/recover
 | 
				
			||||||
 | 
						ContentV2CardsRecoverPost(ctx context.Context, req *ContentV2CardsRecoverPostReq) (ContentV2CardsRecoverPostRes, error)
 | 
				
			||||||
 | 
						// ContentV2CardsUpdatePost implements POST /content/v2/cards/update operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод обновляет карточки товаров. Данные для
 | 
				
			||||||
 | 
						// обновления можно получить через [список карточек
 | 
				
			||||||
 | 
						// товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1list/post) и [список карточек товаров в корзине](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post).
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Карточка товара перезаписывается при обновлении.
 | 
				
			||||||
 | 
						// Поэтому в запросе нужно передать <strong>все</strong>
 | 
				
			||||||
 | 
						// параметры карточки, в том числе те, которые вы не
 | 
				
			||||||
 | 
						// собираетесь обновлять.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// Нельзя редактировать или удалять баркоды, но можно
 | 
				
			||||||
 | 
						// добавить дополнительный баркод к карточке товара.
 | 
				
			||||||
 | 
						// Параметры `photos`, `video` и `tags` редактировать или удалять
 | 
				
			||||||
 | 
						// через данный метод нельзя.<br>
 | 
				
			||||||
 | 
						// Габариты товаров можно указать только в `сантиметрах`,
 | 
				
			||||||
 | 
						//  вес товара с упаковкой — в `килограммах`.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// В одном запросе можно отредактировать максимум 3000
 | 
				
			||||||
 | 
						// карточек товаров (`nmID`). Максимальный размер запроса 10
 | 
				
			||||||
 | 
						// Мб.<br>
 | 
				
			||||||
 | 
						// Если ответ `Успешно` (`200`), но какие-то карточки не
 | 
				
			||||||
 | 
						// обновились, получите [список несозданных карточек
 | 
				
			||||||
 | 
						// товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1error~1list/get).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня для метода будет отдельный
 | 
				
			||||||
 | 
						// лимит — 10 запросов в минуту на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v2/cards/update
 | 
				
			||||||
 | 
						ContentV2CardsUpdatePost(ctx context.Context, req []ContentV2CardsUpdatePostReqItem) (ContentV2CardsUpdatePostRes, error)
 | 
				
			||||||
 | 
						// ContentV2CardsUploadAddPost implements POST /content/v2/cards/upload/add operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод создаёт новые карточки товаров, присоединяя их
 | 
				
			||||||
 | 
						// к существующим карточкам.
 | 
				
			||||||
 | 
						// Габариты товаров можно указать только в `сантиметрах`,
 | 
				
			||||||
 | 
						//  вес товара с упаковкой — в `килограммах`.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Создание карточки товара происходит асинхронно.
 | 
				
			||||||
 | 
						// После отправки запрос становится в очередь на
 | 
				
			||||||
 | 
						// обработку.<br>Максимальный размер запроса 10 Мб.<br>
 | 
				
			||||||
 | 
						// Если ответ `Успешно` (`200`), но какие-то карточки не
 | 
				
			||||||
 | 
						// обновились, получите [список несозданных карточек
 | 
				
			||||||
 | 
						// товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1error~1list/get).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня для метода будет отдельный
 | 
				
			||||||
 | 
						// лимит — 10 запросов в минуту на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v2/cards/upload/add
 | 
				
			||||||
 | 
						ContentV2CardsUploadAddPost(ctx context.Context, req OptContentV2CardsUploadAddPostReq) (ContentV2CardsUploadAddPostRes, error)
 | 
				
			||||||
 | 
						// ContentV2CardsUploadPost implements POST /content/v2/cards/upload operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод создаёт карточки товаров c указанием описаний и
 | 
				
			||||||
 | 
						// характеристик товаров.<br>
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Есть две формы запроса: для создания отдельных и
 | 
				
			||||||
 | 
						// объединённых карточек товаров.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// Габариты товаров можно указать только в `сантиметрах`,
 | 
				
			||||||
 | 
						//  вес товара с упаковкой — в `килограммах`.
 | 
				
			||||||
 | 
						// <br><br>
 | 
				
			||||||
 | 
						// Создание карточки товара происходит асинхронно.
 | 
				
			||||||
 | 
						// После отправки запрос становится в очередь на
 | 
				
			||||||
 | 
						// обработку.<br>
 | 
				
			||||||
 | 
						// В одном запросе можно создать максимум 100
 | 
				
			||||||
 | 
						// объединённых карточек товаров (`imtID`), по 30 карточек
 | 
				
			||||||
 | 
						// товаров в каждой. Максимальный размер запроса 10 Мб.<br>
 | 
				
			||||||
 | 
						// Если ответ `Успешно` (`200`), но какие-то карточки не
 | 
				
			||||||
 | 
						// обновились, получите [список несозданных карточек
 | 
				
			||||||
 | 
						// товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1error~1list/get).
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня для метода будет отдельный
 | 
				
			||||||
 | 
						// лимит — 10 запросов в минуту на один аккаунт продавца
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v2/cards/upload
 | 
				
			||||||
 | 
						ContentV2CardsUploadPost(ctx context.Context, req []ContentV2CardsUploadPostReqItem) (ContentV2CardsUploadPostRes, error)
 | 
				
			||||||
 | 
						// ContentV2DirectoryColorsGet implements GET /content/v2/directory/colors operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет возможные значения
 | 
				
			||||||
 | 
						// [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Цвет`.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/directory/colors
 | 
				
			||||||
 | 
						ContentV2DirectoryColorsGet(ctx context.Context, params ContentV2DirectoryColorsGetParams) (ContentV2DirectoryColorsGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2DirectoryCountriesGet implements GET /content/v2/directory/countries operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет возможные значения
 | 
				
			||||||
 | 
						// [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Страна производства`.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/directory/countries
 | 
				
			||||||
 | 
						ContentV2DirectoryCountriesGet(ctx context.Context, params ContentV2DirectoryCountriesGetParams) (ContentV2DirectoryCountriesGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2DirectoryKindsGet implements GET /content/v2/directory/kinds operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет возможные значения
 | 
				
			||||||
 | 
						// [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Пол`.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/directory/kinds
 | 
				
			||||||
 | 
						ContentV2DirectoryKindsGet(ctx context.Context, params ContentV2DirectoryKindsGetParams) (ContentV2DirectoryKindsGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2DirectorySeasonsGet implements GET /content/v2/directory/seasons operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет возможные значения
 | 
				
			||||||
 | 
						// [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Сезон`.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/directory/seasons
 | 
				
			||||||
 | 
						ContentV2DirectorySeasonsGet(ctx context.Context, params ContentV2DirectorySeasonsGetParams) (ContentV2DirectorySeasonsGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2DirectoryTnvedGet implements GET /content/v2/directory/tnved operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет список ТНВЭД-кодов по ID
 | 
				
			||||||
 | 
						// [предмета](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1all/get) и фрагменту ТНВЭД-кода.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/directory/tnved
 | 
				
			||||||
 | 
						ContentV2DirectoryTnvedGet(ctx context.Context, params ContentV2DirectoryTnvedGetParams) (ContentV2DirectoryTnvedGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2DirectoryVatGet implements GET /content/v2/directory/vat operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет возможные значения
 | 
				
			||||||
 | 
						// [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Ставка НДС`.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/directory/vat
 | 
				
			||||||
 | 
						ContentV2DirectoryVatGet(ctx context.Context, params ContentV2DirectoryVatGetParams) (ContentV2DirectoryVatGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2GetCardsListPost implements POST /content/v2/get/cards/list operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// <div class="description_auth">
 | 
				
			||||||
 | 
						// Метод доступен по <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">токену</a> с
 | 
				
			||||||
 | 
						// категорией <strong>Контент</strong> или <strong>Продвижение</strong>
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// Метод предоставляет список созданных карточек
 | 
				
			||||||
 | 
						// товаров.
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// В ответе метода не будет карточек, находящихся в
 | 
				
			||||||
 | 
						// корзине. Получить такие карточки можно через <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post">отдельный метод</a>.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// Чтобы получить **больше 100** карточек товаров,
 | 
				
			||||||
 | 
						// воспользуйтесь пагинацией:
 | 
				
			||||||
 | 
						// <ol>
 | 
				
			||||||
 | 
						// <li>Сделайте первый запрос: <br>
 | 
				
			||||||
 | 
						// <pre style="background-color: rgb(38 50 56 / 5%); color: #e53935">
 | 
				
			||||||
 | 
						// {
 | 
				
			||||||
 | 
						// "settings": {
 | 
				
			||||||
 | 
						// "cursor": {
 | 
				
			||||||
 | 
						// "limit": 100
 | 
				
			||||||
 | 
						// },
 | 
				
			||||||
 | 
						// "filter": {
 | 
				
			||||||
 | 
						// "withPhoto": -1
 | 
				
			||||||
 | 
						// }
 | 
				
			||||||
 | 
						// }
 | 
				
			||||||
 | 
						// }</pre>
 | 
				
			||||||
 | 
						// </li>
 | 
				
			||||||
 | 
						// <li>Пройдите в конец полученного списка карточек
 | 
				
			||||||
 | 
						// товаров.</li>
 | 
				
			||||||
 | 
						// <li>Скопируйте из <code>cursor</code> две строки:
 | 
				
			||||||
 | 
						// <ul>
 | 
				
			||||||
 | 
						// <li><code>"updatedAt": "***"</code></li>
 | 
				
			||||||
 | 
						// <li><code>"nmID": ***</code></li>
 | 
				
			||||||
 | 
						// </ul></li>
 | 
				
			||||||
 | 
						// <li>Вставьте скопированные строки в параметр запроса
 | 
				
			||||||
 | 
						// <code>cursor</code>.</li>
 | 
				
			||||||
 | 
						// <li>Повторите запрос. </li>
 | 
				
			||||||
 | 
						// <li>Повторяйте пункты со <b>2</b> по <b>5</b>, пока поле
 | 
				
			||||||
 | 
						// <code>total</code> в ответе не станет меньше чем параметр
 | 
				
			||||||
 | 
						// <code>limit</code> в запросе. Это будет означать, что вы
 | 
				
			||||||
 | 
						// получили все карточки.
 | 
				
			||||||
 | 
						// </ol>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v2/get/cards/list
 | 
				
			||||||
 | 
						ContentV2GetCardsListPost(ctx context.Context, req *ContentV2GetCardsListPostReq, params ContentV2GetCardsListPostParams) (ContentV2GetCardsListPostRes, error)
 | 
				
			||||||
 | 
						// ContentV2GetCardsTrashPost implements POST /content/v2/get/cards/trash operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// <div class="description_auth">
 | 
				
			||||||
 | 
						// Метод доступен по <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">токену</a> с
 | 
				
			||||||
 | 
						// категорией <strong>Контент</strong> или <strong>Продвижение</strong>
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// Метод предоставляет список карточек товаров в
 | 
				
			||||||
 | 
						// корзине.<br><br>
 | 
				
			||||||
 | 
						// Чтобы получить **больше 100** карточек товаров,
 | 
				
			||||||
 | 
						// воспользуйтесь пагинацией:
 | 
				
			||||||
 | 
						// <ol>
 | 
				
			||||||
 | 
						// <li>Сделайте первый запрос: <br>
 | 
				
			||||||
 | 
						// <pre style="background-color: rgb(38 50 56 / 5%); color: #e53935">
 | 
				
			||||||
 | 
						// {
 | 
				
			||||||
 | 
						// "settings": {
 | 
				
			||||||
 | 
						// "cursor": {
 | 
				
			||||||
 | 
						// "limit": 100
 | 
				
			||||||
 | 
						// },
 | 
				
			||||||
 | 
						// "filter": {
 | 
				
			||||||
 | 
						// "withPhoto": -1
 | 
				
			||||||
 | 
						// }
 | 
				
			||||||
 | 
						// }
 | 
				
			||||||
 | 
						// }</pre>
 | 
				
			||||||
 | 
						// </li>
 | 
				
			||||||
 | 
						// <li>Пройдите в конец полученного списка карточек
 | 
				
			||||||
 | 
						// товаров.</li>
 | 
				
			||||||
 | 
						// <li>Скопируйте из <code>cursor</code> две строки:
 | 
				
			||||||
 | 
						// <ul>
 | 
				
			||||||
 | 
						// <li><code>"trashedAt": "***"</code></li>
 | 
				
			||||||
 | 
						// <li><code>"nmID": ***</code></li>
 | 
				
			||||||
 | 
						// </ul></li>
 | 
				
			||||||
 | 
						// <li>Вставьте скопированные строки в параметр запроса
 | 
				
			||||||
 | 
						// <code>cursor</code>.</li>
 | 
				
			||||||
 | 
						// <li>Повторите запрос. </li>
 | 
				
			||||||
 | 
						// <li>Повторяйте пункты со <b>2</b> по <b>5</b>, пока поле
 | 
				
			||||||
 | 
						// <code>total</code> в ответе не станет меньше чем параметр
 | 
				
			||||||
 | 
						// <code>limit</code> в запросе. Это будет означать, что вы
 | 
				
			||||||
 | 
						// получили все карточки.
 | 
				
			||||||
 | 
						// </ol>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v2/get/cards/trash
 | 
				
			||||||
 | 
						ContentV2GetCardsTrashPost(ctx context.Context, req *ContentV2GetCardsTrashPostReq, params ContentV2GetCardsTrashPostParams) (ContentV2GetCardsTrashPostRes, error)
 | 
				
			||||||
 | 
						// ContentV2ObjectAllGet implements GET /content/v2/object/all operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет список названий [родительских
 | 
				
			||||||
 | 
						// категорий
 | 
				
			||||||
 | 
						// предметов](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1parent~1all/get) и их предметов с ID. Например, у категории `Игрушки` будут предметы `Калейдоскопы`, `Куклы`, `Мячики`.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/object/all
 | 
				
			||||||
 | 
						ContentV2ObjectAllGet(ctx context.Context, params ContentV2ObjectAllGetParams) (ContentV2ObjectAllGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2ObjectCharcsSubjectIdGet implements GET /content/v2/object/charcs/{subjectId} operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет параметры характеристик
 | 
				
			||||||
 | 
						// предмета: названия, типы данных, единицы измерения и
 | 
				
			||||||
 | 
						// так далее. В запросе необходимо указать ID
 | 
				
			||||||
 | 
						// [предмета](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1all/get).
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Для получения характеристик <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1colors/get">Цвет</a>, <a href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1kinds/get">Пол</a>, <a href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1countries/get">Страна производства</a>, <a href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1seasons/get">Сезон</a>, <a href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1vat/get">Ставка НДС</a> и <a href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1tnved/get">ТНВЭД-код</a> используйте отдельные методы
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/object/charcs/{subjectId}
 | 
				
			||||||
 | 
						ContentV2ObjectCharcsSubjectIdGet(ctx context.Context, params ContentV2ObjectCharcsSubjectIdGetParams) (ContentV2ObjectCharcsSubjectIdGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2ObjectParentAllGet implements GET /content/v2/object/parent/all operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет названия и ID всех родительских
 | 
				
			||||||
 | 
						// категорий для [создания карточек
 | 
				
			||||||
 | 
						// товаров](/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov): например,
 | 
				
			||||||
 | 
						// `Электроника`, `Бытовая химия`, `Рукоделие`.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/object/parent/all
 | 
				
			||||||
 | 
						ContentV2ObjectParentAllGet(ctx context.Context, params ContentV2ObjectParentAllGetParams) (ContentV2ObjectParentAllGetRes, error)
 | 
				
			||||||
 | 
						// ContentV2TagNomenclatureLinkPost implements POST /content/v2/tag/nomenclature/link operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод добавляет или снимает ярлык с карточки товара.
 | 
				
			||||||
 | 
						// К карточке можно добавить максимум 15 ярлыков.<br>
 | 
				
			||||||
 | 
						// При удалении ярлыка из карточки товара он не
 | 
				
			||||||
 | 
						// удаляется из [списка
 | 
				
			||||||
 | 
						// ярлыков](/openapi/work-with-products#tag/Yarlyki/paths/~1content~1v2~1tags/get)
 | 
				
			||||||
 | 
						// продавца.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v2/tag/nomenclature/link
 | 
				
			||||||
 | 
						ContentV2TagNomenclatureLinkPost(ctx context.Context, req *ContentV2TagNomenclatureLinkPostReq) (ContentV2TagNomenclatureLinkPostRes, error)
 | 
				
			||||||
 | 
						// ContentV2TagsGet implements GET /content/v2/tags operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод предоставляет список и характеристики всех
 | 
				
			||||||
 | 
						// ярлыков продавца для группировки и фильтрации
 | 
				
			||||||
 | 
						// товаров.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// GET /content/v2/tags
 | 
				
			||||||
 | 
						ContentV2TagsGet(ctx context.Context) (ContentV2TagsGetRes, error)
 | 
				
			||||||
 | 
						// ContentV3MediaFilePost implements POST /content/v3/media/file operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод загружает и добавляет один медиафайл к
 | 
				
			||||||
 | 
						// карточке товара.
 | 
				
			||||||
 | 
						// Требования к изображениям:
 | 
				
			||||||
 | 
						// * максимум изображений для одной карточки товара — 30
 | 
				
			||||||
 | 
						// * минимальное разрешение — 700x900 px
 | 
				
			||||||
 | 
						// * максимальный размер — 32 Мб
 | 
				
			||||||
 | 
						// * минимальное качество — 65%
 | 
				
			||||||
 | 
						// * форматы — JPG, PNG, BMP, GIF (статичные), WebP
 | 
				
			||||||
 | 
						// Требования к видео:
 | 
				
			||||||
 | 
						// * максимум одно видео для одной карточки товара
 | 
				
			||||||
 | 
						// * максимальный размер — 50 Мб
 | 
				
			||||||
 | 
						// * форматы — MOV, MP4
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v3/media/file
 | 
				
			||||||
 | 
						ContentV3MediaFilePost(ctx context.Context, req *ContentV3MediaFilePostReq, params ContentV3MediaFilePostParams) (ContentV3MediaFilePostRes, error)
 | 
				
			||||||
 | 
						// ContentV3MediaSavePost implements POST /content/v3/media/save operation.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Метод загружает набор медиафайлов в карточку товара
 | 
				
			||||||
 | 
						// через указание ссылок в запросе.
 | 
				
			||||||
 | 
						// <div class="description_important">
 | 
				
			||||||
 | 
						// Новые медиафайлы полностью заменяют старые. Чтобы
 | 
				
			||||||
 | 
						// добавить новые медиафайлы, укажите в запросе ссылки
 | 
				
			||||||
 | 
						// одновременно на новые и старые медиафайлы.
 | 
				
			||||||
 | 
						// </div>
 | 
				
			||||||
 | 
						// Требования к изображениям:
 | 
				
			||||||
 | 
						// * максимум изображений для одной карточки товара — 30
 | 
				
			||||||
 | 
						// * минимальное разрешение — 700×900 px
 | 
				
			||||||
 | 
						// * максимальный размер — 32 Мб
 | 
				
			||||||
 | 
						// * минимальное качество — 65%
 | 
				
			||||||
 | 
						// * форматы — JPG, PNG, BMP, GIF (статичные), WebP
 | 
				
			||||||
 | 
						// Требования к видео:
 | 
				
			||||||
 | 
						// * максимум одно видео для одной карточки товара
 | 
				
			||||||
 | 
						// * максимальный размер — 50 Мб
 | 
				
			||||||
 | 
						// * форматы — MOV, MP4
 | 
				
			||||||
 | 
						// Если видео или хотя бы одно изображение в запросе не
 | 
				
			||||||
 | 
						// соответствует требованиям, то даже при успешном
 | 
				
			||||||
 | 
						// ответе ни одно изображение/видео не загрузится.
 | 
				
			||||||
 | 
						// <div class="description_limit">
 | 
				
			||||||
 | 
						// Максимум 100 запросов в <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
 | 
				
			||||||
 | 
						// методов категории <a
 | 
				
			||||||
 | 
						// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
 | 
				
			||||||
 | 
						// аккаунт продавца. С 5 июня — за исключением методов <a
 | 
				
			||||||
 | 
						// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
 | 
				
			||||||
 | 
						// </div>.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// POST /content/v3/media/save
 | 
				
			||||||
 | 
						ContentV3MediaSavePost(ctx context.Context, req *ContentV3MediaSavePostReq) (ContentV3MediaSavePostRes, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Server implements http server based on OpenAPI v3 specification and
 | 
				
			||||||
 | 
					// calls Handler to handle requests.
 | 
				
			||||||
 | 
					type Server struct {
 | 
				
			||||||
 | 
						h   Handler
 | 
				
			||||||
 | 
						sec SecurityHandler
 | 
				
			||||||
 | 
						baseServer
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewServer creates new Server.
 | 
				
			||||||
 | 
					func NewServer(h Handler, sec SecurityHandler, opts ...ServerOption) (*Server, error) {
 | 
				
			||||||
 | 
						s, err := newServerConfig(opts...).baseServer()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &Server{
 | 
				
			||||||
 | 
							h:          h,
 | 
				
			||||||
 | 
							sec:        sec,
 | 
				
			||||||
 | 
							baseServer: s,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1062
									
								
								pkg/api/wb/client/oas_unimplemented_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1062
									
								
								pkg/api/wb/client/oas_unimplemented_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1661
									
								
								pkg/api/wb/client/oas_validators_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1661
									
								
								pkg/api/wb/client/oas_validators_gen.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3
									
								
								pkg/api/wb/generate.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								pkg/api/wb/generate.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					package wb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//go:generate go run github.com/ogen-go/ogen/cmd/ogen@latest --target client --clean 02-products.yaml
 | 
				
			||||||
							
								
								
									
										7
									
								
								pkg/api/wb/ogen.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								pkg/api/wb/ogen.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					generator:
 | 
				
			||||||
 | 
					  ignore_not_implemented: [ "all" ]
 | 
				
			||||||
 | 
					  content_type_aliases:
 | 
				
			||||||
 | 
					    "application/problem+json": "application/json"
 | 
				
			||||||
 | 
					  features:
 | 
				
			||||||
 | 
					    enable:
 | 
				
			||||||
 | 
					      - 'client/security/reentrant'
 | 
				
			||||||
		Reference in New Issue
	
	Block a user