qrpa 1.0.23__py3-none-any.whl → 1.0.25__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/__init__.py +6 -1
- qrpa/fun_base.py +230 -0
- qrpa/fun_excel.py +65 -13
- qrpa/shein_excel.py +1428 -13
- qrpa/shein_lib.py +436 -0
- qrpa/temu_chrome.py +56 -0
- qrpa/temu_excel.py +109 -0
- qrpa/temu_lib.py +154 -0
- qrpa/wxwork.py +6 -0
- {qrpa-1.0.23.dist-info → qrpa-1.0.25.dist-info}/METADATA +1 -1
- qrpa-1.0.25.dist-info/RECORD +23 -0
- qrpa-1.0.23.dist-info/RECORD +0 -20
- {qrpa-1.0.23.dist-info → qrpa-1.0.25.dist-info}/WHEEL +0 -0
- {qrpa-1.0.23.dist-info → qrpa-1.0.25.dist-info}/top_level.txt +0 -0
qrpa/shein_lib.py
CHANGED
|
@@ -22,6 +22,7 @@ class SheinLib:
|
|
|
22
22
|
self.store_name = store_name
|
|
23
23
|
self.web_page = web_page
|
|
24
24
|
self.dt = None
|
|
25
|
+
self.DictQueryTime = {}
|
|
25
26
|
|
|
26
27
|
self.deal_auth()
|
|
27
28
|
|
|
@@ -82,6 +83,441 @@ class SheinLib:
|
|
|
82
83
|
# web_page.goto('https://sso.geiwohuo.com')
|
|
83
84
|
log('鉴权处理结束')
|
|
84
85
|
|
|
86
|
+
# 获取希音退供明细 和 台账明细一个接口
|
|
87
|
+
def get_back_list(self, source='mb'):
|
|
88
|
+
page_num = 1
|
|
89
|
+
page_size = 200 # 列表最多返回200条数据 大了没有用
|
|
90
|
+
|
|
91
|
+
first_day, last_day = TimeUtils.get_last_month_range()
|
|
92
|
+
|
|
93
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/return_detail_{self.store_username}_{first_day}_{last_day}.json'
|
|
94
|
+
list_item = read_dict_from_file(cache_file, 3600 * 24 * 20)
|
|
95
|
+
if len(list_item) > 0:
|
|
96
|
+
return list_item
|
|
97
|
+
|
|
98
|
+
url = f"https://sso.geiwohuo.com/mils/changeDetail/page"
|
|
99
|
+
payload = {
|
|
100
|
+
"displayChangeTypeList": ["10"],
|
|
101
|
+
"addTimeStart" : f"{first_day} 00:00:00",
|
|
102
|
+
"addTimeEnd" : f"{last_day} 23:59:59",
|
|
103
|
+
"pageNumber" : page_num,
|
|
104
|
+
"pageSize" : page_size,
|
|
105
|
+
"changeTypeIndex" : "2"
|
|
106
|
+
}
|
|
107
|
+
response_text = fetch(self.web_page, url, payload)
|
|
108
|
+
error_code = response_text.get('code')
|
|
109
|
+
if str(error_code) != '0':
|
|
110
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
111
|
+
list_item = response_text['info']['data']['list']
|
|
112
|
+
total = response_text['info']['data']['count']
|
|
113
|
+
totalPage = math.ceil(total / page_size)
|
|
114
|
+
|
|
115
|
+
for page in range(2, totalPage + 1):
|
|
116
|
+
log(f'获取台账明细列表 第{page}/{totalPage}页')
|
|
117
|
+
payload['pageNumber'] = page
|
|
118
|
+
response_text = fetch(self.web_page, url, payload)
|
|
119
|
+
spu_list_new = response_text['info']['data']['list']
|
|
120
|
+
list_item += spu_list_new
|
|
121
|
+
time.sleep(0.1)
|
|
122
|
+
|
|
123
|
+
# cost_price =
|
|
124
|
+
for item in list_item:
|
|
125
|
+
supplierSku = item['supplierSku']
|
|
126
|
+
item['cost_price'] = self.bridge.get_sku_cost(supplierSku, source)
|
|
127
|
+
item['sku_img'] = self.bridge.get_sku_img(supplierSku, source)
|
|
128
|
+
|
|
129
|
+
write_dict_to_file(cache_file, list_item)
|
|
130
|
+
|
|
131
|
+
return list_item
|
|
132
|
+
|
|
133
|
+
# 不结算列表
|
|
134
|
+
def get_no_settlement_list(self, source='mb'):
|
|
135
|
+
page_num = 1
|
|
136
|
+
page_size = 200 # 列表最多返回200条数据 大了没有用
|
|
137
|
+
|
|
138
|
+
first_day, last_day = TimeUtils.get_last_month_range()
|
|
139
|
+
|
|
140
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/no_settlement_{self.store_username}_{first_day}_{last_day}.json'
|
|
141
|
+
list_item = read_dict_from_file(cache_file, 3600 * 24 * 20)
|
|
142
|
+
if len(list_item) > 0:
|
|
143
|
+
return list_item
|
|
144
|
+
|
|
145
|
+
url = f"https://sso.geiwohuo.com/mils/changeDetail/page"
|
|
146
|
+
payload = {
|
|
147
|
+
"addTimeStart" : f"{first_day} 00:00:00",
|
|
148
|
+
"addTimeEnd" : f"{last_day} 23:59:59",
|
|
149
|
+
"pageNumber" : page_num,
|
|
150
|
+
"pageSize" : page_size,
|
|
151
|
+
"changeTypeIndex" : "2",
|
|
152
|
+
"settleTypeList" : ["1"], # 不结算
|
|
153
|
+
"displayChangeTypeList": ["6", "7", "9", "10", "11", "12", "13", "16", "18", "19"] # 出库
|
|
154
|
+
}
|
|
155
|
+
response_text = fetch(self.web_page, url, payload)
|
|
156
|
+
error_code = response_text.get('code')
|
|
157
|
+
if str(error_code) != '0':
|
|
158
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
159
|
+
list_item = response_text['info']['data']['list']
|
|
160
|
+
total = response_text['info']['data']['count']
|
|
161
|
+
totalPage = math.ceil(total / page_size)
|
|
162
|
+
|
|
163
|
+
for page in range(2, totalPage + 1):
|
|
164
|
+
log(f'获取台账明细列表 第{page}/{totalPage}页')
|
|
165
|
+
payload['pageNumber'] = page
|
|
166
|
+
response_text = fetch(self.web_page, url, payload)
|
|
167
|
+
spu_list_new = response_text['info']['data']['list']
|
|
168
|
+
list_item += spu_list_new
|
|
169
|
+
time.sleep(0.1)
|
|
170
|
+
|
|
171
|
+
# cost_price =
|
|
172
|
+
for item in list_item:
|
|
173
|
+
supplierSku = item['supplierSku']
|
|
174
|
+
item['cost_price'] = self.bridge.get_sku_cost(supplierSku, source)
|
|
175
|
+
item['sku_img'] = self.bridge.get_sku_img(supplierSku, source)
|
|
176
|
+
|
|
177
|
+
write_dict_to_file(cache_file, list_item)
|
|
178
|
+
|
|
179
|
+
return list_item
|
|
180
|
+
|
|
181
|
+
def get_ledger_list(self, source='mb'):
|
|
182
|
+
page_num = 1
|
|
183
|
+
page_size = 200 # 列表最多返回200条数据 大了没有用
|
|
184
|
+
|
|
185
|
+
first_day, last_day = TimeUtils.get_last_month_range()
|
|
186
|
+
|
|
187
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/sales_detail_{self.store_username}_{first_day}_{last_day}.json'
|
|
188
|
+
list_item = read_dict_from_file(cache_file, 3600 * 24 * 20)
|
|
189
|
+
if len(list_item) > 0:
|
|
190
|
+
return list_item
|
|
191
|
+
|
|
192
|
+
url = f"https://sso.geiwohuo.com/mils/changeDetail/page"
|
|
193
|
+
payload = {
|
|
194
|
+
"displayChangeTypeList": ["6", "7", "9", "10", "11", "12", "13", "16", "18", "19"], # 出库
|
|
195
|
+
"addTimeStart" : f"{first_day} 00:00:00",
|
|
196
|
+
"addTimeEnd" : f"{last_day} 23:59:59",
|
|
197
|
+
"pageNumber" : page_num,
|
|
198
|
+
"pageSize" : page_size,
|
|
199
|
+
"changeTypeIndex" : "2"
|
|
200
|
+
}
|
|
201
|
+
response_text = fetch(self.web_page, url, payload)
|
|
202
|
+
error_code = response_text.get('code')
|
|
203
|
+
if str(error_code) != '0':
|
|
204
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
205
|
+
list_item = response_text['info']['data']['list']
|
|
206
|
+
total = response_text['info']['data']['count']
|
|
207
|
+
totalPage = math.ceil(total / page_size)
|
|
208
|
+
|
|
209
|
+
for page in range(2, totalPage + 1):
|
|
210
|
+
log(f'获取台账明细列表 第{page}/{totalPage}页')
|
|
211
|
+
payload['pageNumber'] = page
|
|
212
|
+
response_text = fetch(self.web_page, url, payload)
|
|
213
|
+
spu_list_new = response_text['info']['data']['list']
|
|
214
|
+
list_item += spu_list_new
|
|
215
|
+
time.sleep(0.1)
|
|
216
|
+
|
|
217
|
+
# cost_price =
|
|
218
|
+
for item in list_item:
|
|
219
|
+
supplierSku = item['supplierSku']
|
|
220
|
+
item['cost_price'] = self.bridge.get_sku_cost(supplierSku, source)
|
|
221
|
+
item['sku_img'] = self.bridge.get_sku_img(supplierSku, source)
|
|
222
|
+
|
|
223
|
+
write_dict_to_file(cache_file, list_item)
|
|
224
|
+
|
|
225
|
+
return list_item
|
|
226
|
+
|
|
227
|
+
def get_shein_stock_list(self, source='mb'):
|
|
228
|
+
page_num = 1
|
|
229
|
+
page_size = 200 # 列表最多返回200条数据 大了没有用
|
|
230
|
+
|
|
231
|
+
first_day, last_day = TimeUtils.get_last_month_range()
|
|
232
|
+
|
|
233
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/stock_detail_{self.store_username}_{first_day}_{last_day}.json'
|
|
234
|
+
list_item = read_dict_from_file(cache_file, 3600 * 24 * 20)
|
|
235
|
+
if len(list_item) > 0:
|
|
236
|
+
return list_item
|
|
237
|
+
|
|
238
|
+
url = f"https://sso.geiwohuo.com/mils/report/month/detail/list"
|
|
239
|
+
payload = {
|
|
240
|
+
"reportDateStart": first_day,
|
|
241
|
+
"reportDateEnd" : last_day,
|
|
242
|
+
"pageNumber" : page_num,
|
|
243
|
+
"pageSize" : page_size,
|
|
244
|
+
}
|
|
245
|
+
response_text = fetch(self.web_page, url, payload)
|
|
246
|
+
error_code = response_text.get('code')
|
|
247
|
+
if str(error_code) != '0':
|
|
248
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
249
|
+
list_item = response_text['info']['data']['list']
|
|
250
|
+
total = response_text['info']['data']['count']
|
|
251
|
+
totalPage = math.ceil(total / page_size)
|
|
252
|
+
|
|
253
|
+
for page in range(2, totalPage + 1):
|
|
254
|
+
log(f'获取库存结余明细列表 第{page}/{totalPage}页')
|
|
255
|
+
page_num = page
|
|
256
|
+
payload = {
|
|
257
|
+
"reportDateStart": first_day,
|
|
258
|
+
"reportDateEnd" : last_day,
|
|
259
|
+
"pageNumber" : page_num,
|
|
260
|
+
"pageSize" : page_size,
|
|
261
|
+
}
|
|
262
|
+
response_text = fetch(self.web_page, url, payload)
|
|
263
|
+
spu_list_new = response_text['info']['data']['list']
|
|
264
|
+
list_item += spu_list_new
|
|
265
|
+
time.sleep(0.1)
|
|
266
|
+
|
|
267
|
+
for item in list_item:
|
|
268
|
+
supplierSku = item['supplierSku']
|
|
269
|
+
item['cost_price'] = self.bridge.get_sku_cost(supplierSku, source)
|
|
270
|
+
item['sku_img'] = self.bridge.get_sku_img(supplierSku, source)
|
|
271
|
+
|
|
272
|
+
write_dict_to_file(cache_file, list_item)
|
|
273
|
+
|
|
274
|
+
return list_item
|
|
275
|
+
|
|
276
|
+
def get_replenish_list(self):
|
|
277
|
+
page_num = 1
|
|
278
|
+
page_size = 50
|
|
279
|
+
first_day, last_day = TimeUtils.get_last_month_range()
|
|
280
|
+
|
|
281
|
+
cache_file = f'{self.config.auto_dir}/cache/replenish_list_{self.store_username}_{first_day}_{last_day}.json'
|
|
282
|
+
list_item = read_dict_from_file(cache_file, 3600 * 24 * 20)
|
|
283
|
+
if len(list_item) > 0:
|
|
284
|
+
return list_item
|
|
285
|
+
|
|
286
|
+
url = f"https://sso.geiwohuo.com/gsfs/finance/selfReplenish/list"
|
|
287
|
+
payload = {
|
|
288
|
+
"page" : page_num,
|
|
289
|
+
"perPage" : page_size,
|
|
290
|
+
"tabType" : 2,
|
|
291
|
+
"addTimeStart": f"{first_day} 00:00:00",
|
|
292
|
+
"addTimeEnd" : f"{last_day} 23:59:59"
|
|
293
|
+
}
|
|
294
|
+
response_text = fetch(self.web_page, url, payload)
|
|
295
|
+
error_code = response_text.get('code')
|
|
296
|
+
if str(error_code) != '0':
|
|
297
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
298
|
+
list_item = response_text['info']['data']
|
|
299
|
+
total = response_text['info']['meta']['count']
|
|
300
|
+
totalPage = math.ceil(total / page_size)
|
|
301
|
+
|
|
302
|
+
for page in range(2, totalPage + 1):
|
|
303
|
+
log(f'获取不扣款列表 第{page}/{totalPage}页')
|
|
304
|
+
page_num = page
|
|
305
|
+
payload = {
|
|
306
|
+
"page" : page_num,
|
|
307
|
+
"perPage" : page_size,
|
|
308
|
+
"tabType" : 2,
|
|
309
|
+
"addTimeStart": f"{first_day} 00:00:00",
|
|
310
|
+
"addTimeEnd" : f"{last_day} 23:59:59"
|
|
311
|
+
}
|
|
312
|
+
response_text = fetch(self.web_page, url, payload)
|
|
313
|
+
spu_list_new = response_text['info']['data']
|
|
314
|
+
list_item += spu_list_new
|
|
315
|
+
time.sleep(0.1)
|
|
316
|
+
|
|
317
|
+
write_dict_to_file(cache_file, list_item)
|
|
318
|
+
|
|
319
|
+
return list_item
|
|
320
|
+
|
|
321
|
+
def get_return_list(self):
|
|
322
|
+
page_num = 1
|
|
323
|
+
page_size = 200
|
|
324
|
+
first_day, last_day = TimeUtils.get_last_month_range()
|
|
325
|
+
|
|
326
|
+
cache_file = f'{self.config.auto_dir}/cache/return_list_{self.store_username}_{first_day}_{last_day}.json'
|
|
327
|
+
list_item = read_dict_from_file(cache_file, 3600 * 24 * 20)
|
|
328
|
+
if len(list_item) > 0:
|
|
329
|
+
return list_item
|
|
330
|
+
|
|
331
|
+
url = f"https://sso.geiwohuo.com/pfmp/returnOrder/page"
|
|
332
|
+
payload = {
|
|
333
|
+
"addTimeStart" : f"{first_day} 00:00:00",
|
|
334
|
+
"addTimeEnd" : f"{last_day} 23:59:59",
|
|
335
|
+
"returnOrderStatusList": [4],
|
|
336
|
+
"page" : page_num,
|
|
337
|
+
"perPage" : page_size
|
|
338
|
+
}
|
|
339
|
+
response_text = fetch(self.web_page, url, payload)
|
|
340
|
+
error_code = response_text.get('code')
|
|
341
|
+
if str(error_code) != '0':
|
|
342
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
343
|
+
|
|
344
|
+
list_item = response_text['info']['data']
|
|
345
|
+
total = response_text['info']['meta']['count']
|
|
346
|
+
totalPage = math.ceil(total / page_size)
|
|
347
|
+
|
|
348
|
+
for page in range(2, totalPage + 1):
|
|
349
|
+
log(f'获取不扣款列表 第{page}/{totalPage}页')
|
|
350
|
+
page_num = page
|
|
351
|
+
payload = {
|
|
352
|
+
"addTimeStart" : f"{first_day} 00:00:00",
|
|
353
|
+
"addTimeEnd" : f"{last_day} 23:59:59",
|
|
354
|
+
"returnOrderStatusList": [4],
|
|
355
|
+
"page" : page_num,
|
|
356
|
+
"perPage" : page_size
|
|
357
|
+
}
|
|
358
|
+
response_text = fetch(self.web_page, url, payload)
|
|
359
|
+
spu_list_new = response_text['info']['data']
|
|
360
|
+
list_item += spu_list_new
|
|
361
|
+
time.sleep(0.1)
|
|
362
|
+
|
|
363
|
+
write_dict_to_file(cache_file, list_item)
|
|
364
|
+
|
|
365
|
+
return list_item
|
|
366
|
+
|
|
367
|
+
def get_comment_list(self):
|
|
368
|
+
cache_file = f'{self.config.auto_dir}/shein/dict/comment_list_{TimeUtils.today_date()}.json'
|
|
369
|
+
comment_list = read_dict_from_file_ex(cache_file, self.store_username, 3600)
|
|
370
|
+
if len(comment_list) > 0:
|
|
371
|
+
return comment_list
|
|
372
|
+
|
|
373
|
+
page_num = 1
|
|
374
|
+
page_size = 50
|
|
375
|
+
|
|
376
|
+
yesterday = TimeUtils.get_yesterday()
|
|
377
|
+
|
|
378
|
+
url = f"https://sso.geiwohuo.com/gsp/goods/comment/list"
|
|
379
|
+
payload = {
|
|
380
|
+
"page" : page_num,
|
|
381
|
+
"perPage" : page_size,
|
|
382
|
+
"startCommentTime": f"{yesterday} 00:00:00",
|
|
383
|
+
"commentEndTime" : f"{yesterday} 23:59:59",
|
|
384
|
+
"commentStarList" : ["3", "2", "1"]
|
|
385
|
+
}
|
|
386
|
+
response_text = fetch(self.web_page, url, payload)
|
|
387
|
+
error_code = response_text.get('code')
|
|
388
|
+
if str(error_code) != '0':
|
|
389
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
390
|
+
|
|
391
|
+
comment_list = response_text['info']['data']
|
|
392
|
+
total = response_text['info']['meta']['count']
|
|
393
|
+
totalPage = math.ceil(total / page_size)
|
|
394
|
+
|
|
395
|
+
for page in range(2, totalPage + 1):
|
|
396
|
+
log(f'获取评价列表 第{page}/{totalPage}页')
|
|
397
|
+
page_num = page
|
|
398
|
+
payload['page'] = page_num
|
|
399
|
+
response_text = fetch(self.web_page, url, payload)
|
|
400
|
+
comment_list = response_text['info']['data']
|
|
401
|
+
time.sleep(0.1)
|
|
402
|
+
|
|
403
|
+
write_dict_to_file_ex(cache_file, {self.store_username: comment_list}, [self.store_username])
|
|
404
|
+
return comment_list
|
|
405
|
+
|
|
406
|
+
def get_last_month_outbound_amount(self):
|
|
407
|
+
url = "https://sso.geiwohuo.com/mils/report/month/list"
|
|
408
|
+
start, end = TimeUtils.get_current_year_range()
|
|
409
|
+
payload = {
|
|
410
|
+
"reportDateStart": start, "reportDateEnd": end, "pageNumber": 1, "pageSize": 50
|
|
411
|
+
}
|
|
412
|
+
response_text = fetch(self.web_page, url, payload)
|
|
413
|
+
error_code = response_text.get('code')
|
|
414
|
+
if str(error_code) != '0':
|
|
415
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
416
|
+
info = response_text.get('info')
|
|
417
|
+
lst = info.get('data', {}).get('list', [])
|
|
418
|
+
if not lst:
|
|
419
|
+
log(f'⚠️ {self.store_name} 最近一个月无出库记录,金额为0')
|
|
420
|
+
return 0
|
|
421
|
+
|
|
422
|
+
last_item = lst[-1]
|
|
423
|
+
log(f'正在获取 {self.store_name} 最近一个月出库金额: {last_item["totalCustomerAmount"]}')
|
|
424
|
+
return last_item['totalCustomerAmount']
|
|
425
|
+
|
|
426
|
+
def get_funds_data(self):
|
|
427
|
+
log(f'正在获取 {self.store_name} 财务数据')
|
|
428
|
+
url = "https://sso.geiwohuo.com/sso/homePage/dataOverview/v2/detail"
|
|
429
|
+
payload = {
|
|
430
|
+
"metaIndexIds": [
|
|
431
|
+
298,
|
|
432
|
+
67,
|
|
433
|
+
70,
|
|
434
|
+
72
|
|
435
|
+
],
|
|
436
|
+
}
|
|
437
|
+
response_text = fetch(self.web_page, url, payload)
|
|
438
|
+
error_code = response_text.get('code')
|
|
439
|
+
if str(error_code) != '0':
|
|
440
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
441
|
+
info = response_text.get('info')
|
|
442
|
+
num298 = 0 # 在途商品金额
|
|
443
|
+
num67 = 0 # 在仓商品金额
|
|
444
|
+
num70 = 0 # 待结算金额
|
|
445
|
+
num72 = 0 # 可提现金额
|
|
446
|
+
for item in info['list']:
|
|
447
|
+
if item['metaIndexId'] == 298:
|
|
448
|
+
num298 = item['count']
|
|
449
|
+
if item['metaIndexId'] == 67:
|
|
450
|
+
num67 = item['count']
|
|
451
|
+
if item['metaIndexId'] == 70:
|
|
452
|
+
num70 = item['count']
|
|
453
|
+
if item['metaIndexId'] == 72:
|
|
454
|
+
num72 = item['count']
|
|
455
|
+
|
|
456
|
+
outAmount = self.get_last_month_outbound_amount()
|
|
457
|
+
dict_store = read_dict_from_file(self.config.shein_store_alias)
|
|
458
|
+
store_manager = dict_store.get(str(self.store_username).lower())
|
|
459
|
+
NotifyItem = [f'{self.store_name}', self.store_username, store_manager, num298, num67, num70, num72, outAmount, '',
|
|
460
|
+
TimeUtils.current_datetime()]
|
|
461
|
+
|
|
462
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/stat_fund_{TimeUtils.today_date()}.json'
|
|
463
|
+
write_dict_to_file_ex(cache_file, {self.store_username: NotifyItem}, [self.store_username])
|
|
464
|
+
return NotifyItem
|
|
465
|
+
|
|
466
|
+
def getQueryDate(self):
|
|
467
|
+
query_time = self.DictQueryTime.get(self.store_username, None)
|
|
468
|
+
if query_time is not None:
|
|
469
|
+
log(f'从字典获取query_time: {query_time}')
|
|
470
|
+
return query_time
|
|
471
|
+
log('获取日期范围')
|
|
472
|
+
url = "https://sso.geiwohuo.com/mgs-api-prefix/estimate/queryDateRange"
|
|
473
|
+
payload = {}
|
|
474
|
+
response_text = fetch(self.web_page, url, payload)
|
|
475
|
+
error_code = response_text.get('code')
|
|
476
|
+
if str(error_code) != '0':
|
|
477
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
478
|
+
query_time = response_text.get('info').get('quality_goods_query_time')
|
|
479
|
+
self.DictQueryTime.update({self.store_username: query_time})
|
|
480
|
+
log(f'query_time: {query_time}')
|
|
481
|
+
return query_time
|
|
482
|
+
|
|
483
|
+
def get_goods_quality_estimate_list(self, query_date):
|
|
484
|
+
cache_file = f'{self.config.auto_dir}/shein/dict/googs_estimate_{query_date}.json'
|
|
485
|
+
estimate_list = read_dict_from_file_ex(cache_file, self.store_username, 3600 * 8)
|
|
486
|
+
if len(estimate_list) > 0:
|
|
487
|
+
return estimate_list
|
|
488
|
+
|
|
489
|
+
page_num = 1
|
|
490
|
+
page_size = 100
|
|
491
|
+
|
|
492
|
+
url = f"https://sso.geiwohuo.com/mgs-api-prefix/estimate/queryNewQualityGoodsList"
|
|
493
|
+
payload = {
|
|
494
|
+
"page_no" : page_num,
|
|
495
|
+
"page_size" : page_size,
|
|
496
|
+
"start_date": query_date,
|
|
497
|
+
"end_date" : query_date,
|
|
498
|
+
"order_col" : "skc_sale_cnt_14d",
|
|
499
|
+
"order_type": "desc"
|
|
500
|
+
}
|
|
501
|
+
response_text = fetch(self.web_page, url, payload, {'lan': 'CN'})
|
|
502
|
+
error_code = response_text.get('code')
|
|
503
|
+
if str(error_code) != '0':
|
|
504
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
505
|
+
|
|
506
|
+
estimate_list = response_text['info']['data']
|
|
507
|
+
total = response_text['info']['meta']['count']
|
|
508
|
+
totalPage = math.ceil(total / page_size)
|
|
509
|
+
|
|
510
|
+
for page in range(2, totalPage + 1):
|
|
511
|
+
log(f'获取质量评估列表 第{page}/{totalPage}页')
|
|
512
|
+
page_num = page
|
|
513
|
+
payload['page'] = page_num
|
|
514
|
+
response_text = fetch(self.web_page, url, payload)
|
|
515
|
+
estimate_list = response_text['info']['data']
|
|
516
|
+
time.sleep(0.1)
|
|
517
|
+
|
|
518
|
+
write_dict_to_file_ex(cache_file, {self.store_username: estimate_list}, [self.store_username])
|
|
519
|
+
return estimate_list
|
|
520
|
+
|
|
85
521
|
# 已上架备货款A数量
|
|
86
522
|
def get_product_bak_A_count(self):
|
|
87
523
|
url = "https://sso.geiwohuo.com/idms/goods-skc/list"
|
qrpa/temu_chrome.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from playwright.sync_api import sync_playwright, Page
|
|
2
|
+
from qrpa import get_progress_json_ex, done_progress_json_ex, send_exception
|
|
3
|
+
from qrpa import TemuLib, get_chrome_page_v3, log
|
|
4
|
+
|
|
5
|
+
from typing import Literal, Optional, Callable, List, Dict, Any
|
|
6
|
+
|
|
7
|
+
"""不要test开头命名文件 否则会用pytest运行这个程序"""
|
|
8
|
+
|
|
9
|
+
def temu_chrome_excute(settings, run_prepare: Optional[Callable] = None, run: Optional[Callable] = None, run_summary: Optional[Callable] = None, run_notify: Optional[Callable] = None, key_id: Optional[str] = None, just_usernames: Optional[List] = None, just_mall_ids: Optional[List] = None):
|
|
10
|
+
run_prepare()
|
|
11
|
+
with sync_playwright() as p:
|
|
12
|
+
count = 0
|
|
13
|
+
while True:
|
|
14
|
+
try:
|
|
15
|
+
count += 1
|
|
16
|
+
with get_chrome_page_v3(p) as (browser, context, web_page):
|
|
17
|
+
web_page: Page # 显式注解
|
|
18
|
+
|
|
19
|
+
for account in settings.temu_account_list:
|
|
20
|
+
username = account[0]
|
|
21
|
+
password = account[1]
|
|
22
|
+
|
|
23
|
+
if just_usernames and username not in just_usernames:
|
|
24
|
+
continue
|
|
25
|
+
|
|
26
|
+
if get_progress_json_ex(settings, key_id, username):
|
|
27
|
+
continue
|
|
28
|
+
|
|
29
|
+
temu_client = TemuLib(settings, username, password, web_page)
|
|
30
|
+
shop_list = temu_client.get_shop_list()
|
|
31
|
+
# 增加每个店铺的处理进度
|
|
32
|
+
for shop in shop_list:
|
|
33
|
+
mall_id = shop[0]
|
|
34
|
+
mall_name = shop[1]
|
|
35
|
+
if just_mall_ids and mall_id not in just_mall_ids:
|
|
36
|
+
continue
|
|
37
|
+
|
|
38
|
+
store_name = f'{mall_id}_{mall_name}'
|
|
39
|
+
if not get_progress_json_ex(settings, key_id, store_name):
|
|
40
|
+
log(f"正在处理店铺: {mall_name},{mall_id},{username}")
|
|
41
|
+
run(temu_client, web_page, mall_id, mall_name)
|
|
42
|
+
done_progress_json_ex(settings, key_id, store_name)
|
|
43
|
+
|
|
44
|
+
done_progress_json_ex(settings, key_id, username)
|
|
45
|
+
|
|
46
|
+
if not get_progress_json_ex(settings, key_id, 'run_summary'):
|
|
47
|
+
run_summary()
|
|
48
|
+
done_progress_json_ex(settings, key_id, 'run_summary')
|
|
49
|
+
if not get_progress_json_ex(settings, key_id, 'run_notify'):
|
|
50
|
+
run_notify()
|
|
51
|
+
done_progress_json_ex(settings, key_id, 'run_notify')
|
|
52
|
+
break
|
|
53
|
+
except:
|
|
54
|
+
send_exception()
|
|
55
|
+
if count > 1:
|
|
56
|
+
break
|
qrpa/temu_excel.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from .fun_excel import *
|
|
2
|
+
from .fun_base import log
|
|
3
|
+
from .fun_file import read_dict_from_file, read_dict_from_file_ex, write_dict_to_file, write_dict_to_file_ex, delete_file
|
|
4
|
+
from .time_utils import TimeUtils
|
|
5
|
+
from .wxwork import WxWorkBot
|
|
6
|
+
|
|
7
|
+
class TemuExcel:
|
|
8
|
+
|
|
9
|
+
def __init__(self, config, bridge):
|
|
10
|
+
self.config = config
|
|
11
|
+
self.bridge = bridge
|
|
12
|
+
|
|
13
|
+
def write_funds(self):
|
|
14
|
+
cache_file = f'{self.config.auto_dir}/temu/cache/funds_{TimeUtils.today_date()}.json'
|
|
15
|
+
dict = read_dict_from_file(cache_file)
|
|
16
|
+
data = []
|
|
17
|
+
for key, val in dict.items():
|
|
18
|
+
data.append(val)
|
|
19
|
+
|
|
20
|
+
excel_path = create_file_path(self.config.excel_temu_fund)
|
|
21
|
+
data.insert(0, ['汇总', '', '', '', ''])
|
|
22
|
+
data.insert(0, ['店铺名称', '总金额', '可用余额', '-', '导出时间'])
|
|
23
|
+
log(data)
|
|
24
|
+
# 删除第 4 列(索引为 3)
|
|
25
|
+
for row in data:
|
|
26
|
+
row.pop(3) # 删除每行中索引为 3 的元素
|
|
27
|
+
|
|
28
|
+
write_data(excel_path, 'Sheet1', data)
|
|
29
|
+
|
|
30
|
+
app, wb, sheet = open_excel(excel_path, 'Sheet1')
|
|
31
|
+
beautify_title(sheet)
|
|
32
|
+
format_to_money(sheet, ['金额', '余额'])
|
|
33
|
+
format_to_datetime(sheet, ['时间'])
|
|
34
|
+
add_sum_for_cell(sheet, ['总金额', '可用余额'])
|
|
35
|
+
add_borders(sheet)
|
|
36
|
+
close_excel(app, wb)
|
|
37
|
+
|
|
38
|
+
def format_purchase_advise_batch(self, sheet):
|
|
39
|
+
beautify_title(sheet)
|
|
40
|
+
format_to_datetime(sheet, ['时间'])
|
|
41
|
+
format_to_number(sheet, ['平均日销', '本地和采购可售天数', '建议采购'], 1)
|
|
42
|
+
add_borders(sheet)
|
|
43
|
+
add_formula_for_column(sheet, '平均日销', '=G2/7')
|
|
44
|
+
add_formula_for_column(sheet, '本地和采购可售天数', '=IF(H2>0,(E2+F2)/H2,0)')
|
|
45
|
+
add_formula_for_column(sheet, '建议采购', '=IF(J2>I2,H2*9,0)')
|
|
46
|
+
colorize_by_field(sheet, 'SKC')
|
|
47
|
+
autofit_column(sheet, ['店铺名称', '商品信息'])
|
|
48
|
+
column_to_left(sheet, ['商品信息'])
|
|
49
|
+
InsertImageV2(sheet, ['SKC图片', 'SKU图片'], 'temu', 120)
|
|
50
|
+
|
|
51
|
+
def write_purchase_advise(self, erp='mb'):
|
|
52
|
+
cache_file = f'{self.config.auto_dir}/temu/cache/warehouse_list_{TimeUtils.today_date()}.json'
|
|
53
|
+
dict = read_dict_from_file(cache_file)
|
|
54
|
+
|
|
55
|
+
store_info = read_dict_from_file(self.config.temu_store_info)
|
|
56
|
+
|
|
57
|
+
header = ['店铺名称', 'SKC图片', 'SKU图片', '商品信息', '现有库存数量', '已采购数量', '近7日销量', '平均日销', '本地和采购可售天数', '生产天数', '建议采购', '产品起定量', '备货周期(天)', 'SKC', '导出时间']
|
|
58
|
+
new_excel_path_list = []
|
|
59
|
+
for mall_id, subOrderList in dict.items():
|
|
60
|
+
excel_data = []
|
|
61
|
+
mall_name = store_info.get(mall_id)[1]
|
|
62
|
+
for product in subOrderList:
|
|
63
|
+
spu = str(product['productId']) # temu平台 spu_id
|
|
64
|
+
skc = str(product['productSkcId']) # temu平台 skc_id
|
|
65
|
+
skcExtCode = product['skcExtCode'] # 商家 SKC货号
|
|
66
|
+
category = product['category'] # 叶子类目
|
|
67
|
+
onSalesDurationOffline = product['onSalesDurationOffline'] # 加入站点时长
|
|
68
|
+
for sku in product['skuQuantityDetailList']:
|
|
69
|
+
priceReviewStatus = sku['priceReviewStatus']
|
|
70
|
+
if priceReviewStatus == 3: # 过滤 开款价格状态 已作废的 2是已生效
|
|
71
|
+
continue
|
|
72
|
+
mall_info = f'{mall_name}\n{mall_id}'
|
|
73
|
+
productSkcPicture = product['productSkcPicture'] # skc图片
|
|
74
|
+
skuExtCode = str(sku['skuExtCode']) # sku货号
|
|
75
|
+
sku_img = self.bridge.get_sku_img(skuExtCode, erp)
|
|
76
|
+
stock = self.bridge.get_sku_stock(skuExtCode, erp)
|
|
77
|
+
|
|
78
|
+
product_info = f"SPU: {spu}\nSKC: {skc}\nSKC货号: {skcExtCode}\nSKU货号: {skuExtCode}\n属性集: {sku['className']}\n类目: {category}\n加入站点时长: {onSalesDurationOffline}天\n"
|
|
79
|
+
|
|
80
|
+
row_item = []
|
|
81
|
+
row_item.append(mall_info)
|
|
82
|
+
row_item.append(productSkcPicture)
|
|
83
|
+
row_item.append(sku_img)
|
|
84
|
+
row_item.append(product_info)
|
|
85
|
+
row_item.append(stock)
|
|
86
|
+
row_item.append(0)
|
|
87
|
+
row_item.append(sku['lastSevenDaysSaleVolume'])
|
|
88
|
+
row_item.append(0)
|
|
89
|
+
row_item.append(0)
|
|
90
|
+
row_item.append(7)
|
|
91
|
+
row_item.append(0)
|
|
92
|
+
row_item.append(0)
|
|
93
|
+
row_item.append(0)
|
|
94
|
+
row_item.append(skc)
|
|
95
|
+
row_item.append(TimeUtils.current_datetime())
|
|
96
|
+
excel_data.append(row_item)
|
|
97
|
+
|
|
98
|
+
new_excel_path = str(self.config.excel_purcase_advice_temu).replace('#store_name#', mall_name).replace(' ', '_')
|
|
99
|
+
new_excel_path_list.append(new_excel_path)
|
|
100
|
+
sheet_name = 'Sheet1'
|
|
101
|
+
data = [header] + excel_data
|
|
102
|
+
close_excel_file(new_excel_path)
|
|
103
|
+
log(new_excel_path)
|
|
104
|
+
batch_excel_operations(new_excel_path, [
|
|
105
|
+
(sheet_name, 'write', sort_by_column(data, 6, 1), ['N']),
|
|
106
|
+
(sheet_name, 'format', self.format_purchase_advise_batch)
|
|
107
|
+
])
|
|
108
|
+
|
|
109
|
+
return new_excel_path_list
|