qrpa 1.0.16__py3-none-any.whl → 1.0.18__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 +2 -0
- qrpa/fun_excel.py +93 -188
- qrpa/shein_excel.py +117 -0
- qrpa/shein_lib.py +305 -24
- qrpa/shein_sqlite.py +154 -0
- {qrpa-1.0.16.dist-info → qrpa-1.0.18.dist-info}/METADATA +1 -1
- {qrpa-1.0.16.dist-info → qrpa-1.0.18.dist-info}/RECORD +9 -8
- {qrpa-1.0.16.dist-info → qrpa-1.0.18.dist-info}/WHEEL +0 -0
- {qrpa-1.0.16.dist-info → qrpa-1.0.18.dist-info}/top_level.txt +0 -0
qrpa/shein_excel.py
CHANGED
|
@@ -159,3 +159,120 @@ class SheinExcel:
|
|
|
159
159
|
InsertImageV2(app, wb, sheet, ['SKC图片', 'SKU图片'])
|
|
160
160
|
wb.save()
|
|
161
161
|
close_excel(app, wb)
|
|
162
|
+
|
|
163
|
+
def write_week_report(self):
|
|
164
|
+
excel_path = create_file_path(self.config.excel_week_sales_report)
|
|
165
|
+
log(excel_path)
|
|
166
|
+
|
|
167
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/week_sales_{TimeUtils.today_date()}.json'
|
|
168
|
+
dict = read_dict_from_file(cache_file)
|
|
169
|
+
|
|
170
|
+
summary_excel_data = []
|
|
171
|
+
header = []
|
|
172
|
+
for store_name, excel_data in dict.items():
|
|
173
|
+
sheet_name = store_name
|
|
174
|
+
write_data(excel_path, sheet_name, excel_data)
|
|
175
|
+
self.format_week_report(excel_path, sheet_name)
|
|
176
|
+
header = excel_data[0]
|
|
177
|
+
summary_excel_data += excel_data[1:]
|
|
178
|
+
summary_excel_data = [header] + summary_excel_data
|
|
179
|
+
sheet_name = 'Sheet1'
|
|
180
|
+
write_data(excel_path, sheet_name, summary_excel_data)
|
|
181
|
+
self.format_week_report(excel_path, sheet_name)
|
|
182
|
+
|
|
183
|
+
def format_week_report(self, excel_path, sheet_name):
|
|
184
|
+
app, wb, sheet = open_excel(excel_path, sheet_name)
|
|
185
|
+
beautify_title(sheet)
|
|
186
|
+
column_to_left(sheet, ['商品信息'])
|
|
187
|
+
format_to_money(sheet, ['申报价', '成本价', '毛利润', '利润'])
|
|
188
|
+
format_to_percent(sheet, ['支付率', '点击率', '毛利率'])
|
|
189
|
+
self.dealFormula(sheet) # 有空再封装优化
|
|
190
|
+
colorize_by_field(app, wb, sheet, 'SPU')
|
|
191
|
+
autofit_column(sheet, ['店铺名称'])
|
|
192
|
+
specify_column_width(sheet, ['商品标题'], 150 / 6)
|
|
193
|
+
add_borders(sheet)
|
|
194
|
+
InsertImageV2(app, wb, sheet, ['SKC图片', 'SKU图片'], 'shein', 90, None, None, True)
|
|
195
|
+
wb.save()
|
|
196
|
+
close_excel(app, wb)
|
|
197
|
+
|
|
198
|
+
# 处理公式计算
|
|
199
|
+
def dealFormula(self, sheet):
|
|
200
|
+
# 增加列 周销增量 月销增量
|
|
201
|
+
col_week_increment = find_column_by_data(sheet, 1, '周销增量')
|
|
202
|
+
if col_week_increment is None:
|
|
203
|
+
col_week_increment = find_column_by_data(sheet, 1, '远30天销量')
|
|
204
|
+
log(f'{col_week_increment}:{col_week_increment}')
|
|
205
|
+
sheet.range(f'{col_week_increment}:{col_week_increment}').insert('right')
|
|
206
|
+
sheet.range(f'{col_week_increment}1').value = '周销增量'
|
|
207
|
+
log('已增加列 周销增量')
|
|
208
|
+
|
|
209
|
+
col_month_increment = find_column_by_data(sheet, 1, '月销增量')
|
|
210
|
+
if col_month_increment is None:
|
|
211
|
+
col_month_increment = find_column_by_data(sheet, 1, '总销量')
|
|
212
|
+
log(f'{col_month_increment}:{col_month_increment}')
|
|
213
|
+
sheet.range(f'{col_month_increment}:{col_month_increment}').insert('right')
|
|
214
|
+
sheet.range(f'{col_month_increment}1').value = '月销增量'
|
|
215
|
+
log('已增加列 月销增量')
|
|
216
|
+
|
|
217
|
+
col_month_profit = find_column_by_data(sheet, 1, '近30天利润')
|
|
218
|
+
if col_month_profit is None:
|
|
219
|
+
col_month_profit = find_column_by_data(sheet, 1, '总利润')
|
|
220
|
+
sheet.range(f'{col_month_profit}:{col_month_profit}').insert('right')
|
|
221
|
+
log((f'{col_month_profit}:{col_month_profit}'))
|
|
222
|
+
sheet.range(f'{col_month_profit}1').value = '近30天利润'
|
|
223
|
+
log('已增加列 近30天利润')
|
|
224
|
+
|
|
225
|
+
col_week_profit = find_column_by_data(sheet, 1, '近7天利润')
|
|
226
|
+
if col_week_profit is None:
|
|
227
|
+
col_week_profit = find_column_by_data(sheet, 1, '近30天利润')
|
|
228
|
+
sheet.range(f'{col_week_profit}:{col_week_profit}').insert('right')
|
|
229
|
+
log((f'{col_week_profit}:{col_week_profit}'))
|
|
230
|
+
sheet.range(f'{col_week_profit}1').value = '近7天利润'
|
|
231
|
+
log('已增加列 近7天利润')
|
|
232
|
+
|
|
233
|
+
# return
|
|
234
|
+
|
|
235
|
+
# 查找 申报价,成本价,毛利润,毛利润率 所在列
|
|
236
|
+
col_verify_price = find_column_by_data(sheet, 1, '申报价')
|
|
237
|
+
col_cost_price = find_column_by_data(sheet, 1, '成本价')
|
|
238
|
+
col_gross_profit = find_column_by_data(sheet, 1, '毛利润')
|
|
239
|
+
col_gross_margin = find_column_by_data(sheet, 1, '毛利率')
|
|
240
|
+
|
|
241
|
+
col_week_1 = find_column_by_data(sheet, 1, '近7天销量')
|
|
242
|
+
col_week_2 = find_column_by_data(sheet, 1, '远7天销量')
|
|
243
|
+
col_month_1 = find_column_by_data(sheet, 1, '近30天销量')
|
|
244
|
+
col_month_2 = find_column_by_data(sheet, 1, '远30天销量')
|
|
245
|
+
|
|
246
|
+
# 遍历可用行
|
|
247
|
+
used_range_row = sheet.range('A1').expand('down')
|
|
248
|
+
for i, cell in enumerate(used_range_row):
|
|
249
|
+
row = i + 1
|
|
250
|
+
if row < 2:
|
|
251
|
+
continue
|
|
252
|
+
rangeA = f'{col_verify_price}{row}'
|
|
253
|
+
rangeB = f'{col_cost_price}{row}'
|
|
254
|
+
|
|
255
|
+
rangeC = f'{col_week_increment}{row}'
|
|
256
|
+
rangeD = f'{col_month_increment}{row}'
|
|
257
|
+
|
|
258
|
+
# rangeE = f'{col_total_profit}{row}'
|
|
259
|
+
rangeF = f'{col_month_profit}{row}'
|
|
260
|
+
rangeG = f'{col_week_profit}{row}'
|
|
261
|
+
|
|
262
|
+
# 设置毛利润和毛利润率列公式与格式
|
|
263
|
+
sheet.range(f'{col_gross_profit}{row}').formula = f'=IF(ISNUMBER({rangeB}),{rangeA}-{rangeB},"")'
|
|
264
|
+
sheet.range(f'{col_gross_profit}{row}').number_format = '0.00'
|
|
265
|
+
sheet.range(f'{col_gross_margin}{row}').formula = f'=IF(ISNUMBER({rangeB}),({rangeA}-{rangeB})/{rangeA},"")'
|
|
266
|
+
sheet.range(f'{col_gross_margin}{row}').number_format = '0.00%'
|
|
267
|
+
|
|
268
|
+
sheet.range(rangeC).formula = f'={col_week_1}{row}-{col_week_2}{row}'
|
|
269
|
+
sheet.range(rangeC).number_format = '0'
|
|
270
|
+
sheet.range(rangeD).formula = f'={col_month_1}{row}-{col_month_2}{row}'
|
|
271
|
+
sheet.range(rangeD).number_format = '0'
|
|
272
|
+
|
|
273
|
+
# sheet.range(rangeE).formula = f'=IF(ISNUMBER({rangeB}),{col_total}{row}*{col_gross_profit}{row},"")'
|
|
274
|
+
# sheet.range(rangeE).number_format = '0.00'
|
|
275
|
+
sheet.range(rangeF).formula = f'=IF(ISNUMBER({rangeB}),{col_month_1}{row}*{col_gross_profit}{row},"")'
|
|
276
|
+
sheet.range(rangeF).number_format = '0.00'
|
|
277
|
+
sheet.range(rangeG).formula = f'=IF(ISNUMBER({rangeB}),{col_week_1}{row}*{col_gross_profit}{row},"")'
|
|
278
|
+
sheet.range(rangeG).number_format = '0.00'
|
qrpa/shein_lib.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
from
|
|
2
|
-
from
|
|
3
|
-
from
|
|
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
|
|
@@ -418,15 +421,15 @@ class SheinLib:
|
|
|
418
421
|
def query_obm_activity_list(self):
|
|
419
422
|
page_num = 1
|
|
420
423
|
page_size = 100
|
|
421
|
-
date_60_days_ago =
|
|
422
|
-
cache_file = f'{self.config.auto_dir}/shein/cache/obm_activity_{self.store_name}_{date_60_days_ago}_{
|
|
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'
|
|
423
426
|
list_item = read_dict_from_file(cache_file, 3600 * 8)
|
|
424
427
|
if len(list_item) > 0:
|
|
425
428
|
return list_item
|
|
426
429
|
|
|
427
430
|
url = f"https://sso.geiwohuo.com/mrs-api-prefix/promotion/obm/query_obm_activity_list"
|
|
428
431
|
payload = {
|
|
429
|
-
"insert_end_time" : f"{
|
|
432
|
+
"insert_end_time" : f"{TimeUtils.today_date()} 23:59:59",
|
|
430
433
|
"insert_start_time": f"{date_60_days_ago} 00:00:00",
|
|
431
434
|
"page_num" : page_num,
|
|
432
435
|
"page_size" : page_size,
|
|
@@ -497,8 +500,8 @@ class SheinLib:
|
|
|
497
500
|
log(f'正在获取 {self.store_name} 活动列表')
|
|
498
501
|
page_num = 1
|
|
499
502
|
page_size = 100
|
|
500
|
-
date_60_days_ago =
|
|
501
|
-
cache_file = f'{self.config.auto_dir}/shein/cache/platform_activity_{self.store_name}_{date_60_days_ago}_{
|
|
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'
|
|
502
505
|
list_item = read_dict_from_file(cache_file, 3600 * 8)
|
|
503
506
|
if len(list_item) > 0:
|
|
504
507
|
return list_item
|
|
@@ -506,7 +509,7 @@ class SheinLib:
|
|
|
506
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}"
|
|
507
510
|
payload = {
|
|
508
511
|
"goods_audit_status" : 1,
|
|
509
|
-
"insert_zone_time_end" : f"{
|
|
512
|
+
"insert_zone_time_end" : f"{TimeUtils.today_date()} 23:59:59",
|
|
510
513
|
"insert_zone_time_start": f"{date_60_days_ago} 00:00:00"
|
|
511
514
|
}
|
|
512
515
|
|
|
@@ -536,8 +539,8 @@ class SheinLib:
|
|
|
536
539
|
activity_id = activity['activity_id']
|
|
537
540
|
activity_name = activity['act_name']
|
|
538
541
|
sub_type_id = activity['sub_type_id'] # 1.不限量 2.限量
|
|
539
|
-
dateBegin =
|
|
540
|
-
dateEnd =
|
|
542
|
+
dateBegin = TimeUtils.convert_datetime_to_date(activity['start_time'])
|
|
543
|
+
dateEnd = TimeUtils.convert_datetime_to_date(activity['end_time'])
|
|
541
544
|
skc_list = self.query_goods_detail(activity_id)
|
|
542
545
|
for skc_item in skc_list:
|
|
543
546
|
attend_num_sum = skc_item['attend_num_sum']
|
|
@@ -556,8 +559,8 @@ class SheinLib:
|
|
|
556
559
|
activity_name = platform_activity['activity_name']
|
|
557
560
|
text_tag_content = platform_activity['text_tag_content']
|
|
558
561
|
attend_num = platform_activity['attend_num']
|
|
559
|
-
dateBegin =
|
|
560
|
-
dateEnd =
|
|
562
|
+
dateBegin = TimeUtils.convert_timestamp_to_date(platform_activity['start_time'])
|
|
563
|
+
dateEnd = TimeUtils.convert_timestamp_to_date(platform_activity['end_time'])
|
|
561
564
|
if text_tag_content != '新品':
|
|
562
565
|
attend_num = '-'
|
|
563
566
|
for sku_item in platform_activity['activity_sku_list']:
|
|
@@ -569,7 +572,7 @@ class SheinLib:
|
|
|
569
572
|
write_dict_to_file(cache_file, dict_activity_price)
|
|
570
573
|
|
|
571
574
|
def get_skc_week_actual_sales(self, skc):
|
|
572
|
-
first_day, last_day =
|
|
575
|
+
first_day, last_day = TimeUtils.get_past_7_days_range()
|
|
573
576
|
cache_file = f'{self.config.auto_dir}/shein/cache/{skc}_{first_day}_{last_day}.json'
|
|
574
577
|
if datetime.now().hour >= 9:
|
|
575
578
|
DictSkuSalesDate = read_dict_from_file(cache_file)
|
|
@@ -687,13 +690,291 @@ class SheinLib:
|
|
|
687
690
|
log(f'dt: {self.dt}')
|
|
688
691
|
return self.dt
|
|
689
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
|
+
|
|
690
971
|
# 获取一个skc一周内的销售趋势(商品明细中的)
|
|
691
972
|
def get_dict_skc_week_trend_v2(self, spu, skc):
|
|
692
973
|
dt = self.get_dt_time()
|
|
693
974
|
|
|
694
|
-
date_7_days_ago =
|
|
975
|
+
date_7_days_ago = TimeUtils.get_past_nth_day(7, None, '%Y%m%d')
|
|
695
976
|
log('-7', date_7_days_ago)
|
|
696
|
-
date_1_days_ago =
|
|
977
|
+
date_1_days_ago = TimeUtils.get_past_nth_day(1, None, '%Y%m%d')
|
|
697
978
|
log('-1', date_1_days_ago)
|
|
698
979
|
|
|
699
980
|
cache_file = f'{self.config.auto_dir}/shein/dict/dict_skc_week_trend_{skc}_{date_7_days_ago}_{date_1_days_ago}.json'
|
|
@@ -735,8 +1016,8 @@ class SheinLib:
|
|
|
735
1016
|
|
|
736
1017
|
def get_skc_week_sale_list(self, spu, skc, sku):
|
|
737
1018
|
dict_skc = self.get_dict_skc_week_trend_v2(spu, skc)
|
|
738
|
-
date_list =
|
|
739
|
-
first_day, last_day =
|
|
1019
|
+
date_list = TimeUtils.get_past_7_days_list()
|
|
1020
|
+
first_day, last_day = TimeUtils.get_past_7_days_range()
|
|
740
1021
|
cache_file = f'{self.config.auto_dir}/shein/cache/{skc}_{first_day}_{last_day}.json'
|
|
741
1022
|
DictSkuSalesDate = read_dict_from_file(cache_file)
|
|
742
1023
|
sales_detail = []
|
|
@@ -747,7 +1028,7 @@ class SheinLib:
|
|
|
747
1028
|
saleCnt = get_safe_value(dict_skc.get(date, {}), 'saleCnt', 0)
|
|
748
1029
|
epsUvIdx = get_safe_value(dict_skc.get(date, {}), 'epsUvIdx', 0)
|
|
749
1030
|
|
|
750
|
-
sales_detail.append(f'{date}({
|
|
1031
|
+
sales_detail.append(f'{date}({TimeUtils.get_weekday_name(date)}): {sales_num}/{saleCnt}/{epsUvIdx}')
|
|
751
1032
|
|
|
752
1033
|
sales_data = []
|
|
753
1034
|
for date in date_list:
|
|
@@ -757,7 +1038,7 @@ class SheinLib:
|
|
|
757
1038
|
payUvIdx = get_safe_value(dict_skc.get(date, {}), 'payUvIdx', 0) # 支付人数
|
|
758
1039
|
gdsPayCtrIdx = get_safe_value(dict_skc.get(date, {}), 'gdsPayCtrIdx', 0) # 转化率
|
|
759
1040
|
|
|
760
|
-
sales_data.append(f'{date}({
|
|
1041
|
+
sales_data.append(f'{date}({TimeUtils.get_weekday_name(date)}): {epsGdsCtrIdx:.2%}({goodsUvIdx})/{gdsPayCtrIdx:.2%}({payUvIdx})')
|
|
761
1042
|
|
|
762
1043
|
return sales_detail, sales_data
|
|
763
1044
|
|
|
@@ -891,7 +1172,7 @@ class SheinLib:
|
|
|
891
1172
|
dict_advice = read_dict_from_file(cache_file)
|
|
892
1173
|
cache_file = f'{self.config.auto_dir}/shein/sku_price/sku_price_{self.store_username}.json'
|
|
893
1174
|
dict_sku_price = read_dict_from_file(cache_file)
|
|
894
|
-
date_list =
|
|
1175
|
+
date_list = TimeUtils.get_past_7_days_list()
|
|
895
1176
|
if mode in [2, 5, 6, 7, 8, 9, 10]:
|
|
896
1177
|
excel_data = [[
|
|
897
1178
|
'店铺名称', 'SKC图片', 'SKU图片', '商品信息', '建议现货数量', '现有库存数量', '已采购数量', '预测日销',
|
|
@@ -1068,7 +1349,7 @@ class SheinLib:
|
|
|
1068
1349
|
sales_num = DictSkuSalesDate.get(date, {}).get(sku, {}).get("hisActualValue", 0)
|
|
1069
1350
|
sales_num = sales_num if sales_num is not None else 0
|
|
1070
1351
|
sales7cn += sales_num
|
|
1071
|
-
if
|
|
1352
|
+
if TimeUtils.is_yesterday_date(date) and sales_num == 0:
|
|
1072
1353
|
flag_yesterday = 1
|
|
1073
1354
|
|
|
1074
1355
|
if mode == 4 and flag_yesterday:
|
|
@@ -1114,10 +1395,10 @@ class SheinLib:
|
|
|
1114
1395
|
row_item.append(sku)
|
|
1115
1396
|
excel_data.append(row_item)
|
|
1116
1397
|
|
|
1117
|
-
cache_file = f'{self.config.auto_dir}/shein/cache/bak_advice_{mode}_{
|
|
1398
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/bak_advice_{mode}_{TimeUtils.today_date()}.json'
|
|
1118
1399
|
write_dict_to_file_ex(cache_file, {self.store_name: excel_data}, {self.store_name})
|
|
1119
1400
|
|
|
1120
|
-
cache_file = f'{self.config.auto_dir}/shein/cache/bak_advice_notify_{mode}_{
|
|
1401
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/bak_advice_notify_{mode}_{TimeUtils.today_date()}.json'
|
|
1121
1402
|
NotifyItem = [self.store_name, len(excel_data[1:])]
|
|
1122
1403
|
write_dict_to_file_ex(cache_file, {self.store_name: NotifyItem}, {self.store_name})
|
|
1123
1404
|
|