qrpa 1.1.35__tar.gz → 1.1.37__tar.gz
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-1.1.35 → qrpa-1.1.37}/PKG-INFO +1 -1
- {qrpa-1.1.35 → qrpa-1.1.37}/pyproject.toml +1 -1
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/mysql_module/new_product_analysis_model.py +46 -7
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/mysql_module/shein_store_model.py +3 -2
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/shein_lib.py +277 -19
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa.egg-info/PKG-INFO +1 -1
- {qrpa-1.1.35 → qrpa-1.1.37}/README.md +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/RateLimitedSender.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/__init__.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/db_migrator.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/feishu_bot_app.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/feishu_client.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/feishu_logic.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/fun_base.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/fun_excel.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/fun_file.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/fun_web.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/fun_win.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/mysql_module/__init__.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/mysql_module/shein_ledger_model.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/mysql_module/shein_product_model.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/mysql_module/shein_return_order_model.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/shein_daily_report_model.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/shein_excel.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/shein_mysql.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/shein_sqlite.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/shein_ziniao.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/temu_chrome.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/temu_excel.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/temu_lib.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/time_utils.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/time_utils_example.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa/wxwork.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa.egg-info/SOURCES.txt +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa.egg-info/dependency_links.txt +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/qrpa.egg-info/top_level.txt +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/setup.cfg +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/setup.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/tests/test_db_migrator.py +0 -0
- {qrpa-1.1.35 → qrpa-1.1.37}/tests/test_wxwork.py +0 -0
|
@@ -42,6 +42,7 @@ class SheinNewProductAnalysis(Base):
|
|
|
42
42
|
# 状态标识
|
|
43
43
|
onsale_flag = Column(Integer, nullable=True, default=0, comment='在售标识(0-否,1-是)')
|
|
44
44
|
sale_flag = Column(Integer, nullable=True, default=0, comment='上架标识(0-否,1-是)')
|
|
45
|
+
new_goods_tag = Column(Integer, nullable=True, comment='新品标签(1-新品爆款,2-新品畅销,3-潜力新品,4-新品)')
|
|
45
46
|
|
|
46
47
|
# 销售数据
|
|
47
48
|
sale_cnt = Column(Integer, nullable=True, default=0, comment='销量')
|
|
@@ -85,6 +86,35 @@ class SheinNewProductAnalysis(Base):
|
|
|
85
86
|
def __repr__(self):
|
|
86
87
|
return f"<SheinNewProductAnalysis(id={self.id}, store_username='{self.store_username}', skc='{self.skc}', stat_date={self.stat_date})>"
|
|
87
88
|
|
|
89
|
+
@property
|
|
90
|
+
def new_goods_tag_name(self):
|
|
91
|
+
"""
|
|
92
|
+
获取新品标签的文本描述
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
str: 新品标签文本描述
|
|
96
|
+
"""
|
|
97
|
+
return self.get_new_goods_tag_name(self.new_goods_tag)
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def get_new_goods_tag_name(tag):
|
|
101
|
+
"""
|
|
102
|
+
将新品标签代码转换为文本描述
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
tag (str): 新品标签代码
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
str: 新品标签文本描述
|
|
109
|
+
"""
|
|
110
|
+
tag_map = {
|
|
111
|
+
'1': '新品爆款',
|
|
112
|
+
'2': '新品畅销',
|
|
113
|
+
'3': '潜力新品',
|
|
114
|
+
'4': '新品'
|
|
115
|
+
}
|
|
116
|
+
return tag_map.get(str(tag), '') if tag else ''
|
|
117
|
+
|
|
88
118
|
class NewProductAnalysisManager:
|
|
89
119
|
"""
|
|
90
120
|
新品分析数据管理器
|
|
@@ -236,7 +266,13 @@ class NewProductAnalysisManager:
|
|
|
236
266
|
prom_detail = prom.get('promDetail', [])
|
|
237
267
|
|
|
238
268
|
# 根据promId长度判断取哪些字段
|
|
239
|
-
if len(str(prom_id))
|
|
269
|
+
if len(str(prom_id)) >= 11 and prom_detail:
|
|
270
|
+
# 营销工具:取第一个detail的数据
|
|
271
|
+
detail = prom_detail if prom_detail else {}
|
|
272
|
+
prom_info['attend_num_sum'] = detail.get('act_stock_num')
|
|
273
|
+
prom_info['supply_price'] = detail.get('sku_price')
|
|
274
|
+
prom_info['product_act_price'] = detail.get('act_sku_price')
|
|
275
|
+
elif len(str(prom_id)) >= 8 and prom_detail:
|
|
240
276
|
# 营销工具:取第一个detail的数据
|
|
241
277
|
detail = prom_detail[0] if prom_detail else {}
|
|
242
278
|
prom_info['attend_num_sum'] = detail.get('attend_num_sum')
|
|
@@ -307,6 +343,7 @@ class NewProductAnalysisManager:
|
|
|
307
343
|
'img_url' : item.get('imgUrl'),
|
|
308
344
|
'onsale_flag' : int(item.get('onsaleFlag', 0)),
|
|
309
345
|
'sale_flag' : int(item.get('saleFlag', 0)),
|
|
346
|
+
'new_goods_tag' : item.get('newGoodsTag'),
|
|
310
347
|
'sale_cnt' : item.get('saleCnt', 0),
|
|
311
348
|
'pay_order_cnt' : item.get('payOrderCnt', 0),
|
|
312
349
|
'goods_uv' : item.get('goodsUv', 0),
|
|
@@ -464,22 +501,24 @@ def update_front_price(stat_date, skc, front_price):
|
|
|
464
501
|
|
|
465
502
|
|
|
466
503
|
if __name__ == '__main__':
|
|
504
|
+
database_url = "mysql+pymysql://root:123wyk@127.0.0.1:3306/lz"
|
|
505
|
+
|
|
467
506
|
# 测试代码
|
|
468
|
-
manager = NewProductAnalysisManager()
|
|
507
|
+
manager = NewProductAnalysisManager(database_url)
|
|
469
508
|
|
|
470
509
|
# 创建表
|
|
471
510
|
manager.create_table()
|
|
472
511
|
|
|
473
512
|
# 读取JSON文件
|
|
474
|
-
with open('../../docs/skc_model_GS9740414_2025-10-
|
|
513
|
+
with open('../../docs/skc_model_GS9740414_2025-10-22.json', 'r', encoding='utf-8') as f:
|
|
475
514
|
json_data = json.load(f)
|
|
476
515
|
count = manager.import_from_json(json_data)
|
|
477
516
|
print(f"成功导入 {count} 条记录")
|
|
478
517
|
|
|
479
|
-
with open('../../docs/skc_model_S19118100_2025-10-15.json', 'r', encoding='utf-8') as f:
|
|
480
|
-
|
|
481
|
-
count = manager.import_from_json(json_data)
|
|
482
|
-
print(f"成功导入 {count} 条记录")
|
|
518
|
+
# with open('../../docs/skc_model_S19118100_2025-10-15.json', 'r', encoding='utf-8') as f:
|
|
519
|
+
# json_data = json.load(f)
|
|
520
|
+
# count = manager.import_from_json(json_data)
|
|
521
|
+
# print(f"成功导入 {count} 条记录")
|
|
483
522
|
|
|
484
523
|
# 更新前台价格(手动设置,后续导入不会覆盖)
|
|
485
524
|
# manager.update_front_price('2025-10-15', 'si2409238815318914', 19.99)
|
|
@@ -558,8 +558,9 @@ def restore_store(database_url, user_name):
|
|
|
558
558
|
if __name__ == '__main__':
|
|
559
559
|
# 测试代码
|
|
560
560
|
# 注意:需要提供数据库连接URL
|
|
561
|
-
database_url = "mysql+pymysql://root:123wyk@127.0.0.1:3306/lz"
|
|
562
|
-
|
|
561
|
+
#database_url = "mysql+pymysql://root:123wyk@127.0.0.1:3306/lz"
|
|
562
|
+
database_url = "mysql+pymysql://root:123wyk@47.83.212.3:3306/lz"
|
|
563
|
+
|
|
563
564
|
manager = SheinStoreManager(database_url)
|
|
564
565
|
|
|
565
566
|
# 创建表
|
|
@@ -1174,8 +1174,8 @@ class SheinLib:
|
|
|
1174
1174
|
detail_file = f'{self.config.auto_dir}/shein/product/product_detail_file.json'
|
|
1175
1175
|
write_dict_to_file_ex(detail_file, {self.store_username: dict_product_detail}, [self.store_username])
|
|
1176
1176
|
|
|
1177
|
-
def get_skc_diagnose_list(self, shelf_date_begin, shelf_date_end):
|
|
1178
|
-
log(f'获取商品分析列表(
|
|
1177
|
+
def get_skc_diagnose_list(self, shelf_date_begin="", shelf_date_end=""):
|
|
1178
|
+
log(f'获取商品分析列表(最近上架的或在售的) {shelf_date_begin} {shelf_date_end} {self.store_name} {self.store_username}')
|
|
1179
1179
|
|
|
1180
1180
|
dt_goods = self.get_dt_time_goods()
|
|
1181
1181
|
if not TimeUtils.is_yesterday_date(dt_goods, "%Y%m%d"):
|
|
@@ -1188,17 +1188,18 @@ class SheinLib:
|
|
|
1188
1188
|
page_num = 1
|
|
1189
1189
|
page_size = 100
|
|
1190
1190
|
payload = {
|
|
1191
|
-
"areaCd"
|
|
1192
|
-
"dt"
|
|
1193
|
-
"countrySite"
|
|
1191
|
+
"areaCd" : "cn",
|
|
1192
|
+
"dt" : dt_goods,
|
|
1193
|
+
"countrySite": [
|
|
1194
1194
|
"shein-all"
|
|
1195
1195
|
],
|
|
1196
|
-
"startDate"
|
|
1197
|
-
"endDate"
|
|
1198
|
-
"pageNum"
|
|
1199
|
-
"pageSize"
|
|
1200
|
-
"
|
|
1201
|
-
"
|
|
1196
|
+
"startDate" : yesterday,
|
|
1197
|
+
"endDate" : yesterday,
|
|
1198
|
+
"pageNum" : page_num,
|
|
1199
|
+
"pageSize" : page_size,
|
|
1200
|
+
"onsaleFlag" : 1,
|
|
1201
|
+
# "localFrstSaleBeginDate": shelf_date_begin,
|
|
1202
|
+
# "localFrstSaleEndDate" : shelf_date_end,
|
|
1202
1203
|
}
|
|
1203
1204
|
response_text = fetch(self.web_page, url, payload)
|
|
1204
1205
|
error_code = response_text.get('code')
|
|
@@ -1224,6 +1225,12 @@ class SheinLib:
|
|
|
1224
1225
|
|
|
1225
1226
|
# 活动信息
|
|
1226
1227
|
# AB实验数据
|
|
1228
|
+
|
|
1229
|
+
# 预先过滤掉不需要的商品状态
|
|
1230
|
+
log(f'过滤前商品数量: {len(spu_list)}')
|
|
1231
|
+
exclude_levels = ['退供款', '自主停产', '自主下架']
|
|
1232
|
+
spu_list = [item for item in spu_list if item['layerNm'] not in exclude_levels]
|
|
1233
|
+
log(f'过滤后剩余商品数量: {len(spu_list)}')
|
|
1227
1234
|
|
|
1228
1235
|
for skc_item in spu_list:
|
|
1229
1236
|
skc = skc_item['skc']
|
|
@@ -1236,7 +1243,10 @@ class SheinLib:
|
|
|
1236
1243
|
for prom_inf_ing in skc_item['promCampaign'].get('promInfIng') or []:
|
|
1237
1244
|
prom_id = prom_inf_ing['promId']
|
|
1238
1245
|
log('prom_id:', prom_id, len(prom_id))
|
|
1239
|
-
if len(prom_id) >=
|
|
1246
|
+
if len(prom_id) >= 11:
|
|
1247
|
+
# 托管活动
|
|
1248
|
+
prom_inf_ing['promDetail'] = self.get_skc_activity_price_info(skc, prom_id)
|
|
1249
|
+
elif len(prom_id) >= 8:
|
|
1240
1250
|
# 营销工具
|
|
1241
1251
|
prom_inf_ing['promDetail'] = self.query_goods_detail(prom_id)
|
|
1242
1252
|
else:
|
|
@@ -1246,7 +1256,9 @@ class SheinLib:
|
|
|
1246
1256
|
for prom_inf_ready in skc_item['promCampaign'].get('promInfReady') or []:
|
|
1247
1257
|
prom_id = prom_inf_ready['promId']
|
|
1248
1258
|
log('prom_id:', prom_id, len(prom_id))
|
|
1249
|
-
if len(prom_id) >=
|
|
1259
|
+
if len(prom_id) >= 11:
|
|
1260
|
+
prom_inf_ready['promDetail'] = self.get_skc_activity_price_info(skc, prom_id)
|
|
1261
|
+
elif len(prom_id) >= 8:
|
|
1250
1262
|
prom_inf_ready['promDetail'] = self.query_goods_detail(prom_id)
|
|
1251
1263
|
else:
|
|
1252
1264
|
prom_inf_ready['promDetail'] = self.get_partake_activity_detail(prom_id, skc)
|
|
@@ -1257,8 +1269,8 @@ class SheinLib:
|
|
|
1257
1269
|
return spu_list
|
|
1258
1270
|
|
|
1259
1271
|
# 获取备货信息列表 最近35天上架的
|
|
1260
|
-
def get_latest_shelf_list(self, shelf_date_begin, shelf_date_end):
|
|
1261
|
-
log(f'获取备货信息列表(
|
|
1272
|
+
def get_latest_shelf_list(self, shelf_date_begin="", shelf_date_end=""):
|
|
1273
|
+
log(f'获取备货信息列表(最近上架的或已上架的) {shelf_date_begin} {shelf_date_end} {self.store_name} {self.store_username}')
|
|
1262
1274
|
|
|
1263
1275
|
dict_skc_shelf_date = {}
|
|
1264
1276
|
|
|
@@ -1275,7 +1287,7 @@ class SheinLib:
|
|
|
1275
1287
|
"c7dSaleCntEnd" : "",
|
|
1276
1288
|
"goodsLevelIdList" : [],
|
|
1277
1289
|
"supplyStatus" : "",
|
|
1278
|
-
"shelfStatus" :
|
|
1290
|
+
"shelfStatus" : 1, # 已上架
|
|
1279
1291
|
"categoryIdList" : [],
|
|
1280
1292
|
"skcStockBegin" : "",
|
|
1281
1293
|
"skcStockEnd" : "",
|
|
@@ -1331,9 +1343,9 @@ class SheinLib:
|
|
|
1331
1343
|
|
|
1332
1344
|
time.sleep(0.3)
|
|
1333
1345
|
|
|
1334
|
-
key = f'{self.store_username}'
|
|
1335
|
-
cache_file = f'{self.config.auto_dir}/shein/cache/bak_info_list_{key}_{shelf_date_begin}_{shelf_date_end}.json'
|
|
1336
|
-
write_dict_to_file_ex(cache_file, {key: spu_list}, [key])
|
|
1346
|
+
# key = f'{self.store_username}'
|
|
1347
|
+
# cache_file = f'{self.config.auto_dir}/shein/cache/bak_info_list_{key}_{shelf_date_begin}_{shelf_date_end}.json'
|
|
1348
|
+
# write_dict_to_file_ex(cache_file, {key: spu_list}, [key])
|
|
1337
1349
|
|
|
1338
1350
|
for skc_item in spu_list:
|
|
1339
1351
|
skc = skc_item['skc']
|
|
@@ -2373,6 +2385,7 @@ class SheinLib:
|
|
|
2373
2385
|
list_item += response_text['info']['data']
|
|
2374
2386
|
time.sleep(0.1)
|
|
2375
2387
|
|
|
2388
|
+
log(list_item)
|
|
2376
2389
|
write_dict_to_file(cache_file, list_item)
|
|
2377
2390
|
return list_item
|
|
2378
2391
|
|
|
@@ -2398,6 +2411,7 @@ class SheinLib:
|
|
|
2398
2411
|
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
2399
2412
|
list_item = response_text['info']['data']
|
|
2400
2413
|
|
|
2414
|
+
log(list_item)
|
|
2401
2415
|
write_dict_to_file(cache_file, list_item)
|
|
2402
2416
|
return list_item
|
|
2403
2417
|
|
|
@@ -3930,3 +3944,247 @@ class SheinLib:
|
|
|
3930
3944
|
log('临时下载文件已清理')
|
|
3931
3945
|
|
|
3932
3946
|
return output_file_path
|
|
3947
|
+
|
|
3948
|
+
def query_hosting_info_list(self):
|
|
3949
|
+
"""
|
|
3950
|
+
查询店铺活动托管规则列表
|
|
3951
|
+
|
|
3952
|
+
Returns:
|
|
3953
|
+
list: 托管规则列表,每个元素包含:
|
|
3954
|
+
- hosting_id: 托管规则ID
|
|
3955
|
+
- scene_type: 场景类型
|
|
3956
|
+
- state: 状态
|
|
3957
|
+
- hosting_name: 托管规则名称
|
|
3958
|
+
- hosting_tools_id: 托管工具ID
|
|
3959
|
+
- hosting_tools_state: 托管工具状态
|
|
3960
|
+
- time_zone: 时区
|
|
3961
|
+
- create_user: 创建用户
|
|
3962
|
+
- last_update_user: 最后更新用户
|
|
3963
|
+
- insert_time: 创建时间
|
|
3964
|
+
- last_update_time: 最后更新时间
|
|
3965
|
+
- exist_act_goods: 是否存在活动商品
|
|
3966
|
+
"""
|
|
3967
|
+
log(f'正在获取 {self.store_name} 店铺活动托管规则列表')
|
|
3968
|
+
|
|
3969
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/hosting_info_list_{self.store_username}_{TimeUtils.today_date()}.json'
|
|
3970
|
+
hosting_list = read_dict_from_file_ex(cache_file, self.store_username, 3600 * 8)
|
|
3971
|
+
if len(hosting_list) > 0:
|
|
3972
|
+
log('返回缓存数据')
|
|
3973
|
+
return hosting_list
|
|
3974
|
+
|
|
3975
|
+
url = "https://sso.geiwohuo.com/mrs-api-prefix/promotion/hosting/query_hosting_info_list"
|
|
3976
|
+
payload = {}
|
|
3977
|
+
|
|
3978
|
+
response_text = fetch(self.web_page, url, payload)
|
|
3979
|
+
error_code = response_text.get('code')
|
|
3980
|
+
if str(error_code) != '0':
|
|
3981
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
3982
|
+
|
|
3983
|
+
hosting_list = response_text.get('info', [])
|
|
3984
|
+
log(f'获取到 {len(hosting_list)} 条托管规则')
|
|
3985
|
+
|
|
3986
|
+
write_dict_to_file_ex(cache_file, {self.store_username: hosting_list}, [self.store_username])
|
|
3987
|
+
|
|
3988
|
+
return hosting_list
|
|
3989
|
+
|
|
3990
|
+
def query_hosting_activity_goods(self, hosting_id, goods_states=None):
|
|
3991
|
+
"""
|
|
3992
|
+
查询托管活动参与的商品
|
|
3993
|
+
|
|
3994
|
+
Args:
|
|
3995
|
+
hosting_id: 托管规则ID
|
|
3996
|
+
goods_states: 商品状态列表,默认为[1](在售)
|
|
3997
|
+
|
|
3998
|
+
Returns:
|
|
3999
|
+
list: 参与托管活动的商品列表,每个元素包含:
|
|
4000
|
+
- goods_state: 商品状态
|
|
4001
|
+
- skc_info_list: SKC信息列表
|
|
4002
|
+
- skc_id: SKC ID
|
|
4003
|
+
- skc_name: SKC名称
|
|
4004
|
+
- goods_name: 商品名称
|
|
4005
|
+
- image_url: 图片URL
|
|
4006
|
+
- act_stock_num: 活动库存数量
|
|
4007
|
+
- act_sales_num: 活动销量
|
|
4008
|
+
- activity_info: 活动信息
|
|
4009
|
+
- sku_info_list: SKU信息列表
|
|
4010
|
+
"""
|
|
4011
|
+
if goods_states is None:
|
|
4012
|
+
goods_states = [1]
|
|
4013
|
+
|
|
4014
|
+
log(f'正在获取 {self.store_name} 托管活动商品列表 hosting_id={hosting_id}')
|
|
4015
|
+
|
|
4016
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/hosting_activity_goods_{self.store_username}_{hosting_id}_{TimeUtils.today_date()}.json'
|
|
4017
|
+
goods_list = read_dict_from_file_ex(cache_file, self.store_username, 3600 * 8)
|
|
4018
|
+
if len(goods_list) > 0:
|
|
4019
|
+
log('返回缓存数据')
|
|
4020
|
+
return goods_list
|
|
4021
|
+
|
|
4022
|
+
page_num = 1
|
|
4023
|
+
page_size = 100
|
|
4024
|
+
|
|
4025
|
+
url = "https://sso.geiwohuo.com/mrs-api-prefix/promotion/hosting/query_hosting_activity_goods"
|
|
4026
|
+
payload = {
|
|
4027
|
+
"goods_states": goods_states,
|
|
4028
|
+
"hosting_id" : str(hosting_id),
|
|
4029
|
+
"page_num" : page_num,
|
|
4030
|
+
"page_size" : page_size
|
|
4031
|
+
}
|
|
4032
|
+
|
|
4033
|
+
response_text = fetch(self.web_page, url, payload)
|
|
4034
|
+
error_code = response_text.get('code')
|
|
4035
|
+
if str(error_code) != '0':
|
|
4036
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
4037
|
+
|
|
4038
|
+
goods_list = response_text.get('info', [])
|
|
4039
|
+
if not goods_list:
|
|
4040
|
+
log('未获取到商品数据')
|
|
4041
|
+
return []
|
|
4042
|
+
|
|
4043
|
+
# 获取第一页数据
|
|
4044
|
+
first_item = goods_list[0] if goods_list else {}
|
|
4045
|
+
skc_info_list = first_item.get('skc_info_list', {})
|
|
4046
|
+
all_data = skc_info_list.get('data', [])
|
|
4047
|
+
meta = skc_info_list.get('meta', {})
|
|
4048
|
+
total = meta.get('count', 0)
|
|
4049
|
+
|
|
4050
|
+
log(f'第1页获取到 {len(all_data)} 条商品,总数: {total}')
|
|
4051
|
+
|
|
4052
|
+
# 如果有多页,继续获取
|
|
4053
|
+
if total > page_size:
|
|
4054
|
+
totalPage = math.ceil(total / page_size)
|
|
4055
|
+
for page in range(2, totalPage + 1):
|
|
4056
|
+
log(f'获取托管活动商品列表 第{page}/{totalPage}页')
|
|
4057
|
+
payload['page_num'] = page
|
|
4058
|
+
response_text = fetch(self.web_page, url, payload)
|
|
4059
|
+
error_code = response_text.get('code')
|
|
4060
|
+
if str(error_code) != '0':
|
|
4061
|
+
log(f'获取第{page}页失败: {response_text}')
|
|
4062
|
+
continue
|
|
4063
|
+
|
|
4064
|
+
page_goods_list = response_text.get('info', [])
|
|
4065
|
+
if page_goods_list:
|
|
4066
|
+
page_data = page_goods_list[0].get('skc_info_list', {}).get('data', [])
|
|
4067
|
+
all_data.extend(page_data)
|
|
4068
|
+
log(f'第{page}页获取到 {len(page_data)} 条商品')
|
|
4069
|
+
|
|
4070
|
+
time.sleep(0.1)
|
|
4071
|
+
|
|
4072
|
+
log(f'总共获取到 {len(all_data)} 条商品')
|
|
4073
|
+
|
|
4074
|
+
# 保存缓存
|
|
4075
|
+
write_dict_to_file_ex(cache_file, {self.store_username: all_data}, [self.store_username])
|
|
4076
|
+
|
|
4077
|
+
return all_data
|
|
4078
|
+
|
|
4079
|
+
def get_skc_activity_price_info(self, skc, activity_id):
|
|
4080
|
+
"""
|
|
4081
|
+
根据SKC和活动ID获取供货价、活动价和活动库存
|
|
4082
|
+
|
|
4083
|
+
Args:
|
|
4084
|
+
skc: SKC名称
|
|
4085
|
+
activity_id: 活动ID(可以是字符串或整数)
|
|
4086
|
+
|
|
4087
|
+
Returns:
|
|
4088
|
+
dict: 包含以下键值的字典,如果未找到则返回None:
|
|
4089
|
+
- sku_price: SKU供货价(取第一个SKU的价格)
|
|
4090
|
+
- act_sku_price: SKU活动价(取第一个SKU的活动价)
|
|
4091
|
+
- act_stock_num: 活动库存数量
|
|
4092
|
+
- skc_name: SKC名称
|
|
4093
|
+
- goods_name: 商品名称
|
|
4094
|
+
- activity_id: 活动ID
|
|
4095
|
+
- currency: 币种
|
|
4096
|
+
- image_url: 商品图片
|
|
4097
|
+
"""
|
|
4098
|
+
log(f'获取SKC活动价格信息: skc={skc}, activity_id={activity_id}')
|
|
4099
|
+
|
|
4100
|
+
# 转换activity_id为整数进行比较
|
|
4101
|
+
try:
|
|
4102
|
+
target_activity_id = int(activity_id)
|
|
4103
|
+
except (ValueError, TypeError):
|
|
4104
|
+
log(f'无效的activity_id: {activity_id}')
|
|
4105
|
+
return None
|
|
4106
|
+
|
|
4107
|
+
# 缓存文件,使用skc和activity_id作为缓存key
|
|
4108
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/skc_activity_price_{self.store_username}_{skc}_{activity_id}_{TimeUtils.today_date()}.json'
|
|
4109
|
+
cached_data = read_dict_from_file(cache_file, 3600 * 8)
|
|
4110
|
+
if cached_data:
|
|
4111
|
+
log('返回缓存的价格信息')
|
|
4112
|
+
return cached_data
|
|
4113
|
+
|
|
4114
|
+
# 获取所有托管规则
|
|
4115
|
+
hosting_list = self.query_hosting_info_list()
|
|
4116
|
+
|
|
4117
|
+
if not hosting_list:
|
|
4118
|
+
log('未找到任何托管规则')
|
|
4119
|
+
return None
|
|
4120
|
+
|
|
4121
|
+
# 遍历所有托管规则,查找匹配的SKC和活动
|
|
4122
|
+
for hosting in hosting_list:
|
|
4123
|
+
hosting_id = hosting.get('hosting_id')
|
|
4124
|
+
if not hosting_id:
|
|
4125
|
+
continue
|
|
4126
|
+
|
|
4127
|
+
log(f'查询托管规则: hosting_id={hosting_id}, hosting_name={hosting.get("hosting_name")}')
|
|
4128
|
+
|
|
4129
|
+
# 获取该托管规则下的商品
|
|
4130
|
+
goods_list = self.query_hosting_activity_goods(hosting_id)
|
|
4131
|
+
|
|
4132
|
+
# 在商品列表中查找匹配的SKC
|
|
4133
|
+
for goods_item in goods_list:
|
|
4134
|
+
skc_name = goods_item.get('skc_name', '')
|
|
4135
|
+
|
|
4136
|
+
# 匹配SKC名称
|
|
4137
|
+
if skc_name != skc:
|
|
4138
|
+
continue
|
|
4139
|
+
|
|
4140
|
+
# 检查活动信息
|
|
4141
|
+
activity_info = goods_item.get('activity_info', {})
|
|
4142
|
+
goods_activity_id = activity_info.get('activity_id')
|
|
4143
|
+
|
|
4144
|
+
# 匹配活动ID
|
|
4145
|
+
try:
|
|
4146
|
+
if int(goods_activity_id) != target_activity_id:
|
|
4147
|
+
continue
|
|
4148
|
+
except (ValueError, TypeError):
|
|
4149
|
+
continue
|
|
4150
|
+
|
|
4151
|
+
log(f'找到匹配的SKC: {skc_name}, activity_id={goods_activity_id}')
|
|
4152
|
+
|
|
4153
|
+
# 提取活动库存
|
|
4154
|
+
act_stock_num = goods_item.get('act_stock_num', 0)
|
|
4155
|
+
|
|
4156
|
+
# 获取第一个SKU的价格信息
|
|
4157
|
+
sku_info_list = goods_item.get('sku_info_list', [])
|
|
4158
|
+
if not sku_info_list:
|
|
4159
|
+
log(f'SKC {skc_name} 没有SKU信息')
|
|
4160
|
+
continue
|
|
4161
|
+
|
|
4162
|
+
first_sku = sku_info_list[0]
|
|
4163
|
+
sku_price = first_sku.get('sku_price', 0)
|
|
4164
|
+
act_sku_price = first_sku.get('act_sku_price', 0)
|
|
4165
|
+
currency = first_sku.get('currency', 'CNY')
|
|
4166
|
+
|
|
4167
|
+
# 构建返回结果
|
|
4168
|
+
result = {
|
|
4169
|
+
'skc_name' : skc_name,
|
|
4170
|
+
'goods_name' : goods_item.get('goods_name', ''),
|
|
4171
|
+
'image_url' : goods_item.get('image_url', ''),
|
|
4172
|
+
'activity_id' : goods_activity_id,
|
|
4173
|
+
'act_stock_num': act_stock_num,
|
|
4174
|
+
'sku_price' : sku_price,
|
|
4175
|
+
'act_sku_price': act_sku_price,
|
|
4176
|
+
'currency' : currency,
|
|
4177
|
+
'start_time' : activity_info.get('start_time', ''),
|
|
4178
|
+
'end_time' : activity_info.get('end_time', ''),
|
|
4179
|
+
'time_zone' : activity_info.get('time_zone', ''),
|
|
4180
|
+
}
|
|
4181
|
+
|
|
4182
|
+
log(f'SKC供货价: {sku_price} {currency}, 活动价: {act_sku_price} {currency}, 活动库存: {act_stock_num}')
|
|
4183
|
+
|
|
4184
|
+
# 保存缓存
|
|
4185
|
+
write_dict_to_file(cache_file, result)
|
|
4186
|
+
|
|
4187
|
+
return result
|
|
4188
|
+
|
|
4189
|
+
log(f'未找到匹配的SKC和活动: skc={skc}, activity_id={activity_id}')
|
|
4190
|
+
return None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|