tgshops-integrations 3.0__py3-none-any.whl → 3.2__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- tgshops_integrations/middlewares/gateway.py +2 -2
- tgshops_integrations/models/products.py +4 -4
- {tgshops_integrations-3.0.dist-info → tgshops_integrations-3.2.dist-info}/METADATA +1 -1
- {tgshops_integrations-3.0.dist-info → tgshops_integrations-3.2.dist-info}/RECORD +6 -8
- tgshops_integrations/nocodb_connector/categories.py +0 -168
- tgshops_integrations/nocodb_connector/products.py +0 -181
- {tgshops_integrations-3.0.dist-info → tgshops_integrations-3.2.dist-info}/WHEEL +0 -0
- {tgshops_integrations-3.0.dist-info → tgshops_integrations-3.2.dist-info}/top_level.txt +0 -0
@@ -23,8 +23,8 @@ from tgshops_integrations.nocodb_connector.model_mapping import (
|
|
23
23
|
PRODUCT_IMAGES_LOOKUP_FIELD,
|
24
24
|
PRODUCT_EXTERNAL_ID,
|
25
25
|
)
|
26
|
-
from
|
27
|
-
from
|
26
|
+
from tgshops_integrations.nocodb_connector.categories import CategoryManager
|
27
|
+
from tgshops_integrations.nocodb_connector.products import ProductManager
|
28
28
|
from loguru import logger
|
29
29
|
|
30
30
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from pydantic import BaseModel
|
2
|
-
from typing import Any, List, Optional
|
2
|
+
from typing import Any, List,Dict, Optional
|
3
3
|
from datetime import datetime
|
4
4
|
|
5
5
|
from pydantic import BaseModel, Field, schema, validator
|
@@ -28,12 +28,12 @@ class ExternalProductModel(BaseModel):
|
|
28
28
|
class ProductModel(BaseModel):
|
29
29
|
id: Optional[str]
|
30
30
|
external_id: Optional[str]
|
31
|
-
|
32
|
-
|
31
|
+
product_properties: Optional[List[str]]
|
32
|
+
categories_structure: Optional[Dict[str, Any]]
|
33
33
|
name: str
|
34
34
|
description: Optional[str]
|
35
35
|
price: Optional[float]
|
36
|
-
final_price: Optional[
|
36
|
+
final_price: Optional[float]
|
37
37
|
currency: Optional[str]
|
38
38
|
stock_qty: int
|
39
39
|
orders_qty: int = Field(0, hidden_field=True)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: tgshops-integrations
|
3
|
-
Version: 3.
|
3
|
+
Version: 3.2
|
4
4
|
Summary: Library is intended to provide the integration of the external service or CRM system with the TelegramShops/It allows to configure the relationship between NocoDB list of the products used further to display in the shop/As a resultss the products can be synchronized and updated uppon the request.
|
5
5
|
Home-page: https://git.the-devs.com/virtual-shops/shop-system/shop-backend-integrations/integration-library/integration-library
|
6
6
|
Author: Dimi Latoff
|
@@ -1,18 +1,16 @@
|
|
1
1
|
tgshops_integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
tgshops_integrations/middlewares/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
tgshops_integrations/middlewares/gateway.py,sha256
|
3
|
+
tgshops_integrations/middlewares/gateway.py,sha256=-YQi3-62k6gkxJLx27FESe6wlRrD4_Ltqk8wZJ8ExYg,6247
|
4
4
|
tgshops_integrations/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
tgshops_integrations/models/categories.py,sha256=EG6C8g5dOfXB2MH-vtqH13aqB7_VyOobY2FHpDb-fsY,977
|
6
|
-
tgshops_integrations/models/products.py,sha256=
|
6
|
+
tgshops_integrations/models/products.py,sha256=CpQ5LpeigklgVnkKPCm5jR9hfJsoFbWKSsDiTI32RSo,1405
|
7
7
|
tgshops_integrations/nocodb_connector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
tgshops_integrations/nocodb_connector/categories.py,sha256=eoAWRA0aSE84_ONrwflM1ZFXLSCFjYl_CFqUf7lA_EU,9063
|
9
8
|
tgshops_integrations/nocodb_connector/categories_management.py,sha256=dvPXcrgruJyuWFT7Ho-8YRcjJxhR3Hcw0hJiVKQgcyA,6603
|
10
9
|
tgshops_integrations/nocodb_connector/client.py,sha256=U2rNozjluWVul-VZroQW-8b2j6nEtKrhOkFMz1L8KmI,12022
|
11
10
|
tgshops_integrations/nocodb_connector/model_mapping.py,sha256=ixv-uT1Pmt1szZCQ5pGsMbwRvmnHZmn0NqG77nxZkDM,8551
|
12
|
-
tgshops_integrations/nocodb_connector/products.py,sha256=kAp7lUaRO7CkU_SumbIdLOJf38SmDBEyBBZCYyyyOFM,9313
|
13
11
|
tgshops_integrations/nocodb_connector/products_management.py,sha256=t_ZDyIAPTe_6UrxLuJ32Uhlk8ssErP6Eo0n-TIZfEko,6046
|
14
12
|
tgshops_integrations/nocodb_connector/tables.py,sha256=ha_QXZXd93mht0fR5E1nM0wUpz1ePon-pIdO2HI67l8,356
|
15
|
-
tgshops_integrations-3.
|
16
|
-
tgshops_integrations-3.
|
17
|
-
tgshops_integrations-3.
|
18
|
-
tgshops_integrations-3.
|
13
|
+
tgshops_integrations-3.2.dist-info/METADATA,sha256=daiTMAx10_7qtGpB4ILTHYZCEnU9eFtuYENzwki-VTc,2774
|
14
|
+
tgshops_integrations-3.2.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
15
|
+
tgshops_integrations-3.2.dist-info/top_level.txt,sha256=HFNtxqDpzmlF4ZLnMiwhbU7pOa_YozxU2zBl0bnUmcY,21
|
16
|
+
tgshops_integrations-3.2.dist-info/RECORD,,
|
@@ -1,168 +0,0 @@
|
|
1
|
-
from typing import List
|
2
|
-
from loguru import logger
|
3
|
-
|
4
|
-
from aiocache import cached
|
5
|
-
from tgshops_integrations.models.categories import CategoryModel,CategoryResponseModel,CategoryListResponseModel
|
6
|
-
from tgshops_integrations.models.products import ProductModel
|
7
|
-
from tgshops_integrations.nocodb_connector.client import custom_key_builder, NocodbClient
|
8
|
-
from tgshops_integrations.nocodb_connector.model_mapping import CATEGORY_IMAGE_FIELD, CATEGORY_NAME_FIELD, CATEGORY_PARENT_FIELD, \
|
9
|
-
CATEGORY_PARENT_ID_FIELD, PRODUCT_NAME_FIELD,CATEGORY_ID_OF_CATEGORY_FIELD, dump_category_data, get_pagination_info, parse_category_data
|
10
|
-
|
11
|
-
|
12
|
-
class CategoryManager(NocodbClient):
|
13
|
-
def __init__(self,table_id=None,logging=False,config_type=None,NOCODB_HOST=None,NOCODB_API_KEY=None,SOURCE=None,filter_buttons=[]):
|
14
|
-
super().__init__(NOCODB_HOST=NOCODB_HOST,NOCODB_API_KEY=NOCODB_API_KEY,SOURCE=SOURCE)
|
15
|
-
self.NOCODB_HOST = NOCODB_HOST
|
16
|
-
self.NOCODB_API_KEY = NOCODB_API_KEY
|
17
|
-
self.SOURCE=SOURCE
|
18
|
-
self.CONFIG_TYPE=config_type
|
19
|
-
self.categories_table=table_id
|
20
|
-
self.external_categories={}
|
21
|
-
self.logging=logging
|
22
|
-
self.filter_categories=[]
|
23
|
-
self.filter_buttons=filter_buttons
|
24
|
-
self.required_fields = [CATEGORY_NAME_FIELD]
|
25
|
-
self.projection = ["Id", CATEGORY_NAME_FIELD, CATEGORY_PARENT_ID_FIELD, CATEGORY_ID_OF_CATEGORY_FIELD]
|
26
|
-
# self.projection = ["Id"]
|
27
|
-
|
28
|
-
@cached(ttl=30, key_builder=custom_key_builder)
|
29
|
-
async def get_categories(self, table_id: str) -> List[CategoryModel]:
|
30
|
-
records = await self.get_table_records(table_id, self.required_fields, self.projection)
|
31
|
-
return [parse_category_data(record) for record in records]
|
32
|
-
|
33
|
-
@cached(ttl=30, key_builder=custom_key_builder)
|
34
|
-
async def get_categories_v2(self,
|
35
|
-
table_id: str,
|
36
|
-
offset: int = None,
|
37
|
-
limit: int = None) -> CategoryModel:
|
38
|
-
response = (await self.get_table_records_v2(table_name=self.categories_table,
|
39
|
-
required_fields=self.required_fields,
|
40
|
-
projection=self.projection,
|
41
|
-
offset=offset,
|
42
|
-
limit=limit))
|
43
|
-
page_info = get_pagination_info(page_info=response['pageInfo'])
|
44
|
-
categories = [parse_category_data(record) for record in response['list']]
|
45
|
-
return CategoryListResponseModel(categories=categories, page_info=page_info)
|
46
|
-
|
47
|
-
@cached(ttl=30, key_builder=custom_key_builder)
|
48
|
-
async def get_category(self, table_id: str, category_id: str) -> CategoryModel:
|
49
|
-
record = await self.get_table_record(self.categories_table, category_id, self.required_fields, self.projection)
|
50
|
-
return parse_category_data(record)
|
51
|
-
|
52
|
-
async def create_category(self, table_id: str, category: CategoryModel) -> CategoryModel:
|
53
|
-
category_json = dump_category_data(category)
|
54
|
-
record = await self.create_table_record(self.categories_table, category_json)
|
55
|
-
return parse_category_data(record)
|
56
|
-
|
57
|
-
@cached(ttl=30, key_builder=custom_key_builder)
|
58
|
-
async def get_categories_in_category(self, table_id: str, category_id: str) -> List[CategoryModel]:
|
59
|
-
# ! In case category_id == 0,
|
60
|
-
# we need to get all categories without parent by field CATEGORY_PARENT_FIELD not CATEGORY_PARENT_ID_FIELD
|
61
|
-
records = await self.get_table_records(
|
62
|
-
table_name=self.categories_table,
|
63
|
-
required_fields=self.required_fields,
|
64
|
-
projection=self.projection,
|
65
|
-
extra_where=(f"({CATEGORY_PARENT_ID_FIELD},eq,{category_id})"
|
66
|
-
if category_id else f"({CATEGORY_PARENT_FIELD},eq,0)"))
|
67
|
-
return [parse_category_data(record) for record in records]
|
68
|
-
|
69
|
-
@cached(ttl=30, key_builder=custom_key_builder)
|
70
|
-
async def get_categories_in_category_v2(self,
|
71
|
-
table_id: str,
|
72
|
-
category_id: str,
|
73
|
-
offset: int,
|
74
|
-
limit: int) -> CategoryModel:
|
75
|
-
|
76
|
-
response = await self.get_table_records_v2(
|
77
|
-
table_name=self.categories_table,
|
78
|
-
required_fields=self.required_fields,
|
79
|
-
projection=self.projection,
|
80
|
-
extra_where=(f"({CATEGORY_PARENT_ID_FIELD},eq,{category_id})"
|
81
|
-
if category_id else f"({CATEGORY_PARENT_FIELD},eq,0)"),
|
82
|
-
offset=offset,
|
83
|
-
limit=limit)
|
84
|
-
categories = [parse_category_data(record) for record in response['list']]
|
85
|
-
page_info = get_pagination_info(page_info=response['pageInfo'])
|
86
|
-
return CategoryModel(categories=categories, page_info=page_info)
|
87
|
-
|
88
|
-
async def update_categories(self,external_products: List[ProductModel]) -> List[ProductModel]:
|
89
|
-
# Get the names of the tables from the DB for further handling
|
90
|
-
self.categories=await self.get_product_categories(table_id=self.categories_table, table_name=PRODUCT_NAME_FIELD)
|
91
|
-
|
92
|
-
categories_list=[*self.categories.keys()]
|
93
|
-
categories_to_create=[]
|
94
|
-
|
95
|
-
for product in external_products:
|
96
|
-
# Check for new categories
|
97
|
-
# DEPRECATED IF some category number exists on external side
|
98
|
-
# if product.category:
|
99
|
-
# for external_category_id,category_name in zip(product.category,product.category_name):
|
100
|
-
# if category_name not in [*self.categories.keys()]:
|
101
|
-
# new_category= await self.create_product_category(table_id=self.categories_table,category_name=category_name,category_id=external_category_id,table_name=PRODUCT_NAME_FIELD)
|
102
|
-
# if self.logging:
|
103
|
-
# logger.info(f"New Category {new_category}")
|
104
|
-
# self.external_categories[new_category["Id"]]=external_category_id
|
105
|
-
# self.categories=await self.get_product_categories(table_id=self.categories_table, table_name=PRODUCT_NAME_FIELD)
|
106
|
-
#Else if there is just the name, create the category with new id
|
107
|
-
# else:
|
108
|
-
#Needs the buttons to be initialized, can connect items to buttons , which allows filtered acces through the menu
|
109
|
-
for num,category_name in enumerate(product.category_name):
|
110
|
-
if category_name not in categories_list:
|
111
|
-
if self.filter_buttons:
|
112
|
-
parent_id=self.categories[self.filter_buttons[num]]
|
113
|
-
else:
|
114
|
-
parent_id=self.categories[product.category_II_name[0]]
|
115
|
-
categories_to_create.append([category_name,parent_id])
|
116
|
-
categories_list.append(category_name)
|
117
|
-
|
118
|
-
if categories_to_create:
|
119
|
-
categories_to_create.sort(key=lambda x: x[0])
|
120
|
-
if [*self.categories.values()]:
|
121
|
-
new_id=max(self.categories.values())+1
|
122
|
-
else:
|
123
|
-
new_id=1
|
124
|
-
for category,parent_id in categories_to_create:
|
125
|
-
new_category= await self.create_product_category(table_id=self.categories_table,category_name=category,category_id=new_id,table_name=PRODUCT_NAME_FIELD)
|
126
|
-
if self.logging:
|
127
|
-
logger.info(f"New Category {new_category}")
|
128
|
-
if self.filter_buttons:
|
129
|
-
#Rewind categories
|
130
|
-
await self.link_categories(parent_id=parent_id,child_id=new_id)
|
131
|
-
new_id+=1
|
132
|
-
|
133
|
-
async def link_categories(self,parent_id:int,child_id:int):
|
134
|
-
metadata = await self.get_table_meta(self.categories_table)
|
135
|
-
|
136
|
-
linked_column = None
|
137
|
-
for col in metadata['columns']:
|
138
|
-
if (col["title"]=="Set parent category" and col["uidt"] == "Links"):
|
139
|
-
linked_column = col
|
140
|
-
break
|
141
|
-
await self.link_table_record(
|
142
|
-
linked_column["base_id"],
|
143
|
-
linked_column["fk_model_id"],
|
144
|
-
child_id,
|
145
|
-
linked_column["id"],
|
146
|
-
parent_id)
|
147
|
-
|
148
|
-
async def unlink_categories(self,parent_id:int,child_id:int):
|
149
|
-
metadata = await self.get_table_meta(self.categories_table)
|
150
|
-
|
151
|
-
linked_column = None
|
152
|
-
for col in metadata['columns']:
|
153
|
-
if col["uidt"] == "Links":
|
154
|
-
linked_column = col
|
155
|
-
break
|
156
|
-
await self.unlink_table_record(
|
157
|
-
linked_column["base_id"],
|
158
|
-
linked_column["fk_model_id"],
|
159
|
-
parent_id,
|
160
|
-
linked_column["id"],
|
161
|
-
child_id)
|
162
|
-
|
163
|
-
async def map_categories(self,external_products: List[ProductModel]) -> List[ProductModel]:
|
164
|
-
for num,product in enumerate(external_products):
|
165
|
-
if not product.category:
|
166
|
-
if product.category_name:
|
167
|
-
external_products[num].category=[str(self.categories[category_name]) for category_name in product.category_name]
|
168
|
-
return external_products
|
@@ -1,181 +0,0 @@
|
|
1
|
-
from typing import List,Optional
|
2
|
-
|
3
|
-
from aiocache import cached
|
4
|
-
from tgshops_integrations.models.products import ProductModel
|
5
|
-
from tgshops_integrations.models.products import ProductModel, ProductModel
|
6
|
-
from tgshops_integrations.nocodb_connector.client import custom_key_builder, NocodbClient
|
7
|
-
from tgshops_integrations.nocodb_connector.model_mapping import dump_product_data,dump_product_data_with_check, get_pagination_info, ID_FIELD, \
|
8
|
-
parse_product_data, PRODUCT_CATEGORY_ID_LOOKUP_FIELD, PRODUCT_NAME_FIELD, PRODUCT_PRICE_FIELD, \
|
9
|
-
PRODUCT_STOCK_FIELD,PRODUCT_EXTERNAL_ID,PRODUCT_IMAGES_LOOKUP_FIELD
|
10
|
-
|
11
|
-
from tgshops_integrations.nocodb_connector.tables import *
|
12
|
-
from loguru import logger
|
13
|
-
import hashlib
|
14
|
-
|
15
|
-
|
16
|
-
class ProductManager(NocodbClient):
|
17
|
-
|
18
|
-
def __init__(self, table_id=None, logging=False, NOCODB_HOST=None, NOCODB_API_KEY=None, SOURCE=None):
|
19
|
-
super().__init__(NOCODB_HOST=NOCODB_HOST, NOCODB_API_KEY=NOCODB_API_KEY, SOURCE=SOURCE)
|
20
|
-
self.NOCODB_HOST = NOCODB_HOST
|
21
|
-
self.NOCODB_API_KEY = NOCODB_API_KEY
|
22
|
-
self.SOURCE = SOURCE
|
23
|
-
self.logging = logging
|
24
|
-
self.required_fields = [PRODUCT_NAME_FIELD, PRODUCT_PRICE_FIELD]
|
25
|
-
self.projection = []
|
26
|
-
self.external_categories = {}
|
27
|
-
self.products_table = table_id
|
28
|
-
self.actual_products = []
|
29
|
-
self.columns = []
|
30
|
-
|
31
|
-
def hash_product(self,product,special_attributes=False):
|
32
|
-
if special_attributes:
|
33
|
-
hash_string = ''.join(attr.description for attr in product.extra_attributes if attr.name.endswith('*'))
|
34
|
-
# hash_string = f"{product.external_id}{product.price}{product.category_name.sort()}{product.name}{product.description}"
|
35
|
-
else:
|
36
|
-
# Concatenate relevant attributes into a single string
|
37
|
-
hash_string = f"{product.external_id}{product.price}{product.category_name.sort()}{product.name}{product.description}"
|
38
|
-
# hash_string = f"{product.external_id}{product.price}{product.category_name}{product.name}{product.description}{product.preview_url}"
|
39
|
-
# Hash the concatenated string
|
40
|
-
hash_object = hashlib.sha256(hash_string.encode())
|
41
|
-
hex_dig = hash_object.hexdigest()
|
42
|
-
return hex_dig
|
43
|
-
|
44
|
-
@cached(ttl=30, key_builder=custom_key_builder)
|
45
|
-
async def get_products(self, table_id: str) -> List[ProductModel]:
|
46
|
-
records = await self.get_table_records(self.products_table, self.required_fields, self.projection)
|
47
|
-
return [parse_product_data(record) for record in records]
|
48
|
-
|
49
|
-
# @cached(ttl=30, key_builder=custom_key_builder)
|
50
|
-
async def get_products_v2(self, offset: int, limit: int, table_id: Optional[str] = None) -> List[ProductModel]:
|
51
|
-
# Get the names of the tables from the DB for further handling
|
52
|
-
await self.get_all_tables()
|
53
|
-
response = await self.get_table_records_v2(table_name=self.products_table,
|
54
|
-
required_fields=self.required_fields,
|
55
|
-
projection=self.projection,
|
56
|
-
offset=offset,
|
57
|
-
limit=limit)
|
58
|
-
products = [await parse_product_data(record) for record in response['list']]
|
59
|
-
|
60
|
-
return products
|
61
|
-
|
62
|
-
@cached(ttl=180, key_builder=custom_key_builder)
|
63
|
-
async def search_products(self, table_id: str, search_string: str, limit: int) -> List[ProductModel]:
|
64
|
-
records = await self.get_table_records(
|
65
|
-
table_name=self.products_table,
|
66
|
-
required_fields=self.required_fields,
|
67
|
-
projection=self.projection,
|
68
|
-
extra_where=f"({PRODUCT_NAME_FIELD},like,%{search_string}%)", # Update with actual product name field
|
69
|
-
limit=limit
|
70
|
-
)
|
71
|
-
return [parse_product_data(record) for record in records]
|
72
|
-
|
73
|
-
@cached(ttl=180, key_builder=custom_key_builder)
|
74
|
-
async def search_products_v2(self, table_id: str, search_string: str, limit: int) -> List[ProductModel]:
|
75
|
-
records = (await self.get_table_records_v2(
|
76
|
-
table_name=self.products_table,
|
77
|
-
required_fields=self.required_fields,
|
78
|
-
projection=self.projection,
|
79
|
-
extra_where=f"({PRODUCT_NAME_FIELD},like,%{search_string}%)", # Update with actual product name field
|
80
|
-
limit=limit
|
81
|
-
))['list']
|
82
|
-
return [parse_product_data(record) for record in records]
|
83
|
-
|
84
|
-
@cached(ttl=60, key_builder=custom_key_builder)
|
85
|
-
async def get_product(self, table_id: str, product_id: str) -> ProductModel:
|
86
|
-
record = await self.get_table_record(self.products_table, product_id)
|
87
|
-
return parse_product_data(record)
|
88
|
-
|
89
|
-
@cached(ttl=60, key_builder=custom_key_builder)
|
90
|
-
async def get_product_v2(self, table_id: str, product_id: str) -> ProductModel:
|
91
|
-
record = await self.get_table_record(self.products_table, product_id)
|
92
|
-
product = parse_product_data(record)
|
93
|
-
|
94
|
-
related_products = await self.get_table_records_v2(
|
95
|
-
table_name=self.products_table,
|
96
|
-
required_fields=self.required_fields,
|
97
|
-
projection=self.projection,
|
98
|
-
extra_where=(f'({PRODUCT_STOCK_FIELD},gt,0)~and'
|
99
|
-
f"({PRODUCT_CATEGORY_ID_LOOKUP_FIELD},eq,{product.category[0]})~and"
|
100
|
-
f'({PRODUCT_NAME_FIELD},neq,{product.name})'),
|
101
|
-
limit=5
|
102
|
-
)
|
103
|
-
related_products = [parse_product_data(product) for product in related_products['list']]
|
104
|
-
|
105
|
-
product.related_products = related_products
|
106
|
-
return product
|
107
|
-
|
108
|
-
@cached(ttl=60, key_builder=custom_key_builder)
|
109
|
-
async def get_product_in_category(self, table_id: str, category_id: str = None) -> List[ProductModel]:
|
110
|
-
if category_id is None:
|
111
|
-
return await self.get_products(table_id=self.products_table)
|
112
|
-
|
113
|
-
records = await self.get_table_records(
|
114
|
-
table_name=self.products_table,
|
115
|
-
required_fields=self.required_fields,
|
116
|
-
projection=self.projection,
|
117
|
-
extra_where=(f'({PRODUCT_STOCK_FIELD},gt,0)~and'
|
118
|
-
f"({PRODUCT_CATEGORY_ID_LOOKUP_FIELD},eq,{category_id})")
|
119
|
-
)
|
120
|
-
return [parse_product_data(record) for record in records]
|
121
|
-
|
122
|
-
@cached(ttl=60, key_builder=custom_key_builder)
|
123
|
-
async def get_product_in_category_v2(self,
|
124
|
-
table_id: str,
|
125
|
-
offset: int,
|
126
|
-
limit: int,
|
127
|
-
category_id: str = None) -> ProductModel:
|
128
|
-
if category_id is None:
|
129
|
-
return await self.get_products_v2(table_id=self.products_table, offset=offset, limit=limit)
|
130
|
-
|
131
|
-
response = (await self.get_table_records_v2(
|
132
|
-
table_name=self.products_table,
|
133
|
-
required_fields=self.required_fields,
|
134
|
-
projection=self.projection,
|
135
|
-
extra_where=(f'({PRODUCT_STOCK_FIELD},gt,0)~and'
|
136
|
-
f"({PRODUCT_CATEGORY_ID_LOOKUP_FIELD},eq,{category_id})"),
|
137
|
-
offset=offset,
|
138
|
-
limit=limit
|
139
|
-
))
|
140
|
-
page_info = get_pagination_info(page_info=response['pageInfo'])
|
141
|
-
products = [parse_product_data(record) for record in response['list']]
|
142
|
-
return ProductModel(products=products, page_info=page_info)
|
143
|
-
|
144
|
-
@cached(ttl=60, key_builder=custom_key_builder)
|
145
|
-
async def get_products_by_ids(self, table_id: str, product_ids: list) -> List[ProductModel]:
|
146
|
-
product_ids_str = ','.join(str(product_id) for product_id in product_ids)
|
147
|
-
|
148
|
-
records = await self.get_table_records(
|
149
|
-
table_name=self.products_table,
|
150
|
-
required_fields=self.required_fields,
|
151
|
-
projection=self.projection,
|
152
|
-
extra_where=f"({ID_FIELD},in,{product_ids_str})")
|
153
|
-
return [parse_product_data(record) for record in records]
|
154
|
-
|
155
|
-
@cached(ttl=60, key_builder=custom_key_builder)
|
156
|
-
async def update_attributes(self,products:List[ProductModel]):
|
157
|
-
system_attributes = [PRODUCT_EXTERNAL_ID,PRODUCT_IMAGES_LOOKUP_FIELD]
|
158
|
-
attributes=await self.get_table_meta(table_name=self.products_table)
|
159
|
-
self.columns =[item['title'].lower() for item in attributes.get('columns', [])]
|
160
|
-
|
161
|
-
#TODO Requires Validation
|
162
|
-
for attribute_name in system_attributes:
|
163
|
-
if attribute_name.lower() not in self.columns:
|
164
|
-
response =await self.create_table_column(table_name=self.products_table,name=attribute_name)
|
165
|
-
logger.info(f"Created attribute: {attribute_name}")
|
166
|
-
|
167
|
-
for item in products:
|
168
|
-
attributes=await self.get_table_meta(table_name=self.products_table)
|
169
|
-
self.columns =[item['title'].lower() for item in attributes.get('columns', [])]
|
170
|
-
|
171
|
-
for attribute in item.extra_attributes:
|
172
|
-
if attribute.name.rstrip().lower() not in self.columns:
|
173
|
-
response =await self.create_table_column(table_name=self.products_table,name=attribute.name.lower())
|
174
|
-
logger.info(f"Created attribute: {attribute.name.lower()}")
|
175
|
-
|
176
|
-
|
177
|
-
def find_product_id_by_name(self,name: str):
|
178
|
-
for product in self.actual_products.products:
|
179
|
-
if product.name == name:
|
180
|
-
return product.id
|
181
|
-
return None # Return None if no product is found with the given name
|
File without changes
|
File without changes
|