qrpa 1.1.34__py3-none-any.whl → 1.1.35__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.
Potentially problematic release.
This version of qrpa might be problematic. Click here for more details.
- qrpa/mysql_module/new_product_analysis_model.py +60 -1
- qrpa/mysql_module/shein_store_model.py +594 -0
- {qrpa-1.1.34.dist-info → qrpa-1.1.35.dist-info}/METADATA +1 -1
- {qrpa-1.1.34.dist-info → qrpa-1.1.35.dist-info}/RECORD +6 -5
- {qrpa-1.1.34.dist-info → qrpa-1.1.35.dist-info}/WHEEL +0 -0
- {qrpa-1.1.34.dist-info → qrpa-1.1.35.dist-info}/top_level.txt +0 -0
|
@@ -63,6 +63,7 @@ class SheinNewProductAnalysis(Base):
|
|
|
63
63
|
ab_test = Column(Text, nullable=True, comment='AB测试数据(JSON)')
|
|
64
64
|
|
|
65
65
|
# 分析字段(不参与更新)
|
|
66
|
+
front_price = Column(DECIMAL(10, 2), nullable=True, comment='前台价格')
|
|
66
67
|
reason_analysis = Column(Text, nullable=True, comment='原因分析')
|
|
67
68
|
optimization_action = Column(Text, nullable=True, comment='优化动作')
|
|
68
69
|
|
|
@@ -144,7 +145,7 @@ class NewProductAnalysisManager:
|
|
|
144
145
|
|
|
145
146
|
if existing:
|
|
146
147
|
# 更新现有记录(排除不更新的分析字段)
|
|
147
|
-
exclude_fields = {'reason_analysis', 'optimization_action'}
|
|
148
|
+
exclude_fields = {'front_price', 'reason_analysis', 'optimization_action'}
|
|
148
149
|
for key, value in data.items():
|
|
149
150
|
if key not in exclude_fields:
|
|
150
151
|
setattr(existing, key, value)
|
|
@@ -328,6 +329,41 @@ class NewProductAnalysisManager:
|
|
|
328
329
|
# 调用insert_data方法插入数据
|
|
329
330
|
return self.insert_data(data_list)
|
|
330
331
|
|
|
332
|
+
def update_front_price(self, stat_date, skc, front_price):
|
|
333
|
+
"""
|
|
334
|
+
更新指定SKC的前台价格
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
stat_date (str): 统计日期
|
|
338
|
+
skc (str): 平台SKC
|
|
339
|
+
front_price (float): 前台价格
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
bool: 是否成功
|
|
343
|
+
"""
|
|
344
|
+
session = self.Session()
|
|
345
|
+
try:
|
|
346
|
+
record = session.query(SheinNewProductAnalysis).filter(
|
|
347
|
+
SheinNewProductAnalysis.stat_date == stat_date,
|
|
348
|
+
SheinNewProductAnalysis.skc == skc
|
|
349
|
+
).first()
|
|
350
|
+
|
|
351
|
+
if record:
|
|
352
|
+
record.front_price = front_price
|
|
353
|
+
setattr(record, 'updated_at', datetime.now())
|
|
354
|
+
session.commit()
|
|
355
|
+
print(f"成功更新前台价格: {skc} ({stat_date}) -> {front_price}")
|
|
356
|
+
return True
|
|
357
|
+
else:
|
|
358
|
+
print(f"未找到记录: SKC={skc}, 日期={stat_date}")
|
|
359
|
+
return False
|
|
360
|
+
except Exception as e:
|
|
361
|
+
session.rollback()
|
|
362
|
+
print(f"更新前台价格失败: {e}")
|
|
363
|
+
raise
|
|
364
|
+
finally:
|
|
365
|
+
session.close()
|
|
366
|
+
|
|
331
367
|
def delete_records_by_date(self, store_username, stat_date):
|
|
332
368
|
"""
|
|
333
369
|
删除指定日期的记录
|
|
@@ -410,6 +446,23 @@ def get_records_by_skc(store_username, skc):
|
|
|
410
446
|
manager = get_new_product_analysis_manager()
|
|
411
447
|
return manager.get_records_by_skc(store_username, skc)
|
|
412
448
|
|
|
449
|
+
|
|
450
|
+
def update_front_price(stat_date, skc, front_price):
|
|
451
|
+
"""
|
|
452
|
+
更新前台价格的便捷函数
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
stat_date (str): 统计日期
|
|
456
|
+
skc (str): 平台SKC
|
|
457
|
+
front_price (float): 前台价格
|
|
458
|
+
|
|
459
|
+
Returns:
|
|
460
|
+
bool: 是否成功
|
|
461
|
+
"""
|
|
462
|
+
manager = get_new_product_analysis_manager()
|
|
463
|
+
return manager.update_front_price(stat_date, skc, front_price)
|
|
464
|
+
|
|
465
|
+
|
|
413
466
|
if __name__ == '__main__':
|
|
414
467
|
# 测试代码
|
|
415
468
|
manager = NewProductAnalysisManager()
|
|
@@ -427,3 +480,9 @@ if __name__ == '__main__':
|
|
|
427
480
|
json_data = json.load(f)
|
|
428
481
|
count = manager.import_from_json(json_data)
|
|
429
482
|
print(f"成功导入 {count} 条记录")
|
|
483
|
+
|
|
484
|
+
# 更新前台价格(手动设置,后续导入不会覆盖)
|
|
485
|
+
# manager.update_front_price('2025-10-15', 'si2409238815318914', 19.99)
|
|
486
|
+
|
|
487
|
+
# 或使用便捷函数
|
|
488
|
+
# update_front_price('2025-10-15', 'si2409238815318914', 19.99)
|
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
店铺信息数据模型
|
|
5
|
+
使用SQLAlchemy定义shein_store表结构
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from sqlalchemy import create_engine, Column, Integer, String, BigInteger, DateTime, Index
|
|
9
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
10
|
+
from sqlalchemy.orm import sessionmaker
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
import json
|
|
13
|
+
|
|
14
|
+
# 创建基类
|
|
15
|
+
Base = declarative_base()
|
|
16
|
+
|
|
17
|
+
class SheinStore(Base):
|
|
18
|
+
"""
|
|
19
|
+
希音店铺信息表
|
|
20
|
+
存储店铺基础信息
|
|
21
|
+
"""
|
|
22
|
+
__tablename__ = 'shein_store'
|
|
23
|
+
|
|
24
|
+
# 主键ID
|
|
25
|
+
id = Column(BigInteger, primary_key=True, autoincrement=True, comment='主键ID')
|
|
26
|
+
|
|
27
|
+
# 店铺账号信息(唯一)
|
|
28
|
+
user_name = Column(String(100), nullable=False, unique=True, comment='店铺账号')
|
|
29
|
+
store_username = Column(String(100), nullable=True, comment='店铺用户名')
|
|
30
|
+
store_name = Column(String(200), nullable=True, comment='店铺名称')
|
|
31
|
+
|
|
32
|
+
# 用户ID信息
|
|
33
|
+
user_id = Column(BigInteger, nullable=True, comment='用户ID')
|
|
34
|
+
supplier_id = Column(BigInteger, nullable=True, comment='供应商ID')
|
|
35
|
+
main_user_name = Column(String(100), nullable=True, comment='主账号用户名')
|
|
36
|
+
main_user_id = Column(BigInteger, nullable=True, comment='主账号用户ID')
|
|
37
|
+
|
|
38
|
+
# ULP信息
|
|
39
|
+
ulp_name = Column(String(200), nullable=True, comment='ULP名称')
|
|
40
|
+
ulp_en_name = Column(String(200), nullable=True, comment='ULP英文名称')
|
|
41
|
+
ulp_emplid = Column(String(100), nullable=True, comment='ULP员工ID')
|
|
42
|
+
is_ulp_login = Column(Integer, nullable=True, comment='是否ULP登录')
|
|
43
|
+
|
|
44
|
+
# 时区信息
|
|
45
|
+
timezone = Column(String(100), nullable=True, comment='时区')
|
|
46
|
+
timezone_name = Column(String(200), nullable=True, comment='时区名称')
|
|
47
|
+
utc_timezone = Column(String(50), nullable=True, comment='UTC时区')
|
|
48
|
+
area_timezone = Column(String(100), nullable=True, comment='地区时区')
|
|
49
|
+
|
|
50
|
+
# 系统配置
|
|
51
|
+
switch_new_menu = Column(Integer, nullable=True, comment='是否切换新菜单')
|
|
52
|
+
supplier_user_name = Column(String(100), nullable=True, comment='供应商用户名')
|
|
53
|
+
sso_top_nav = Column(Integer, nullable=True, comment='SSO顶部导航')
|
|
54
|
+
sso_host = Column(String(500), nullable=True, comment='SSO主机地址')
|
|
55
|
+
|
|
56
|
+
# 类目信息
|
|
57
|
+
category_id = Column(BigInteger, nullable=True, comment='类目ID')
|
|
58
|
+
category_out_id = Column(BigInteger, nullable=True, comment='外部类目ID')
|
|
59
|
+
lv1_category_id = Column(BigInteger, nullable=True, comment='一级类目ID')
|
|
60
|
+
lv1_category_name = Column(String(200), nullable=True, comment='一级类目名称')
|
|
61
|
+
lv2_category_name = Column(String(200), nullable=True, comment='二级类目名称')
|
|
62
|
+
|
|
63
|
+
# 其他信息
|
|
64
|
+
supplier_source = Column(Integer, nullable=True, comment='供应商来源')
|
|
65
|
+
external_id = Column(BigInteger, nullable=True, comment='外部ID')
|
|
66
|
+
store_code = Column(BigInteger, nullable=True, comment='店铺编码')
|
|
67
|
+
merchant_code = Column(String(100), nullable=True, comment='商户编码')
|
|
68
|
+
schat_id = Column(BigInteger, nullable=True, comment='Schat ID')
|
|
69
|
+
|
|
70
|
+
# 管理字段(不参与更新)
|
|
71
|
+
store_manager_id = Column(BigInteger, default=0, comment='店长ID(用户表ID)')
|
|
72
|
+
is_deleted = Column(Integer, nullable=True, default=0, comment='软删除标志(0-未删除,1-已删除)')
|
|
73
|
+
|
|
74
|
+
# 备注
|
|
75
|
+
remark = Column(String(500), nullable=True, comment='备注')
|
|
76
|
+
|
|
77
|
+
# 时间戳
|
|
78
|
+
created_at = Column(DateTime, nullable=True, default=datetime.now, comment='创建时间')
|
|
79
|
+
updated_at = Column(DateTime, nullable=True, default=datetime.now, onupdate=datetime.now, comment='更新时间')
|
|
80
|
+
|
|
81
|
+
# 创建索引
|
|
82
|
+
__table_args__ = (
|
|
83
|
+
Index('idx_store_username', 'store_username',unique=True),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def __repr__(self):
|
|
87
|
+
return f"<SheinStore(id={self.id}, user_name='{self.user_name}', store_name='{self.store_name}')>"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class SheinStoreManager:
|
|
91
|
+
"""
|
|
92
|
+
店铺信息数据管理器
|
|
93
|
+
提供数据库操作相关方法
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def __init__(self, database_url):
|
|
98
|
+
"""
|
|
99
|
+
初始化数据库连接
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
database_url (str): 数据库连接URL
|
|
103
|
+
"""
|
|
104
|
+
print(f"连接数据库: {database_url}")
|
|
105
|
+
self.engine = create_engine(database_url, echo=False)
|
|
106
|
+
self.Session = sessionmaker(bind=self.engine)
|
|
107
|
+
|
|
108
|
+
def create_table(self):
|
|
109
|
+
"""
|
|
110
|
+
创建数据表
|
|
111
|
+
"""
|
|
112
|
+
Base.metadata.create_all(self.engine)
|
|
113
|
+
print("店铺表创建成功")
|
|
114
|
+
|
|
115
|
+
def insert_data(self, data_list):
|
|
116
|
+
"""
|
|
117
|
+
批量插入数据
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
data_list (list): 数据字典列表
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
int: 成功插入的记录数
|
|
124
|
+
"""
|
|
125
|
+
session = self.Session()
|
|
126
|
+
try:
|
|
127
|
+
insert_count = 0
|
|
128
|
+
update_count = 0
|
|
129
|
+
|
|
130
|
+
for data in data_list:
|
|
131
|
+
# 检查是否存在(根据唯一索引:user_name)
|
|
132
|
+
existing = session.query(SheinStore).filter(
|
|
133
|
+
SheinStore.user_name == data.get('user_name')
|
|
134
|
+
).first()
|
|
135
|
+
|
|
136
|
+
if existing:
|
|
137
|
+
# 更新现有记录(排除不更新的字段)
|
|
138
|
+
exclude_fields = {'store_manager_id', 'is_deleted'}
|
|
139
|
+
for key, value in data.items():
|
|
140
|
+
if key not in exclude_fields:
|
|
141
|
+
setattr(existing, key, value)
|
|
142
|
+
setattr(existing, 'updated_at', datetime.now())
|
|
143
|
+
update_count += 1
|
|
144
|
+
else:
|
|
145
|
+
# 插入新记录
|
|
146
|
+
new_record = SheinStore(**data)
|
|
147
|
+
session.add(new_record)
|
|
148
|
+
insert_count += 1
|
|
149
|
+
|
|
150
|
+
session.commit()
|
|
151
|
+
print(f"成功插入 {insert_count} 条记录,更新 {update_count} 条记录")
|
|
152
|
+
return insert_count
|
|
153
|
+
except Exception as e:
|
|
154
|
+
session.rollback()
|
|
155
|
+
print(f"插入数据失败: {e}")
|
|
156
|
+
raise
|
|
157
|
+
finally:
|
|
158
|
+
session.close()
|
|
159
|
+
|
|
160
|
+
def import_from_json_dict(self, json_dict):
|
|
161
|
+
"""
|
|
162
|
+
从JSON字典数据导入到数据库(JSON格式:{userName: {店铺信息}})
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
json_dict (dict): JSON字典数据,key为userName,value为店铺信息
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
int: 成功导入的记录数
|
|
169
|
+
"""
|
|
170
|
+
print(f"开始处理 {len(json_dict)} 个店铺数据")
|
|
171
|
+
data_list = []
|
|
172
|
+
skipped_count = 0
|
|
173
|
+
|
|
174
|
+
for user_name, item in json_dict.items():
|
|
175
|
+
# 验证必填字段
|
|
176
|
+
if not user_name:
|
|
177
|
+
print(f"⚠️ 警告: 缺少必填字段 user_name,跳过该记录")
|
|
178
|
+
skipped_count += 1
|
|
179
|
+
continue
|
|
180
|
+
|
|
181
|
+
# 构建数据库记录(字段名转换:驼峰转下划线)
|
|
182
|
+
record = {
|
|
183
|
+
'user_name': item.get('userName'),
|
|
184
|
+
'store_username': item.get('store_username'),
|
|
185
|
+
'store_name': item.get('store_name'),
|
|
186
|
+
'user_id': item.get('userId'),
|
|
187
|
+
'supplier_id': item.get('supplierId'),
|
|
188
|
+
'main_user_name': item.get('mainUserName'),
|
|
189
|
+
'main_user_id': item.get('mainUserId'),
|
|
190
|
+
'ulp_name': item.get('ulpName'),
|
|
191
|
+
'ulp_en_name': item.get('ulpEnName'),
|
|
192
|
+
'ulp_emplid': item.get('ulpEmplid'),
|
|
193
|
+
'is_ulp_login': item.get('isUlpLogin'),
|
|
194
|
+
'timezone': item.get('timezone'),
|
|
195
|
+
'timezone_name': item.get('timezoneName'),
|
|
196
|
+
'utc_timezone': item.get('utcTimezone'),
|
|
197
|
+
'area_timezone': item.get('areaTimezone'),
|
|
198
|
+
'switch_new_menu': item.get('switchNewMenu'),
|
|
199
|
+
'supplier_user_name': item.get('supplierUserName'),
|
|
200
|
+
'sso_top_nav': item.get('ssoTopNav'),
|
|
201
|
+
'sso_host': item.get('ssoHost'),
|
|
202
|
+
'category_id': item.get('categoryId'),
|
|
203
|
+
'category_out_id': item.get('categoryOutId'),
|
|
204
|
+
'lv1_category_id': item.get('lv1CategoryId'),
|
|
205
|
+
'lv1_category_name': item.get('lv1CategoryName'),
|
|
206
|
+
'lv2_category_name': item.get('lv2CategoryName'),
|
|
207
|
+
'supplier_source': item.get('supplierSource'),
|
|
208
|
+
'external_id': item.get('externalId'),
|
|
209
|
+
'store_code': item.get('storeCode'),
|
|
210
|
+
'merchant_code': item.get('merchantCode'),
|
|
211
|
+
'schat_id': item.get('schatId'),
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
print(f"✓ 处理店铺: {record['user_name']} - {record['store_name']}")
|
|
215
|
+
data_list.append(record)
|
|
216
|
+
|
|
217
|
+
if skipped_count > 0:
|
|
218
|
+
print(f"⚠️ 共跳过 {skipped_count} 条记录(缺少必填字段)")
|
|
219
|
+
|
|
220
|
+
# 调用insert_data方法插入数据
|
|
221
|
+
return self.insert_data(data_list)
|
|
222
|
+
|
|
223
|
+
def import_from_json_list(self, json_list):
|
|
224
|
+
"""
|
|
225
|
+
从JSON列表数据导入到数据库(JSON格式:[{店铺信息}, {店铺信息}])
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
json_list (list): JSON列表数据
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
int: 成功导入的记录数
|
|
232
|
+
"""
|
|
233
|
+
# 转换为字典格式,然后调用 import_from_json_dict
|
|
234
|
+
json_dict = {item.get('userName'): item for item in json_list if item.get('userName')}
|
|
235
|
+
return self.import_from_json_dict(json_dict)
|
|
236
|
+
|
|
237
|
+
def get_store_by_username(self, user_name, include_deleted=False):
|
|
238
|
+
"""
|
|
239
|
+
根据用户名查询店铺信息
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
user_name (str): 店铺账号
|
|
243
|
+
include_deleted (bool): 是否包含已删除的店铺,默认False
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
SheinStore: 店铺对象
|
|
247
|
+
"""
|
|
248
|
+
session = self.Session()
|
|
249
|
+
try:
|
|
250
|
+
query = session.query(SheinStore).filter(
|
|
251
|
+
SheinStore.user_name == user_name
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# 默认只查询未删除的
|
|
255
|
+
if not include_deleted:
|
|
256
|
+
query = query.filter(SheinStore.is_deleted == 0)
|
|
257
|
+
|
|
258
|
+
store = query.first()
|
|
259
|
+
return store
|
|
260
|
+
finally:
|
|
261
|
+
session.close()
|
|
262
|
+
|
|
263
|
+
def get_all_stores(self, include_deleted=False):
|
|
264
|
+
"""
|
|
265
|
+
获取所有店铺列表
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
include_deleted (bool): 是否包含已删除的店铺,默认False
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
list: 店铺列表
|
|
272
|
+
"""
|
|
273
|
+
session = self.Session()
|
|
274
|
+
try:
|
|
275
|
+
query = session.query(SheinStore)
|
|
276
|
+
|
|
277
|
+
# 默认只查询未删除的
|
|
278
|
+
if not include_deleted:
|
|
279
|
+
query = query.filter(SheinStore.is_deleted == 0)
|
|
280
|
+
|
|
281
|
+
stores = query.all()
|
|
282
|
+
return stores
|
|
283
|
+
finally:
|
|
284
|
+
session.close()
|
|
285
|
+
|
|
286
|
+
def get_stores_by_category(self, lv1_category_name=None, lv2_category_name=None, include_deleted=False):
|
|
287
|
+
"""
|
|
288
|
+
根据类目查询店铺列表
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
lv1_category_name (str): 一级类目名称
|
|
292
|
+
lv2_category_name (str): 二级类目名称
|
|
293
|
+
include_deleted (bool): 是否包含已删除的店铺,默认False
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
list: 店铺列表
|
|
297
|
+
"""
|
|
298
|
+
session = self.Session()
|
|
299
|
+
try:
|
|
300
|
+
query = session.query(SheinStore)
|
|
301
|
+
|
|
302
|
+
# 默认只查询未删除的
|
|
303
|
+
if not include_deleted:
|
|
304
|
+
query = query.filter(SheinStore.is_deleted == 0)
|
|
305
|
+
|
|
306
|
+
if lv1_category_name:
|
|
307
|
+
query = query.filter(SheinStore.lv1_category_name == lv1_category_name)
|
|
308
|
+
|
|
309
|
+
if lv2_category_name:
|
|
310
|
+
query = query.filter(SheinStore.lv2_category_name == lv2_category_name)
|
|
311
|
+
|
|
312
|
+
stores = query.all()
|
|
313
|
+
return stores
|
|
314
|
+
finally:
|
|
315
|
+
session.close()
|
|
316
|
+
|
|
317
|
+
def update_store_manager(self, user_name, manager_id):
|
|
318
|
+
"""
|
|
319
|
+
更新店铺的店长ID
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
user_name (str): 店铺账号
|
|
323
|
+
manager_id (int): 店长ID(用户表ID)
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
bool: 是否成功
|
|
327
|
+
"""
|
|
328
|
+
session = self.Session()
|
|
329
|
+
try:
|
|
330
|
+
store = session.query(SheinStore).filter(
|
|
331
|
+
SheinStore.user_name == user_name
|
|
332
|
+
).first()
|
|
333
|
+
|
|
334
|
+
if store:
|
|
335
|
+
store.store_manager_id = manager_id
|
|
336
|
+
store.updated_at = datetime.now()
|
|
337
|
+
session.commit()
|
|
338
|
+
print(f"成功更新店长ID: {user_name} -> {manager_id}")
|
|
339
|
+
return True
|
|
340
|
+
else:
|
|
341
|
+
print(f"未找到店铺: {user_name}")
|
|
342
|
+
return False
|
|
343
|
+
except Exception as e:
|
|
344
|
+
session.rollback()
|
|
345
|
+
print(f"更新店长ID失败: {e}")
|
|
346
|
+
raise
|
|
347
|
+
finally:
|
|
348
|
+
session.close()
|
|
349
|
+
|
|
350
|
+
def soft_delete_store(self, user_name):
|
|
351
|
+
"""
|
|
352
|
+
软删除指定店铺(设置is_deleted=1)
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
user_name (str): 店铺账号
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
bool: 是否成功
|
|
359
|
+
"""
|
|
360
|
+
session = self.Session()
|
|
361
|
+
try:
|
|
362
|
+
store = session.query(SheinStore).filter(
|
|
363
|
+
SheinStore.user_name == user_name
|
|
364
|
+
).first()
|
|
365
|
+
|
|
366
|
+
if store:
|
|
367
|
+
store.is_deleted = 1
|
|
368
|
+
store.updated_at = datetime.now()
|
|
369
|
+
session.commit()
|
|
370
|
+
print(f"成功软删除店铺: {user_name}")
|
|
371
|
+
return True
|
|
372
|
+
else:
|
|
373
|
+
print(f"未找到店铺: {user_name}")
|
|
374
|
+
return False
|
|
375
|
+
except Exception as e:
|
|
376
|
+
session.rollback()
|
|
377
|
+
print(f"软删除失败: {e}")
|
|
378
|
+
raise
|
|
379
|
+
finally:
|
|
380
|
+
session.close()
|
|
381
|
+
|
|
382
|
+
def restore_store(self, user_name):
|
|
383
|
+
"""
|
|
384
|
+
恢复软删除的店铺(设置is_deleted=0)
|
|
385
|
+
|
|
386
|
+
Args:
|
|
387
|
+
user_name (str): 店铺账号
|
|
388
|
+
|
|
389
|
+
Returns:
|
|
390
|
+
bool: 是否成功
|
|
391
|
+
"""
|
|
392
|
+
session = self.Session()
|
|
393
|
+
try:
|
|
394
|
+
store = session.query(SheinStore).filter(
|
|
395
|
+
SheinStore.user_name == user_name
|
|
396
|
+
).first()
|
|
397
|
+
|
|
398
|
+
if store:
|
|
399
|
+
store.is_deleted = 0
|
|
400
|
+
store.updated_at = datetime.now()
|
|
401
|
+
session.commit()
|
|
402
|
+
print(f"成功恢复店铺: {user_name}")
|
|
403
|
+
return True
|
|
404
|
+
else:
|
|
405
|
+
print(f"未找到店铺: {user_name}")
|
|
406
|
+
return False
|
|
407
|
+
except Exception as e:
|
|
408
|
+
session.rollback()
|
|
409
|
+
print(f"恢复失败: {e}")
|
|
410
|
+
raise
|
|
411
|
+
finally:
|
|
412
|
+
session.close()
|
|
413
|
+
|
|
414
|
+
def delete_store(self, user_name):
|
|
415
|
+
"""
|
|
416
|
+
物理删除指定店铺(真正从数据库删除,慎用!)
|
|
417
|
+
|
|
418
|
+
Args:
|
|
419
|
+
user_name (str): 店铺账号
|
|
420
|
+
|
|
421
|
+
Returns:
|
|
422
|
+
int: 删除的记录数
|
|
423
|
+
"""
|
|
424
|
+
session = self.Session()
|
|
425
|
+
try:
|
|
426
|
+
delete_count = session.query(SheinStore).filter(
|
|
427
|
+
SheinStore.user_name == user_name
|
|
428
|
+
).delete()
|
|
429
|
+
session.commit()
|
|
430
|
+
print(f"成功物理删除 {delete_count} 条记录")
|
|
431
|
+
return delete_count
|
|
432
|
+
except Exception as e:
|
|
433
|
+
session.rollback()
|
|
434
|
+
print(f"删除数据失败: {e}")
|
|
435
|
+
raise
|
|
436
|
+
finally:
|
|
437
|
+
session.close()
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
# 创建全局实例,用于快速访问
|
|
441
|
+
_shein_store_manager = None
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def get_shein_store_manager(database_url):
|
|
445
|
+
"""
|
|
446
|
+
获取店铺管理器实例
|
|
447
|
+
|
|
448
|
+
Args:
|
|
449
|
+
database_url (str): 数据库连接URL
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
SheinStoreManager: 店铺管理器实例
|
|
453
|
+
"""
|
|
454
|
+
global _shein_store_manager
|
|
455
|
+
if _shein_store_manager is None:
|
|
456
|
+
_shein_store_manager = SheinStoreManager(database_url)
|
|
457
|
+
return _shein_store_manager
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def insert_store_data(database_url, data_list):
|
|
461
|
+
"""
|
|
462
|
+
插入店铺数据的便捷函数
|
|
463
|
+
|
|
464
|
+
Args:
|
|
465
|
+
database_url (str): 数据库连接URL
|
|
466
|
+
data_list (list): 数据字典列表
|
|
467
|
+
|
|
468
|
+
Returns:
|
|
469
|
+
int: 成功插入的记录数
|
|
470
|
+
"""
|
|
471
|
+
manager = get_shein_store_manager(database_url)
|
|
472
|
+
return manager.insert_data(data_list)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def import_from_json(database_url, json_data):
|
|
476
|
+
"""
|
|
477
|
+
从JSON数据导入的便捷函数(自动识别字典或列表格式)
|
|
478
|
+
|
|
479
|
+
Args:
|
|
480
|
+
database_url (str): 数据库连接URL
|
|
481
|
+
json_data (dict|list): JSON数据(字典或列表)
|
|
482
|
+
|
|
483
|
+
Returns:
|
|
484
|
+
int: 成功导入的记录数
|
|
485
|
+
"""
|
|
486
|
+
manager = get_shein_store_manager(database_url)
|
|
487
|
+
|
|
488
|
+
if isinstance(json_data, dict):
|
|
489
|
+
return manager.import_from_json_dict(json_data)
|
|
490
|
+
elif isinstance(json_data, list):
|
|
491
|
+
return manager.import_from_json_list(json_data)
|
|
492
|
+
else:
|
|
493
|
+
raise ValueError("json_data 必须是字典或列表类型")
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
def get_store_by_username(database_url, user_name, include_deleted=False):
|
|
497
|
+
"""
|
|
498
|
+
根据用户名查询店铺的便捷函数
|
|
499
|
+
|
|
500
|
+
Args:
|
|
501
|
+
database_url (str): 数据库连接URL
|
|
502
|
+
user_name (str): 店铺账号
|
|
503
|
+
include_deleted (bool): 是否包含已删除的店铺,默认False
|
|
504
|
+
|
|
505
|
+
Returns:
|
|
506
|
+
SheinStore: 店铺对象
|
|
507
|
+
"""
|
|
508
|
+
manager = get_shein_store_manager(database_url)
|
|
509
|
+
return manager.get_store_by_username(user_name, include_deleted)
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def update_store_manager(database_url, user_name, manager_id):
|
|
513
|
+
"""
|
|
514
|
+
更新店长ID的便捷函数
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
database_url (str): 数据库连接URL
|
|
518
|
+
user_name (str): 店铺账号
|
|
519
|
+
manager_id (int): 店长ID(用户表ID)
|
|
520
|
+
|
|
521
|
+
Returns:
|
|
522
|
+
bool: 是否成功
|
|
523
|
+
"""
|
|
524
|
+
manager = get_shein_store_manager(database_url)
|
|
525
|
+
return manager.update_store_manager(user_name, manager_id)
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
def soft_delete_store(database_url, user_name):
|
|
529
|
+
"""
|
|
530
|
+
软删除店铺的便捷函数
|
|
531
|
+
|
|
532
|
+
Args:
|
|
533
|
+
database_url (str): 数据库连接URL
|
|
534
|
+
user_name (str): 店铺账号
|
|
535
|
+
|
|
536
|
+
Returns:
|
|
537
|
+
bool: 是否成功
|
|
538
|
+
"""
|
|
539
|
+
manager = get_shein_store_manager(database_url)
|
|
540
|
+
return manager.soft_delete_store(user_name)
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def restore_store(database_url, user_name):
|
|
544
|
+
"""
|
|
545
|
+
恢复店铺的便捷函数
|
|
546
|
+
|
|
547
|
+
Args:
|
|
548
|
+
database_url (str): 数据库连接URL
|
|
549
|
+
user_name (str): 店铺账号
|
|
550
|
+
|
|
551
|
+
Returns:
|
|
552
|
+
bool: 是否成功
|
|
553
|
+
"""
|
|
554
|
+
manager = get_shein_store_manager(database_url)
|
|
555
|
+
return manager.restore_store(user_name)
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
if __name__ == '__main__':
|
|
559
|
+
# 测试代码
|
|
560
|
+
# 注意:需要提供数据库连接URL
|
|
561
|
+
database_url = "mysql+pymysql://root:123wyk@127.0.0.1:3306/lz"
|
|
562
|
+
|
|
563
|
+
manager = SheinStoreManager(database_url)
|
|
564
|
+
|
|
565
|
+
# 创建表
|
|
566
|
+
manager.create_table()
|
|
567
|
+
|
|
568
|
+
# 读取JSON文件
|
|
569
|
+
with open('../../docs/shein_user.json', 'r', encoding='utf-8') as f:
|
|
570
|
+
json_data = json.load(f)
|
|
571
|
+
|
|
572
|
+
count = manager.import_from_json_dict(json_data)
|
|
573
|
+
print(f"成功导入 {count} 条店铺记录")
|
|
574
|
+
|
|
575
|
+
# 更新店长ID(手动设置,后续导入不会覆盖)
|
|
576
|
+
# manager.update_store_manager('GS0628340', 123) # 123是用户表的ID
|
|
577
|
+
|
|
578
|
+
# 软删除测试
|
|
579
|
+
# manager.soft_delete_store('GS0628340')
|
|
580
|
+
|
|
581
|
+
# 查询店铺(默认不包含已删除)
|
|
582
|
+
# store = manager.get_store_by_username('GS0628340')
|
|
583
|
+
# print(f"查询结果: {store}")
|
|
584
|
+
|
|
585
|
+
# 查询店铺(包含已删除)
|
|
586
|
+
# store = manager.get_store_by_username('GS0628340', include_deleted=True)
|
|
587
|
+
# print(f"查询结果(包含已删除): {store}")
|
|
588
|
+
|
|
589
|
+
# 恢复店铺
|
|
590
|
+
# manager.restore_store('GS0628340')
|
|
591
|
+
|
|
592
|
+
# 按类目查询示例
|
|
593
|
+
# stores = manager.get_stores_by_category(lv2_category_name='全托管-备CN-中国团队-内睡服装')
|
|
594
|
+
# print(f"找到 {len(stores)} 个店铺")
|
|
@@ -22,11 +22,12 @@ qrpa/time_utils.py,sha256=bOTSi_ewXPCxwgG_ndFGf8dl7S4fvSGT9sQ-90LESuo,31458
|
|
|
22
22
|
qrpa/time_utils_example.py,sha256=80zzunKw7F1S8MOwNFmmiCnI8MOYoh4PH-25UrEGuF0,7810
|
|
23
23
|
qrpa/wxwork.py,sha256=Vy8PGEtlTWt4-1laVhuqpJUGCFH2JymgbjvH00aaBog,10946
|
|
24
24
|
qrpa/mysql_module/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
-
qrpa/mysql_module/new_product_analysis_model.py,sha256=
|
|
25
|
+
qrpa/mysql_module/new_product_analysis_model.py,sha256=SpPH9_O5c6ssRTguVHDPBvQYbLWPKaw98mRnGj23tSY,18210
|
|
26
26
|
qrpa/mysql_module/shein_ledger_model.py,sha256=KGKfGyzS00rbBZhiZhAzypwYPGs7OdfRLnH2ea36Vm8,18161
|
|
27
27
|
qrpa/mysql_module/shein_product_model.py,sha256=KiXMjPT93XkANCM53cCFaISja0sTmAWsionFrRy8DQ4,18773
|
|
28
28
|
qrpa/mysql_module/shein_return_order_model.py,sha256=8xvKhOzpcJS5FHfyA33UednaqRNCyXo3qeXBzwTXeN8,25993
|
|
29
|
-
qrpa
|
|
30
|
-
qrpa-1.1.
|
|
31
|
-
qrpa-1.1.
|
|
32
|
-
qrpa-1.1.
|
|
29
|
+
qrpa/mysql_module/shein_store_model.py,sha256=tSXB7w8gmLXQfvuzk3te4OL1Tok-kEgGPYrCutDrzSw,20469
|
|
30
|
+
qrpa-1.1.35.dist-info/METADATA,sha256=zh1-0lY_YuzPQA0YPT_GepQDQ8IBzv4fhm0bR7UJO-Q,231
|
|
31
|
+
qrpa-1.1.35.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
32
|
+
qrpa-1.1.35.dist-info/top_level.txt,sha256=F6T5igi0fhXDucPPUbmmSC0qFCDEsH5eVijfVF48OFU,5
|
|
33
|
+
qrpa-1.1.35.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|