qrpa 1.0.15__py3-none-any.whl → 1.0.17__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/shein_lib.py CHANGED
@@ -1,6 +1,9 @@
1
- from qrpa import read_dict_from_file, write_dict_to_file, read_dict_from_file_ex, write_dict_to_file_ex
2
- from qrpa import log, fetch, send_exception, md5_string
3
- from qrpa import time_utils, get_safe_value
1
+ from .fun_file import read_dict_from_file, write_dict_to_file, read_dict_from_file_ex, write_dict_to_file_ex
2
+ from .fun_base import log, send_exception, md5_string, get_safe_value
3
+ from .fun_web import fetch
4
+ from .time_utils import TimeUtils
5
+
6
+ from .shein_sqlite import insert_sales,get_last_week_sales,get_near_week_sales,get_near_month_sales,get_last_month_sales
4
7
 
5
8
  import math
6
9
  import time
@@ -77,6 +80,287 @@ class SheinLib:
77
80
  # web_page.goto('https://sso.geiwohuo.com')
78
81
  log('鉴权处理结束')
79
82
 
83
+ def get_delivery_order_list(self, orderType=2):
84
+ page_num = 1
85
+ page_size = 200
86
+
87
+ url = f"https://sso.geiwohuo.com/pfmp/order/list"
88
+ payload = {}
89
+ if orderType == 1:
90
+ payload = {
91
+ "orderType": orderType,
92
+ "page" : page_num,
93
+ "perPage" : page_size,
94
+ "status" : [2],
95
+ }
96
+ elif orderType == 2:
97
+ payload = {
98
+ "orderType" : orderType,
99
+ "page" : page_num,
100
+ "perPage" : page_size,
101
+ "status" : [2],
102
+ "isJitOrder": 2
103
+ }
104
+ response_text = fetch(self.web_page, url, payload)
105
+ error_code = response_text.get('code')
106
+ if str(error_code) != '0':
107
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
108
+
109
+ spu_list = response_text['info']['data']
110
+ total = response_text['info']['meta']['count']
111
+ totalPage = math.ceil(total / page_size)
112
+
113
+ skc_list = [item['goods']['skcName'] for item in spu_list]
114
+ self.get_activity_label(skc_list)
115
+
116
+ for page in range(2, totalPage + 1):
117
+ log(f'获取订单列表 第{page}/{totalPage}页')
118
+ page_num = page
119
+ if orderType == 1:
120
+ payload = {
121
+ "orderType": orderType,
122
+ "page" : page_num,
123
+ "perPage" : page_size,
124
+ "status" : [2],
125
+ }
126
+ elif orderType == 2:
127
+ payload = {
128
+ "orderType" : orderType,
129
+ "page" : page_num,
130
+ "perPage" : page_size,
131
+ "status" : [2],
132
+ "isJitOrder": 2
133
+ }
134
+ response_text = fetch(self.web_page, url, payload)
135
+ spu_list_new = response_text['info']['data']
136
+ skc_list = [item['goods']['skcName'] for item in spu_list_new]
137
+ self.get_activity_label(skc_list)
138
+ spu_list += spu_list_new
139
+ time.sleep(0.3)
140
+
141
+ if len(spu_list) == 0:
142
+ log(f'无{["", "急采", "备货"][orderType]}发货单')
143
+ return None
144
+
145
+ write_to_excel = [
146
+ # 0 1 2 3 4 5 6 7
147
+ ['店铺名称', 'SKC图片', 'SKU图片', '商品信息', '下单/需求数量', '库存(模式/本地/在途/希音)', '成本价', '核价',
148
+ '近7天SKU销量/SKC销量/SKC曝光', 'SKC点击率/SKC转化率', '自主参与活动', '最晚预约上门取件', '要求实际完成取件',
149
+ 'SKC', 'SKU']
150
+ ]
151
+ cache_file2 = f'{self.config.auto_dir}/shein/dict/skc_shelf_{self.store_username}.json'
152
+ DictSkcShelf = read_dict_from_file(cache_file2)
153
+ cache_file3 = f'{self.config.auto_dir}/shein/dict/skc_product_{self.store_username}.json'
154
+ DictSkcProduct = read_dict_from_file(cache_file3)
155
+ cache_file = f'{self.config.auto_dir}/shein/dict/activity_price_{self.store_name}.json'
156
+ dictActivityPrice = read_dict_from_file(cache_file)
157
+ cache_file4 = f'{self.config.auto_dir}/shein/dict/dict_sku_info_{self.store_username}.json'
158
+ DictSkuInfo = read_dict_from_file(cache_file4)
159
+ for spu_item in spu_list:
160
+ skc = spu_item['goods']['skcName']
161
+ skcCode = spu_item['goods']['supplierCode']
162
+ skc_img = str(spu_item['goods']['imgPath'])
163
+ orderNum = spu_item['sellerOrderNo']
164
+ orderTime = spu_item['allocateTime']
165
+ requestTakeParcelTime = spu_item['requestTakeParcelTime']
166
+ suggestedReserveTime = spu_item['suggestedReserveTime']
167
+ good_level = spu_item['goods']['goodsLevelName']
168
+
169
+ self.get_skc_week_actual_sales(skc)
170
+
171
+ spu = DictSkcProduct[skc]['spu_name']
172
+ log('spu', spu)
173
+ for sku_item in spu_item['detail']:
174
+ needQuantity = sku_item['needQuantity']
175
+ orderQuantity = sku_item['orderQuantity']
176
+ # sku_img = sku_item['skuThumb']
177
+ skuCode = sku_item['supplierSku']
178
+ stock = self.bridge.get_sku_stock(skuCode, 'mb')
179
+ cost_price = self.bridge.get_sku_cost(skuCode, 'mb')
180
+ suffixZh = sku_item['suffixZh']
181
+ sku = sku_item['skuCode']
182
+ supplyPrice = sku_item['supplyPrice']
183
+ sku_img = self.bridge.get_sku_img(skuCode, 'mb')
184
+ sale_model = DictSkuInfo[skuCode][0]
185
+ shein_stock = DictSkuInfo[skuCode][1]
186
+ shelf_days = DictSkuInfo[skuCode][2]
187
+ real_transit = DictSkuInfo[skuCode][3]
188
+ stock_str = f'{sale_model}\n{stock}/{real_transit}/{shein_stock}'
189
+
190
+ item = []
191
+ item.append(f'{self.store_name}\n{good_level}')
192
+ item.append(skc_img)
193
+ item.append(sku_img)
194
+ if cost_price == '-':
195
+ profit = '-'
196
+ else:
197
+ profit = f'{float(supplyPrice) - float(cost_price):.2f}'
198
+ # item.append(f'订单号: {orderNum}\n下单时间: {orderTime}\n最晚预约上门取件: {suggestedReserveTime}\nSKC: {skc}\nSKC货号: {skcCode}\nSKU货号: {skuCode}\n属性集: {suffixZh}\n上架时间: {DictSkcShelf[skc]}\n上架天数: {shelf_days}\n成本/核价/利润: ¥{cost_price}/¥{supplyPrice}/¥{profit}\n下单/需求数量: {orderQuantity}/{needQuantity}\n库存模式/本地/在途/希音: {sale_model}/{stock}/{real_transit}/{shein_stock}\n')
199
+ item.append(f'订单号: {orderNum}\n下单时间: {orderTime}\n最晚预约上门取件: {suggestedReserveTime}\nSKC: {skc}\nSKC货号: {skcCode}\nSKU货号: {skuCode}\n属性集: {suffixZh}\n上架时间: {DictSkcShelf[skc]}\n上架天数: {shelf_days}\n成本/核价/利润: ¥{cost_price}/¥{supplyPrice}/¥{profit}')
200
+ item.append(f'[{orderQuantity}/{needQuantity}]')
201
+ item.append(stock_str)
202
+ item.append(cost_price)
203
+ item.append(supplyPrice)
204
+ sale_num_list, sale_data_list = self.get_skc_week_sale_list(spu, skc, sku)
205
+ item.append("\n".join(sale_num_list))
206
+ item.append("\n".join(sale_data_list))
207
+ item.append(self.get_skc_activity_label(skc, sku, dictActivityPrice))
208
+ item.append(suggestedReserveTime)
209
+ item.append(requestTakeParcelTime)
210
+ item.append(skc)
211
+ item.append(sku)
212
+ write_to_excel.append(item)
213
+
214
+ cache_file = f'{self.config.auto_dir}/shein/cache/jit_{TimeUtils.today_date()}_{orderType}_{TimeUtils.get_period()}.json'
215
+ write_dict_to_file_ex(cache_file, {self.store_username: write_to_excel}, {self.store_username})
216
+
217
+ return write_to_excel
218
+
219
+ # 获取商品包含sku销量的列表
220
+ def get_dict_sku_stock_detail(self):
221
+ log(f'获取备货信息商品列表 做成字典')
222
+ url = "https://sso.geiwohuo.com/idms/goods-skc/list"
223
+ pageNumber = 1
224
+ pageSize = 100
225
+ dictPayload = {
226
+ "pageNumber" : pageNumber,
227
+ "pageSize" : pageSize,
228
+ "supplierCodes" : "",
229
+ "skcs" : "",
230
+ "spu" : "",
231
+ "c7dSaleCntBegin" : "",
232
+ "c7dSaleCntEnd" : "",
233
+ "goodsLevelIdList" : [],
234
+ "supplyStatus" : "",
235
+ "shelfStatus" : "",
236
+ "categoryIdList" : [],
237
+ "skcStockBegin" : "",
238
+ "skcStockEnd" : "",
239
+ "skuStockBegin" : "",
240
+ "skuStockEnd" : "",
241
+ "skcSaleDaysBegin" : "",
242
+ "skcSaleDaysEnd" : "",
243
+ "skuSaleDaysBegin" : "",
244
+ "skuSaleDaysEnd" : "",
245
+ "planUrgentCountBegin" : "",
246
+ "planUrgentCountEnd" : "",
247
+ "skcAvailableOrderBegin": "",
248
+ "skcAvailableOrderEnd" : "",
249
+ "skuAvailableOrderBegin": "",
250
+ "skuAvailableOrderEnd" : "",
251
+ "shelfDateBegin" : "",
252
+ "shelfDateEnd" : "",
253
+ "stockWarnStatusList" : [],
254
+ "labelFakeIdList" : [],
255
+ "sheinSaleByInventory" : "",
256
+ "tspIdList" : [],
257
+ "adviceStatus" : [],
258
+ "sortBy7dSaleCnt" : 2
259
+ }
260
+ payload = dictPayload
261
+ response_text = fetch(self.web_page, url, payload)
262
+ error_code = response_text.get('code')
263
+ if str(error_code) != '0':
264
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
265
+
266
+ spu_list = response_text['info']['list']
267
+
268
+ total = response_text['info']['count']
269
+ totalPage = math.ceil(total / pageSize)
270
+ for page in range(2, totalPage + 1):
271
+ log(f'获取备货信息商品列表 第{page}/{totalPage}页')
272
+ dictPayload['pageNumber'] = page
273
+ payload = dictPayload
274
+ response_text = fetch(self.web_page, url, payload)
275
+ spu_list_new = response_text['info']['list']
276
+ spu_list += spu_list_new
277
+ time.sleep(0.3)
278
+
279
+ DictSkuInfo = {}
280
+ for spu_info in spu_list:
281
+ sale_model = spu_info.get('saleModel', {}).get('name') if spu_info.get('saleModel') else '-'
282
+ shelfDays = spu_info['shelfDays']
283
+ for sku_info in spu_info['skuList']:
284
+ attr = sku_info['attr']
285
+ if attr == '合计':
286
+ continue
287
+ skuExtCode = str(sku_info['supplierSku'])
288
+ shein_stock = sku_info['stock']
289
+
290
+ transit = sku_info['transit'] # 在途
291
+ real_transit = transit + sku_info['stayShelf'] - sku_info['transitSale']
292
+
293
+ DictSkuInfo[skuExtCode] = [sale_model, shein_stock, shelfDays, real_transit]
294
+
295
+ write_dict_to_file(f'{self.config.auto_dir}/shein/dict/dict_sku_info_{self.store_username}.json', DictSkuInfo)
296
+
297
+ return DictSkuInfo
298
+
299
+ def get_shop_notify_num(self):
300
+ log(f'正在获取 {self.store_name} 通知数据')
301
+ url = "https://sso.geiwohuo.com/sso/homePage/v4/detail"
302
+ payload = {
303
+ "metaIndexIds": [
304
+ 246, # 急采-待发货
305
+ 245 # 备货-待发货
306
+ ],
307
+ "templateType": 0
308
+ }
309
+ response_text = fetch(self.web_page, url, payload)
310
+ error_code = response_text.get('code')
311
+ if str(error_code) != '0':
312
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
313
+ info = response_text.get('info')
314
+
315
+ cache_file = f'{self.config.auto_dir}/shein/notify/{self.store_name}_{TimeUtils.get_current_datetime()}.json'
316
+ write_dict_to_file(cache_file, info)
317
+
318
+ num245 = 0
319
+ num246 = 0
320
+ for item in info['list']:
321
+ if item['metaIndexId'] == 245:
322
+ num245 = item['count']
323
+ if item['metaIndexId'] == 246:
324
+ num246 = item['count']
325
+
326
+ NotifyItem = [self.store_name, num246, num245]
327
+
328
+ cache_file = f'{self.config.auto_dir}/shein/cache/jit_notify_{TimeUtils.today_date()}.json'
329
+ write_dict_to_file_ex(cache_file, {self.store_username: NotifyItem}, {self.store_username})
330
+
331
+ return info
332
+
333
+ def get_activity_list(self):
334
+ url = "https://sso.geiwohuo.com/mrs-api-prefix/mbrs/activity/get_activity_list?page_num=1&page_size=100"
335
+ payload = {}
336
+ response_text = fetch(self.web_page, url, payload)
337
+ error_code = response_text.get('code')
338
+ if str(error_code) != '0':
339
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
340
+ total = response_text.get('info', {}).get('total_count')
341
+ excel_data = [[
342
+ '店铺名称', '活动信息', '已报数量', '可报数量'
343
+ ]]
344
+ if total > 0:
345
+ for item in response_text.get('info', {}).get('activity_detail_list'):
346
+ activity_tag = item.get('text_tag_content')
347
+ activity_name = item['activity_name']
348
+ start_time = item['activity_start_zone_time']
349
+ end_time = item['activity_end_zone_time']
350
+ start_time2 = item['start_zone_time']
351
+ end_time2 = item['end_zone_time']
352
+ allow_goods_num = item.get('allow_goods_num')
353
+ apply_goods_num = item.get('apply_goods_num')
354
+ row_item = [
355
+ self.store_name,
356
+ f"活动名称: 【{activity_tag}】{activity_name}\n报名时间: {start_time}~{end_time}\n活动时间: {start_time2}~{end_time2}\n已报数量: {apply_goods_num}/{allow_goods_num}",
357
+ apply_goods_num,
358
+ allow_goods_num,
359
+ ]
360
+ excel_data.append(row_item)
361
+ cache_file = f'{self.config.auto_dir}/shein/activity_list/activity_list_{TimeUtils.today_date()}.json'
362
+ write_dict_to_file_ex(cache_file, {self.store_username: excel_data}, [self.store_username])
363
+
80
364
  def get_product_list(self):
