qrpa 1.0.57__tar.gz → 1.0.59__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.

Files changed (36) hide show
  1. {qrpa-1.0.57 → qrpa-1.0.59}/PKG-INFO +1 -1
  2. {qrpa-1.0.57 → qrpa-1.0.59}/pyproject.toml +1 -1
  3. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/fun_excel.py +43 -0
  4. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/shein_excel.py +171 -1
  5. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/shein_lib.py +208 -10
  6. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa.egg-info/PKG-INFO +1 -1
  7. {qrpa-1.0.57 → qrpa-1.0.59}/README.md +0 -0
  8. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/RateLimitedSender.py +0 -0
  9. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/__init__.py +0 -0
  10. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/db_migrator.py +0 -0
  11. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/feishu_bot_app.py +0 -0
  12. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/feishu_client.py +0 -0
  13. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/feishu_logic.py +0 -0
  14. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/fun_base.py +0 -0
  15. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/fun_file.py +0 -0
  16. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/fun_web.py +0 -0
  17. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/fun_win.py +0 -0
  18. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/mysql_module/__init__.py +0 -0
  19. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/mysql_module/shein_return_order_model.py +0 -0
  20. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/shein_daily_report_model.py +0 -0
  21. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/shein_mysql.py +0 -0
  22. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/shein_sqlite.py +0 -0
  23. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/shein_ziniao.py +0 -0
  24. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/temu_chrome.py +0 -0
  25. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/temu_excel.py +0 -0
  26. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/temu_lib.py +0 -0
  27. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/time_utils.py +0 -0
  28. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/time_utils_example.py +0 -0
  29. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa/wxwork.py +0 -0
  30. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa.egg-info/SOURCES.txt +0 -0
  31. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa.egg-info/dependency_links.txt +0 -0
  32. {qrpa-1.0.57 → qrpa-1.0.59}/qrpa.egg-info/top_level.txt +0 -0
  33. {qrpa-1.0.57 → qrpa-1.0.59}/setup.cfg +0 -0
  34. {qrpa-1.0.57 → qrpa-1.0.59}/setup.py +0 -0
  35. {qrpa-1.0.57 → qrpa-1.0.59}/tests/test_db_migrator.py +0 -0
  36. {qrpa-1.0.57 → qrpa-1.0.59}/tests/test_wxwork.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrpa
3
- Version: 1.0.57
3
+ Version: 1.0.59
4
4
  Summary: qsir's rpa library
5
5
  Author: QSir
6
6
  Author-email: QSir <1171725650@qq.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qrpa"
7
- version = "1.0.57"
7
+ version = "1.0.59"
8
8
  description = "qsir's rpa library"
9
9
  authors = [{ name = "QSir", email = "1171725650@qq.com" }]
10
10
  readme = "README.md"
@@ -73,6 +73,49 @@ excel_color_index = {
73
73
  "深蓝灰色" : 55, # #333399
74
74
  }
75
75
 
76
+ def aggregate_by_column(data, group_by_col_name):
77
+ """
78
+ 根据指定列名对二维表数据聚合:
79
+ - 数字列求和
80
+ - 字符串列用换行符拼接
81
+
82
+ :param data: 二维列表,第一行为表头
83
+ :param group_by_col_name: 要聚合的列名,如 "店长"
84
+ :return: 聚合后的二维列表
85
+ """
86
+ headers = data[0]
87
+ group_index = headers.index(group_by_col_name)
88
+ grouped = defaultdict(list)
89
+
90
+ # 按 group_by 列聚合行
91
+ for row in data[1:]:
92
+ key = row[group_index]
93
+ grouped[key].append(row)
94
+
95
+ result = [headers]
96
+
97
+ for key, rows in grouped.items():
98
+ agg_row = []
99
+ for col_idx in range(len(headers)):
100
+ col_values = [r[col_idx] for r in rows]
101
+ # 聚合字段
102
+ if col_idx == group_index:
103
+ agg_value = key
104
+ else:
105
+ # 尝试将值转为 float,如果成功就求和,否则拼接
106
+ try:
107
+ nums = [float(v) for v in col_values if
108
+ isinstance(v, (int, float)) or (isinstance(v, str) and v.strip() != '')]
109
+ agg_value = sum(nums)
110
+ except ValueError:
111
+ # 拼接字符串(去重可加 set)
112
+ strings = [str(v).strip() for v in col_values if str(v).strip()]
113
+ agg_value = '\n'.join(strings)
114
+ agg_row.append(agg_value)
115
+ result.append(agg_row)
116
+
117
+ return result
118
+
76
119
  def set_cell_prefix_red(cell, n, color_name):
