qrpa 1.0.33__py3-none-any.whl → 1.0.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/feishu_bot_app.py +15 -15
- qrpa/fun_excel.py +17 -2
- qrpa/shein_excel.py +211 -6
- qrpa/shein_lib.py +89 -0
- {qrpa-1.0.33.dist-info → qrpa-1.0.34.dist-info}/METADATA +1 -1
- {qrpa-1.0.33.dist-info → qrpa-1.0.34.dist-info}/RECORD +8 -8
- {qrpa-1.0.33.dist-info → qrpa-1.0.34.dist-info}/WHEEL +0 -0
- {qrpa-1.0.33.dist-info → qrpa-1.0.34.dist-info}/top_level.txt +0 -0
qrpa/feishu_bot_app.py
CHANGED
|
@@ -32,17 +32,17 @@ class FeishuBot:
|
|
|
32
32
|
.build()
|
|
33
33
|
return self._client
|
|
34
34
|
|
|
35
|
-
def _get_chat_id(self,
|
|
35
|
+
def _get_chat_id(self, bot_name: str) -> Optional[str]:
|
|
36
36
|
"""
|
|
37
37
|
根据群组别名获取群组ID
|
|
38
38
|
|
|
39
39
|
Args:
|
|
40
|
-
|
|
40
|
+
bot_name: 群组别名
|
|
41
41
|
|
|
42
42
|
Returns:
|
|
43
43
|
群组ID,如果别名不存在则返回None
|
|
44
44
|
"""
|
|
45
|
-
return self.config.dict_feishu_group.get(
|
|
45
|
+
return self.config.dict_feishu_group.get(bot_name)
|
|
46
46
|
|
|
47
47
|
def _handle_response_error(self, response, operation_name: str):
|
|
48
48
|
"""
|
|
@@ -61,20 +61,20 @@ class FeishuBot:
|
|
|
61
61
|
return True
|
|
62
62
|
return False
|
|
63
63
|
|
|
64
|
-
def send_text(self, content: str,
|
|
64
|
+
def send_text(self, content: str, bot_name: str = 'test') -> bool:
|
|
65
65
|
"""
|
|
66
66
|
发送文本消息
|
|
67
67
|
|
|
68
68
|
Args:
|
|
69
69
|
content: 文本内容
|
|
70
|
-
|
|
70
|
+
bot_name: 群组别名,默认为'test'
|
|
71
71
|
|
|
72
72
|
Returns:
|
|
73
73
|
发送是否成功
|
|
74
74
|
"""
|
|
75
|
-
chat_id = self._get_chat_id(
|
|
75
|
+
chat_id = self._get_chat_id(bot_name)
|
|
76
76
|
if not chat_id:
|
|
77
|
-
lark.logger.error(f"未找到群组别名 '{
|
|
77
|
+
lark.logger.error(f"未找到群组别名 '{bot_name}' 对应的群组ID")
|
|
78
78
|
return False
|
|
79
79
|
|
|
80
80
|
message_content = {"text": content}
|
|
@@ -101,13 +101,13 @@ class FeishuBot:
|
|
|
101
101
|
lark.logger.info(lark.JSON.marshal(response.data, indent=4))
|
|
102
102
|
return True
|
|
103
103
|
|
|
104
|
-
def send_image(self, file_path: str,
|
|
104
|
+
def send_image(self, file_path: str, bot_name: str = 'test') -> bool:
|
|
105
105
|
"""
|
|
106
106
|
发送图片消息
|
|
107
107
|
|
|
108
108
|
Args:
|
|
109
109
|
file_path: 图片文件路径
|
|
110
|
-
|
|
110
|
+
bot_name: 群组别名,默认为'test'
|
|
111
111
|
|
|
112
112
|
Returns:
|
|
113
113
|
发送是否成功
|
|
@@ -117,9 +117,9 @@ class FeishuBot:
|
|
|
117
117
|
if not image_key:
|
|
118
118
|
return False
|
|
119
119
|
|
|
120
|
-
chat_id = self._get_chat_id(
|
|
120
|
+
chat_id = self._get_chat_id(bot_name)
|
|
121
121
|
if not chat_id:
|
|
122
|
-
lark.logger.error(f"未找到群组别名 '{
|
|
122
|
+
lark.logger.error(f"未找到群组别名 '{bot_name}' 对应的群组ID")
|
|
123
123
|
return False
|
|
124
124
|
|
|
125
125
|
message_content = {"image_key": image_key}
|
|
@@ -146,13 +146,13 @@ class FeishuBot:
|
|
|
146
146
|
lark.logger.info(lark.JSON.marshal(response.data, indent=4))
|
|
147
147
|
return True
|
|
148
148
|
|
|
149
|
-
def send_excel(self, file_path: str,
|
|
149
|
+
def send_excel(self, file_path: str, bot_name: str = 'test') -> bool:
|
|
150
150
|
"""
|
|
151
151
|
发送Excel文件
|
|
152
152
|
|
|
153
153
|
Args:
|
|
154
154
|
file_path: Excel文件路径
|
|
155
|
-
|
|
155
|
+
bot_name: 群组别名,默认为'test'
|
|
156
156
|
|
|
157
157
|
Returns:
|
|
158
158
|
发送是否成功
|
|
@@ -162,9 +162,9 @@ class FeishuBot:
|
|
|
162
162
|
if not file_key:
|
|
163
163
|
return False
|
|
164
164
|
|
|
165
|
-
chat_id = self._get_chat_id(
|
|
165
|
+
chat_id = self._get_chat_id(bot_name)
|
|
166
166
|
if not chat_id:
|
|
167
|
-
lark.logger.error(f"未找到群组别名 '{
|
|
167
|
+
lark.logger.error(f"未找到群组别名 '{bot_name}' 对应的群组ID")
|
|
168
168
|
return False
|
|
169
169
|
|
|
170
170
|
message_content = {"file_key": file_key}
|
qrpa/fun_excel.py
CHANGED
|
@@ -90,6 +90,21 @@ def set_cell_prefix_red(cell, n, color_name):
|
|
|
90
90
|
except Exception as e:
|
|
91
91
|
print(f"设置字体颜色失败: {e}")
|
|
92
92
|
|
|
93
|
+
def wrap_column(sheet, columns=None, WrapText=True):
|
|
94
|
+
if columns is None:
|
|
95
|
+
return
|
|
96
|
+
used_range_col = sheet.range('A1').expand('right')
|
|
97
|
+
for j, cell in enumerate(used_range_col):
|
|
98
|
+
col = j + 1
|
|
99
|
+
col_name = index_to_column_name(col)
|
|
100
|
+
col_val = sheet.range(f'{col_name}1').value
|
|
101
|
+
if col_val is None:
|
|
102
|
+
continue
|
|
103
|
+
for c in columns:
|
|
104
|
+
if c in col_val:
|
|
105
|
+
log(f'设置[{c}] 换行 {WrapText}')
|
|
106
|
+
sheet.range(f'{col_name}:{col_name}').api.WrapText = WrapText
|
|
107
|
+
|
|
93
108
|
def sort_by_column(data, col_index, header_rows=2, reverse=True):
|
|
94
109
|
if not data or header_rows >= len(data):
|
|
95
110
|
return data
|
|
@@ -2626,13 +2641,13 @@ def _execute_operations_batch(excel_path, operations):
|
|
|
2626
2641
|
for sheet_name, operation_type, *args in operations:
|
|
2627
2642
|
# 根据操作类型决定是否需要获取或创建工作表
|
|
2628
2643
|
sheet = None
|
|
2629
|
-
|
|
2644
|
+
|
|
2630
2645
|
# 删除操作不需要获取sheet对象
|
|
2631
2646
|
if operation_type == 'delete':
|
|
2632
2647
|
log(f'删除sheet: {sheet_name}')
|
|
2633
2648
|
delete_sheet_if_exists(wb, sheet_name)
|
|
2634
2649
|
continue
|
|
2635
|
-
|
|
2650
|
+
|
|
2636
2651
|
# 其他操作需要获取或创建工作表
|
|
2637
2652
|
if isinstance(sheet_name, str):
|
|
2638
2653
|
sheet_names = [s.name.strip().lower() for s in wb.sheets]
|
qrpa/shein_excel.py
CHANGED
|
@@ -10,10 +10,214 @@ import numpy as np
|
|
|
10
10
|
|
|
11
11
|
class SheinExcel:
|
|
12
12
|
|
|
13
|
-
def __init__(self, config):
|
|
13
|
+
def __init__(self, config, bridge=None):
|
|
14
14
|
self.config = config
|
|
15
|
+
self.bridge = bridge
|
|
15
16
|
pass
|
|
16
17
|
|
|
18
|
+
# 退货列表
|
|
19
|
+
def write_return_list(self, erp, start_date, end_date):
|
|
20
|
+
header = ['退货单号', '退货出库时间', '签收状态', '店铺信息', '店长', '退货类型', '退货原因', 'SKC图片', 'SKC信息', '商家SKU', '属性集', 'SKU退货数量', '平台SKU', 'ERP默认供货商', 'ERP成本', '包裹名', '包裹号', '退货计划单号', '订单号', '发货单', '退回方式', '快递名称', '运单号', '退货地址', '商家联系人', '商家手机号', '入库问题图片地址']
|
|
21
|
+
excel_data = [header]
|
|
22
|
+
|
|
23
|
+
dict_store = read_dict_from_file(self.config.shein_store_alias)
|
|
24
|
+
|
|
25
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/shein_return_order_list_{start_date}_{end_date}.json'
|
|
26
|
+
dict = read_dict_from_file(cache_file)
|
|
27
|
+
for store_username, shein_back_list in dict.items():
|
|
28
|
+
for item in shein_back_list:
|
|
29
|
+
|
|
30
|
+
store_name = dict_store.get(store_username)
|
|
31
|
+
|
|
32
|
+
returnOrderId = item['id']
|
|
33
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/shein_return_order_box_detail_{returnOrderId}.json'
|
|
34
|
+
return_detail = read_dict_from_file(cache_file)
|
|
35
|
+
if len(return_detail) == 0:
|
|
36
|
+
continue
|
|
37
|
+
|
|
38
|
+
returnOrderNo = item['returnOrderNo']
|
|
39
|
+
returnOrderTypeName = item['returnOrderTypeName']
|
|
40
|
+
returnOrderStatusName = item['returnOrderStatusName']
|
|
41
|
+
returnReasonTypeName = item['returnReasonTypeName']
|
|
42
|
+
returnReason = item['returnReason']
|
|
43
|
+
waitReturnQuantity = item['waitReturnQuantity']
|
|
44
|
+
skcReturnQuantity = item['returnQuantity']
|
|
45
|
+
returnAmount = item['returnAmount']
|
|
46
|
+
currencyCode = item['currencyCode']
|
|
47
|
+
returnPlanNo = item['returnPlanNo']
|
|
48
|
+
sellerOrderNo = item['sellerOrderNo']
|
|
49
|
+
sellerDeliveryNo = item['sellerDeliveryNo']
|
|
50
|
+
completeTime = item['completeTime']
|
|
51
|
+
returnWayTypeName = item['returnWayTypeName']
|
|
52
|
+
returnExpressCompanyName = item['returnExpressCompanyName']
|
|
53
|
+
expressNoList = item['expressNoList']
|
|
54
|
+
returnAddress = item['returnAddress']
|
|
55
|
+
sellerContract = item['sellerContract']
|
|
56
|
+
sellerContractPhone = item['sellerContractPhone']
|
|
57
|
+
isSign = ['已报废', '已签收', '待签收'][item['isSign']]
|
|
58
|
+
if item['returnScrapType'] == 1:
|
|
59
|
+
urls = item.get('qc_report_url', '-')
|
|
60
|
+
else:
|
|
61
|
+
urls = '\n'.join(item['rejectPicUrlList'])
|
|
62
|
+
|
|
63
|
+
for package_list in return_detail[0]['boxList']:
|
|
64
|
+
package_name = package_list['packageName']
|
|
65
|
+
package_no = package_list['returnBoxNo']
|
|
66
|
+
for skc_item in package_list['goods']:
|
|
67
|
+
skc_img = skc_item['imgPath']
|
|
68
|
+
skc = skc_item['skc']
|
|
69
|
+
supplierCode = skc_item['supplierCode']
|
|
70
|
+
for sku_item in skc_item['details']:
|
|
71
|
+
platformSku = sku_item['platformSku']
|
|
72
|
+
supplierSku = sku_item['supplierSku']
|
|
73
|
+
suffixZh = sku_item['suffixZh']
|
|
74
|
+
returnQuantity = sku_item['returnQuantity']
|
|
75
|
+
|
|
76
|
+
store_info = f'{store_username}\n{store_name}\n处理类型: {returnOrderTypeName}\n退货状态: {returnOrderStatusName}'
|
|
77
|
+
skc_info = f'SKC: {skc}\n供方货号: {supplierCode}\n预计退货数量/执行退货数量: {waitReturnQuantity}/{skcReturnQuantity}\n预计退货货值: {returnAmount} {currencyCode}'
|
|
78
|
+
|
|
79
|
+
row_item = []
|
|
80
|
+
row_item.append(returnOrderNo)
|
|
81
|
+
row_item.append(completeTime)
|
|
82
|
+
row_item.append(isSign)
|
|
83
|
+
row_item.append(store_info)
|
|
84
|
+
row_item.append(self.config.shein_store_manager.get(str(store_username).lower()))
|
|
85
|
+
row_item.append(returnReasonTypeName)
|
|
86
|
+
row_item.append(returnReason)
|
|
87
|
+
row_item.append(skc_img)
|
|
88
|
+
row_item.append(skc_info)
|
|
89
|
+
row_item.append(supplierSku)
|
|
90
|
+
row_item.append(suffixZh)
|
|
91
|
+
row_item.append(returnQuantity)
|
|
92
|
+
row_item.append(platformSku)
|
|
93
|
+
row_item.append(self.bridge.get_sku_supplier(supplierSku, erp))
|
|
94
|
+
row_item.append(self.bridge.get_sku_cost(supplierSku, erp))
|
|
95
|
+
row_item.append(package_name)
|
|
96
|
+
row_item.append(package_no)
|
|
97
|
+
row_item.append(returnPlanNo)
|
|
98
|
+
row_item.append(sellerOrderNo)
|
|
99
|
+
row_item.append(sellerDeliveryNo)
|
|
100
|
+
row_item.append(returnWayTypeName)
|
|
101
|
+
row_item.append(returnExpressCompanyName)
|
|
102
|
+
row_item.append(expressNoList)
|
|
103
|
+
row_item.append(returnAddress)
|
|
104
|
+
row_item.append(sellerContract)
|
|
105
|
+
row_item.append(sellerContractPhone)
|
|
106
|
+
row_item.append(urls)
|
|
107
|
+
|
|
108
|
+
excel_data.append(row_item)
|
|
109
|
+
|
|
110
|
+
cache_file_excel = f'{self.config.auto_dir}/shein/cache/shein_return_order_list_excel_{start_date}_{end_date}.json'
|
|
111
|
+
write_dict_to_file(cache_file_excel, excel_data)
|
|
112
|
+
|
|
113
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/shein_return_order_list_{TimeUtils.today_date()}.json'
|
|
114
|
+
dict = read_dict_from_file(cache_file)
|
|
115
|
+
for store_username, shein_back_list in dict.items():
|
|
116
|
+
for item in shein_back_list:
|
|
117
|
+
|
|
118
|
+
store_name = dict_store.get(store_username)
|
|
119
|
+
|
|
120
|
+
returnOrderId = item['id']
|
|
121
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/shein_return_order_box_detail_{returnOrderId}.json'
|
|
122
|
+
return_detail = read_dict_from_file(cache_file)
|
|
123
|
+
if len(return_detail) == 0:
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
returnOrderNo = item['returnOrderNo']
|
|
127
|
+
returnOrderTypeName = item['returnOrderTypeName']
|
|
128
|
+
returnOrderStatusName = item['returnOrderStatusName']
|
|
129
|
+
returnReasonTypeName = item['returnReasonTypeName']
|
|
130
|
+
returnReason = item['returnReason']
|
|
131
|
+
waitReturnQuantity = item['waitReturnQuantity']
|
|
132
|
+
skcReturnQuantity = item['returnQuantity']
|
|
133
|
+
returnAmount = item['returnAmount']
|
|
134
|
+
currencyCode = item['currencyCode']
|
|
135
|
+
returnPlanNo = item['returnPlanNo']
|
|
136
|
+
sellerOrderNo = item['sellerOrderNo']
|
|
137
|
+
sellerDeliveryNo = item['sellerDeliveryNo']
|
|
138
|
+
completeTime = item['completeTime']
|
|
139
|
+
returnWayTypeName = item['returnWayTypeName']
|
|
140
|
+
returnExpressCompanyName = item['returnExpressCompanyName']
|
|
141
|
+
expressNoList = item['expressNoList']
|
|
142
|
+
returnAddress = item['returnAddress']
|
|
143
|
+
sellerContract = item['sellerContract']
|
|
144
|
+
sellerContractPhone = item['sellerContractPhone']
|
|
145
|
+
isSign = ['已报废', '已签收', '待签收'][item['isSign']]
|
|
146
|
+
if item['returnScrapType'] == 1:
|
|
147
|
+
urls = item.get('qc_report_url', '-')
|
|
148
|
+
else:
|
|
149
|
+
urls = '\n'.join(item['rejectPicUrlList'])
|
|
150
|
+
|
|
151
|
+
for package_list in return_detail[0]['boxList']:
|
|
152
|
+
package_name = package_list['packageName']
|
|
153
|
+
package_no = package_list['returnBoxNo']
|
|
154
|
+
for skc_item in package_list['goods']:
|
|
155
|
+
skc_img = skc_item['imgPath']
|
|
156
|
+
skc = skc_item['skc']
|
|
157
|
+
supplierCode = skc_item['supplierCode']
|
|
158
|
+
for sku_item in skc_item['details']:
|
|
159
|
+
platformSku = sku_item['platformSku']
|
|
160
|
+
supplierSku = sku_item['supplierSku']
|
|
161
|
+
suffixZh = sku_item['suffixZh']
|
|
162
|
+
returnQuantity = sku_item['returnQuantity']
|
|
163
|
+
|
|
164
|
+
store_info = f'{store_username}\n{store_name}\n处理类型: {returnOrderTypeName}\n退货状态: {returnOrderStatusName}'
|
|
165
|
+
skc_info = f'SKC: {skc}\n供方货号: {supplierCode}\n预计退货数量/执行退货数量: {waitReturnQuantity}/{skcReturnQuantity}\n预计退货货值: {returnAmount} {currencyCode}'
|
|
166
|
+
|
|
167
|
+
row_item = []
|
|
168
|
+
row_item.append(returnOrderNo)
|
|
169
|
+
row_item.append(completeTime)
|
|
170
|
+
row_item.append(isSign)
|
|
171
|
+
row_item.append(store_info)
|
|
172
|
+
row_item.append(self.config.shein_store_manager.get(str(store_username).lower()))
|
|
173
|
+
row_item.append(returnReasonTypeName)
|
|
174
|
+
row_item.append(returnReason)
|
|
175
|
+
row_item.append(skc_img)
|
|
176
|
+
row_item.append(skc_info)
|
|
177
|
+
row_item.append(supplierSku)
|
|
178
|
+
row_item.append(suffixZh)
|
|
179
|
+
row_item.append(returnQuantity)
|
|
180
|
+
row_item.append(platformSku)
|
|
181
|
+
row_item.append(self.bridge.get_sku_supplier(supplierSku, erp))
|
|
182
|
+
row_item.append(self.bridge.get_sku_cost(supplierSku, erp))
|
|
183
|
+
row_item.append(package_name)
|
|
184
|
+
row_item.append(package_no)
|
|
185
|
+
row_item.append(returnPlanNo)
|
|
186
|
+
row_item.append(sellerOrderNo)
|
|
187
|
+
row_item.append(sellerDeliveryNo)
|
|
188
|
+
row_item.append(returnWayTypeName)
|
|
189
|
+
row_item.append(returnExpressCompanyName)
|
|
190
|
+
row_item.append(expressNoList)
|
|
191
|
+
row_item.append(returnAddress)
|
|
192
|
+
row_item.append(sellerContract)
|
|
193
|
+
row_item.append(sellerContractPhone)
|
|
194
|
+
row_item.append(urls)
|
|
195
|
+
|
|
196
|
+
excel_data.append(row_item)
|
|
197
|
+
|
|
198
|
+
sheet_name = '昨日退货列表'
|
|
199
|
+
|
|
200
|
+
cache_file_excel = f'{self.config.auto_dir}/shein/cache/shein_return_order_list_excel_{TimeUtils.today_date()}.json'
|
|
201
|
+
write_dict_to_file(cache_file_excel, excel_data)
|
|
202
|
+
|
|
203
|
+
batch_excel_operations(self.config.excel_return_list, [
|
|
204
|
+
(sheet_name, 'write', excel_data, ['W', 'Z']),
|
|
205
|
+
(sheet_name, 'format', self.format_return_list)
|
|
206
|
+
])
|
|
207
|
+
|
|
208
|
+
def format_return_list(self, sheet):
|
|
209
|
+
merge_by_column_v2(sheet, '退货单号', ['签收状态', '店铺信息', '店长', '退货类型', '退货原因', 'SKC图片', 'SKC信息', '包裹名', '包裹号', '退货计划单号', '订单号', '发货单', '退货出库时间', '退回方式', '快递名称', '运单号', '退货地址', '商家联系人', '商家手机号', '入库问题图片地址'])
|
|
210
|
+
beautify_title(sheet)
|
|
211
|
+
add_borders(sheet)
|
|
212
|
+
format_to_datetime(sheet, ['时间'])
|
|
213
|
+
format_to_money(sheet, ['单价', '金额', '成本'])
|
|
214
|
+
column_to_right(sheet, ['单价', '金额', '成本'])
|
|
215
|
+
wrap_column(sheet, ['退货原因', '退货地址', '入库问题图片地址'])
|
|
216
|
+
autofit_column(sheet, ['店铺别名', 'SKC信息'])
|
|
217
|
+
column_to_left(sheet, ['店铺信息', '商家SKU', '供方货号', '属性集', 'SKC信息', '退货地址'])
|
|
218
|
+
specify_column_width(sheet, ['退货原因', 'SKC信息', '商家SKU', '退货地址'], 200 / 6)
|
|
219
|
+
InsertImageV2(sheet, ['SKC图片'])
|
|
220
|
+
|
|
17
221
|
def dealReturn(self, sheet):
|
|
18
222
|
# 遍历可用行
|
|
19
223
|
used_range_row = sheet.range('A1').expand('down')
|
|
@@ -1076,10 +1280,10 @@ class SheinExcel:
|
|
|
1076
1280
|
excel_path = self.config.excel_shein_finance_month_report_summary
|
|
1077
1281
|
|
|
1078
1282
|
sheet_name = '总表-算法1'
|
|
1079
|
-
|
|
1283
|
+
dict_store = read_dict_from_file(self.config.shein_store_alias)
|
|
1080
1284
|
total_data = []
|
|
1081
1285
|
header = ['店铺账号', '店铺别名']
|
|
1082
|
-
for mall_id, excel_data in
|
|
1286
|
+
for mall_id, excel_data in dict_store.items():
|
|
1083
1287
|
total_data += [[mall_id, excel_data]]
|
|
1084
1288
|
|
|
1085
1289
|
log(total_data)
|
|
@@ -1099,7 +1303,7 @@ class SheinExcel:
|
|
|
1099
1303
|
filtered_value = add_suffixed_column(filtered_value, '毛利', '')
|
|
1100
1304
|
|
|
1101
1305
|
# 匹配店铺店长
|
|
1102
|
-
dict_store_manager_shein =
|
|
1306
|
+
dict_store_manager_shein = self.config.shein_store_manager
|
|
1103
1307
|
for row in filtered_value:
|
|
1104
1308
|
mall_name = row[0]
|
|
1105
1309
|
if mall_name == '店铺账号':
|
|
@@ -1118,10 +1322,10 @@ class SheinExcel:
|
|
|
1118
1322
|
wb.save()
|
|
1119
1323
|
close_excel(app, wb)
|
|
1120
1324
|
|
|
1121
|
-
|
|
1325
|
+
dict_store = read_dict_from_file(self.config.shein_store_alias)
|
|
1122
1326
|
total_data = []
|
|
1123
1327
|
header = ['店铺账号', '店铺别名']
|
|
1124
|
-
for mall_id, excel_data in
|
|
1328
|
+
for mall_id, excel_data in dict_store.items():
|
|
1125
1329
|
total_data += [[mall_id, excel_data]]
|
|
1126
1330
|
|
|
1127
1331
|
filtered_value = [header] + total_data
|
|
@@ -1139,6 +1343,7 @@ class SheinExcel:
|
|
|
1139
1343
|
filtered_value = add_suffixed_column(filtered_value, '毛利', '')
|
|
1140
1344
|
|
|
1141
1345
|
# 匹配店铺店长
|
|
1346
|
+
dict_store_manager_shein = self.config.shein_store_manager
|
|
1142
1347
|
for row in filtered_value:
|
|
1143
1348
|
mall_name = row[0]
|
|
1144
1349
|
if mall_name == '店铺账号':
|
qrpa/shein_lib.py
CHANGED
|
@@ -119,6 +119,95 @@ class SheinLib:
|
|
|
119
119
|
|
|
120
120
|
log('鉴权处理结束')
|
|
121
121
|
|
|
122
|
+
# 获取质检报告pdf地址
|
|
123
|
+
def get_qc_report_url(self, deliverCode, purchaseCode):
|
|
124
|
+
log(f'获取质检报告:{deliverCode} {purchaseCode}')
|
|
125
|
+
url = f"https://sso.geiwohuo.com/pfmp/returnPlan/queryQcReport"
|
|
126
|
+
payload = {
|
|
127
|
+
"deliverCode" : deliverCode,
|
|
128
|
+
"purchaseCode": purchaseCode
|
|
129
|
+
}
|
|
130
|
+
response_text = fetch(self.web_page, url, payload)
|
|
131
|
+
error_code = response_text.get('code')
|
|
132
|
+
if str(error_code) != '0':
|
|
133
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
134
|
+
qc_report_url = (response_text.get('info', {}).get('data') or [{'qcReportUrl': '质检报告生成中,请稍后查看'}])[0].get('qcReportUrl')
|
|
135
|
+
log(qc_report_url)
|
|
136
|
+
return qc_report_url
|
|
137
|
+
|
|
138
|
+
def get_return_order_box_detail(self, returnOrderId):
|
|
139
|
+
log(f'获取退货包裹详情: {returnOrderId}')
|
|
140
|
+
url = f"https://sso.geiwohuo.com/pfmp/returnOrder/getReturnOrderBoxDetail"
|
|
141
|
+
payload = {
|
|
142
|
+
"returnOrderId": returnOrderId,
|
|
143
|
+
"page" : 1,
|
|
144
|
+
"perPage" : 50
|
|
145
|
+
}
|
|
146
|
+
response_text = fetch(self.web_page, url, payload)
|
|
147
|
+
error_code = response_text.get('code')
|
|
148
|
+
if str(error_code) != '0':
|
|
149
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
150
|
+
list_item = response_text['info']['data']
|
|
151
|
+
|
|
152
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/shein_return_order_box_detail_{returnOrderId}.json'
|
|
153
|
+
write_dict_to_file(cache_file, list_item)
|
|
154
|
+
|
|
155
|
+
def get_return_order_list(self, start_date, end_date, only_yesterday=1):
|
|
156
|
+
|
|
157
|
+
log(f'获取退货列表: {self.store_username} {self.store_name} {start_date} {end_date}')
|
|
158
|
+
|
|
159
|
+
page_num = 1
|
|
160
|
+
page_size = 200 # 列表最多返回200条数据 大了没有用
|
|
161
|
+
|
|
162
|
+
url = f"https://sso.geiwohuo.com/pfmp/returnOrder/page"
|
|
163
|
+
payload = {
|
|
164
|
+
"addTimeStart": f"{start_date} 00:00:00",
|
|
165
|
+
"addTimeEnd" : f"{end_date} 23:59:59",
|
|
166
|
+
"page" : page_num,
|
|
167
|
+
"perPage" : page_size
|
|
168
|
+
}
|
|
169
|
+
response_text = fetch(self.web_page, url, payload)
|
|
170
|
+
error_code = response_text.get('code')
|
|
171
|
+
if str(error_code) != '0':
|
|
172
|
+
raise send_exception(json.dumps(response_text, ensure_ascii=False))
|
|
173
|
+
list_item = response_text['info']['data']
|
|
174
|
+
total = response_text['info']['meta']['count']
|
|
175
|
+
totalPage = math.ceil(total / page_size)
|
|
176
|
+
|
|
177
|
+
for page in range(2, totalPage + 1):
|
|
178
|
+
log(f'获取退供列表 第{page}/{totalPage}页 共{total}条记录')
|
|
179
|
+
payload['page'] = page
|
|
180
|
+
response_text = fetch(self.web_page, url, payload)
|
|
181
|
+
spu_list_new = response_text['info']['data']
|
|
182
|
+
list_item += spu_list_new
|
|
183
|
+
time.sleep(0.1)
|
|
184
|
+
|
|
185
|
+
all_list_item = []
|
|
186
|
+
today_list_item = []
|
|
187
|
+
# 过滤 退货出库时间 是昨天的
|
|
188
|
+
for item in list_item:
|
|
189
|
+
has_valid_package = item.get('hasPackage') == 1
|
|
190
|
+
is_valid_yesterday = TimeUtils.is_yesterday(item['completeTime'], None) if item.get('completeTime') else False
|
|
191
|
+
if has_valid_package:
|
|
192
|
+
if int(item['returnScrapType']) == 1:
|
|
193
|
+
purchaseCode = item['sellerOrderNo']
|
|
194
|
+
delivery_code = item['sellerDeliveryNo']
|
|
195
|
+
item['qc_report_url'] = self.get_qc_report_url(delivery_code, purchaseCode)
|
|
196
|
+
returnOrderId = item['id']
|
|
197
|
+
self.get_return_order_box_detail(returnOrderId)
|
|
198
|
+
|
|
199
|
+
all_list_item.append(item)
|
|
200
|
+
if is_valid_yesterday:
|
|
201
|
+
today_list_item.append(item)
|
|
202
|
+
|
|
203
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/shein_return_order_list_{TimeUtils.today_date()}.json'
|
|
204
|
+
write_dict_to_file_ex(cache_file, {self.store_username: today_list_item}, [self.store_username])
|
|
205
|
+
|
|
206
|
+
cache_file = f'{self.config.auto_dir}/shein/cache/shein_return_order_list_{start_date}_{end_date}.json'
|
|
207
|
+
write_dict_to_file_ex(cache_file, {self.store_username: all_list_item}, [self.store_username])
|
|
208
|
+
|
|
209
|
+
return list_item
|
|
210
|
+
|
|
122
211
|
# 获取希音退供明细 和 台账明细一个接口
|
|
123
212
|
def get_back_list(self, source='mb'):
|
|
124
213
|
page_num = 1
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
qrpa/RateLimitedSender.py,sha256=hqvb1qspDFaW4RsLuVufylOrefkMgixANKeBaGEqYb4,1421
|
|
2
2
|
qrpa/__init__.py,sha256=p4n9kXm1j9G-GWKDPWQa1WIyrDUeC33zeM27xky9otg,1019
|
|
3
3
|
qrpa/db_migrator.py,sha256=2VmhzcMsU0MKpl-mNCwKyV8tLTqyEysSpP27-S_rQZ8,21862
|
|
4
|
-
qrpa/feishu_bot_app.py,sha256=
|
|
4
|
+
qrpa/feishu_bot_app.py,sha256=6r2YqCAMUN7y3F7onoABRmHC7S-UPOLHwbhsQnQ3IRc,9452
|
|
5
5
|
qrpa/fun_base.py,sha256=qg6SvR-GEj2TclB1OL9eLu711jV-bysXJ5Eh2gW9pE8,10600
|
|
6
|
-
qrpa/fun_excel.py,sha256=
|
|
6
|
+
qrpa/fun_excel.py,sha256=kXR3fU0XqsdBuSEToqA3TzYWSP5Cgh1aZ1QPgaZ0y08,114758
|
|
7
7
|
qrpa/fun_file.py,sha256=yzjDV16WL5vRys7J4uQcNzIFkX4D5MAlSCwxcD-mwQo,11966
|
|
8
8
|
qrpa/fun_web.py,sha256=5QLQorAhRzMOGMRh4eCJ2UH8ZhVHvxkHwobWhmgU5qM,6286
|
|
9
9
|
qrpa/fun_win.py,sha256=-LnTeocdTt72NVH6VgLdpAT9_C5oV9okeudXG6CftMA,8034
|
|
10
10
|
qrpa/shein_daily_report_model.py,sha256=H8oZmIN5Pyqe306W1_xuz87lOqLQ_LI5RjXbaxDkIzE,12589
|
|
11
|
-
qrpa/shein_excel.py,sha256=
|
|
12
|
-
qrpa/shein_lib.py,sha256=
|
|
11
|
+
qrpa/shein_excel.py,sha256=qWEq0WZgbAIIVoygOd97EykXpPRDF3tFPEiqCX3zM8k,114965
|
|
12
|
+
qrpa/shein_lib.py,sha256=41EjsUglJk-2rf-YP8VM69vQgURe4ACtBe-m9z4uAO0,105902
|
|
13
13
|
qrpa/shein_sqlite.py,sha256=ZQwD0Gz81q9WY7tY2HMEYvSF9r3N_G_Aur3bYfST9WY,5707
|
|
14
14
|
qrpa/shein_ziniao.py,sha256=nSqqcEPh4nVQtUxUnIRzeZfTLyXywGPjPZn5pP-w57U,18309
|
|
15
15
|
qrpa/temu_chrome.py,sha256=CbtFy1QPan9xJdJcNZj-EsVGhUvv3ZTEPVDEA4-im40,2803
|
|
@@ -18,7 +18,7 @@ qrpa/temu_lib.py,sha256=hYB59zsLS3m3NTic_duTwPMOTSxlHyQVa8OhHnHm-1g,7199
|
|
|
18
18
|
qrpa/time_utils.py,sha256=ef0hhbN_6b-gcnz5ETIVOoxemIMvcxGVGGIRnHnGaBo,29564
|
|
19
19
|
qrpa/time_utils_example.py,sha256=shHOXKKF3QSzb0SHsNc34M61wEkkLuM30U9X1THKNS8,8053
|
|
20
20
|
qrpa/wxwork.py,sha256=gIytG19DZ5g7Tsl0-W3EbjfSnpIqZw-ua24gcB78YEg,11264
|
|
21
|
-
qrpa-1.0.
|
|
22
|
-
qrpa-1.0.
|
|
23
|
-
qrpa-1.0.
|
|
24
|
-
qrpa-1.0.
|
|
21
|
+
qrpa-1.0.34.dist-info/METADATA,sha256=G9wYjP5ED9eQgG32w8tw-UqQ6s0vGIsIdnCDMyyzLDM,231
|
|
22
|
+
qrpa-1.0.34.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
23
|
+
qrpa-1.0.34.dist-info/top_level.txt,sha256=F6T5igi0fhXDucPPUbmmSC0qFCDEsH5eVijfVF48OFU,5
|
|
24
|
+
qrpa-1.0.34.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|