-
Notifications
You must be signed in to change notification settings - Fork 0
/
Category.py
198 lines (177 loc) · 8.29 KB
/
Category.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import Product
class Category:
categories = {}
def __init__(self, name, parent, en_name=None, entity_id=''):
if not (name and isinstance(name, str)): raise ValueError('Category_init')
self.name = name
if not (parent is None or isinstance(parent, Category)): raise ValueError('Category_init')
self.parent = parent
if parent: self.parent.children.add(self)
self.entity_id = entity_id
self.children = set()
self.categories[str(self)] = self
self.position = '1'
self.is_anchor = '1'
if not (en_name is None or isinstance(en_name, str)): raise ValueError('Category_init')
self.en_name = en_name or ''
self.id = None
def __str__(self):
path = self.path()
return f'{path}|{self.name}' if path else f'{self.name}'
def __repr__(self):
path = self.path()
return f'{path}|{self.name}' if path else f'{self.name}'
def path(self, cats=None):
if cats is None: cats = []
if not isinstance(cats, list): raise ValueError('Category_path')
if self.parent:
cats.append(self.parent.name)
return self.parent.path(cats)
else:
return '|'.join(cats[::-1])
def find_children(self, show_cats=True, show_products=True, text=False):
if not isinstance(show_cats, bool): raise ValueError('Category_children')
if not isinstance(show_products, bool): raise ValueError('Category_children')
if not isinstance(text, bool): raise ValueError('Category_children')
if not text:
result = []
if show_cats:
children_categories = [cat for cat in self.children if isinstance(cat, Category)]
result.extend(children_categories)
if show_products:
children_products = [product for product in self.children if isinstance(product, Product.Product)]
result.extend(children_products)
return result
else:
result = ''
if show_cats:
children_categories = [cat.name for cat in self.children if isinstance(cat, Category)]
if children_categories:
result += f'Categories({len(children_categories)}): ' + ', '.join(children_categories) + '\n'
if show_products:
children_products = [product.full_sku for product in self.children if
isinstance(product, Product.Product)]
if children_products:
result += f'Products({len(children_products)}): ' + ', '.join(children_products)
return result.strip('\n')
@property
def children_categories_count(self):
return len([cat for cat in self.children if isinstance(cat, Category)])
@property
def children_products_count(self):
return len([product for product in self.children if isinstance(product, Product.Product)])
def add_product(self, product):
if not isinstance(product, Product.Product): raise ValueError('bad add_product')
self.children.add(product)
product.categories.add(self)
@classmethod
def create_category(cls, path, en_path=None, entity_id=''):
if not isinstance(path, str): raise ValueError('Category_create_category')
if not (en_path is None or isinstance(path, str)): raise ValueError('Category_create_category')
path = path.split('|')
if en_path:
en_path = en_path.split('|')
if len(path) != len(en_path):
print(f'=== разная длина пути категорий {path} {en_path}')
en_path = None
for i in range(len(path)):
check_path = '|'.join(path[0:i + 1])
find_result = cls.categories.get(check_path, None)
if not find_result:
parent_path = '|'.join(path[0:i])
find_result = Category(
path[i],
cls.categories.get(parent_path, None),
en_path[i] if en_path else None,
entity_id if (i == len(path) - 1) else ''
)
return find_result
def export(self):
data = {}
data['entity_id'] = self.entity_id
data['path'] = self.path()
data['name'] = self.name
data['position'] = self.position
data['is_anchor'] = self.is_anchor
data['en_name'] = self.en_name
return data
@classmethod
def count(cls):
return len(cls.categories)
def delete(self):
self.categories.pop(str(self))
if self.parent:
self.parent.children.remove(self)
for child in self.children:
if isinstance(child, Category):
child.parent = self.parent
if isinstance(child, Product.Product):
child.categories.remove(self)
child.categories.add(self.parent)
self.parent.children.add(child)
else:
raise ValueError
Category.reindex()
# print(f'категория {str(self)} удалена')
@classmethod
def reindex(cls):
cls.categories = {str(cat): cat for cat in cls.categories.values()}
@classmethod
def clear(cls):
cls.categories = {}
@classmethod
def reorganize_categories(cls, lang, col=1):
new_cat_name = {'de': 'Mehr', 'en': 'More', 'ru': 'Прочее'}
print(f'всего {int(cls.count() / col)} категорий')
while True:
a, b = 0, 0
for each in list(cls.categories.values()).copy():
# if str(each).count('|') < 3: continue
### удаляем папки с количеством товаров меньше 3
if each.children_categories_count == 0 and each.children_products_count < 3:
each.delete()
a += 1
### удаляем промежуточные папки без товаров
elif each.children_categories_count == 1 and each.children_products_count == 0:
each.delete()
b += 1
if a or b: print(f'удалено {int(a / col)}+{int(b / col)} категорий')
if (a + b) == 0: break
print(f'всего {int(cls.count() / col)} категорий')
### перемещаем "промежуточные" товары в новую папку
while True:
c = 0
for each in list(cls.categories.values()).copy():
if each.children_categories_count > 0 and each.children_products_count > 0:
new_cat = cls.create_category(f'{each}|{new_cat_name[lang]}')
for child in each.find_children(show_cats=False, show_products=True, text=False):
child.move(each, new_cat)
c += 1
if c: print(f'создано {c // col} новых категорий {new_cat_name[lang]}. '
f'итого {cls.count() // col} категорий')
if c == 0: break
@classmethod
def find_english_names(cls, site_categories, products):
import LoadDictFromFile
for each in site_categories.values():
full_path = f"{each['path']}|{each['name']}"
full_path_en = LoadDictFromFile.find_value(products, 'category_ids', full_path)
if full_path_en:
cls.create_category(
full_path,
en_path=full_path_en.get('category_ids_en', ''),
entity_id=each['entity_id'])
cls.__add_column_with_english_name(site_categories)
@classmethod
def find_english_names2(cls, site_categories, products):
for each in products.values():
cls.create_category(each['category_ids'], en_path=each['category_ids_en'])
cls.__add_column_with_english_name(site_categories)
@classmethod
def __add_column_with_english_name(cls, site_categories):
for each in site_categories.values():
find_result = cls.categories.get(f"{each['path']}|{each['name']}", None)
if find_result:
each['name_en'] = find_result.en_name
else:
print(f'=== category {find_result} not found')