ey-commerce-lib 1.0.0__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 ey-commerce-lib might be problematic. Click here for more details.
- ey_commerce_lib/__init__.py +1 -0
- ey_commerce_lib/dxm/__init__.py +0 -0
- ey_commerce_lib/dxm/constant/__init__.py +0 -0
- ey_commerce_lib/dxm/constant/order.py +80 -0
- ey_commerce_lib/dxm/exception/__init__.py +0 -0
- ey_commerce_lib/dxm/exception/common.py +7 -0
- ey_commerce_lib/dxm/main.py +396 -0
- ey_commerce_lib/dxm/order.py +2 -0
- ey_commerce_lib/dxm/parser/__init__.py +0 -0
- ey_commerce_lib/dxm/parser/common.py +72 -0
- ey_commerce_lib/dxm/parser/order.py +337 -0
- ey_commerce_lib/dxm/parser/purchase.py +40 -0
- ey_commerce_lib/dxm/parser/warehouse.py +65 -0
- ey_commerce_lib/dxm/schemas/__init__.py +0 -0
- ey_commerce_lib/dxm/schemas/common.py +13 -0
- ey_commerce_lib/dxm/schemas/order.py +273 -0
- ey_commerce_lib/dxm/schemas/warehouse.py +161 -0
- ey_commerce_lib/py.typed +0 -0
- ey_commerce_lib/utils/__init__.py +0 -0
- ey_commerce_lib/utils/dxm.py +43 -0
- ey_commerce_lib/utils/list_util.py +23 -0
- ey_commerce_lib/utils/str.py +3 -0
- ey_commerce_lib-1.0.0.dist-info/METADATA +11 -0
- ey_commerce_lib-1.0.0.dist-info/RECORD +25 -0
- ey_commerce_lib-1.0.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# 待审核搜索配置
|
|
2
|
+
from enum import StrEnum
|
|
3
|
+
|
|
4
|
+
from ey_commerce_lib.dxm.schemas.order import DxmOrderSearchForm
|
|
5
|
+
|
|
6
|
+
# 待审核搜索基础配置
|
|
7
|
+
ORDER_SEARCH_APPROVAL_BASE_FORM = DxmOrderSearchForm(**{
|
|
8
|
+
'state': 'paid',
|
|
9
|
+
'is_voided': '0',
|
|
10
|
+
'is_removed': '0',
|
|
11
|
+
'order_field': 'order_pay_time',
|
|
12
|
+
'is_desc': '0'
|
|
13
|
+
})
|
|
14
|
+
# 待处理搜索基础配置
|
|
15
|
+
ORDER_SEARCH_PENDING_PROCESSING_BASE_FORM = DxmOrderSearchForm(**{
|
|
16
|
+
'state': 'approved',
|
|
17
|
+
'is_voided': '0',
|
|
18
|
+
'is_removed': '0',
|
|
19
|
+
'order_field': 'order_pay_time',
|
|
20
|
+
'is_desc': '0',
|
|
21
|
+
})
|
|
22
|
+
# 自营仓库搜索配置(非海外仓)
|
|
23
|
+
ORDER_SEARCH_SELF_WAREHOUSE_BASE_FORM = DxmOrderSearchForm(**{
|
|
24
|
+
'search_types': 'packageNum',
|
|
25
|
+
'state': 'processed',
|
|
26
|
+
'is_voided': '0',
|
|
27
|
+
'is_removed': '0',
|
|
28
|
+
'is_oversea': '0',
|
|
29
|
+
'order_field': 'order_pay_time',
|
|
30
|
+
'is_desc': '0',
|
|
31
|
+
})
|
|
32
|
+
# 海外仓库搜索配置(海外仓)
|
|
33
|
+
ORDER_SEARCH_OVERSEA_WAREHOUSE_BASE_FORM = DxmOrderSearchForm(**{
|
|
34
|
+
'state': 'processed',
|
|
35
|
+
'is_voided': '0',
|
|
36
|
+
'is_removed': '0',
|
|
37
|
+
'is_oversea': '1',
|
|
38
|
+
'order_field': 'order_pay_time',
|
|
39
|
+
'is_desc': '0',
|
|
40
|
+
})
|
|
41
|
+
# 有货搜索配置
|
|
42
|
+
ORDER_SEARCH_HAVE_GOODS_BASE_FORM = DxmOrderSearchForm(**{
|
|
43
|
+
'state': 'allocated_has',
|
|
44
|
+
'is_voided': '0',
|
|
45
|
+
'is_removed': '0',
|
|
46
|
+
'order_field': 'order_pay_time',
|
|
47
|
+
'is_desc': '0',
|
|
48
|
+
})
|
|
49
|
+
# 缺货搜索配置
|
|
50
|
+
ORDER_SEARCH_OUT_OF_STOCK_BASE_FORM = DxmOrderSearchForm(**{
|
|
51
|
+
'state': 'allocated_out',
|
|
52
|
+
'is_voided': '0',
|
|
53
|
+
'is_removed': '0',
|
|
54
|
+
'order_field': 'order_pay_time',
|
|
55
|
+
'is_desc': '0',
|
|
56
|
+
})
|
|
57
|
+
# 发货失败搜索配置
|
|
58
|
+
ORDER_SEARCH_DELIVERY_FAILURE_BASE_FORM = DxmOrderSearchForm(**{
|
|
59
|
+
'state': 'fail',
|
|
60
|
+
'is_voided': '0',
|
|
61
|
+
'is_removed': '0',
|
|
62
|
+
'order_field': 'order_pay_time',
|
|
63
|
+
'is_desc': '0'
|
|
64
|
+
})
|
|
65
|
+
# 发货成功搜索配置
|
|
66
|
+
ORDER_SEARCH_DELIVERY_SUCCESS_BASE_FORM = DxmOrderSearchForm(**{
|
|
67
|
+
'state': 'shipped',
|
|
68
|
+
'is_voided': '0',
|
|
69
|
+
'is_removed': '0',
|
|
70
|
+
'commit_platforms': 'success',
|
|
71
|
+
'order_field': 'shipped_time',
|
|
72
|
+
'is_desc': '0'}
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class DxmOrderRuleType(StrEnum):
|
|
77
|
+
# 审单规则
|
|
78
|
+
ORDER_APPROVAL = '1'
|
|
79
|
+
# 物流规则
|
|
80
|
+
LOGISTICS = '2'
|
|
File without changes
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
from ey_commerce_lib.dxm.constant.order import DxmOrderRuleType
|
|
4
|
+
from ey_commerce_lib.dxm.parser.common import get_page_info
|
|
5
|
+
from ey_commerce_lib.dxm.parser.order import list_order_base_by_html, list_order_rule, get_rule_detail, \
|
|
6
|
+
get_order_detail_by_html
|
|
7
|
+
from ey_commerce_lib.dxm.parser.purchase import list_purchasing_all
|
|
8
|
+
from ey_commerce_lib.dxm.parser.warehouse import list_warehouse_product
|
|
9
|
+
from ey_commerce_lib.dxm.schemas.common import Page
|
|
10
|
+
from ey_commerce_lib.dxm.schemas.order import DxmOrderSearchForm, DxmJsonResponse, DxmCheckProcessResponse, DxmOrderRule
|
|
11
|
+
from ey_commerce_lib.dxm.schemas.warehouse import WarehouseProduct, WarehouseProductQuery, PurchasingAllQuery
|
|
12
|
+
from httpx import AsyncClient
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DxmClient:
|
|
16
|
+
|
|
17
|
+
def __init__(self, cookies: dict, headers: dict, sem: int = 10):
|
|
18
|
+
self.__cookies = cookies
|
|
19
|
+
self.__headers = headers
|
|
20
|
+
self.__sem = asyncio.Semaphore(sem)
|
|
21
|
+
self.__async_client = AsyncClient(base_url="https://www.dianxiaomi.com", cookies=cookies, headers=headers)
|
|
22
|
+
|
|
23
|
+
async def page_order_base_async(self, query: DxmOrderSearchForm):
|
|
24
|
+
"""
|
|
25
|
+
条件分页查询订单基础信息
|
|
26
|
+
:param query:
|
|
27
|
+
:return:
|
|
28
|
+
"""
|
|
29
|
+
# 查询分页数据
|
|
30
|
+
data = await self.__async_client.post("/package/advancedSearch.htm", data=query.model_dump(by_alias=True))
|
|
31
|
+
# 获取分页信息
|
|
32
|
+
page_info = get_page_info(data.text)
|
|
33
|
+
data = list_order_base_by_html(data.text)
|
|
34
|
+
return {
|
|
35
|
+
**page_info,
|
|
36
|
+
'data': data
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async def list_order_base_async(self, query: DxmOrderSearchForm):
|
|
40
|
+
"""
|
|
41
|
+
条件查询订单信息列表
|
|
42
|
+
:return:
|
|
43
|
+
"""
|
|
44
|
+
query.page_no = 1
|
|
45
|
+
data = await self.page_order_base_async(query)
|
|
46
|
+
total_page = data['total_page']
|
|
47
|
+
result = data['data']
|
|
48
|
+
for page_number in range(2, total_page + 1):
|
|
49
|
+
query.page_no = page_number
|
|
50
|
+
data = await self.page_order_base_async(query)
|
|
51
|
+
result.extend(data['data'])
|
|
52
|
+
return result
|
|
53
|
+
|
|
54
|
+
async def page_order_detail_async(self, query: DxmOrderSearchForm):
|
|
55
|
+
async def set_detail(order_base: dict):
|
|
56
|
+
"""
|
|
57
|
+
设置详情
|
|
58
|
+
:param order_base:
|
|
59
|
+
:return:
|
|
60
|
+
"""
|
|
61
|
+
order_base['detail'] = await self.package_detail(order_base['package_id'])
|
|
62
|
+
|
|
63
|
+
# 获取基本分页数据信息
|
|
64
|
+
page_base_order = await self.page_order_base_async(query)
|
|
65
|
+
# 获取并设置详情信息
|
|
66
|
+
await asyncio.gather(*[
|
|
67
|
+
set_detail(item)
|
|
68
|
+
for item in page_base_order['data']])
|
|
69
|
+
|
|
70
|
+
return page_base_order
|
|
71
|
+
|
|
72
|
+
async def list_order_detail_async(self, query: DxmOrderSearchForm):
|
|
73
|
+
query.page_no = 1
|
|
74
|
+
data = await self.page_order_detail_async(query)
|
|
75
|
+
total_page = data['total_page']
|
|
76
|
+
result = data['data']
|
|
77
|
+
for page_number in range(2, total_page + 1):
|
|
78
|
+
query.page_no = page_number
|
|
79
|
+
data = await self.page_order_detail_async(query)
|
|
80
|
+
result.extend(data['data'])
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
async def package_detail(self, package_id: str):
|
|
84
|
+
"""
|
|
85
|
+
获取包裹的详情数据
|
|
86
|
+
:param package_id:
|
|
87
|
+
:return:
|
|
88
|
+
"""
|
|
89
|
+
async with self.__sem:
|
|
90
|
+
package_detail_res = await self.__async_client.post('/package/detail.htm', data={
|
|
91
|
+
'packageId': package_id,
|
|
92
|
+
'history': ''
|
|
93
|
+
})
|
|
94
|
+
return get_order_detail_by_html(package_detail_res.text)
|
|
95
|
+
|
|
96
|
+
async def move_process(self, package_id: str) -> DxmJsonResponse:
|
|
97
|
+
"""
|
|
98
|
+
申请运单号
|
|
99
|
+
:return:
|
|
100
|
+
"""
|
|
101
|
+
async with self.__sem:
|
|
102
|
+
move_processed_json = await self.__async_client.post("/package/moveProcessed.json", data={
|
|
103
|
+
"packageId": package_id
|
|
104
|
+
})
|
|
105
|
+
return move_processed_json.json()
|
|
106
|
+
|
|
107
|
+
async def move_allocated(self, package_id: str) -> DxmJsonResponse:
|
|
108
|
+
"""
|
|
109
|
+
移入待打单
|
|
110
|
+
:param package_id:
|
|
111
|
+
:return:
|
|
112
|
+
"""
|
|
113
|
+
async with self.__sem:
|
|
114
|
+
move_allocated_json = await self.__async_client.post("/package/moveAllocated.json", data={
|
|
115
|
+
"packageId": package_id
|
|
116
|
+
})
|
|
117
|
+
return move_allocated_json.json()
|
|
118
|
+
|
|
119
|
+
async def upload_track_num(self, package_id: str, track_num: str, auth_id) -> DxmJsonResponse:
|
|
120
|
+
"""
|
|
121
|
+
上传运单号
|
|
122
|
+
:param package_id: package_id
|
|
123
|
+
:param track_num: 运单号
|
|
124
|
+
:param auth_id: 物流方式id
|
|
125
|
+
:return:
|
|
126
|
+
"""
|
|
127
|
+
async with self.__sem:
|
|
128
|
+
upload_track_num_json = await self.__async_client.post("/package/uploadTrackNum.json", data={
|
|
129
|
+
"packageId": package_id,
|
|
130
|
+
"trackNum": track_num,
|
|
131
|
+
"authId": auth_id
|
|
132
|
+
})
|
|
133
|
+
return upload_track_num_json.json()
|
|
134
|
+
|
|
135
|
+
async def get_warehouse_dict(self):
|
|
136
|
+
"""
|
|
137
|
+
获取仓库字典映射
|
|
138
|
+
:return:
|
|
139
|
+
"""
|
|
140
|
+
warehouse_info_res = await self.__async_client.get("/dxmWarehoseCon/getWarehoseInfo.json")
|
|
141
|
+
warehouse_info_dict = warehouse_info_res.json()
|
|
142
|
+
result = dict()
|
|
143
|
+
for item in warehouse_info_dict.items():
|
|
144
|
+
result[item[1]['name']] = item[0]
|
|
145
|
+
return result
|
|
146
|
+
|
|
147
|
+
async def commit_platform(self, package_id: str):
|
|
148
|
+
"""
|
|
149
|
+
虚拟发货
|
|
150
|
+
:param package_id: 包裹id
|
|
151
|
+
:return:
|
|
152
|
+
"""
|
|
153
|
+
async with self.__sem:
|
|
154
|
+
commit_platform_res = await self.__async_client.post("/package/commitPlatform.json", data={
|
|
155
|
+
'packageId': package_id
|
|
156
|
+
})
|
|
157
|
+
return commit_platform_res.json()
|
|
158
|
+
|
|
159
|
+
async def save_storage_id_for_order(self, package_id: str, storage_id: str):
|
|
160
|
+
"""
|
|
161
|
+
订单详情修改订单仓库
|
|
162
|
+
:param package_id:
|
|
163
|
+
:param storage_id:
|
|
164
|
+
:return:
|
|
165
|
+
"""
|
|
166
|
+
async with self.__sem:
|
|
167
|
+
save_storage_id_for_order_res = await self.__async_client.post("/package/saveStorageIdForOrder.json", data={
|
|
168
|
+
'packageId': package_id,
|
|
169
|
+
'storageId': storage_id,
|
|
170
|
+
'pids': ''
|
|
171
|
+
})
|
|
172
|
+
return save_storage_id_for_order_res.json()
|
|
173
|
+
|
|
174
|
+
async def __refresh_logistics_rule(self, uri: str, all_refresh: int):
|
|
175
|
+
async with self.__sem:
|
|
176
|
+
refresh_logistics_rule_res = await self.__async_client.post(f'/order/{uri}.json', data={
|
|
177
|
+
'shopId': '-1',
|
|
178
|
+
'platform': '',
|
|
179
|
+
'allRefresh': f'{all_refresh}',
|
|
180
|
+
})
|
|
181
|
+
uuid = refresh_logistics_rule_res.json().get('uuid')
|
|
182
|
+
check_process_res = await self.__check_process(uuid)
|
|
183
|
+
# 任务没有完成就一直监测直到任务完成为止
|
|
184
|
+
while int(check_process_res['processMsg']['num']) < int(check_process_res['processMsg']['totalNum']):
|
|
185
|
+
check_process_res = await self.__check_process(uuid)
|
|
186
|
+
await asyncio.sleep(1)
|
|
187
|
+
return check_process_res
|
|
188
|
+
|
|
189
|
+
async def refresh_logistics_rule_no_select_logistics_method(self) -> DxmCheckProcessResponse:
|
|
190
|
+
"""
|
|
191
|
+
刷新物流规则(待处理中的未选择物流方式的订单)
|
|
192
|
+
:return:
|
|
193
|
+
"""
|
|
194
|
+
return await self.__refresh_logistics_rule(uri='refreshLogisticRule', all_refresh=0)
|
|
195
|
+
|
|
196
|
+
async def refresh_logistics_rule_all(self) -> DxmCheckProcessResponse:
|
|
197
|
+
"""
|
|
198
|
+
刷新物流规则(待处理中的所有订单)
|
|
199
|
+
:return:
|
|
200
|
+
"""
|
|
201
|
+
return await self.__refresh_logistics_rule(uri='refreshLogisticRule', all_refresh=1)
|
|
202
|
+
|
|
203
|
+
async def refresh_rule_all(self):
|
|
204
|
+
"""
|
|
205
|
+
刷新物流规则(待审核中的所有订单)
|
|
206
|
+
:return:
|
|
207
|
+
"""
|
|
208
|
+
return await self.__refresh_logistics_rule(uri='refreshRule', all_refresh=1)
|
|
209
|
+
|
|
210
|
+
async def refresh_no_select_logistics_method_rule(self):
|
|
211
|
+
"""
|
|
212
|
+
刷新物流规则(待审核未选择物流方式的订单)
|
|
213
|
+
:return:
|
|
214
|
+
"""
|
|
215
|
+
return await self.__refresh_logistics_rule(uri='refreshRule', all_refresh=0)
|
|
216
|
+
|
|
217
|
+
async def __check_process(self, uuid: str) -> DxmCheckProcessResponse:
|
|
218
|
+
"""
|
|
219
|
+
检测任务的进度
|
|
220
|
+
:param uuid: 任务id
|
|
221
|
+
:return:
|
|
222
|
+
"""
|
|
223
|
+
async with self.__sem:
|
|
224
|
+
check_process_res = await self.__async_client.post("/checkProcess.json", data={
|
|
225
|
+
'uuid': uuid
|
|
226
|
+
})
|
|
227
|
+
return check_process_res.json()
|
|
228
|
+
|
|
229
|
+
async def ship_goods(self, package_id: str):
|
|
230
|
+
"""
|
|
231
|
+
发货
|
|
232
|
+
:param package_id:
|
|
233
|
+
:return:
|
|
234
|
+
"""
|
|
235
|
+
async with self.__sem:
|
|
236
|
+
ship_goods_res = await self.__async_client.post("/package/shipGoods.json", data={
|
|
237
|
+
"packageId": package_id
|
|
238
|
+
})
|
|
239
|
+
return ship_goods_res.json()
|
|
240
|
+
|
|
241
|
+
async def batch_ship_goods(self, package_ids: list):
|
|
242
|
+
"""
|
|
243
|
+
批量发货
|
|
244
|
+
:param package_ids: package_id列表
|
|
245
|
+
:return:
|
|
246
|
+
"""
|
|
247
|
+
async with self.__sem:
|
|
248
|
+
batch_ship_goods_res = await self.__async_client.post("/package/batchShipGoods.json", data={
|
|
249
|
+
"packageIds": ','.join(package_ids)
|
|
250
|
+
})
|
|
251
|
+
return batch_ship_goods_res.json()
|
|
252
|
+
|
|
253
|
+
async def list_rule(self, rule_type: DxmOrderRuleType) -> dict:
|
|
254
|
+
"""
|
|
255
|
+
获取审单规则列表
|
|
256
|
+
:return:
|
|
257
|
+
"""
|
|
258
|
+
async with self.__sem:
|
|
259
|
+
list_rule_res = await self.__async_client.get("/rule/index.htm", params={
|
|
260
|
+
'type': rule_type
|
|
261
|
+
})
|
|
262
|
+
list_rule_html = list_rule_res.text
|
|
263
|
+
data = list_order_rule(list_rule_html)
|
|
264
|
+
# 遍历设置Type
|
|
265
|
+
for item in data:
|
|
266
|
+
item['type'] = rule_type.value
|
|
267
|
+
return data
|
|
268
|
+
|
|
269
|
+
async def get_rule_id_by_name(self, rule_name: str, rule_type: DxmOrderRuleType) -> str:
|
|
270
|
+
"""
|
|
271
|
+
根据规则名称获取规则
|
|
272
|
+
:param rule_name:
|
|
273
|
+
:param rule_type:
|
|
274
|
+
:return:
|
|
275
|
+
"""
|
|
276
|
+
data = await self.list_rule(rule_type)
|
|
277
|
+
for item in data:
|
|
278
|
+
if item['rule_name'] == rule_name:
|
|
279
|
+
return item['rule_id']
|
|
280
|
+
|
|
281
|
+
async def rule_detail(self, rule_id: str, rule_type: int):
|
|
282
|
+
"""
|
|
283
|
+
获取审单规则详情
|
|
284
|
+
:param rule_id:
|
|
285
|
+
:param rule_type:
|
|
286
|
+
:return:
|
|
287
|
+
"""
|
|
288
|
+
async with self.__sem:
|
|
289
|
+
rule_detail_res = await self.__async_client.get("/rule/detail.htm", params={
|
|
290
|
+
'id': rule_id,
|
|
291
|
+
'type': rule_type,
|
|
292
|
+
'isCopy': '0'
|
|
293
|
+
})
|
|
294
|
+
rule_detail_html = rule_detail_res.text
|
|
295
|
+
return get_rule_detail(rule_detail_html)
|
|
296
|
+
|
|
297
|
+
async def update_rule(self, dxm_rule_order: DxmOrderRule):
|
|
298
|
+
"""
|
|
299
|
+
更新审单规则
|
|
300
|
+
:param dxm_rule_order:
|
|
301
|
+
:return:
|
|
302
|
+
"""
|
|
303
|
+
data = dxm_rule_order.to_update_rule_data()
|
|
304
|
+
async with self.__sem:
|
|
305
|
+
update_rule_res = await self.__async_client.post("/rule/update.json", content=data)
|
|
306
|
+
return update_rule_res.json()
|
|
307
|
+
|
|
308
|
+
async def edit_rule_state(self, rule_id: str, state: int):
|
|
309
|
+
"""
|
|
310
|
+
编辑规则状态
|
|
311
|
+
:param rule_id: 规则id
|
|
312
|
+
:param state: 1启用 0禁用
|
|
313
|
+
:return:
|
|
314
|
+
"""
|
|
315
|
+
async with self.__sem:
|
|
316
|
+
edit_rule_state_res = await self.__async_client.post("/rule/editRuleState.json", data={
|
|
317
|
+
'id': rule_id,
|
|
318
|
+
'state': state
|
|
319
|
+
})
|
|
320
|
+
return edit_rule_state_res.json()
|
|
321
|
+
|
|
322
|
+
async def enable_rule(self, rule_id: str):
|
|
323
|
+
"""
|
|
324
|
+
启用规则
|
|
325
|
+
:param rule_id:
|
|
326
|
+
:return:
|
|
327
|
+
"""
|
|
328
|
+
return await self.edit_rule_state(rule_id, 1)
|
|
329
|
+
|
|
330
|
+
async def disable_rule(self, rule_id: str):
|
|
331
|
+
"""
|
|
332
|
+
禁用规则
|
|
333
|
+
:param rule_id:
|
|
334
|
+
:return:
|
|
335
|
+
"""
|
|
336
|
+
return await self.edit_rule_state(rule_id, 0)
|
|
337
|
+
|
|
338
|
+
async def batch_enable_rule(self, rule_id_list: list):
|
|
339
|
+
"""
|
|
340
|
+
批量启用规则
|
|
341
|
+
:param rule_id_list:
|
|
342
|
+
:return:
|
|
343
|
+
"""
|
|
344
|
+
await asyncio.gather(*[self.enable_rule(rule_id) for rule_id in rule_id_list])
|
|
345
|
+
|
|
346
|
+
async def batch_disable_rule(self, rule_id_list: list):
|
|
347
|
+
"""
|
|
348
|
+
批量禁用规则
|
|
349
|
+
:param rule_id_list:
|
|
350
|
+
:return:
|
|
351
|
+
"""
|
|
352
|
+
await asyncio.gather(*[self.disable_rule(rule_id) for rule_id in rule_id_list])
|
|
353
|
+
|
|
354
|
+
async def page_warehouse_product(self, query: WarehouseProductQuery) -> Page[WarehouseProduct]:
|
|
355
|
+
"""
|
|
356
|
+
分页查询仓库商品
|
|
357
|
+
:param query: 查询条件
|
|
358
|
+
:return:
|
|
359
|
+
"""
|
|
360
|
+
async with self.__sem:
|
|
361
|
+
page_warehouse_product_res = await self.__async_client.post("/warehouseProduct/pageList.htm",
|
|
362
|
+
data=query.model_dump(by_alias=True))
|
|
363
|
+
return Page(data=list_warehouse_product(page_warehouse_product_res.text),
|
|
364
|
+
**get_page_info(page_warehouse_product_res.text))
|
|
365
|
+
|
|
366
|
+
async def list_warehouse_product(self, query: WarehouseProductQuery) -> list[WarehouseProduct]:
|
|
367
|
+
"""
|
|
368
|
+
查询仓库商品
|
|
369
|
+
:param query:
|
|
370
|
+
:return:
|
|
371
|
+
"""
|
|
372
|
+
data = await self.page_warehouse_product(query)
|
|
373
|
+
total_page = data.total_page
|
|
374
|
+
result = data.data
|
|
375
|
+
for page_number in range(2, total_page + 1):
|
|
376
|
+
query.page_no = page_number
|
|
377
|
+
data = await self.page_warehouse_product(query)
|
|
378
|
+
result.extend(data.data)
|
|
379
|
+
return result
|
|
380
|
+
|
|
381
|
+
async def page_purchasing_all(self, query: PurchasingAllQuery):
|
|
382
|
+
"""
|
|
383
|
+
分页查询采购单
|
|
384
|
+
:return:
|
|
385
|
+
"""
|
|
386
|
+
async with self.__sem:
|
|
387
|
+
page_purchasing_all_pageList_res = await self.__async_client.post(
|
|
388
|
+
"/dxmPurchasingNote/purchasingAllPageList.htm",
|
|
389
|
+
data=query.model_dump(by_alias=True))
|
|
390
|
+
list_purchasing_all(page_purchasing_all_pageList_res.text)
|
|
391
|
+
|
|
392
|
+
async def __aenter__(self):
|
|
393
|
+
return self
|
|
394
|
+
|
|
395
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
396
|
+
await self.__async_client.aclose()
|
|
File without changes
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import TypedDict
|
|
3
|
+
|
|
4
|
+
from ey_commerce_lib.dxm.exception.common import PageInfoNotFoundException
|
|
5
|
+
from lxml import html
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PageInfo(TypedDict):
|
|
9
|
+
page_size: int
|
|
10
|
+
total_page: int
|
|
11
|
+
total_size: int
|
|
12
|
+
page_number: int
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_page_info(html_str: str) -> PageInfo:
|
|
16
|
+
"""
|
|
17
|
+
获取分页信息和分页数据
|
|
18
|
+
:return:
|
|
19
|
+
"""
|
|
20
|
+
tree = html.fromstring(html_str)
|
|
21
|
+
page_size_list = tree.xpath('//input[@id="pageSize"]/@value')
|
|
22
|
+
total_page_list = tree.xpath('//input[@id="totalPage"]/@value')
|
|
23
|
+
total_size_list = tree.xpath('//input[@id="totalSize"]/@value')
|
|
24
|
+
page_number_list = tree.xpath('//input[@id="pageNo"]/@value')
|
|
25
|
+
if len(page_size_list) == 0 or len(total_page_list) == 0:
|
|
26
|
+
raise PageInfoNotFoundException("分页信息获取失败")
|
|
27
|
+
return {
|
|
28
|
+
'page_size': int(page_size_list[0]),
|
|
29
|
+
'total_page': int(total_page_list[0]),
|
|
30
|
+
'total_size': int(total_size_list[0]),
|
|
31
|
+
'page_number': int(page_number_list[0])
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def __parse_js_vals(js_snippet: str) -> dict[str, int]:
|
|
36
|
+
"""
|
|
37
|
+
从一段包含 jQuery .val(...) 赋值语句的 JS 代码字符串中,
|
|
38
|
+
提取所有 id 和对应的数值,并返回一个 {id: int} 形式的字典。
|
|
39
|
+
|
|
40
|
+
参数
|
|
41
|
+
----
|
|
42
|
+
js_snippet : str
|
|
43
|
+
包含类似 `$('#pageNo').val('1');` 的 JavaScript 代码。
|
|
44
|
+
|
|
45
|
+
返回
|
|
46
|
+
----
|
|
47
|
+
Dict[str, int]
|
|
48
|
+
键是每个 .val() 前的 id(如 'pageNo'),值是对应的整数。
|
|
49
|
+
"""
|
|
50
|
+
pattern = r"\$\('#(?P<key>\w+)'\)\.val\('(?P<value>\d+)'\);"
|
|
51
|
+
matches = re.findall(pattern, js_snippet)
|
|
52
|
+
return {key: int(value) for key, value in matches}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_purchasing_page_info(html_str: str):
|
|
56
|
+
"""
|
|
57
|
+
获取分页信息和分页数据(店小秘->采购部分)
|
|
58
|
+
:param html_str:
|
|
59
|
+
:return:
|
|
60
|
+
"""
|
|
61
|
+
page_number = __parse_js_vals(html_str).get('pageNo')
|
|
62
|
+
page_size = __parse_js_vals(html_str).get('pageSize')
|
|
63
|
+
total_page = __parse_js_vals(html_str).get('totalPage')
|
|
64
|
+
total_size = __parse_js_vals(html_str).get('totalSize')
|
|
65
|
+
if page_number is None or page_size is None or total_page is None or total_size is None:
|
|
66
|
+
raise PageInfoNotFoundException("分页信息获取失败")
|
|
67
|
+
return {
|
|
68
|
+
'page_size': page_size,
|
|
69
|
+
'total_page': total_page,
|
|
70
|
+
'total_size': total_size,
|
|
71
|
+
'page_number': page_number
|
|
72
|
+
}
|