producteca 2.0.14__py3-none-any.whl → 2.0.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- producteca/__init__.py +3 -0
- producteca/abstract/abstract_dataclass.py +13 -1
- producteca/client.py +2 -0
- producteca/payments/tests/test_payments.py +18 -2
- producteca/products/products.py +161 -39
- producteca/products/search_products.py +71 -74
- producteca/products/tests/test_products.py +96 -11
- producteca/products/tests/test_search_products.py +10 -10
- producteca/sales_orders/sales_orders.py +140 -97
- producteca/sales_orders/search_sale_orders.py +21 -21
- producteca/sales_orders/tests/test_sales_orders.py +49 -19
- producteca/sales_orders/tests/test_search_so.py +2 -4
- producteca/shipments/tests/test_shipment.py +19 -7
- {producteca-2.0.14.dist-info → producteca-2.0.16.dist-info}/METADATA +5 -5
- producteca-2.0.16.dist-info/RECORD +31 -0
- producteca-2.0.14.dist-info/RECORD +0 -31
- {producteca-2.0.14.dist-info → producteca-2.0.16.dist-info}/WHEEL +0 -0
- {producteca-2.0.14.dist-info → producteca-2.0.16.dist-info}/entry_points.txt +0 -0
producteca/__init__.py
CHANGED
@@ -8,4 +8,16 @@ from typing import Optional
|
|
8
8
|
class BaseService[T](ABC):
|
9
9
|
config: ConfigProducteca
|
10
10
|
endpoint: str
|
11
|
-
_record: Optional[T] = None
|
11
|
+
_record: Optional[T] = None
|
12
|
+
|
13
|
+
def __repr__(self):
|
14
|
+
return repr(self._record)
|
15
|
+
|
16
|
+
def to_dict(self):
|
17
|
+
return self._record.model_dump(by_alias=True)
|
18
|
+
|
19
|
+
def to_json(self):
|
20
|
+
return self._record.model_dump_json(by_alias=True)
|
21
|
+
|
22
|
+
def __getattr__(self, key):
|
23
|
+
return getattr(self._record, key)
|
producteca/client.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from producteca.config.config import ConfigProducteca
|
2
2
|
from producteca.products.products import ProductService
|
3
3
|
from producteca.sales_orders.sales_orders import SaleOrderService
|
4
|
+
|
4
5
|
import os
|
5
6
|
|
6
7
|
|
@@ -20,3 +21,4 @@ class ProductecaClient:
|
|
20
21
|
@property
|
21
22
|
def SalesOrder(self):
|
22
23
|
return SaleOrderService(self.config)
|
24
|
+
|
@@ -35,7 +35,15 @@ class TestPayments(unittest.TestCase):
|
|
35
35
|
payment = Payment(**self.payment_data)
|
36
36
|
|
37
37
|
# Test create method
|
38
|
-
result = self.client.SalesOrder(id=self.sale_order_id
|
38
|
+
result = self.client.SalesOrder(id=self.sale_order_id, invoiceIntegration={
|
39
|
+
'id': 1,
|
40
|
+
'integrationId': 'test-integration',
|
41
|
+
'app': 1,
|
42
|
+
'createdAt': '2023-01-01',
|
43
|
+
'decreaseStock': True,
|
44
|
+
"documentUrl": "https://aallala.copm",
|
45
|
+
"xmlUrl": "https://aallala.copm",
|
46
|
+
}).add_payment(payment.model_dump(by_alias=True))
|
39
47
|
|
40
48
|
# Assertions
|
41
49
|
mock_post.assert_called_once()
|
@@ -55,7 +63,15 @@ class TestPayments(unittest.TestCase):
|
|
55
63
|
payment = Payment(**self.payment_data)
|
56
64
|
|
57
65
|
# Test update method
|
58
|
-
result = self.client.SalesOrder(id=self.sale_order_id
|
66
|
+
result = self.client.SalesOrder(id=self.sale_order_id, invoiceIntegration={
|
67
|
+
'id': 1,
|
68
|
+
'integrationId': 'test-integration',
|
69
|
+
'app': 1,
|
70
|
+
'createdAt': '2023-01-01',
|
71
|
+
'decreaseStock': True,
|
72
|
+
"documentUrl": "https://aallala.copm",
|
73
|
+
"xmlUrl": "https://aallala.copm",
|
74
|
+
}).update_payment(self.payment_id, payment.model_dump(by_alias=True))
|
59
75
|
|
60
76
|
# Assertions
|
61
77
|
mock_put.assert_called_once()
|
producteca/products/products.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from typing import List, Optional, Union
|
2
|
-
from pydantic import BaseModel, Field
|
2
|
+
from pydantic import BaseModel, Field, ValidationError
|
3
3
|
from dataclasses import dataclass
|
4
4
|
from producteca.abstract.abstract_dataclass import BaseService
|
5
5
|
from producteca.products.search_products import SearchProduct, SearchProductParams
|
@@ -88,23 +88,71 @@ class MeliCategory(BaseModel):
|
|
88
88
|
fixed: Optional[bool] = None
|
89
89
|
|
90
90
|
|
91
|
+
class BundleComponent(BaseModel):
|
92
|
+
quantity: int
|
93
|
+
variation_id: int = Field(alias='variationId')
|
94
|
+
product_id: int = Field(alias='productId')
|
95
|
+
|
96
|
+
|
97
|
+
class BundleVariation(BaseModel):
|
98
|
+
variation_id: int = Field(alias='variationId')
|
99
|
+
components: List[BundleComponent]
|
100
|
+
|
101
|
+
|
102
|
+
class BundleResult(BaseModel):
|
103
|
+
company_id: int = Field(alias='companyId')
|
104
|
+
product_id: int = Field(alias='productId')
|
105
|
+
variations: List[BundleVariation]
|
106
|
+
id: str
|
107
|
+
|
108
|
+
|
109
|
+
class BundleResponse(BaseModel):
|
110
|
+
results: List[BundleResult]
|
111
|
+
count: int
|
112
|
+
|
113
|
+
|
91
114
|
class Product(BaseModel):
|
115
|
+
integrations: Optional[List[Integration]] = None
|
116
|
+
variations: Optional[List[Variation]] = None
|
117
|
+
is_simple: Optional[bool] = Field(default=None, alias='isSimple')
|
118
|
+
has_variations: Optional[bool] = Field(default=None, alias='hasVariations')
|
119
|
+
thumbnail: Optional[str] = None
|
120
|
+
category: Optional[str] = None
|
121
|
+
notes: Optional[str] = None
|
122
|
+
prices: Optional[List[Price]] = None
|
123
|
+
buying_price: Optional[float] = Field(default=None, alias='buyingPrice')
|
124
|
+
is_archived: Optional[bool] = Field(default=None, alias='isArchived')
|
125
|
+
dimensions: Optional[Dimensions] = None
|
126
|
+
attributes: Optional[List[Attribute]] = None
|
127
|
+
metadata: Optional[List[str]] = None
|
128
|
+
is_original: Optional[bool] = Field(default=None, alias='isOriginal')
|
129
|
+
name: str
|
130
|
+
code: Optional[str] = None
|
92
131
|
sku: Optional[str] = None
|
93
|
-
|
132
|
+
brand: Optional[str] = None
|
133
|
+
id: Optional[int] = None
|
134
|
+
|
135
|
+
|
136
|
+
class ProductVariationBase(BaseModel):
|
137
|
+
sku: str
|
138
|
+
variation_id: Optional[int] = Field(default=None, alias='variationId')
|
94
139
|
code: Optional[str] = None
|
95
|
-
name: Optional[str] = None
|
96
140
|
barcode: Optional[str] = None
|
97
|
-
attributes:
|
98
|
-
tags: Optional[List[str]] =
|
99
|
-
buying_price: Optional[float] =
|
100
|
-
dimensions: Optional[Dimensions] =
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
141
|
+
attributes: List[Attribute] = []
|
142
|
+
tags: Optional[List[str]] = []
|
143
|
+
buying_price: Optional[float] = Field(0, alias='buyingPrice')
|
144
|
+
dimensions: Optional[Dimensions] = Field(default_factory=Dimensions)
|
145
|
+
brand: Optional[str] = ''
|
146
|
+
notes: Optional[str] = ''
|
147
|
+
deals: Optional[List[Deal]] = []
|
148
|
+
stocks: List[Stock]
|
149
|
+
prices: Optional[List[Price]] = []
|
150
|
+
pictures: Optional[List[Picture]] = []
|
151
|
+
|
152
|
+
|
153
|
+
class ProductVariation(ProductVariationBase):
|
154
|
+
category: Optional[str] = Field(default=None)
|
155
|
+
name: str
|
108
156
|
|
109
157
|
|
110
158
|
class Shipping(BaseModel):
|
@@ -128,13 +176,14 @@ class AttributeCompletion(BaseModel):
|
|
128
176
|
total: Optional[int] = None
|
129
177
|
|
130
178
|
|
131
|
-
class MeliProduct(
|
179
|
+
class MeliProduct(BaseModel):
|
132
180
|
product_id: Optional[int] = Field(default=None, alias='productId')
|
181
|
+
tags: Optional[List[str]] = Field(default=None)
|
133
182
|
has_custom_shipping_costs: Optional[bool] = Field(default=None, alias='hasCustomShippingCosts')
|
134
183
|
shipping: Optional[Shipping] = None
|
135
184
|
mshops_shipping: Optional[MShopsShipping] = Field(default=None, alias='mShopsShipping')
|
136
185
|
add_free_shipping_cost_to_price: Optional[bool] = Field(default=None, alias='addFreeShippingCostToPrice')
|
137
|
-
category:
|
186
|
+
category: MeliCategory
|
138
187
|
attribute_completion: Optional[AttributeCompletion] = Field(default=None, alias='attributeCompletion')
|
139
188
|
catalog_products: Optional[List[str]] = Field(default=None, alias='catalogProducts')
|
140
189
|
warranty: Optional[str] = None
|
@@ -143,65 +192,138 @@ class MeliProduct(Product):
|
|
143
192
|
catalog_products_status: Optional[str] = Field(default=None, alias='catalogProductsStatus')
|
144
193
|
|
145
194
|
|
195
|
+
class ErrorMessage(BaseModel):
|
196
|
+
en: str
|
197
|
+
es: str
|
198
|
+
pt: str
|
199
|
+
|
200
|
+
|
201
|
+
class ErrorReason(BaseModel):
|
202
|
+
code: str
|
203
|
+
error: str
|
204
|
+
message: ErrorMessage
|
205
|
+
data: Optional[dict] = None
|
206
|
+
|
207
|
+
|
208
|
+
class ResolvedValue(BaseModel):
|
209
|
+
updated: bool
|
210
|
+
|
211
|
+
|
212
|
+
class ResolvedError(BaseModel):
|
213
|
+
resolved: Optional[bool] = None
|
214
|
+
reason: Optional[ErrorReason] = None
|
215
|
+
value: Optional[ResolvedValue] = None
|
216
|
+
statusCode: Optional[int] = None
|
217
|
+
|
218
|
+
|
219
|
+
class ErrorContext(BaseModel):
|
220
|
+
_ns_name: str
|
221
|
+
id: int
|
222
|
+
requestId: str
|
223
|
+
tokenAppId: str
|
224
|
+
appId: str
|
225
|
+
bearer: str
|
226
|
+
eventId: str
|
227
|
+
|
228
|
+
|
229
|
+
class SynchronizeResponse(BaseModel):
|
230
|
+
product: Optional[ResolvedError] = None
|
231
|
+
variation: Optional[ResolvedError] = None
|
232
|
+
deals: Optional[ResolvedError] = None
|
233
|
+
bundles: Optional[ResolvedError] = None
|
234
|
+
taxes: Optional[ResolvedError] = None
|
235
|
+
meliProductListingIntegrations: Optional[ResolvedError] = None
|
236
|
+
tags: Optional[ResolvedError] = None
|
237
|
+
productIntegrations: Optional[ResolvedError] = None
|
238
|
+
statusCode: Optional[int] = None
|
239
|
+
error_context: Optional[ErrorContext] = Field(None, alias='error@context')
|
240
|
+
|
241
|
+
|
242
|
+
class ListedSynchronizeResponse(BaseModel):
|
243
|
+
results: List[SynchronizeResponse]
|
244
|
+
|
245
|
+
|
146
246
|
@dataclass
|
147
247
|
class ProductService(BaseService[Product]):
|
148
|
-
endpoint: str =
|
248
|
+
endpoint: str = 'products'
|
149
249
|
create_if_it_doesnt_exist: bool = Field(default=False, exclude=True)
|
150
250
|
|
151
251
|
def __call__(self, **payload):
|
152
252
|
self._record = Product(**payload)
|
153
253
|
return self
|
154
254
|
|
155
|
-
def
|
255
|
+
def synchronize(self, payload) -> Union[Product, SynchronizeResponse]:
|
256
|
+
|
156
257
|
endpoint_url = self.config.get_endpoint(f'{self.endpoint}/synchronize')
|
157
258
|
headers = self.config.headers.copy()
|
158
259
|
headers.update({"createifitdoesntexist": str(self.create_if_it_doesnt_exist).lower()})
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
260
|
+
product_variation = ProductVariation(**payload)
|
261
|
+
if not product_variation.code and not product_variation.sku:
|
262
|
+
raise Exception("Sku or code should be provided to update the product")
|
263
|
+
data = product_variation.model_dump(by_alias=True, exclude_none=True)
|
264
|
+
response = requests.post(endpoint_url, json=data, headers=headers)
|
265
|
+
response_data = response.json()
|
266
|
+
try:
|
267
|
+
return Product(**response_data)
|
268
|
+
except ValidationError:
|
269
|
+
pass
|
270
|
+
if isinstance(response_data, list):
|
271
|
+
res = ListedSynchronizeResponse(results=response_data)
|
272
|
+
if any([r.error_context for r in res.results]):
|
273
|
+
raise Exception(f"Errored while updating {res.results[0].error_context} {res.model_dump_json()}")
|
274
|
+
else:
|
275
|
+
return res.results[0]
|
276
|
+
else:
|
277
|
+
try:
|
278
|
+
sync_resp = SynchronizeResponse(**response_data)
|
279
|
+
if sync_resp.error_context:
|
280
|
+
raise Exception(f"Errored while updating {sync_resp.error_context} - {sync_resp.model_dump_json()}")
|
281
|
+
else:
|
282
|
+
return sync_resp
|
283
|
+
except ValidationError:
|
284
|
+
try:
|
285
|
+
error_res = ErrorReason(**response_data)
|
286
|
+
raise Exception(f"Errored with the following message {error_res.message} - {error_res.model_dump_json()}")
|
287
|
+
except ValidationError:
|
288
|
+
pass
|
164
289
|
|
165
|
-
|
166
|
-
|
167
|
-
endpoint_url = self.config.get_endpoint(f'{self.endpoint}/synchronize')
|
168
|
-
headers = self.config.headers.copy()
|
169
|
-
data = self._record.model_dump_json(by_alias=True, exclude_none=True)
|
170
|
-
if not self._record.code and not self._record.sku:
|
171
|
-
raise "Sku or code should be provided to update the product"
|
172
|
-
response = requests.post(endpoint_url, data=data, headers=headers)
|
290
|
+
if not response.ok:
|
291
|
+
raise Exception(f"Error getting product {product_variation.sku} - {product_variation.code}\n {response.text}")
|
173
292
|
if response.status_code == 204:
|
174
|
-
raise Exception("
|
175
|
-
|
293
|
+
raise Exception("Status code is 204, meaning nothing was updated or created")
|
294
|
+
raise Exception(f"Unhandled error, check response {response.text}")
|
176
295
|
|
177
|
-
def get(self, product_id: int) -> "
|
296
|
+
def get(self, product_id: int) -> "ProductService":
|
178
297
|
endpoint_url = self.config.get_endpoint(f'{self.endpoint}/{product_id}')
|
179
298
|
headers = self.config.headers
|
180
299
|
response = requests.get(endpoint_url, headers=headers)
|
181
300
|
if not response.ok:
|
182
301
|
raise Exception(f"Error getting product {product_id}\n {response.text}")
|
183
302
|
response_data = response.json()
|
184
|
-
return
|
303
|
+
return self(**response_data)
|
185
304
|
|
186
|
-
def get_bundle(self, product_id: int) ->
|
305
|
+
def get_bundle(self, product_id: int) -> BundleResponse:
|
187
306
|
endpoint_url = self.config.get_endpoint(f'{self.endpoint}/{product_id}/bundles')
|
188
307
|
headers = self.config.headers
|
189
308
|
response = requests.get(endpoint_url, headers=headers)
|
190
309
|
if not response.ok:
|
191
310
|
raise Exception(f"Error getting bundle {product_id}\n {response.text}")
|
192
|
-
return
|
311
|
+
return BundleResponse(**response.json())
|
193
312
|
|
194
|
-
def get_ml_integration(self, product_id: int) ->
|
313
|
+
def get_ml_integration(self, product_id: int) -> MeliProduct:
|
195
314
|
endpoint_url = self.config.get_endpoint(f'{self.endpoint}/{product_id}/listingintegration')
|
196
315
|
headers = self.config.headers
|
197
316
|
response = requests.get(endpoint_url, headers=headers)
|
198
317
|
if not response.ok:
|
199
318
|
raise Exception(f"Error getting ml integration {product_id}\n {response.text}")
|
200
|
-
|
319
|
+
response_data = response.json()
|
320
|
+
return MeliProduct(**response_data)
|
201
321
|
|
202
322
|
def search(self, params: SearchProductParams) -> SearchProduct:
|
203
323
|
endpoint: str = f'search/{self.endpoint}'
|
204
324
|
headers = self.config.headers
|
205
325
|
url = self.config.get_endpoint(endpoint)
|
206
326
|
response = requests.get(url, headers=headers, params=params.model_dump(by_alias=True, exclude_none=True))
|
327
|
+
if not response.ok:
|
328
|
+
raise Exception(f"error in searching products {response.text}")
|
207
329
|
return SearchProduct(**response.json())
|
@@ -1,17 +1,17 @@
|
|
1
|
-
from typing import List, Optional
|
1
|
+
from typing import List, Optional, Union
|
2
2
|
from pydantic import BaseModel, Field
|
3
3
|
|
4
4
|
|
5
5
|
class FacetValue(BaseModel):
|
6
6
|
count: int
|
7
|
-
value: str
|
8
|
-
label: str
|
7
|
+
value: Optional[Union[str, bool]] = None
|
8
|
+
label: Union[str, bool]
|
9
9
|
|
10
10
|
|
11
11
|
class Facet(BaseModel):
|
12
12
|
key: str
|
13
13
|
value: List[FacetValue]
|
14
|
-
is_collection: bool
|
14
|
+
is_collection: Optional[bool] = False
|
15
15
|
translate: bool
|
16
16
|
|
17
17
|
|
@@ -22,23 +22,23 @@ class SearchStocks(BaseModel):
|
|
22
22
|
|
23
23
|
|
24
24
|
class SearchPrices(BaseModel):
|
25
|
-
price_list_id: int
|
26
|
-
price_list: str
|
25
|
+
price_list_id: int = Field(..., alias='priceListId')
|
26
|
+
price_list: str = Field(..., alias='priceList')
|
27
27
|
amount: float
|
28
28
|
currency: str
|
29
29
|
|
30
30
|
|
31
31
|
class SearchIntegration(BaseModel):
|
32
|
-
app: Optional[int]
|
33
|
-
integration_id: Optional[str]
|
34
|
-
permalink: Optional[str]
|
35
|
-
status: Optional[str]
|
36
|
-
listing_type: Optional[str]
|
37
|
-
safety_stock: Optional[int]
|
38
|
-
synchronize_stock: Optional[bool]
|
39
|
-
is_active: Optional[bool]
|
40
|
-
is_active_or_paused: Optional[bool]
|
41
|
-
id: Optional[int]
|
32
|
+
app: Optional[int] = None
|
33
|
+
integration_id: Optional[str] = Field(None, alias='integrationId')
|
34
|
+
permalink: Optional[str] = None
|
35
|
+
status: Optional[str] = None
|
36
|
+
listing_type: Optional[str] = Field(None, alias='listingType')
|
37
|
+
safety_stock: Optional[int] = Field(None, alias='safetyStock')
|
38
|
+
synchronize_stock: Optional[bool] = Field(None, alias='synchronizeStock')
|
39
|
+
is_active: Optional[bool] = Field(None, alias='isActive')
|
40
|
+
is_active_or_paused: Optional[bool] = Field(None, alias='isActiveOrPaused')
|
41
|
+
id: Optional[int] = None
|
42
42
|
|
43
43
|
|
44
44
|
class SearchDeals(BaseModel):
|
@@ -56,8 +56,8 @@ class SearchDeals(BaseModel):
|
|
56
56
|
class SearchResultItem(BaseModel):
|
57
57
|
search_score: float = Field(..., alias='@search.score')
|
58
58
|
id: int
|
59
|
-
product_id: int
|
60
|
-
company_id: int
|
59
|
+
product_id: int = Field(..., alias='productId')
|
60
|
+
company_id: int = Field(..., alias='companyId')
|
61
61
|
name: str
|
62
62
|
code: str
|
63
63
|
skus: List[str]
|
@@ -65,61 +65,61 @@ class SearchResultItem(BaseModel):
|
|
65
65
|
category: str
|
66
66
|
thumbnail: str
|
67
67
|
stocks: List[SearchStocks]
|
68
|
-
warehouses_with_stock: List[str]
|
69
|
-
total_stock: int
|
70
|
-
has_pictures: bool
|
71
|
-
buying_price: float
|
68
|
+
warehouses_with_stock: List[str] = Field(..., alias='warehousesWithStock')
|
69
|
+
total_stock: int = Field(..., alias='totalStock')
|
70
|
+
has_pictures: bool = Field(..., alias='hasPictures')
|
71
|
+
buying_price: float = Field(..., alias='buyingPrice')
|
72
72
|
prices: List[SearchPrices]
|
73
|
-
integration_ids: List[str]
|
74
|
-
integration_apps: List[str]
|
73
|
+
integration_ids: List[str] = Field(..., alias='integrationIds')
|
74
|
+
integration_apps: List[str] = Field(..., alias='integrationApps')
|
75
75
|
integrations: List[SearchIntegration]
|
76
76
|
campaigns: List[str]
|
77
|
-
app: Optional[int]
|
78
|
-
status: Optional[str]
|
79
|
-
synchronize_stock: Optional[bool]
|
80
|
-
listing_type: Optional[str]
|
81
|
-
price_amount: Optional[float]
|
82
|
-
price_currency: Optional[str]
|
83
|
-
category_id: Optional[str]
|
84
|
-
category_base_id: Optional[str]
|
85
|
-
category_l1: Optional[str]
|
86
|
-
category_l2: Optional[str]
|
87
|
-
category_l3: Optional[str]
|
88
|
-
category_l4: Optional[str]
|
89
|
-
category_l5: Optional[str]
|
90
|
-
category_l6: Optional[str]
|
91
|
-
has_category: Optional[bool]
|
92
|
-
category_fixed: Optional[bool]
|
93
|
-
accepts_mercadoenvios: Optional[bool]
|
94
|
-
shipping_mode: Optional[str]
|
95
|
-
local_pickup: Optional[bool]
|
96
|
-
mandatory_free_shipping: Optional[bool]
|
97
|
-
free_shipping: Optional[bool]
|
98
|
-
free_shipping_cost: Optional[float]
|
99
|
-
template: Optional[str]
|
100
|
-
youtube_id: Optional[str]
|
101
|
-
warranty: Optional[str]
|
102
|
-
permalink: Optional[str]
|
103
|
-
domain: Optional[str]
|
104
|
-
attribute_completion_status: Optional[str]
|
105
|
-
attribute_completion_count: Optional[int]
|
106
|
-
attribute_completion_total: Optional[int]
|
107
|
-
deals: Optional[SearchDeals]
|
108
|
-
campaign_status: Optional[List[str]]
|
109
|
-
size_chart: Optional[str]
|
110
|
-
channel_status: Optional[List[str]]
|
111
|
-
channel_category_l1: Optional[List[str]]
|
112
|
-
channel_category_l2: Optional[List[str]]
|
113
|
-
channel_category_l3: Optional[List[str]]
|
114
|
-
channel_category_id: Optional[List[str]]
|
115
|
-
channel_synchronizes_stock: Optional[List[str]]
|
116
|
-
channel_has_category: Optional[List[str]]
|
117
|
-
catalog_products_status: Optional[List[str]]
|
118
|
-
metadata: Optional[List[str]]
|
119
|
-
integration_tags: Optional[List[str]]
|
120
|
-
variations_integration_ids: Optional[List[str]]
|
121
|
-
channel_pictures_templates: Optional[List[str]]
|
122
|
-
channel_pictures_templates_apps: Optional[List[str]]
|
77
|
+
app: Optional[int] = None
|
78
|
+
status: Optional[str] = None
|
79
|
+
synchronize_stock: Optional[bool] = Field(None, alias='synchronizeStock')
|
80
|
+
listing_type: Optional[str] = Field(None, alias='listingType')
|
81
|
+
price_amount: Optional[float] = Field(None, alias='priceAmount')
|
82
|
+
price_currency: Optional[str] = Field(None, alias='priceCurrency')
|
83
|
+
category_id: Optional[str] = Field(None, alias='categoryId')
|
84
|
+
category_base_id: Optional[str] = Field(None, alias='categoryBaseId')
|
85
|
+
category_l1: Optional[str] = Field(None, alias='categoryL1')
|
86
|
+
category_l2: Optional[str] = Field(None, alias='categoryL2')
|
87
|
+
category_l3: Optional[str] = Field(None, alias='categoryL3')
|
88
|
+
category_l4: Optional[str] = Field(None, alias='categoryL4')
|
89
|
+
category_l5: Optional[str] = Field(None, alias='categoryL5')
|
90
|
+
category_l6: Optional[str] = Field(None, alias='categoryL6')
|
91
|
+
has_category: Optional[bool] = Field(None, alias='hasCategory')
|
92
|
+
category_fixed: Optional[bool] = Field(None, alias='categoryFixed')
|
93
|
+
accepts_mercadoenvios: Optional[bool] = Field(None, alias='acceptsMercadoenvios')
|
94
|
+
shipping_mode: Optional[str] = Field(None, alias='shippingMode')
|
95
|
+
local_pickup: Optional[bool] = Field(None, alias='localPickup')
|
96
|
+
mandatory_free_shipping: Optional[bool] = Field(None, alias='mandatoryFreeShipping')
|
97
|
+
free_shipping: Optional[bool] = Field(None, alias='freeShipping')
|
98
|
+
free_shipping_cost: Optional[float] = Field(None, alias='freeShippingCost')
|
99
|
+
template: Optional[str] = None
|
100
|
+
youtube_id: Optional[str] = Field(None, alias='youtubeId')
|
101
|
+
warranty: Optional[str] = None
|
102
|
+
permalink: Optional[str] = None
|
103
|
+
domain: Optional[str] = None
|
104
|
+
attribute_completion_status: Optional[str] = Field(None, alias='attributeCompletionStatus')
|
105
|
+
attribute_completion_count: Optional[int] = Field(None, alias='attributeCompletionCount')
|
106
|
+
attribute_completion_total: Optional[int] = Field(None, alias='attributeCompletionTotal')
|
107
|
+
deals: Optional[SearchDeals] = None
|
108
|
+
campaign_status: Optional[List[str]] = Field(None, alias='campaignStatus')
|
109
|
+
size_chart: Optional[str] = Field(None, alias='sizeChart')
|
110
|
+
channel_status: Optional[List[str]] = Field(None, alias='channelStatus')
|
111
|
+
channel_category_l1: Optional[List[str]] = Field(None, alias='channelCategoryL1')
|
112
|
+
channel_category_l2: Optional[List[str]] = Field(None, alias='channelCategoryL2')
|
113
|
+
channel_category_l3: Optional[List[str]] = Field(None, alias='channelCategoryL3')
|
114
|
+
channel_category_id: Optional[List[str]] = Field(None, alias='channelCategoryId')
|
115
|
+
channel_synchronizes_stock: Optional[List[str]] = Field(None, alias='channelSynchronizesStock')
|
116
|
+
channel_has_category: Optional[List[str]] = Field(None, alias='channelHasCategory')
|
117
|
+
catalog_products_status: Optional[List[str]] = Field(None, alias='catalogProductsStatus')
|
118
|
+
metadata: Optional[List[str]] = None
|
119
|
+
integration_tags: Optional[List[str]] = Field(None, alias='integrationTags')
|
120
|
+
variations_integration_ids: Optional[List[str]] = Field(None, alias='variationsIntegrationIds')
|
121
|
+
channel_pictures_templates: Optional[List[str]] = Field(None, alias='channelPicturesTemplates')
|
122
|
+
channel_pictures_templates_apps: Optional[List[str]] = Field(None, alias='channelPicturesTemplatesApps')
|
123
123
|
|
124
124
|
|
125
125
|
class SearchProduct(BaseModel):
|
@@ -132,8 +132,5 @@ class SearchProductParams(BaseModel):
|
|
132
132
|
top: Optional[int]
|
133
133
|
skip: Optional[int]
|
134
134
|
filter: Optional[str] = Field(default=None, alias='$filter')
|
135
|
-
search: Optional[str]
|
135
|
+
search: Optional[str] = Field(default=None)
|
136
136
|
sales_channel: Optional[str] = Field(default='2', alias='salesChannel')
|
137
|
-
|
138
|
-
|
139
|
-
|