tgshops-integrations 3.0__py3-none-any.whl → 3.2__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.
- 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
|