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{
|
||||||
Metadata: "wb/products.proto",
|
{
|
||||||
|
StreamName: "GetProducts",
|
||||||
|
Handler: _ProductsService_GetProducts_Handler,
|
||||||
|
ServerStreams: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
create table marketplaces
|
create table marketplaces
|
||||||
(
|
(
|
||||||
id serial
|
id serial
|
||||||
primary key,
|
primary key,
|
||||||
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