81
365
  self.web_page.goto('https://sso.geiwohuo.com/#/spmp/commdities/list')
82
366
  self.web_page.wait_for_load_state("load")
@@ -137,15 +421,15 @@ class SheinLib:
137
421
  def query_obm_activity_list(self):
138
422
  page_num = 1
139
423
  page_size = 100
140
- date_60_days_ago = time_utils.get_past_nth_day(59)
141
- cache_file = f'{self.config.auto_dir}/shein/cache/obm_activity_{self.store_name}_{date_60_days_ago}_{time_utils.today_date()}.json'
424
+ date_60_days_ago = TimeUtils.get_past_nth_day(59)
425
+ cache_file = f'{self.config.auto_dir}/shein/cache/obm_activity_{self.store_name}_{date_60_days_ago}_{TimeUtils.today_date()}.json'
142
426
  list_item = read_dict_from_file(cache_file, 3600 * 8)
143
427
  if len(list_item) > 0:
144
428
  return list_item
145
429
 
146
430
  url = f"https://sso.geiwohuo.com/mrs-api-prefix/promotion/obm/query_obm_activity_list"
147
431
  payload = {
148
- "insert_end_time" : f"{time_utils.today_date()} 23:59:59",
432
+ "insert_end_time" : f"{TimeUtils.today_date()} 23:59:59",
149
433
  "insert_start_time": f"{date_60_days_ago} 00:00:00",
150
434
  "page_num" : page_num,
151
435
  "page_size" : page_size,
@@ -216,8 +500,8 @@ class SheinLib:
216
500
  log(f'正在获取 {self.store_name} 活动列表')
217
501
  page_num = 1
218
502
  page_size = 100
219
- date_60_days_ago = time_utils.get_past_nth_day(59)
220
- cache_file = f'{self.config.auto_dir}/shein/cache/platform_activity_{self.store_name}_{date_60_days_ago}_{time_utils.today_date()}.json'
503
+ date_60_days_ago = TimeUtils.get_past_nth_day(59)
504
+ cache_file = f'{self.config.auto_dir}/shein/cache/platform_activity_{self.store_name}_{date_60_days_ago}_{TimeUtils.today_date()}.json'
221
505
  list_item = read_dict_from_file(cache_file, 3600 * 8)
222
506
  if len(list_item) > 0:
223
507
  return list_item
@@ -225,7 +509,7 @@ class SheinLib:
225
509
  url = f"https://sso.geiwohuo.com/mrs-api-prefix/mbrs/activity/get_partake_activity_goods_list?page_num={page_num}&page_size={page_size}"
226
510
  payload = {
227
511
  "goods_audit_status" : 1,
228
- "insert_zone_time_end" : f"{time_utils.today_date()} 23:59:59",
512
+ "insert_zone_time_end" : f"{TimeUtils.today_date()} 23:59:59",
229
513
  "insert_zone_time_start": f"{date_60_days_ago} 00:00:00"
230
514
  }
231
515
 
@@ -255,8 +539,8 @@ class SheinLib:
255
539
  activity_id = activity['activity_id']
256
540
  activity_name = activity['act_name']
257
541
  sub_type_id = activity['sub_type_id'] # 1.不限量 2.限量
258
- dateBegin = time_utils.convert_datetime_to_date(activity['start_time'])
259
- dateEnd = time_utils.convert_datetime_to_date(activity['end_time'])
542
+ dateBegin = TimeUtils.convert_datetime_to_date(activity['start_time'])
543
+ dateEnd = TimeUtils.convert_datetime_to_date(activity['end_time'])
260
544
  skc_list = self.query_goods_detail(activity_id)
261
545
  for skc_item in skc_list:
262
546
  attend_num_sum = skc_item['attend_num_sum']
@@ -275,8 +559,8 @@ class SheinLib:
275
559
  activity_name = platform_activity['activity_name']
276
560
  text_tag_content = platform_activity['text_tag_content']
277
561
  attend_num = platform_activity['attend_num']
278
- dateBegin = time_utils.convert_timestamp_to_date(platform_activity['start_time'])
279
- dateEnd = time_utils.convert_timestamp_to_date(platform_activity['end_time'])
562
+ dateBegin = TimeUtils.convert_timestamp_to_date(platform_activity['start_time'])
563
+ dateEnd = TimeUtils.convert_timestamp_to_date(platform_activity['end_time'])
280
564
  if text_tag_content != '新品':
281
565
  attend_num = '-'
282
566
  for sku_item in platform_activity['activity_sku_list']:
@@ -288,7 +572,7 @@ class SheinLib:
288
572
  write_dict_to_file(cache_file, dict_activity_price)
289
573
 
290
574
  def get_skc_week_actual_sales(self, skc):
291
- first_day, last_day = time_utils.TimeUtils.get_past_7_days_range()
575
+ first_day, last_day = TimeUtils.get_past_7_days_range()
292
576
  cache_file = f'{self.config.auto_dir}/shein/cache/{skc}_{first_day}_{last_day}.json'
293
577
  if datetime.now().hour >= 9:
294
578
  DictSkuSalesDate = read_dict_from_file(cache_file)
@@ -406,13 +690,291 @@ class SheinLib:
406
690
  log(f'dt: {self.dt}')
407
691
  return self.dt
408
692
 
693
+ def get_dict_skc_week_trend(self):
694
+ page_num = 1
695
+ page_size = 100
696
+
697
+ date_7_days_ago = TimeUtils.get_past_nth_day(7, None, '%Y%m%d')
698
+ log('-7', date_7_days_ago)
699
+ date_1_days_ago = TimeUtils.get_past_nth_day(1, None, '%Y%m%d')
700
+ log('-1', date_1_days_ago)
701
+
702
+ url = f"https://sso.geiwohuo.com/sbn/new_goods/get_skc_diagnose_list"
703
+ payload = {
704
+ "areaCd" : "cn",
705
+ "countrySite": [
706
+ "shein-all"
707
+ ],
708
+ "startDate" : date_7_days_ago,
709
+ "endDate" : date_1_days_ago,
710
+ "pageNum" : page_num,
711
+ "pageSize" : page_size
712
+ }
713
+ response_text = fetch(self.web_page, url, payload)
714
+ error_code = response_text.get('code')
715
+ if str(error_code) != '0':
716
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
717
+ spu_list = response_text['info']['data']
718
+ total = response_text['info']['meta']['count']
719
+ totalPage = math.ceil(total / page_size)
720
+
721
+ for page in range(2, totalPage + 1):
722
+ log(f'获取商品列表 第{page}/{totalPage}页')
723
+ page_num = page
724
+ payload = {
725
+ "areaCd" : "cn",
726
+ "countrySite": [
727
+ "shein-all"
728
+ ],
729
+ "startDate" : date_7_days_ago,
730
+ "endDate" : date_1_days_ago,
731
+ "pageNum" : page_num,
732
+ "pageSize" : page_size
733
+ }
734
+ response_text = fetch(self.web_page, url, payload)
735
+ spu_list_new = response_text['info']['data']
736
+ spu_list += spu_list_new
737
+ time.sleep(0.3)
738
+
739
+ DictSkcWeekTrend = {}
740
+ for spu_item in spu_list:
741
+ skc = str(spu_item['skc'])
742
+ DictSkcWeekTrend[skc] = spu_item
743
+
744
+ log('len(DictSkcWeekTrend)', len(DictSkcWeekTrend))
745
+ write_dict_to_file(f'{self.config.auto_dir}/shein/dict/dict_skc_week_trend_{self.store_username}.json', DictSkcWeekTrend)
746
+ return DictSkcWeekTrend
747
+
748
+ def get_skc_sales(self, skc, start_date, end_date):
749
+ url = "https://sso.geiwohuo.com/idms/stockadvice/saleTrendDetail"
750
+ payload = {
751
+ "skc" : skc,
752
+ "startDate": start_date,
753
+ "endDate" : end_date
754
+ }
755
+ response_text = fetch(self.web_page, url, payload)
756
+ error_code = response_text.get('code')
757
+ error_msg = response_text.get('msg')
758
+ if str(error_code) != '0':
759
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
760
+
761
+ sales_list = response_text['info']['saleTrendDetailList']
762
+ if sales_list:
763
+ for skc_list in sales_list:
764
+ date = skc_list['date']
765
+ if date == '合计':
766
+ log('无销量skc: ', skc)
767
+ continue
768
+ skc_sale = skc_list['skcSale']
769
+ skc_order = skc_list['skcOrder']
770
+ for sku_list in skc_list['skuSaleTrendDetailList']:
771
+ sku = sku_list['skuCode']
772
+ attr_name = sku_list['attributeName']
773
+ sku_sale = sku_list['skuSale']
774
+ sku_order = sku_list['skuOrder']
775
+ if sku_sale > 0:
776
+ insert_sales(skc, date, skc_sale, skc_order, sku, attr_name, sku_sale, sku_order)
777
+ return sales_list
778
+
779
+ # 获取商品包含sku销量的列表
780
+ def get_product_sku_sales_list(self, source='mb'):
781
+ log(f'获取销量列表')
782
+ url = "https://sso.geiwohuo.com/idms/goods-skc/list"
783
+ pageNumber = 1
784
+ pageSize = 100
785
+ dictPayload = {
786
+ "pageNumber" : pageNumber,
787
+ "pageSize" : pageSize,
788
+ "supplierCodes" : "",
789
+ "skcs" : "",
790
+ "spu" : "",
791
+ "c7dSaleCntBegin" : "",
792
+ "c7dSaleCntEnd" : "",
793
+ "goodsLevelIdList" : [],
794
+ "supplyStatus" : "",
795
+ "shelfStatus" : 1,
796
+ "categoryIdList" : [],
797
+ "skcStockBegin" : "",
798
+ "skcStockEnd" : "",
799
+ "skuStockBegin" : "",
800
+ "skuStockEnd" : "",
801
+ "skcSaleDaysBegin" : "",
802
+ "skcSaleDaysEnd" : "",
803
+ "skuSaleDaysBegin" : "",
804
+ "skuSaleDaysEnd" : "",
805
+ "planUrgentCountBegin" : "",
806
+ "planUrgentCountEnd" : "",
807
+ "skcAvailableOrderBegin": "",
808
+ "skcAvailableOrderEnd" : "",
809
+ "skuAvailableOrderBegin": "",
810
+ "skuAvailableOrderEnd" : "",
811
+ "shelfDateBegin" : "",
812
+ "shelfDateEnd" : "",
813
+ "stockWarnStatusList" : [],
814
+ "labelFakeIdList" : [],
815
+ "sheinSaleByInventory" : "",
816
+ "tspIdList" : [],
817
+ "adviceStatus" : [],
818
+ "sortBy7dSaleCnt" : 2
819
+ }
820
+ payload = dictPayload
821
+ response_text = fetch(self.web_page, url, payload)
822
+ error_code = response_text.get('code')
823
+ if str(error_code) != '0':
824
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
825
+
826
+ spu_list = response_text['info']['list']
827
+
828
+ total = response_text['info']['count']
829
+ totalPage = math.ceil(total / pageSize)
830
+ for page in range(2, totalPage + 1):
831
+ log(f'获取SKU销量列表 第{page}/{totalPage}页')
832
+ dictPayload['pageNumber'] = page
833
+ payload = dictPayload
834
+ response_text = fetch(self.web_page, url, payload)
835
+ spu_list_new = response_text['info']['list']
836
+ spu_list += spu_list_new
837
+ time.sleep(0.3)
838
+
839
+ cache_file = f'{self.config.auto_dir}/shein/sku_price/sku_price_{self.store_username}.json'
840
+ dict_sku_price = read_dict_from_file(cache_file)
841
+
842
+ cache_file2 = f'{self.config.auto_dir}/shein/dict/dict_skc_week_trend_{self.store_username}.json'
843
+ DictSkcWeekTrend = read_dict_from_file(cache_file2)
844
+
845
+ cache_file3 = f'{self.config.auto_dir}/shein/dict/product_list_{self.store_username}.json'
846
+ DictSpuInfo = read_dict_from_file(cache_file3)
847
+
848
+ product_sku_list = [
849
+ [
850
+ '店铺名称', '商品信息', 'SKC图片', 'SKU图片', 'SKU', 'SKU货号', '在售天数', '库存(模式/本地/在途/希音)',
851
+ '今天销量', '今日订单数', # 9
852
+ '远7天销量', '远7天订单数', '近7天销量', '近7天订单数', '周销增量', '远30天销量', '远30天订单数',
853
+ '近30天销量', '近30天订单数', '月销增量', '总销量', # 11
854
+ '申报价', '成本价', '毛利润', '毛利率', '近7天利润', '近30天利润', # 6
855
+ 'SPU', 'SKC', 'SKC货号', '商品标题', '叶子类目', # 5
856
+ 'SKC近7天销量', 'SKC近7天曝光人数', 'SKC近7天商详访客', 'SKC近7天点击率', 'SKC近7天支付人数',
857
+ 'SKC近7天支付率', 'SKC近7天评论数'
858
+ ]
859
+ ]
860
+
861
+ date_60_days_ago = TimeUtils.get_past_nth_day(60, None, '%Y-%m-%d')
862
+ log('-60', date_60_days_ago)
863
+ date_7_days_ago = TimeUtils.get_past_nth_day(7, None, '%Y-%m-%d')
864
+ log('-7', date_7_days_ago)
865
+ date_1_days_ago = TimeUtils.get_past_nth_day(1, None, '%Y-%m-%d')
866
+ log('-1', date_1_days_ago)
867
+
868
+ count = 0
869
+ for spu_info in spu_list:
870
+ count += 1
871
+ # if count > 10:
872
+ # break
873
+ spu = spu_info['spu']
874
+ skc = str(spu_info['skc'])
875
+ # if not shein_db.exists_sales_1_days_ago(skc):
876
+ # log(f'未查到昨天销量: {skc}')
877
+ self.get_skc_sales(skc, date_60_days_ago, date_1_days_ago)
878
+ skcCode = spu_info['supplierCode']
879
+ product_name = DictSpuInfo[spu]['product_name_en']
880
+ category_name = spu_info['categoryName']
881
+ shelfDays = spu_info['shelfDays']
882
+ shelf_status = DictSpuInfo[spu]['shelf_status']
883
+ dictStatus = {
884
+ 'WAIT_SHELF': "待上架",
885
+ 'ON_SHELF' : "已上架",
886
+ 'SOLD_OUT' : "已售罄",
887
+ 'OUT_SHELF' : "已下架"
888
+ }
889
+ status_cn = dictStatus[shelf_status]
890
+ good_level = spu_info['goodsLevel']['name']
891
+ sale_model = spu_info['saleModel']['name']
892
+
893
+ for sku_info in spu_info['skuList']:
894
+ sku = sku_info['skuCode']
895
+ skuExtCode = str(sku_info['supplierSku'])
896
+ if sku == '合计':
897
+ continue
898
+ sku_item = ["" for _ in range(len(product_sku_list[0]))]
899
+ sku_item[0] = f'{self.store_name}\n({status_cn})\n{good_level}\n{date_7_days_ago}\n{date_1_days_ago}' # 店铺名称
900
+ product_info = f"{product_name}\n类目: {category_name}\nSKC: {skc}\nSKC货号: {skcCode}\nSPU: {spu}\n在售天数: {shelfDays}"
901
+ sku_item[1] = product_info # 商品信息
902
+ sku_item[2] = spu_info['picUrl'] # skc图片
903
+
904
+ sku_img = self.bridge.get_sku_img(skuExtCode, source)
905
+
906
+ sku_item[3] = sku_img # sku图片
907
+ sku_item[4] = sku # sku
908
+ sku_item[5] = f"{sku_info['supplierSku']}" # sku货号
909
+ sku_item[6] = shelfDays # 在售天数
910
+
911
+ stock = self.bridge.get_sku_stock(skuExtCode, source)
912
+
913
+ shein_stock = sku_info['stock']
914
+ transit = sku_info['transit'] # 在途
915
+ real_transit = transit + sku_info['stayShelf'] - sku_info['transitSale']
916
+ sku_item[7] = f'{sale_model}\n{stock}/{real_transit}/{shein_stock}' # 本地组合库存
917
+
918
+ sku_item[8] = sku_info['totalSaleVolume'] # 今日销量
919
+ sku_item[9] = sku_info['orderCnt'] # 今日订单数
920
+
921
+ week_sales = get_last_week_sales(sku)
922
+ sku_item[10] = week_sales[0] # 远7日销量
923
+ sku_item[11] = week_sales[1] # 远7日订单数
924
+
925
+ week_sales2 = get_near_week_sales(sku)
926
+ sku_item[12] = week_sales2[0] # 近7日销量
927
+ sku_item[13] = week_sales2[1] # 近7日订单数
928
+ sku_item[14] = week_sales2[1] - week_sales2[0] # 周增销量
929
+
930
+ month_sales = get_last_month_sales(sku)
931
+ sku_item[15] = month_sales[0] # 远30日销量
932
+ sku_item[16] = month_sales[1] # 远30日订单数
933
+
934
+ month_sales2 = get_near_month_sales(sku)
935
+ sku_item[17] = month_sales2[0] # 近30日销量
936
+ sku_item[18] = month_sales2[1] # 近30日订单数
937
+ sku_item[19] = month_sales2[1] - month_sales2[0] # 月增销量
938
+ sku_item[20] = '-' # 总销量
939
+
940
+ sku_item[21] = dict_sku_price[sku] # 申报价
941
+
942
+ cost_price = self.bridge.get_sku_cost(skuExtCode, source)
943
+
944
+ sku_item[22] = cost_price # 成本价
945
+ sku_item[23] = '' # 毛利润
946
+ sku_item[24] = '' # 毛利率
947
+ sku_item[25] = '' # 近7天利润
948
+ sku_item[26] = '' # 近30天利润
949
+ sku_item[27] = spu # spu
950
+ sku_item[28] = skc # skc
951
+ sku_item[29] = spu_info['supplierCode'] # skc货号
952
+ sku_item[30] = product_name # 商品标题
953
+ sku_item[31] = category_name # 叶子类目
954
+
955
+ key = str(skc)
956
+ sku_item[32] = DictSkcWeekTrend.get(key, {'saleCnt': 0})['saleCnt'] # 'SKC近7天销量',
957
+ sku_item[33] = DictSkcWeekTrend.get(key, {'epsUvIdx': 0})['epsUvIdx'] # 'SKC近7天曝光人数',
958
+ sku_item[34] = DictSkcWeekTrend.get(key, {'goodsUvIdx': 0})['goodsUvIdx'] # 'SKC近7天商详访客',
959
+ sku_item[35] = DictSkcWeekTrend.get(key, {'epsGdsCtrIdx': 0})['epsGdsCtrIdx'] # 'SKC近7天点击率',
960
+ sku_item[36] = DictSkcWeekTrend.get(key, {'payUvIdx': 0})['payUvIdx'] # 'SKC近7天支付人数',
961
+ sku_item[37] = DictSkcWeekTrend.get(key, {'gdsPayCtrIdx': 0})['gdsPayCtrIdx'] # 'SKC近7天支付率',
962
+ sku_item[38] = DictSkcWeekTrend.get(key, {'totalCommentCnt': 0})['totalCommentCnt'] # '评论数'
963
+
964
+ product_sku_list.append(sku_item)
965
+
966
+ cache_file = f'{self.config.auto_dir}/shein/cache/week_sales_{TimeUtils.today_date()}.json'
967
+ write_dict_to_file_ex(cache_file, {self.store_name: product_sku_list}, [self.store_name])
968
+
969
+ return product_sku_list
970
+
409
971
  # 获取一个skc一周内的销售趋势(商品明细中的)
410
972
  def get_dict_skc_week_trend_v2(self, spu, skc):
411
973
  dt = self.get_dt_time()
412
974
 
413
- date_7_days_ago = time_utils.TimeUtils.get_past_nth_day(7, None, '%Y%m%d')
975
+ date_7_days_ago = TimeUtils.get_past_nth_day(7, None, '%Y%m%d')
414
976
  log('-7', date_7_days_ago)
415
- date_1_days_ago = time_utils.TimeUtils.get_past_nth_day(1, None, '%Y%m%d')
977
+ date_1_days_ago = TimeUtils.get_past_nth_day(1, None, '%Y%m%d')
416
978
  log('-1', date_1_days_ago)
417
979
 
418
980
  cache_file = f'{self.config.auto_dir}/shein/dict/dict_skc_week_trend_{skc}_{date_7_days_ago}_{date_1_days_ago}.json'
@@ -454,8 +1016,8 @@ class SheinLib:
454
1016
 
455
1017
  def get_skc_week_sale_list(self, spu, skc, sku):
456
1018
  dict_skc = self.get_dict_skc_week_trend_v2(spu, skc)
457
- date_list = time_utils.get_past_7_days_list()
458
- first_day, last_day = time_utils.TimeUtils.get_past_7_days_range()
1019
+ date_list = TimeUtils.get_past_7_days_list()
1020
+ first_day, last_day = TimeUtils.get_past_7_days_range()
459
1021
  cache_file = f'{self.config.auto_dir}/shein/cache/{skc}_{first_day}_{last_day}.json'
460
1022
  DictSkuSalesDate = read_dict_from_file(cache_file)
461
1023
  sales_detail = []
@@ -466,7 +1028,7 @@ class SheinLib:
466
1028
  saleCnt = get_safe_value(dict_skc.get(date, {}), 'saleCnt', 0)
467
1029
  epsUvIdx = get_safe_value(dict_skc.get(date, {}), 'epsUvIdx', 0)
468
1030
 
469
- sales_detail.append(f'{date}({time_utils.get_weekday_name(date)}): {sales_num}/{saleCnt}/{epsUvIdx}')
1031
+ sales_detail.append(f'{date}({TimeUtils.get_weekday_name(date)}): {sales_num}/{saleCnt}/{epsUvIdx}')
470
1032
 
471
1033
  sales_data = []
472
1034
  for date in date_list:
@@ -476,7 +1038,7 @@ class SheinLib:
476
1038
  payUvIdx = get_safe_value(dict_skc.get(date, {}), 'payUvIdx', 0) # 支付人数
477
1039
  gdsPayCtrIdx = get_safe_value(dict_skc.get(date, {}), 'gdsPayCtrIdx', 0) # 转化率
478
1040
 
479
- sales_data.append(f'{date}({time_utils.get_weekday_name(date)}): {epsGdsCtrIdx:.2%}({goodsUvIdx})/{gdsPayCtrIdx:.2%}({payUvIdx})')
1041
+ sales_data.append(f'{date}({TimeUtils.get_weekday_name(date)}): {epsGdsCtrIdx:.2%}({goodsUvIdx})/{gdsPayCtrIdx:.2%}({payUvIdx})')
480
1042
 
481
1043
  return sales_detail, sales_data
482
1044
 
@@ -521,7 +1083,6 @@ class SheinLib:
521
1083
  # 10.运营-热销款 (有现货建议 30天外 有销量)
522
1084
  def get_bak_advice(self, mode=1, skcs=None, source='mb'):
523
1085
  log(f'获取备货信息商品列表 做成字典')
524
- global DictSkuInfo
525
1086
  if skcs == None or len(skcs) == 0:
526
1087
  # if mode == 3:
527
1088
  # skcs = "sh2405133614611175" # 这是一个不存在的skc
@@ -611,7 +1172,7 @@ class SheinLib:
611
1172
  dict_advice = read_dict_from_file(cache_file)
612
1173
  cache_file = f'{self.config.auto_dir}/shein/sku_price/sku_price_{self.store_username}.json'
613
1174
  dict_sku_price = read_dict_from_file(cache_file)
614
- date_list = time_utils.get_past_7_days_list()
1175
+ date_list = TimeUtils.get_past_7_days_list()
615
1176
  if mode in [2, 5, 6, 7, 8, 9, 10]:
616
1177
  excel_data = [[
617
1178
  '店铺名称', 'SKC图片', 'SKU图片', '商品信息', '建议现货数量', '现有库存数量', '已采购数量', '预测日销',
@@ -788,7 +1349,7 @@ class SheinLib:
788
1349
  sales_num = DictSkuSalesDate.get(date, {}).get(sku, {}).get("hisActualValue", 0)
789
1350
  sales_num = sales_num if sales_num is not None else 0
790
1351
  sales7cn += sales_num
791
- if time_utils.is_yesterday_date(date) and sales_num == 0:
1352
+ if TimeUtils.is_yesterday_date(date) and sales_num == 0:
792
1353
  flag_yesterday = 1
793
1354
 
794
1355
  if mode == 4 and flag_yesterday:
@@ -834,10 +1395,10 @@ class SheinLib:
834
1395
  row_item.append(sku)
835
1396
  excel_data.append(row_item)
836
1397
 
837
- cache_file = f'{self.config.auto_dir}/shein/cache/bak_advice_{mode}_{time_utils.today_date()}.json'
1398
+ cache_file = f'{self.config.auto_dir}/shein/cache/bak_advice_{mode}_{TimeUtils.today_date()}.json'
838
1399
  write_dict_to_file_ex(cache_file, {self.store_name: excel_data}, {self.store_name})
839
1400
 
840
- cache_file = f'{self.config.auto_dir}/shein/cache/bak_advice_notify_{mode}_{time_utils.today_date()}.json'
1401
+ cache_file = f'{self.config.auto_dir}/shein/cache/bak_advice_notify_{mode}_{TimeUtils.today_date()}.json'
841
1402
  NotifyItem = [self.store_name, len(excel_data[1:])]
842
1403
  write_dict_to_file_ex(cache_file, {self.store_name: NotifyItem}, {self.store_name})
843
1404