77
120
  """
78
121
  将指定 Excel 单元格内容的前 n 个字符设置为红色。
@@ -15,6 +15,176 @@ class SheinExcel:
15
15
  self.bridge = bridge
16
16
  pass
17
17
 
18
+ def write_week_ntb(self):
19
+ excel_path = create_file_path(self.config.excel_week_report)
20
+
21
+ cache_file = f'{self.config.auto_dir}/shein/dict/new_product_to_bak_{TimeUtils.today_date()}.json'
22
+ dict = read_dict_from_file(cache_file)
23
+ # dict_store = read_dict_from_file(config.dict_store_cache)
24
+
25
+ summary_excel_data = []
26
+ header = []
27
+ dict_store_bak_stat = {}
28
+ for store_username, excel_data in dict.items():
29
+ # store_name = dict_store.get(store_username)
30
+ if dict_store_bak_stat.get(store_username) is None:
31
+ dict_store_bak_stat[store_username] = [0, 0]
32
+ for item in excel_data[1:]:
33
+ dict_store_bak_stat[store_username][0] += 1
34
+ if int(item[6]) == 1:
35
+ dict_store_bak_stat[store_username][1] += 1
36
+ header = excel_data[0]
37
+ summary_excel_data += excel_data[1:]
38
+ summary_excel_data = [header] + summary_excel_data
39
+ log(summary_excel_data)
40
+ sheet_name = '新品转备货款明细'
41
+
42
+ # write_data(excel_path, sheet_name, summary_excel_data)
43
+ # self.format_week_ntb(excel_path, sheet_name)
44
+
45
+ batch_excel_operations(excel_path, [
46
+ (sheet_name, 'write', summary_excel_data),
47
+ (sheet_name, 'format', self.format_week_ntb),
48
+ ])
49
+
50
+ dict_key = f'{self.config.auto_dir}/shein/dict/dict_store_bak_stat_{TimeUtils.today_date()}.json'
51
+ write_dict_to_file(dict_key, dict_store_bak_stat)
52
+
53
+ def format_week_ntb(self, sheet):
54
+ beautify_title(sheet)
55
+ format_to_date(sheet, ['统计日期'])
56
+ format_to_percent(sheet, ['占比'])
57
+ colorize_by_field(sheet, 'SPU')
58
+ column_to_left(sheet, ['商品信息', '第4周SKC点击率/SKC转化率', '第4周SKC销量/SKC曝光'])
59
+ autofit_column(sheet, ['店铺名称', '商品信息', '第4周SKC点击率/SKC转化率', '第4周SKC销量/SKC曝光'])
60
+ add_borders(sheet)
61
+ InsertImageV2(sheet, ['SKC图片'], 'shein', 120)
62
+
63
+ def dealFundsExcelFormat(self, sheet):
64
+ col_a = find_column_by_data(sheet, 1, '店铺名称')
65
+ col_b = find_column_by_data(sheet, 1, '在途商品金额')
66
+ col_c = find_column_by_data(sheet, 1, '在仓商品金额')
67
+ col_d = find_column_by_data(sheet, 1, '待结算金额')
68
+ col_e = find_column_by_data(sheet, 1, '可提现金额')
69
+ col_f = find_column_by_data(sheet, 1, '汇总')
70
+ col_g = find_column_by_data(sheet, 1, '导出时间')
71
+ col_h = find_column_by_data(sheet, 1, '销售出库金额')
72
+
73
+ sheet.range(f'{col_a}:{col_a}').column_width = 25
74
+ sheet.range(f'{col_g}:{col_g}').number_format = 'yyyy-mm-dd hh:mm:ss'
75
+
76
+ last_row = sheet.range('A' + str(sheet.cells.last_cell.row)).end('up').row
77
+ sheet.range(f'{col_b}2').formula = f'=SUM({col_b}3:{col_b}{last_row})'
78
+ sheet.range(f'{col_b}2').number_format = '¥#,##0.00'
79
+ cell = sheet.range(f'{col_b}2')
80
+ cell.api.Font.Color = 255 # RGB(255, 0, 0),红色对应的颜色代码
81
+ cell.api.Font.Bold = True
82
+
83
+ sheet.range(f'{col_c}2').formula = f'=SUM({col_c}3:{col_c}{last_row})'
84
+ sheet.range(f'{col_c}2').number_format = '¥#,##0.00'
85
+ cell = sheet.range(f'{col_c}2')
86
+ cell.api.Font.Color = 255 # RGB(255, 0, 0),红色对应的颜色代码
87
+ cell.api.Font.Bold = True
88
+
89
+ sheet.range(f'{col_d}2').formula = f'=SUM({col_d}3:{col_d}{last_row})'
90
+ sheet.range(f'{col_d}2').number_format = '¥#,##0.00'
91
+ cell = sheet.range(f'{col_d}2')
92
+ cell.api.Font.Color = 255 # RGB(255, 0, 0),红色对应的颜色代码
93
+ cell.api.Font.Bold = True
94
+
95
+ sheet.range(f'{col_e}2').formula = f'=SUM({col_e}3:{col_e}{last_row})'
96
+ sheet.range(f'{col_e}2').number_format = '¥#,##0.00'
97
+ cell = sheet.range(f'{col_e}2')
98
+ cell.api.Font.Color = 255 # RGB(255, 0, 0),红色对应的颜色代码
99
+ cell.api.Font.Bold = True
100
+
101
+ sheet.range(f'{col_h}2').formula = f'=SUM({col_h}3:{col_h}{last_row})'
102
+ sheet.range(f'{col_h}2').number_format = '¥#,##0.00'
103
+ cell = sheet.range(f'{col_h}2')
104
+ cell.api.Font.Color = 255 # RGB(255, 0, 0),红色对应的颜色代码
105
+ cell.api.Font.Bold = True
106
+
107
+ # 遍历可用行
108
+ used_range_row = sheet.range('A1').expand('down')
109
+ for i, cell in enumerate(used_range_row):
110
+ row = i + 1
111
+ if row < 2:
112
+ continue
113
+ # 设置数字格式
114
+ sheet.range(f'{col_b}{row}').number_format = '¥#,##0.00'
115
+ sheet.range(f'{col_c}{row}').number_format = '¥#,##0.00'
116
+ sheet.range(f'{col_d}{row}').number_format = '¥#,##0.00'
117
+ sheet.range(f'{col_e}{row}').number_format = '¥#,##0.00'
118
+ sheet.range(f'{col_f}{row}').formula = f'=SUM({col_b}{row}:{col_e}{row})'
119
+ sheet.range(f'{col_f}{row}').number_format = '¥#,##0.00'
120
+ sheet.range(f'{col_f}{row}').api.Font.Color = 255
121
+ sheet.range(f'{col_f}{row}').api.Font.Bold = True
122
+
123
+ add_borders(sheet)
124
+
125
+ def write_week_finance_report(self):
126
+ cache_file = f'{self.config.auto_dir}/shein/cache/stat_fund_lz_{TimeUtils.today_date()}.json'
127
+ dict = read_dict_from_file(cache_file)
128
+ dict_key = f'{self.config.auto_dir}/shein/dict/dict_store_bak_stat_{TimeUtils.today_date()}.json'
129
+ dict_store_bak_stat = read_dict_from_file(dict_key)
130
+ data = []
131
+ for key, val in dict.items():
132
+ data.append(val)
133
+ log(data)
134
+ for item in data:
135
+ store_username = item[1]
136
+ item[9] = dict_store_bak_stat[store_username][0]
137
+ item[10] = dict_store_bak_stat[store_username][1]
138
+
139
+ data.sort(key=lambda row: row[8], reverse=True)
140
+ excel_path = create_file_path(self.config.excel_week_report)
141
+ sheet_name = '按店铺汇总'
142
+ data.insert(0, ['汇总', '', '', '', '', '', '', '', '', '', '', '', ''])
143
+ data.insert(0, ['店铺名称', '店铺账号', '店长', '在途商品金额', '在仓商品金额', '待结算金额', '可提现金额', '汇总',
144
+ '销售出库金额', '新品上架数量', '成功转备货款', '成功率', '导出时间'])
145
+ write_data(excel_path, sheet_name, data)
146
+ app, wb, sheet = open_excel(excel_path, sheet_name)
147
+ beautify_title(sheet)
148
+
149
+ self.dealFundsExcelFormat(sheet)
150
+ format_to_percent(sheet, ['成功率'], 0)
151
+ add_formula_for_column(sheet, '成功率', '=IF(J2=0, 0, k2/J2)', 2)
152
+ add_formula_for_column(sheet, '新品上架数量', "=COUNTIF('新品转备货款明细'!A:A, B3)", 3)
153
+ add_formula_for_column(sheet, '成功转备货款', "=COUNTIFS('新品转备货款明细'!A:A, B3, '新品转备货款明细'!G:G, 1)", 3)
154
+ add_sum_for_cell(sheet, ['新品上架数量', '成功转备货款'])
155
+ column_to_right(sheet, ['金额', '汇总'])
156
+ sheet.autofit()
157
+ delete_sheet_if_exists(wb, 'Sheet1')
158
+ wb.save()
159
+ close_excel(app, wb)
160
+
161
+ new_data = data
162
+ new_data = aggregate_by_column(new_data, '店长')
163
+ new_data_sorted = new_data[2:]
164
+ new_data_sorted.sort(key=lambda row: row[8], reverse=True)
165
+
166
+ sheet_name = '按店长汇总'
167
+ write_data(excel_path, sheet_name, data[:2] + new_data_sorted)
168
+ app, wb, sheet = open_excel(excel_path, sheet_name)
169
+ add_borders(sheet)
170
+ format_to_money(sheet, ['金额', '成本'])
171
+ format_to_datetime(sheet, ['时间'])
172
+ format_to_percent(sheet, ['成功率'], 0)
173
+ add_formula_for_column(sheet, '成功率', '=IF(J2=0, 0, k2/J2)', 2)
174
+ # 聚合的不能使用这种公式
175
+ # add_formula_for_column(sheet, '新品上架数量',"=COUNTIF('新品转备货款明细'!A:A, B3)",3)
176
+ # add_formula_for_column(sheet, '成功转备货款',"=COUNTIFS('新品转备货款明细'!A:A, B3, '新品转备货款明细'!G:G, 1)",3)
177
+ add_sum_for_cell(sheet, ['在途商品金额', '在仓商品金额', '待结算金额', '可提现金额', '汇总', '销售出库金额',
178
+ '新品上架数量', '成功转备货款'])
179
+ clear_for_cell(sheet, ['店铺账号', '导出时间'])
180
+ add_formula_for_column(sheet, '汇总', f'=SUM(D3:G3)', 3)
181
+ set_title_style(sheet)
182
+ column_to_right(sheet, ['金额', '汇总'])
183
+ autofit_column(sheet, ['店铺名称', '店铺账号', '导出时间'])
184
+ wb.save()
185
+ close_excel(app, wb)
186
+ WxWorkBot('b30aaa8d-1a1f-4378-841a-8b0f8295f2d9').send_file(excel_path)
187
+
18
188
  # 退货列表
19
189
  def write_return_list(self, erp, start_date, end_date):
20
190
  header = ['退货单号', '退货出库时间', '签收状态', '店铺信息', '店长', '退货类型', '退货原因', 'SKC图片', 'SKC信息', '商家SKU', '属性集', 'SKU退货数量', '平台SKU', 'ERP默认供货商', 'ERP成本', '包裹名', '包裹号', '退货计划单号', '订单号', '发货单', '退回方式', '快递名称', '运单号', '退货地址', '商家联系人', '商家手机号', '入库问题图片地址']
@@ -217,7 +387,7 @@ class SheinExcel:
217
387
  format_to_money(sheet, ['单价', '金额', '成本'])
218
388
  column_to_right(sheet, ['单价', '金额', '成本'])
219
389
  wrap_column(sheet, ['退货原因', '退货地址', '入库问题图片地址'])
220
- autofit_column(sheet, ['店铺信息','店铺别名', 'SKC信息'])
390
+ autofit_column(sheet, ['店铺信息', '店铺别名', 'SKC信息'])
221
391
  column_to_left(sheet, ['店铺信息', '商家SKU', '供方货号', '属性集', 'SKC信息', '退货地址'])
222
392
  specify_column_width(sheet, ['退货原因', 'SKC信息', '商家SKU', '退货地址'], 200 / 6)
223
393
  InsertImageV2(sheet, ['SKC图片'])
@@ -617,6 +617,201 @@ class SheinLib:
617
617
  log(f'正在获取 {self.store_name} 最近一个月出库金额: {last_item["totalCustomerAmount"]}')
618
618
  return last_item['totalCustomerAmount']
619
619
 
620
+ # 获取备货信息列表
621
+ def get_bak_base_info(self):
622
+ log(f'获取备货信息列表 {self.store_name} {self.store_username}')
623
+ url = "https://sso.geiwohuo.com/idms/goods-skc/list"
624
+ pageNumber = 1
625
+ pageSize = 100
626
+ payload = {
627
+ "pageNumber" : pageNumber,
628
+ "pageSize" : pageSize,
629
+ "supplierCodes" : "",
630
+ "skcs" : "",
631
+ "spu" : "",
632
+ "c7dSaleCntBegin" : "",
633
+ "c7dSaleCntEnd" : "",
634
+ "goodsLevelIdList" : [],
635
+ "supplyStatus" : "",
636
+ "shelfStatus" : "",
637
+ "categoryIdList" : [],
638
+ "skcStockBegin" : "",
639
+ "skcStockEnd" : "",
640
+ "skuStockBegin" : "",
641
+ "skuStockEnd" : "",
642
+ "skcSaleDaysBegin" : "",
643
+ "skcSaleDaysEnd" : "",
644
+ "skuSaleDaysBegin" : "",
645
+ "skuSaleDaysEnd" : "",
646
+ "planUrgentCountBegin" : "",
647
+ "planUrgentCountEnd" : "",
648
+ "skcAvailableOrderBegin": "",
649
+ "skcAvailableOrderEnd" : "",
650
+ "skuAvailableOrderBegin": "",
651
+ "skuAvailableOrderEnd" : "",
652
+ "shelfDateBegin" : "",
653
+ "shelfDateEnd" : "",
654
+ "stockWarnStatusList" : [],
655
+ "labelFakeIdList" : [],
656
+ "sheinSaleByInventory" : "",
657
+ "tspIdList" : [],
658
+ "adviceStatus" : [],
659
+ "sortBy7dSaleCnt" : 2
660
+ }
661
+ response_text = fetch(self.web_page, url, payload)
662
+ error_code = response_text.get('code')
663
+ if str(error_code) != '0':
664
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
665
+
666
+ spu_list = response_text['info']['list']
667
+
668
+ skc_list = [item['skc'] for item in spu_list]
669
+ self.get_sku_price_v2(skc_list)
670
+
671
+ total = response_text['info']['count']
672
+ totalPage = math.ceil(total / pageSize)
673
+ for page in range(2, totalPage + 1):
674
+ log(f'获取备货信息商品列表 第{page}/{totalPage}页')
675
+ payload['pageNumber'] = page
676
+ response_text = fetch(self.web_page, url, payload)
677
+
678
+ new_spu_list = response_text['info']['list']
679
+ spu_list += new_spu_list
680
+
681
+ skc_list = [item['skc'] for item in new_spu_list]
682
+ self.get_sku_price_v2(skc_list)
683
+
684
+ time.sleep(0.3)
685
+
686
+ key = f'{self.store_username}'
687
+ cache_file = f'{self.config.auto_dir}/shein/cache/bak_info_list_{key}.json'
688
+ write_dict_to_file_ex(cache_file, {key: spu_list}, [key])
689
+
690
+ return spu_list
691
+
692
+ def get_skc_week_sale_list(self, spu, skc, start_from=None):
693
+ dict_skc = self.get_dict_skc_week_trend_v2(spu, skc, start_from)
694
+ date_list = TimeUtils.get_past_7_days_list(start_from)
695
+ saleCnt7d = 0
696
+ sales_detail = []
697
+ for date in date_list:
698
+ saleCnt = get_safe_value(dict_skc.get(date, {}), 'saleCnt', 0)
699
+ epsUvIdx = get_safe_value(dict_skc.get(date, {}), 'epsUvIdx', 0)
700
+
701
+ saleCnt7d += saleCnt
702
+ sales_detail.append(f'{date}({TimeUtils.get_weekday_name(date)}): {saleCnt}/{epsUvIdx}')
703
+
704
+ sales_data = []
705
+ for date in date_list:
706
+ goodsUvIdx = get_safe_value(dict_skc.get(date, {}), 'goodsUvIdx', 0) # 商详访客
707
+ epsGdsCtrIdx = get_safe_value(dict_skc.get(date, {}), 'epsGdsCtrIdx', 0) # 点击率
708
+
709
+ payUvIdx = get_safe_value(dict_skc.get(date, {}), 'payUvIdx', 0) # 支付人数
710
+ gdsPayCtrIdx = get_safe_value(dict_skc.get(date, {}), 'gdsPayCtrIdx', 0) # 转化率
711
+
712
+ sales_data.append(f'{date}({TimeUtils.get_weekday_name(date)}): {epsGdsCtrIdx:.2%}({goodsUvIdx})/{gdsPayCtrIdx:.2%}({payUvIdx})')
713
+
714
+ return sales_detail, sales_data, saleCnt7d
715
+
716
+ def stat_new_product_to_bak(self):
717
+ # 直接调用 get_skc_week_actual_sales 來获取周销 计算是否能转成备货款
718
+ skc_list = self.get_bak_base_info() # 这个地方 不要加已上架和正常供货参数 直接取所有的skc列表
719
+ # 以算昨日7.2日为例 上架天数为29天(转换成上架日期),且过去7天销量达到类目备货标准和没有达到备货标准的skc数量
720
+ # 1.计算某个skc的上架日期
721
+ # 2.计算某个skc的基于某个日期的过去7天销量
722
+ # 3.获取叶子类目的备货标准
723
+ header = ['店铺账号', '店铺名称', '店长', '统计日期', 'SKC图片', '商品信息', '新品成功转备货款', '第4周SKC销量/SKC曝光', '第4周SKC点击率/SKC转化率', 'SKC', 'SPU']
724
+ excel_data = []
725
+ stat_date_list = TimeUtils.get_dates_from_first_of_month_to_yesterday()
726
+ for stat_date in stat_date_list:
727
+ # 计算 stat_date 这天 的上架日期 是 filter_shelf_date
728
+ filter_shelf_date = TimeUtils.get_past_nth_day(29, stat_date)
729
+ log(f'stat_date:{stat_date},filter_shelf_date:{filter_shelf_date}')
730
+ # 筛选 上架日期是 filter_shelf_date 这天的skc有哪些
731
+ filter_skc_list = [skc_item for skc_item in skc_list if skc_item['shelfDate'] == filter_shelf_date]
732
+ # 再统计 这些skc 在 stat_date 这天的 前7天销量
733
+ # 看看这个7天销量是否达到了类目的备货标准 统计 计数
734
+ for skc_item in filter_skc_list:
735
+ skc = skc_item['skc']
736
+ spu = skc_item['spu']
737
+ log(f'skc:{skc}, spu:{spu}')
738
+
739
+ row_item = []
740
+ row_item.append(self.store_username)
741
+
742
+ status_cn = skc_item.get('shelfStatus').get('name')
743
+ goods_level = skc_item['goodsLevel']['name']
744
+ goods_label = [label["name"] for label in skc_item['goodsLabelList']]
745
+ store_info = f'{self.store_name}\n({status_cn})\n{goods_level}\n{",".join(goods_label).strip()}\n{stat_date_list[-1]}\n{stat_date_list[0]}'
746
+ row_item.append(store_info)
747
+ store_manager = self.config.shein_store_manager.get(str(self.store_username).lower())
748
+ row_item.append(store_manager)
749
+ row_item.append(stat_date)
750
+ row_item.append(skc_item['picUrl'])
751
+
752
+ standard_value = (skc_item.get('stockStandard') or {}).get('value') or 0
753
+
754
+ sale_detail, sale_rate, sale_num = self.get_skc_week_sale_list(spu, skc, stat_date)
755
+ success = int(standard_value > 0 and sale_num >= standard_value)
756
+
757
+ categoryName = skc_item['categoryName']
758
+ shelfDate = skc_item['shelfDate']
759
+ product_info = (
760
+ f'SPU: {spu}\n'
761
+ f'SKC: {skc}\n'
762
+ f'上架日期: {shelfDate}\n'
763
+ f'类目: {categoryName}\n'
764
+ f'备货标准/第4周销: {standard_value}/{sale_num}\n'
765
+ )
766
+ row_item.append(product_info)
767
+ row_item.append(success)
768
+ row_item.append("\n".join(sale_detail))
769
+ row_item.append("\n".join(sale_rate))
770
+ row_item.append(skc)
771
+ row_item.append(spu)
772
+ excel_data.append(row_item)
773
+
774
+ cache_file = f'{self.config.auto_dir}/shein/dict/new_product_to_bak_{TimeUtils.today_date()}.json'
775
+ write_dict_to_file_ex(cache_file, {self.store_username: [header] + excel_data}, [self.store_username])
776
+
777
+ def get_funds_data_lz(self):
778
+ log(f'正在获取 {self.store_name} 财务数据')
779
+ url = "https://sso.geiwohuo.com/sso/homePage/dataOverview/v2/detail"
780
+ payload = {
781
+ "metaIndexIds": [
782
+ 298,
783
+ 67,
784
+ 70,
785
+ 72
786
+ ],
787
+ }
788
+ response_text = fetch(self.web_page, url, payload)
789
+ error_code = response_text.get('code')
790
+ if str(error_code) != '0':
791
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
792
+ info = response_text.get('info')
793
+ num298 = 0 # 在途商品金额
794
+ num67 = 0 # 在仓商品金额
795
+ num70 = 0 # 待结算金额
796
+ num72 = 0 # 可提现金额
797
+ for item in info['list']:
798
+ if item['metaIndexId'] == 298:
799
+ num298 = item['count']
800
+ if item['metaIndexId'] == 67:
801
+ num67 = item['count']
802
+ if item['metaIndexId'] == 70:
803
+ num70 = item['count']
804
+ if item['metaIndexId'] == 72:
805
+ num72 = item['count']
806
+
807
+ outAmount = self.get_last_month_outbound_amount()
808
+ store_manager = self.config.shein_store_manager.get(str(self.store_username).lower())
809
+ NotifyItem = [f'{self.store_name}', self.store_username, store_manager, num298, num67, num70, num72, '', outAmount, '', '', '', TimeUtils.current_datetime()]
810
+ log(NotifyItem)
811
+ cache_file = f'{self.config.auto_dir}/shein/cache/stat_fund_lz_{TimeUtils.today_date()}.json'
812
+ write_dict_to_file_ex(cache_file, {self.store_username: NotifyItem}, [self.store_username])
813
+ return NotifyItem
814
+
620
815
  def get_funds_data(self):
621
816
  log(f'正在获取 {self.store_name} 财务数据')
622
817
  url = "https://sso.geiwohuo.com/sso/homePage/dataOverview/v2/detail"
@@ -968,7 +1163,6 @@ class SheinLib:
968
1163
  return count
969
1164
 
970
1165
  def get_week_sales_stat_detail(self):
971
- global ListNotify, NotifyItem
972
1166
  dt = self.get_dt_time()
973
1167
  yesterday = TimeUtils.get_yesterday(dt)
974
1168
  date_7_days_ago = TimeUtils.get_past_nth_day(6, None, '%Y-%m-%d')
@@ -1145,7 +1339,7 @@ class SheinLib:
1145
1339
  item.append(stock_str)
1146
1340
  item.append(cost_price)
1147
1341
  item.append(supplyPrice)
1148
- sale_num_list, sale_data_list = self.get_skc_week_sale_list(spu, skc, sku)
1342
+ sale_num_list, sale_data_list = self.get_sku_week_sale_list(spu, skc, sku)
1149
1343
  item.append("\n".join(sale_num_list))
1150
1344
  item.append("\n".join(sale_data_list))
1151
1345
  item.append(self.get_skc_activity_label(skc, sku, dictActivityPrice))
@@ -1943,7 +2137,7 @@ class SheinLib:
1943
2137
  sku_item.append(skc) # SKC
1944
2138
  sku_item.append(spu_info['supplierCode']) # SKC货号
1945
2139
 
1946
- sale_num_list, sale_data_list = self.get_skc_week_sale_list(spu, skc, sku)
2140
+ sale_num_list, sale_data_list = self.get_sku_week_sale_list(spu, skc, sku)
1947
2141
  sku_item.append("\n".join(sale_num_list))
1948
2142
  sku_item.append("\n".join(sale_data_list))
1949
2143
  sku_item.append(self.get_skc_activity_label(skc, sku, dictActivityPrice))
@@ -1968,13 +2162,17 @@ class SheinLib:
1968
2162
  return product_sku_list
1969
2163
 
1970
2164
  # 获取一个skc一周内的销售趋势(商品明细中的)
1971
- def get_dict_skc_week_trend_v2(self, spu, skc):
2165
+ def get_dict_skc_week_trend_v2(self, spu, skc, start_from=None):
1972
2166
  dt = self.get_dt_time()
1973
2167
 
1974
- date_7_days_ago = TimeUtils.get_past_nth_day(7, None, '%Y%m%d')
1975
- log('-7', date_7_days_ago)
1976
- date_1_days_ago = TimeUtils.get_past_nth_day(1, None, '%Y%m%d')
1977
- log('-1', date_1_days_ago)
2168
+ date_7_days_ago, date_1_days_ago = TimeUtils.get_past_7_days_range_format(start_from, '%Y%m%d')
2169
+ log(date_7_days_ago, date_1_days_ago, 'dt', dt)
2170
+
2171
+ # 将字符串转换为日期对象
2172
+ date1 = datetime.strptime(date_1_days_ago, "%Y%m%d").date()
2173
+ date2 = datetime.strptime(dt, "%Y%m%d").date()
2174
+ if date1 > date2:
2175
+ send_exception(f'get_dict_skc_week_trend_v2: dt:{dt} < date_1_days_ago: {date_1_days_ago}')
1978
2176
 
1979
2177
  cache_file = f'{self.config.auto_dir}/shein/dict/dict_skc_week_trend_{skc}_{date_7_days_ago}_{date_1_days_ago}.json'
1980
2178
  if datetime.now().hour >= 9:
@@ -2013,7 +2211,7 @@ class SheinLib:
2013
2211
  write_dict_to_file(cache_file, DictSkc)
2014
2212
  return DictSkc
2015
2213
 
2016
- def get_skc_week_sale_list(self, spu, skc, sku):
2214
+ def get_sku_week_sale_list(self, spu, skc, sku):
2017
2215
  dict_skc = self.get_dict_skc_week_trend_v2(spu, skc)
2018
2216
  date_list = TimeUtils.get_past_7_days_list()
2019
2217
  first_day, last_day = TimeUtils.get_past_7_days_range()
@@ -2386,7 +2584,7 @@ class SheinLib:
2386
2584
  if mode in [6] and sales7cn > 0:
2387
2585
  continue
2388
2586
 
2389
- sale_num_list, sale_data_list = self.get_skc_week_sale_list(spu, skc, sku)
2587
+ sale_num_list, sale_data_list = self.get_sku_week_sale_list(spu, skc, sku)
2390
2588
  row_item.append("\n".join(sale_num_list))
2391
2589
  row_item.append("\n".join(sale_data_list))
2392
2590
  row_item.append(self.get_skc_activity_label(skc, sku, dictActivityPrice))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrpa
3
- Version: 1.0.57
3
+ Version: 1.0.59
4
4
  Summary: qsir's rpa library
5
5
  Author: QSir
6
6
  Author-email: QSir <1171725650@qq.com>
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