qrpa 1.1.33__py3-none-any.whl → 1.1.34__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/temu_chrome.py CHANGED
@@ -1,56 +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
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 CHANGED
@@ -1,139 +1,139 @@
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
- import os
7
-
8
- class TemuExcel:
9
-
10
- def __init__(self, config, bridge):
11
- self.config = config
12
- self.bridge = bridge
13
-
14
- def write_funds(self):
15
- cache_file = f'{self.config.auto_dir}/temu/cache/funds_{TimeUtils.today_date()}.json'
16
- dict = read_dict_from_file(cache_file)
17
- data = []
18
- for key, val in dict.items():
19
- data.append(val)
20
-
21
- excel_path = create_file_path(self.config.excel_temu_fund)
22
- data.insert(0, ['汇总', '', '', '', ''])
23
- data.insert(0, ['店铺名称', '总金额', '可用余额', '-', '导出时间'])
24
- log(data)
25
- # 删除第 4 列(索引为 3)
26
- for row in data:
27
- row.pop(3) # 删除每行中索引为 3 的元素
28
-
29
- write_data(excel_path, 'Sheet1', data)
30
-
31
- app, wb, sheet = open_excel(excel_path, 'Sheet1')
32
- beautify_title(sheet)
33
- format_to_money(sheet, ['金额', '余额'])
34
- format_to_datetime(sheet, ['时间'])
35
- add_sum_for_cell(sheet, ['总金额', '可用余额'])
36
- add_borders(sheet)
37
- close_excel(app, wb)
38
-
39
- def format_purchase_advise_batch(self, sheet):
40
- beautify_title(sheet)
41
- format_to_datetime(sheet, ['时间'])
42
- format_to_number(sheet, ['平均日销', '本地和采购可售天数', '建议采购'], 1)
43
- add_borders(sheet)
44
- add_formula_for_column(sheet, '平均日销', '=G2/7')
45
- add_formula_for_column(sheet, '本地和采购可售天数', '=IF(H2>0,(E2+F2)/H2,0)')
46
- add_formula_for_column(sheet, '建议采购', '=IF(J2>I2,H2*9,0)')
47
- colorize_by_field(sheet, 'SKC')
48
- autofit_column(sheet, ['店铺名称', '商品信息'])
49
- column_to_left(sheet, ['商品信息'])
50
- InsertImageV2(sheet, ['SKC图片', 'SKU图片'], 'temu', 120)
51
- # if sheet.used_range.rows.count > 330:
52
- # log('表格数据行数超过了330行,将删除SKC图片')
53
- # remove_excel_columns(sheet, ['SKC图片'])
54
-
55
- def write_purchase_advise(self, erp='mb'):
56
- cache_file = f'{self.config.auto_dir}/temu/cache/warehouse_list_{TimeUtils.today_date()}.json'
57
- dict = read_dict_from_file(cache_file)
58
-
59
- store_info = read_dict_from_file(self.config.temu_store_info)
60
-
61
- header = ['店铺名称', 'SKC图片', 'SKU图片', '商品信息', '现有库存数量', '已采购数量', '近7日销量', '平均日销', '本地和采购可售天数', '生产天数', '建议采购', '产品起定量', '备货周期(天)', 'SKC', '导出时间']
62
- new_excel_path_list = []
63
-
64
- for mall_id, subOrderList in dict.items():
65
- excel_data = []
66
- mall_name = store_info.get(mall_id)[1]
67
-
68
- for product in subOrderList:
69
- spu = str(product['productId']) # temu平台 spu_id
70
- skc = str(product['productSkcId']) # temu平台 skc_id
71
- skcExtCode = product['skcExtCode'] # 商家 SKC货号
72
- category = product['category'] # 叶子类目
73
- onSalesDurationOffline = product['onSalesDurationOffline'] # 加入站点时长
74
-
75
- for sku in product['skuQuantityDetailList']:
76
- priceReviewStatus = sku['priceReviewStatus']
77
- if priceReviewStatus == 3: # 过滤 开款价格状态 已作废的 2是已生效
78
- continue
79
-
80
- mall_info = f'{mall_name}\n{mall_id}'
81
- productSkcPicture = product['productSkcPicture'] # skc图片
82
- skuExtCode = str(sku['skuExtCode']) # sku货号
83
- sku_img = self.bridge.get_sku_img(skuExtCode, erp)
84
- stock = self.bridge.get_sku_stock(skuExtCode, erp)
85
-
86
- product_info = f"SPU: {spu}\nSKC: {skc}\nSKC货号: {skcExtCode}\nSKU货号: {skuExtCode}\n属性集: {sku['className']}\n类目: {category}\n加入站点时长: {onSalesDurationOffline}天\n"
87
-
88
- row_item = []
89
- row_item.append(mall_info)
90
- row_item.append(productSkcPicture)
91
- row_item.append(sku_img)
92
- row_item.append(product_info)
93
- row_item.append(stock)
94
- row_item.append(0)
95
- row_item.append(sku['lastSevenDaysSaleVolume'])
96
- row_item.append(0)
97
- row_item.append(0)
98
- row_item.append(7)
99
- row_item.append(0)
100
- row_item.append(0)
101
- row_item.append(0)
102
- row_item.append(skc)
103
- row_item.append(TimeUtils.current_datetime())
104
- excel_data.append(row_item)
105
-
106
- # 按近7日销量排序
107
- excel_data = sort_by_column(excel_data, 6, 1)
108
-
109
- # 计算需要多少个文件(每个文件最多320行数据,包含表头)
110
- max_data_rows = 250 - 1 # 减去表头行
111
- total_files = (len(excel_data) + max_data_rows - 1) // max_data_rows # 通过加(max_data_rows-1)实现向上取整
112
-
113
- for file_index in range(total_files):
114
- start_idx = file_index * max_data_rows
115
- end_idx = min((file_index + 1) * max_data_rows, len(excel_data))
116
- current_data = excel_data[start_idx:end_idx]
117
-
118
- # 生成文件名,如果超过一个文件则添加序号
119
- if total_files == 1:
120
- new_excel_path = str(self.config.excel_purcase_advice_temu).replace('#store_name#', mall_name).replace(' ', '_')
121
- else:
122
- # 在文件名后添加 _2, _3 等序号
123
- base_path = str(self.config.excel_purcase_advice_temu).replace('#store_name#', mall_name).replace(' ', '_')
124
- file_name, file_ext = os.path.splitext(base_path)
125
- new_excel_path = f"{file_name}_{file_index + 1}{file_ext}"
126
-
127
- new_excel_path_list.append(new_excel_path)
128
- sheet_name = 'Sheet1'
129
- data = [header] + current_data
130
-
131
- close_excel_file(new_excel_path)
132
- log(f"创建文件: {new_excel_path}, 数据行数: {len(current_data)}")
133
-
134
- batch_excel_operations(new_excel_path, [
135
- (sheet_name, 'write', data, ['N']),
136
- (sheet_name, 'format', self.format_purchase_advise_batch)
137
- ])
138
-
139
- return new_excel_path_list
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
+ import os
7
+
8
+ class TemuExcel:
9
+
10
+ def __init__(self, config, bridge):
11
+ self.config = config
12
+ self.bridge = bridge
13
+
14
+ def write_funds(self):
15
+ cache_file = f'{self.config.auto_dir}/temu/cache/funds_{TimeUtils.today_date()}.json'
16
+ dict = read_dict_from_file(cache_file)
17
+ data = []
18
+ for key, val in dict.items():
19
+ data.append(val)
20
+
21
+ excel_path = create_file_path(self.config.excel_temu_fund)
22
+ data.insert(0, ['汇总', '', '', '', ''])
23
+ data.insert(0, ['店铺名称', '总金额', '可用余额', '-', '导出时间'])
24
+ log(data)
25
+ # 删除第 4 列(索引为 3)
26
+ for row in data:
27
+ row.pop(3) # 删除每行中索引为 3 的元素
28
+
29
+ write_data(excel_path, 'Sheet1', data)
30
+
31
+ app, wb, sheet = open_excel(excel_path, 'Sheet1')
32
+ beautify_title(sheet)
33
+ format_to_money(sheet, ['金额', '余额'])
34
+ format_to_datetime(sheet, ['时间'])
35
+ add_sum_for_cell(sheet, ['总金额', '可用余额'])
36
+ add_borders(sheet)
37
+ close_excel(app, wb)
38
+
39
+ def format_purchase_advise_batch(self, sheet):
40
+ beautify_title(sheet)
41
+ format_to_datetime(sheet, ['时间'])
42
+ format_to_number(sheet, ['平均日销', '本地和采购可售天数', '建议采购'], 1)
43
+ add_borders(sheet)
44
+ add_formula_for_column(sheet, '平均日销', '=G2/7')
45
+ add_formula_for_column(sheet, '本地和采购可售天数', '=IF(H2>0,(E2+F2)/H2,0)')
46
+ add_formula_for_column(sheet, '建议采购', '=IF(J2>I2,H2*9,0)')
47
+ colorize_by_field(sheet, 'SKC')
48
+ autofit_column(sheet, ['店铺名称', '商品信息'])
49
+ column_to_left(sheet, ['商品信息'])
50
+ InsertImageV2(sheet, ['SKC图片', 'SKU图片'], 'temu', 120)
51
+ # if sheet.used_range.rows.count > 330:
52
+ # log('表格数据行数超过了330行,将删除SKC图片')
53
+ # remove_excel_columns(sheet, ['SKC图片'])
54
+
55
+ def write_purchase_advise(self, erp='mb'):
56
+ cache_file = f'{self.config.auto_dir}/temu/cache/warehouse_list_{TimeUtils.today_date()}.json'
57
+ dict = read_dict_from_file(cache_file)
58
+
59
+ store_info = read_dict_from_file(self.config.temu_store_info)
60
+
61
+ header = ['店铺名称', 'SKC图片', 'SKU图片', '商品信息', '现有库存数量', '已采购数量', '近7日销量', '平均日销', '本地和采购可售天数', '生产天数', '建议采购', '产品起定量', '备货周期(天)', 'SKC', '导出时间']
62
+ new_excel_path_list = []
63
+
64
+ for mall_id, subOrderList in dict.items():
65
+ excel_data = []
66
+ mall_name = store_info.get(mall_id)[1]
67
+
68
+ for product in subOrderList:
69
+ spu = str(product['productId']) # temu平台 spu_id
70
+ skc = str(product['productSkcId']) # temu平台 skc_id
71
+ skcExtCode = product['skcExtCode'] # 商家 SKC货号
72
+ category = product['category'] # 叶子类目
73
+ onSalesDurationOffline = product['onSalesDurationOffline'] # 加入站点时长
74
+
75
+ for sku in product['skuQuantityDetailList']:
76
+ priceReviewStatus = sku['priceReviewStatus']
77
+ if priceReviewStatus == 3: # 过滤 开款价格状态 已作废的 2是已生效
78
+ continue
79
+
80
+ mall_info = f'{mall_name}\n{mall_id}'
81
+ productSkcPicture = product['productSkcPicture'] # skc图片
82
+ skuExtCode = str(sku['skuExtCode']) # sku货号
83
+ sku_img = self.bridge.get_sku_img(skuExtCode, erp)
84
+ stock = self.bridge.get_sku_stock(skuExtCode, erp)
85
+
86
+ product_info = f"SPU: {spu}\nSKC: {skc}\nSKC货号: {skcExtCode}\nSKU货号: {skuExtCode}\n属性集: {sku['className']}\n类目: {category}\n加入站点时长: {onSalesDurationOffline}天\n"
87
+
88
+ row_item = []
89
+ row_item.append(mall_info)
90
+ row_item.append(productSkcPicture)
91
+ row_item.append(sku_img)
92
+ row_item.append(product_info)
93
+ row_item.append(stock)
94
+ row_item.append(0)
95
+ row_item.append(sku['lastSevenDaysSaleVolume'])
96
+ row_item.append(0)
97
+ row_item.append(0)
98
+ row_item.append(7)
99
+ row_item.append(0)
100
+ row_item.append(0)
101
+ row_item.append(0)
102
+ row_item.append(skc)
103
+ row_item.append(TimeUtils.current_datetime())
104
+ excel_data.append(row_item)
105
+
106
+ # 按近7日销量排序
107
+ excel_data = sort_by_column(excel_data, 6, 1)
108
+
109
+ # 计算需要多少个文件(每个文件最多320行数据,包含表头)
110
+ max_data_rows = 250 - 1 # 减去表头行
111
+ total_files = (len(excel_data) + max_data_rows - 1) // max_data_rows # 通过加(max_data_rows-1)实现向上取整
112
+
113
+ for file_index in range(total_files):
114
+ start_idx = file_index * max_data_rows
115
+ end_idx = min((file_index + 1) * max_data_rows, len(excel_data))
116
+ current_data = excel_data[start_idx:end_idx]
117
+
118
+ # 生成文件名,如果超过一个文件则添加序号
119
+ if total_files == 1:
120
+ new_excel_path = str(self.config.excel_purcase_advice_temu).replace('#store_name#', mall_name).replace(' ', '_')
121
+ else:
122
+ # 在文件名后添加 _2, _3 等序号
123
+ base_path = str(self.config.excel_purcase_advice_temu).replace('#store_name#', mall_name).replace(' ', '_')
124
+ file_name, file_ext = os.path.splitext(base_path)
125
+ new_excel_path = f"{file_name}_{file_index + 1}{file_ext}"
126
+
127
+ new_excel_path_list.append(new_excel_path)
128
+ sheet_name = 'Sheet1'
129
+ data = [header] + current_data
130
+
131
+ close_excel_file(new_excel_path)
132
+ log(f"创建文件: {new_excel_path}, 数据行数: {len(current_data)}")
133
+
134
+ batch_excel_operations(new_excel_path, [
135
+ (sheet_name, 'write', data, ['N']),
136
+ (sheet_name, 'format', self.format_purchase_advise_batch)
137
+ ])
138
+
139
+ return new_excel_path_list