python-qlv-helper 0.2.0__py3-none-any.whl → 0.6.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.
- {python_qlv_helper-0.2.0.dist-info → python_qlv_helper-0.6.0.dist-info}/METADATA +3 -2
- {python_qlv_helper-0.2.0.dist-info → python_qlv_helper-0.6.0.dist-info}/RECORD +17 -14
- qlv_helper/config/__init__.py +11 -0
- qlv_helper/config/custom_exception.py +35 -0
- qlv_helper/config/url_const.py +13 -0
- qlv_helper/controller/order_detail.py +412 -4
- qlv_helper/controller/order_table.py +17 -1
- qlv_helper/http/order_page.py +143 -42
- qlv_helper/http/order_table_page.py +30 -4
- qlv_helper/po/domestic_activity_order_page.py +2 -4
- qlv_helper/po/login_page.py +1 -1
- qlv_helper/po/main_page.py +3 -4
- qlv_helper/po/order_detail_page.py +275 -0
- qlv_helper/po/wechat_auth_page.py +1 -1
- qlv_helper/po/base_po.py +0 -40
- {python_qlv_helper-0.2.0.dist-info → python_qlv_helper-0.6.0.dist-info}/WHEEL +0 -0
- {python_qlv_helper-0.2.0.dist-info → python_qlv_helper-0.6.0.dist-info}/licenses/LICENSE +0 -0
- {python_qlv_helper-0.2.0.dist-info → python_qlv_helper-0.6.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python_qlv_helper
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: qlv helper python package
|
|
5
5
|
Author-email: ckf10000 <ckf10000@sina.com>
|
|
6
6
|
License: Apache License
|
|
@@ -216,7 +216,8 @@ Requires-Dist: ddddocr==1.5.6; python_version >= "3.12" and platform_system == "
|
|
|
216
216
|
Requires-Dist: aiohttp==3.13.2; python_version >= "3.12"
|
|
217
217
|
Requires-Dist: beautifulsoup4==4.14.2; python_version >= "3.12"
|
|
218
218
|
Requires-Dist: airtest==1.3.6; python_version >= "3.12" and platform_system == "Windows"
|
|
219
|
-
Requires-Dist: python_http_helper
|
|
219
|
+
Requires-Dist: python_http_helper>=0.2.0; python_version >= "3.12"
|
|
220
|
+
Requires-Dist: python_playwright_helper>=0.2.9; python_version >= "3.12"
|
|
220
221
|
Dynamic: license-file
|
|
221
222
|
|
|
222
223
|
# qlv-helper
|
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
python_qlv_helper-0.
|
|
1
|
+
python_qlv_helper-0.6.0.dist-info/licenses/LICENSE,sha256=WtjCEwlcVzkh1ziO35P2qfVEkLjr87Flro7xlHz3CEY,11556
|
|
2
2
|
qlv_helper/__init__.py,sha256=5DCc5JhfdsgtIuFWgkxPOW5VVKZ8RPikQLGIuyZX6_Y,465
|
|
3
|
+
qlv_helper/config/__init__.py,sha256=0pKLgui-sC6yMNBBuuTTLkUGhPybiJQSTKTbi66alvg,465
|
|
4
|
+
qlv_helper/config/custom_exception.py,sha256=uYme0iseQt_dP-Y6-hZ_H2OA2OQR0Kp5PmmZvhEZlEc,805
|
|
5
|
+
qlv_helper/config/url_const.py,sha256=PbKKKH4heqP6SO186MTt-CEpf-Ix5ODlLQ2Aq2ZBZhU,537
|
|
3
6
|
qlv_helper/controller/__init__.py,sha256=cOJA0xMIytv17oICzPYqWLaSy-Ro2Ceeti0hHhsUj6Y,468
|
|
4
7
|
qlv_helper/controller/domestic_activity_order.py,sha256=MlmsDVsMBWq2h4Yjh1rhO372Z3p8tu2-4IZGP-nkfr8,1136
|
|
5
8
|
qlv_helper/controller/main_page.py,sha256=JtkB6BdKYHoNYZ4fkeALpSmAj-NAuiv1x6BvCcBtpic,1252
|
|
6
|
-
qlv_helper/controller/order_detail.py,sha256=
|
|
7
|
-
qlv_helper/controller/order_table.py,sha256=
|
|
9
|
+
qlv_helper/controller/order_detail.py,sha256=PjBS1YmiRzWaXg0brJef96k0-0uLr6oaEYz5zZzpjoo,22675
|
|
10
|
+
qlv_helper/controller/order_table.py,sha256=4AgA9EO0_GVuwnW3ltXPoN74U_6YpOqkRJVdeLb6L1o,6082
|
|
8
11
|
qlv_helper/controller/user_login.py,sha256=iyyDbOREsXtV5bqAFeXGwurvcCmDHmquh6ReWCfnOBE,5281
|
|
9
12
|
qlv_helper/http/__init__.py,sha256=yDh1xi_o7ohXqDAzLu62qCWIGk4_aD1dhnUaCon3klM,484
|
|
10
13
|
qlv_helper/http/main_page.py,sha256=LTpwrG8H_NqwCa3185irgcGd6JQkChAk7HQsDM-TNTI,1519
|
|
11
|
-
qlv_helper/http/order_page.py,sha256=
|
|
12
|
-
qlv_helper/http/order_table_page.py,sha256=
|
|
14
|
+
qlv_helper/http/order_page.py,sha256=uhCnRPvIvSg5ACMCfpw5_Z62iAAw-Dm-yDRloe5QBP8,16934
|
|
15
|
+
qlv_helper/http/order_table_page.py,sha256=IaXn5wjqPi1aRXHz0kucdHEdZswUWAZfECC13y57y8k,14440
|
|
13
16
|
qlv_helper/po/__init__.py,sha256=eDr06o0eYapBsYpOhA11bbxzs2F0dsuDjOKmxk_2HVE,480
|
|
14
|
-
qlv_helper/po/
|
|
15
|
-
qlv_helper/po/
|
|
16
|
-
qlv_helper/po/
|
|
17
|
-
qlv_helper/po/
|
|
18
|
-
qlv_helper/po/wechat_auth_page.py,sha256=
|
|
17
|
+
qlv_helper/po/domestic_activity_order_page.py,sha256=f-XSc2HD6GYisUJZwK2-u0Tr4W3B_vb5JpXvHnjfHOQ,5030
|
|
18
|
+
qlv_helper/po/login_page.py,sha256=HKGjS4WrkWnDdnh0JQAYxA3DyEWbInviQTna_KrP2FA,5960
|
|
19
|
+
qlv_helper/po/main_page.py,sha256=Hf8Wj7D9GitIj4HIi_zDHHIc5kasFQwraqEMZObYI7w,3320
|
|
20
|
+
qlv_helper/po/order_detail_page.py,sha256=zCB-pWyXdZz8vlDhvl1K79-bQ7C7Y12DiDSXlS_woYw,13681
|
|
21
|
+
qlv_helper/po/wechat_auth_page.py,sha256=a4YZlM5JOS0l3CNJm_oJFBhZY7AbNOpdIwilSjAO5bY,3171
|
|
19
22
|
qlv_helper/utils/__init__.py,sha256=rGzBkUf1tslG4WRPQjVWTVuwWG76pkckuKO_6K4sEus,465
|
|
20
23
|
qlv_helper/utils/browser_utils.py,sha256=mKoqSEz1vFrVemp9cgI4R5UhA4k7i0Cd9cWsIXJZ6E4,986
|
|
21
24
|
qlv_helper/utils/datetime_utils.py,sha256=BaDJKuH-yqc2NF9KYN66zUYUEJ9ZRHj09AV4-gILf3o,606
|
|
@@ -26,7 +29,7 @@ qlv_helper/utils/po_utils.py,sha256=SwQKL58HERGG2Weou_AwY_TQoYSvgi0gvaVCJBput_k,
|
|
|
26
29
|
qlv_helper/utils/stealth_browser.py,sha256=srNOYJOboYo30TvW5OP5TaVpg4jgHm9GxqmYnuwcUQU,3140
|
|
27
30
|
qlv_helper/utils/type_utils.py,sha256=S5FXUje2mbDuq27LU05WymxNu1VGOLBUV3tuqcx51dE,3792
|
|
28
31
|
qlv_helper/utils/windows_utils.py,sha256=Cvedsk1c2ujgPNVxszz8XWANkvEr8G9kne6povtZRU4,2866
|
|
29
|
-
python_qlv_helper-0.
|
|
30
|
-
python_qlv_helper-0.
|
|
31
|
-
python_qlv_helper-0.
|
|
32
|
-
python_qlv_helper-0.
|
|
32
|
+
python_qlv_helper-0.6.0.dist-info/METADATA,sha256=cG17GIsXVxDMdh92lqvgtJKpMI4Qn1dNjgtTrQbZMjc,14853
|
|
33
|
+
python_qlv_helper-0.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
34
|
+
python_qlv_helper-0.6.0.dist-info/top_level.txt,sha256=0pYdhD8SfBcC57LzLYGHY7cwwPqdqAkB1twysCJh5OA,11
|
|
35
|
+
python_qlv_helper-0.6.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
4
|
+
# ProjectName: qlv-helper
|
|
5
|
+
# FileName: __init__.py
|
|
6
|
+
# Description: 配置包
|
|
7
|
+
# Author: ASUS
|
|
8
|
+
# CreateDate: 2025/12/16
|
|
9
|
+
# Copyright ©2011-2025. Hunan xxxxxxx Company limited. All rights reserved.
|
|
10
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
11
|
+
"""
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
4
|
+
# ProjectName: qlv-helper
|
|
5
|
+
# FileName: custom_exception.py
|
|
6
|
+
# Description: 自定义异常模块
|
|
7
|
+
# Author: ASUS
|
|
8
|
+
# CreateDate: 2025/12/17
|
|
9
|
+
# Copyright ©2011-2025. Hunan xxxxxxx Company limited. All rights reserved.
|
|
10
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FirstPhaseException(Exception):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SecondPhaseException(Exception):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ThirdPhaseException(Exception):
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FourthPhaseException(Exception):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class FifthPhaseException(Exception):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class sixthPhaseException(Exception):
|
|
35
|
+
pass
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
4
|
+
# ProjectName: qlv-helper
|
|
5
|
+
# FileName: url_const.py
|
|
6
|
+
# Description: url配置常量
|
|
7
|
+
# Author: ASUS
|
|
8
|
+
# CreateDate: 2025/12/16
|
|
9
|
+
# Copyright ©2011-2025. Hunan xxxxxxx Company limited. All rights reserved.
|
|
10
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
order_detail_url = "/OrderProcessing/NewTicket_show/{}?&r={}"
|
|
@@ -10,13 +10,20 @@
|
|
|
10
10
|
# ---------------------------------------------------------------------------------------------------------
|
|
11
11
|
"""
|
|
12
12
|
import aiohttp
|
|
13
|
-
|
|
14
|
-
from
|
|
13
|
+
import asyncio
|
|
14
|
+
from logging import Logger
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
import qlv_helper.config.url_const as url_const
|
|
17
|
+
from typing import Dict, Any, List, cast, Optional
|
|
18
|
+
from qlv_helper.po.order_detail_page import OrderDetailPage
|
|
19
|
+
from qlv_helper.http.order_page import parser_order_info, get_order_page_html, parser_order_flight_table, \
|
|
20
|
+
fill_procurement_info_with_http
|
|
21
|
+
from playwright.async_api import Page, Locator, Error as PlaywrightError, TimeoutError as PlaywrightTimeoutError
|
|
15
22
|
|
|
16
23
|
|
|
17
24
|
async def get_order_info_with_http(
|
|
18
|
-
order_id: int, domain: str, protocol: str = "http", retry: int = 1, timeout: int = 5,
|
|
19
|
-
cookie_jar: Optional[aiohttp.CookieJar] = None, playwright_state: Dict[str, Any] = None
|
|
25
|
+
*, order_id: int, domain: str, protocol: str = "http", retry: int = 1, timeout: int = 5,
|
|
26
|
+
enable_log: bool = True, cookie_jar: Optional[aiohttp.CookieJar] = None, playwright_state: Dict[str, Any] = None
|
|
20
27
|
) -> Dict[str, Any]:
|
|
21
28
|
response = await get_order_page_html(
|
|
22
29
|
order_id=order_id, domain=domain, protocol=protocol, retry=retry, timeout=timeout, enable_log=enable_log,
|
|
@@ -33,3 +40,404 @@ async def get_order_info_with_http(
|
|
|
33
40
|
order_info["peoples"] = flight_info
|
|
34
41
|
response["data"] = order_info
|
|
35
42
|
return response
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
async def open_order_detail_page(
|
|
46
|
+
*, page: Page, logger: Logger, protocol: str, domain: str, order_id: int, timeout: float = 20.0
|
|
47
|
+
) -> OrderDetailPage:
|
|
48
|
+
url_prefix = f"{protocol}://{domain}"
|
|
49
|
+
current_dtstr: str = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
50
|
+
order_detail_url_suffix = url_const.order_detail_url.format(order_id, current_dtstr)
|
|
51
|
+
order_detail_url = url_prefix + order_detail_url_suffix
|
|
52
|
+
await page.goto(order_detail_url)
|
|
53
|
+
|
|
54
|
+
order_detail_po = OrderDetailPage(page=page, url=order_detail_url)
|
|
55
|
+
await order_detail_po.url_wait_for(url=order_detail_url, timeout=timeout)
|
|
56
|
+
logger.info(f"即将劲旅订单详情页面,页面URL<{order_detail_url}>")
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
confirm_btn = await order_detail_po.get_message_notice_dialog_confirm_btn(timeout=1)
|
|
60
|
+
await confirm_btn.click(button="left")
|
|
61
|
+
logger.info("订单详情页面,消息提醒弹框,【确认】按钮点击完成")
|
|
62
|
+
except (PlaywrightTimeoutError, PlaywrightError, RuntimeError, Exception):
|
|
63
|
+
pass
|
|
64
|
+
return order_detail_po
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def add_custom_remark(*, logger: Logger, page: OrderDetailPage, remark: str, timeout: float = 5.0) -> None:
|
|
68
|
+
# 1. 添加自定义备注
|
|
69
|
+
custom_remark_input = await page.get_custom_remark_input(timeout=timeout)
|
|
70
|
+
await custom_remark_input.fill(value=remark)
|
|
71
|
+
logger.info(f"订单详情页面,日志记录栏,自定义备注:{remark},输入完成")
|
|
72
|
+
|
|
73
|
+
# 2. 点击【保存备注】按钮
|
|
74
|
+
custom_remark_save_btn = await page.get_custom_remark_save_btn(timeout=timeout)
|
|
75
|
+
await custom_remark_save_btn.click(button="left")
|
|
76
|
+
logger.info(f"订单详情页面,日志记录栏,【保存备注】按钮点击完成")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
async def update_order_policy(
|
|
80
|
+
*, page: OrderDetailPage, logger: Logger, policy: str, order_id: int, timeout: float = 5.0
|
|
81
|
+
) -> None:
|
|
82
|
+
# 1. 修改政策代码
|
|
83
|
+
policy_input = await page.get_policy_input(timeout=timeout)
|
|
84
|
+
await policy_input.fill(value=policy)
|
|
85
|
+
|
|
86
|
+
# 2. 执行回车按键
|
|
87
|
+
await policy_input.press("Enter")
|
|
88
|
+
logger.info(f"订单<{order_id}>,政策代码已更新成<{policy}>完成")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
async def order_unlock(
|
|
92
|
+
*, logger: Logger, page: OrderDetailPage, remark: str, order_id: int, is_force: bool = False,
|
|
93
|
+
qlv_user_id: Optional[str] = None, timeout: float = 5.0
|
|
94
|
+
) -> None:
|
|
95
|
+
# 1. 获取订单操作锁的状态
|
|
96
|
+
lock_state, lock_btn = await page.get_order_lock_state_btn(timeout=timeout)
|
|
97
|
+
if "强制解锁" in lock_state:
|
|
98
|
+
if is_force is False:
|
|
99
|
+
raise EnvironmentError(f"被他人锁定,无需解锁处理")
|
|
100
|
+
await lock_btn.click(button="left")
|
|
101
|
+
logger.info(f"订单详情页面,用户操作【{lock_state}】按钮点击完成")
|
|
102
|
+
try:
|
|
103
|
+
confirm_btn = await page.get_message_notice_dialog_confirm_btn(timeout=1)
|
|
104
|
+
await confirm_btn.click(button="left")
|
|
105
|
+
logger.info("订单详情页面,强制解锁弹框确认,【确认】按钮点击完成")
|
|
106
|
+
await asyncio.sleep(2)
|
|
107
|
+
except (PlaywrightTimeoutError, PlaywrightError, RuntimeError, Exception):
|
|
108
|
+
pass
|
|
109
|
+
logger.warning(f"订单<{order_id}>,已被用户<{qlv_user_id or '无记录'}>强制解锁")
|
|
110
|
+
# 再次获取订单操作锁的状态
|
|
111
|
+
lock_state, lock_btn = await page.get_order_lock_state_btn(timeout=timeout)
|
|
112
|
+
elif "锁定" in lock_state:
|
|
113
|
+
logger.info(f"订单<{order_id}>,处于无锁状态,无需解锁处理")
|
|
114
|
+
return
|
|
115
|
+
elif "操作" in lock_state:
|
|
116
|
+
await lock_btn.click(button="left")
|
|
117
|
+
await asyncio.sleep(2)
|
|
118
|
+
lock_state_temp = lock_state
|
|
119
|
+
lock_state, lock_btn = await page.get_order_lock_state_btn(timeout=timeout)
|
|
120
|
+
logger.info(f"订单详情页面,日志记录栏,【{lock_state_temp}】按钮点击完成")
|
|
121
|
+
if remark:
|
|
122
|
+
# 2. 添加解锁备注
|
|
123
|
+
await add_custom_remark(logger=logger, page=page, remark=remark, timeout=timeout)
|
|
124
|
+
|
|
125
|
+
# 3. 点击【解锁返回】按钮
|
|
126
|
+
await lock_btn.click(button="left")
|
|
127
|
+
await asyncio.sleep(2)
|
|
128
|
+
logger.info(f"订单详情页面,日志记录栏,【{lock_state}】按钮点击完成")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
async def order_locked(
|
|
132
|
+
*, logger: Logger, page: OrderDetailPage, order_id: int, is_force: bool = False, timeout: float = 5.0,
|
|
133
|
+
qlv_user_id: Optional[str] = None
|
|
134
|
+
) -> None:
|
|
135
|
+
# 1. 获取订单操作锁的状态
|
|
136
|
+
lock_state, lock_btn = await page.get_order_lock_state_btn(timeout=timeout)
|
|
137
|
+
if "强制解锁" in lock_state:
|
|
138
|
+
if is_force is False:
|
|
139
|
+
raise EnvironmentError(f"被他人锁定,不做加锁处理")
|
|
140
|
+
await lock_btn.click(button="left")
|
|
141
|
+
logger.info(f"订单详情页面,用户操作【{lock_state}】按钮点击完成")
|
|
142
|
+
try:
|
|
143
|
+
confirm_btn = await page.get_message_notice_dialog_confirm_btn(timeout=1)
|
|
144
|
+
await confirm_btn.click(button="left")
|
|
145
|
+
logger.info("订单详情页面,强制解锁弹框确认,【确认】按钮点击完成")
|
|
146
|
+
await asyncio.sleep(2)
|
|
147
|
+
except (PlaywrightTimeoutError, PlaywrightError, RuntimeError, Exception):
|
|
148
|
+
pass
|
|
149
|
+
logger.warning(f"订单<{order_id}>,已被用户<{qlv_user_id or '无记录'}>强制解锁")
|
|
150
|
+
return
|
|
151
|
+
elif "解锁返回" in lock_state:
|
|
152
|
+
logger.warning(f"订单<{order_id}>,处于锁定状态,不做加锁处理")
|
|
153
|
+
return
|
|
154
|
+
# 2. 点击【锁定|操作】按钮
|
|
155
|
+
await lock_btn.click(button="left")
|
|
156
|
+
logger.info(f"订单详情页面,日志记录栏,【{lock_state}】按钮点击完成")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
async def first_open_page_order_locked(
|
|
160
|
+
*, logger: Logger, page: Page, protocol: str, domain: str, order_id: int, is_force: bool = False,
|
|
161
|
+
qlv_user_id: Optional[str] = None, timeout: float = 5.0, **kwargs
|
|
162
|
+
) -> OrderDetailPage:
|
|
163
|
+
# 1. 打开页面
|
|
164
|
+
order_detail_po = await open_order_detail_page(
|
|
165
|
+
page=page, logger=logger, protocol=protocol, domain=domain, order_id=order_id, timeout=timeout
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# 2. 锁定订单
|
|
169
|
+
await order_locked(
|
|
170
|
+
logger=logger, page=order_detail_po, order_id=order_id, timeout=timeout, is_force=is_force,
|
|
171
|
+
qlv_user_id=qlv_user_id
|
|
172
|
+
)
|
|
173
|
+
return order_detail_po
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
async def first_open_page_order_unlock(
|
|
177
|
+
*, logger: Logger, page: Page, protocol: str, domain: str, order_id: int, is_force: bool = False,
|
|
178
|
+
qlv_user_id: Optional[str] = None, timeout: float = 5.0, remark: Optional[str] = None, **kwargs
|
|
179
|
+
) -> OrderDetailPage:
|
|
180
|
+
# 1. 打开页面
|
|
181
|
+
order_detail_po = await open_order_detail_page(
|
|
182
|
+
page=page, logger=logger, protocol=protocol, domain=domain, order_id=order_id, timeout=timeout
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# 2. 解锁订单
|
|
186
|
+
await order_unlock(
|
|
187
|
+
logger=logger, page=order_detail_po, order_id=order_id, timeout=timeout, is_force=is_force,
|
|
188
|
+
qlv_user_id=qlv_user_id, remark=remark
|
|
189
|
+
)
|
|
190
|
+
return order_detail_po
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
async def fill_procurement_info(
|
|
194
|
+
*, logger: Logger, page: OrderDetailPage, order_id: int, out_ticket_platform_type: str, purchase_amount: float,
|
|
195
|
+
out_ticket_platform: str, out_ticket_account: str, purchase_account_type: str, purchase_account: str,
|
|
196
|
+
ceair_user_id: str, ceair_password: str, payment_id: str, platform_order_id: str, timeout: float = 5.0
|
|
197
|
+
) -> None:
|
|
198
|
+
# 1. 出票地类型选择【out_ticket_platform_type】
|
|
199
|
+
out_ticket_platform_type_dropdown = await page.get_out_ticket_platform_type_dropdown(timeout=timeout)
|
|
200
|
+
await out_ticket_platform_type_dropdown.select_option(label=out_ticket_platform_type)
|
|
201
|
+
# await out_ticket_platform_type_dropdown.click(button="left")
|
|
202
|
+
# out_ticket_platform_type_select_option = await page.get_out_ticket_platform_type_select_option(
|
|
203
|
+
# select_option=out_ticket_platform_type, timeout=timeout
|
|
204
|
+
# )
|
|
205
|
+
# await out_ticket_platform_type_select_option.click(button="left")
|
|
206
|
+
logger.info(f"订单详情页面,采购信息栏,出票地类型选择<{out_ticket_platform_type}>已完成")
|
|
207
|
+
await asyncio.sleep(1)
|
|
208
|
+
|
|
209
|
+
# 2. 出票平台选择【out_ticket_platform】
|
|
210
|
+
out_ticket_platform_dropdown = await page.get_out_ticket_platform_dropdown(timeout=timeout)
|
|
211
|
+
await out_ticket_platform_dropdown.select_option(label=out_ticket_platform)
|
|
212
|
+
# await out_ticket_platform_dropdown.click(button="left")
|
|
213
|
+
# out_ticket_platform_select_option = await page.get_out_ticket_platform_select_option(
|
|
214
|
+
# select_option=out_ticket_platform, timeout=timeout
|
|
215
|
+
# )
|
|
216
|
+
# await out_ticket_platform_select_option.click(button="left")
|
|
217
|
+
logger.info(f"订单详情页面,采购信息栏,出票平台选择<{out_ticket_platform}>已完成")
|
|
218
|
+
await asyncio.sleep(1)
|
|
219
|
+
|
|
220
|
+
# 3. 出票账号选择【out_ticket_account】
|
|
221
|
+
out_ticket_account_dropdown = await page.get_out_ticket_account_dropdown(timeout=timeout)
|
|
222
|
+
await out_ticket_account_dropdown.select_option(label=out_ticket_account)
|
|
223
|
+
# await out_ticket_account_dropdown.click(button="left")
|
|
224
|
+
# out_ticket_account_select_option = await page.get_out_ticket_account_select_option(
|
|
225
|
+
# select_option=out_ticket_account, timeout=timeout
|
|
226
|
+
# )
|
|
227
|
+
# await out_ticket_account_select_option.click(button="left")
|
|
228
|
+
logger.info(f"订单详情页面,采购信息栏,出票账号选择<{out_ticket_account}>已完成")
|
|
229
|
+
await asyncio.sleep(1)
|
|
230
|
+
|
|
231
|
+
# 4. 采购账号类型选择【purchase_account_type】
|
|
232
|
+
purchase_account_type_dropdown = await page.get_purchase_account_type_dropdown(timeout=timeout)
|
|
233
|
+
await purchase_account_type_dropdown.select_option(label=purchase_account_type)
|
|
234
|
+
# await purchase_account_type_dropdown.click(button="left")
|
|
235
|
+
# purchase_account_type_select_option = await page.get_purchase_account_type_select_option(
|
|
236
|
+
# select_option=purchase_account_type, timeout=timeout
|
|
237
|
+
# )
|
|
238
|
+
# await purchase_account_type_select_option.click(button="left")
|
|
239
|
+
logger.info(f"订单详情页面,采购信息栏,采购账号类型选择<{purchase_account_type}>已完成")
|
|
240
|
+
await asyncio.sleep(1)
|
|
241
|
+
|
|
242
|
+
# 5. 采购账号选择【purchase_account】
|
|
243
|
+
purchase_account_dropdown = await page.get_purchase_account_dropdown(timeout=timeout)
|
|
244
|
+
await purchase_account_dropdown.select_option(label=purchase_account)
|
|
245
|
+
# await purchase_account_dropdown.click(button="left")
|
|
246
|
+
# purchase_account_select_option = await page.get_purchase_account_select_option(
|
|
247
|
+
# select_option=purchase_account, timeout=timeout
|
|
248
|
+
# )
|
|
249
|
+
# await purchase_account_select_option.click(button="left")
|
|
250
|
+
logger.info(f"订单详情页面,采购信息栏,采购账号选择<{purchase_account}>已完成")
|
|
251
|
+
await asyncio.sleep(1)
|
|
252
|
+
|
|
253
|
+
# 6. 填写采购金额
|
|
254
|
+
purchase_amount_input = await page.get_purchase_amount_input(timeout=timeout)
|
|
255
|
+
await purchase_amount_input.fill(value=str(purchase_amount))
|
|
256
|
+
logger.info(f"订单详情页面,采购信息栏,采购金额<{purchase_amount}>输入完成")
|
|
257
|
+
|
|
258
|
+
# 7. 填写备注
|
|
259
|
+
remark_input = await page.get_remark_input(timeout=timeout)
|
|
260
|
+
value = f"{ceair_user_id}/{ceair_password}"
|
|
261
|
+
await remark_input.fill(value=value)
|
|
262
|
+
logger.info(f"订单详情页面,采购信息栏,备注<{value}>输入完成")
|
|
263
|
+
|
|
264
|
+
# 8. 填写对账标识
|
|
265
|
+
main_check_input = await page.get_main_check_input(timeout=timeout)
|
|
266
|
+
await main_check_input.fill(value=payment_id)
|
|
267
|
+
logger.info(f"订单详情页面,采购信息栏,对账标识<{payment_id}>输入完成")
|
|
268
|
+
|
|
269
|
+
# 9. 填写官网订单号
|
|
270
|
+
air_comp_order_id_input = await page.get_air_comp_order_id_input(timeout=timeout)
|
|
271
|
+
await air_comp_order_id_input.fill(value=platform_order_id)
|
|
272
|
+
logger.info(f"订单详情页面,采购信息栏,官网订单号<{platform_order_id}>输入完成")
|
|
273
|
+
|
|
274
|
+
# 10. 点击【保存采购】按钮
|
|
275
|
+
procurement_info_save_btn = await page.get_procurement_info_save_btn(timeout=timeout)
|
|
276
|
+
await procurement_info_save_btn.click(button="left")
|
|
277
|
+
logger.info(f"订单详情页面,采购信息栏,【保存采购】按钮点击完成")
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
async def first_open_page_fill_procurement_info(
|
|
281
|
+
*, logger: Logger, page: Page, order_id: int, protocol: str, domain: str, out_ticket_platform_type: str,
|
|
282
|
+
purchase_amount: float, out_ticket_platform: str, out_ticket_account: str, purchase_account_type: str,
|
|
283
|
+
purchase_account: str, ceair_user_id: str, ceair_password: str, payment_id: str, platform_order_id: str,
|
|
284
|
+
is_force: bool = False, qlv_user_id: Optional[str] = None, timeout: float = 5.0, **kwargs: Any
|
|
285
|
+
) -> OrderDetailPage:
|
|
286
|
+
# 1. 打开页面
|
|
287
|
+
order_detail_po = await open_order_detail_page(
|
|
288
|
+
page=page, logger=logger, protocol=protocol, domain=domain, order_id=order_id, timeout=timeout
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# 2. 锁定订单
|
|
292
|
+
await order_locked(
|
|
293
|
+
logger=logger, page=order_detail_po, order_id=order_id, is_force=is_force, timeout=timeout,
|
|
294
|
+
qlv_user_id=qlv_user_id
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# 3. 回填采购信息
|
|
298
|
+
await fill_procurement_info(
|
|
299
|
+
out_ticket_platform_type=out_ticket_platform_type, out_ticket_account=out_ticket_account, payment_id=payment_id,
|
|
300
|
+
purchase_amount=purchase_amount, out_ticket_platform=out_ticket_platform, purchase_account=purchase_account,
|
|
301
|
+
purchase_account_type=purchase_account_type, ceair_user_id=ceair_user_id, ceair_password=ceair_password,
|
|
302
|
+
platform_order_id=platform_order_id, timeout=timeout, logger=logger, page=order_detail_po, order_id=order_id
|
|
303
|
+
)
|
|
304
|
+
return order_detail_po
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
async def fill_itinerary(
|
|
308
|
+
*, logger: Logger, page: OrderDetailPage, order_id: int, passengers_itinerary: Dict[str, Any],
|
|
309
|
+
timeout: float = 5.0
|
|
310
|
+
) -> None:
|
|
311
|
+
# 1. 获取订单操作锁的状态
|
|
312
|
+
passenger_itinerary_locators: List[Dict[str, Any]] = await page.get_passenger_itinerary_locators(timeout=timeout)
|
|
313
|
+
if not passenger_itinerary_locators:
|
|
314
|
+
logger.warning(f"订单<{order_id}>,没有需要填写票号的乘客,直接跳过")
|
|
315
|
+
return
|
|
316
|
+
current_passengers = set([x.get("username") for x in passenger_itinerary_locators])
|
|
317
|
+
kwargs_passengers = set(passengers_itinerary.keys())
|
|
318
|
+
diff = kwargs_passengers.difference(current_passengers)
|
|
319
|
+
if diff:
|
|
320
|
+
raise RuntimeError(
|
|
321
|
+
f"传递回填票号的乘客证件信息<{kwargs_passengers}>与订单实际乘客信息<{current_passengers}>不一致"
|
|
322
|
+
)
|
|
323
|
+
passenger_itinerary_locator = cast(Locator, None)
|
|
324
|
+
for passenger_locator in passenger_itinerary_locators:
|
|
325
|
+
current_passenger = passenger_locator.get("username")
|
|
326
|
+
passenger_itinerary = passengers_itinerary.get(current_passenger)
|
|
327
|
+
if passenger_itinerary:
|
|
328
|
+
passenger_itinerary_locator: Locator = passenger_locator.get("locator")
|
|
329
|
+
await passenger_itinerary_locator.fill(value=passenger_itinerary)
|
|
330
|
+
logger.info(f"订单<{order_id}>,乘客<{current_passenger}>的票号<{passenger_itinerary}>填写完成")
|
|
331
|
+
else:
|
|
332
|
+
logger.warning(f"订单<{order_id}>,乘客<{current_passenger}>的票号没有获取到,本次回填跳过,等待下一次")
|
|
333
|
+
if passenger_itinerary_locator:
|
|
334
|
+
await passenger_itinerary_locator.press("Enter")
|
|
335
|
+
logger.info(f"订单<{order_id}>,本次的票号回填完成")
|
|
336
|
+
else:
|
|
337
|
+
raise RuntimeError(f"回填票号过程异常,回填失败")
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
async def first_open_page_fill_itinerary(
|
|
341
|
+
*, page: Page, logger: Logger, protocol: str, domain: str, order_id: int,
|
|
342
|
+
passengers_itinerary: Dict[str, Any], timeout: float = 20.0, **kwargs: Any
|
|
343
|
+
) -> OrderDetailPage:
|
|
344
|
+
# 1. 开发页面
|
|
345
|
+
order_detail_po = await open_order_detail_page(
|
|
346
|
+
page=page, logger=logger, protocol=protocol, domain=domain, order_id=order_id, timeout=timeout
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
# 2. 回填票号
|
|
350
|
+
await fill_itinerary(
|
|
351
|
+
logger=logger, page=order_detail_po, order_id=order_id, timeout=timeout,
|
|
352
|
+
passengers_itinerary=passengers_itinerary
|
|
353
|
+
)
|
|
354
|
+
logger.info(f"订单<{order_id}>,票号回填流程结束")
|
|
355
|
+
await order_unlock(logger=logger, page=order_detail_po, order_id=order_id, timeout=timeout, remark="")
|
|
356
|
+
logger.info(f"订单<{order_id}>,订单解锁成功")
|
|
357
|
+
return order_detail_po
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
async def first_open_page_update_policy(
|
|
361
|
+
*, page: Page, logger: Logger, protocol: str, domain: str, order_id: int, policy: str, timeout: float = 20.0,
|
|
362
|
+
**kwargs: Any
|
|
363
|
+
) -> OrderDetailPage:
|
|
364
|
+
# 1. 打开页面
|
|
365
|
+
order_detail_po = await open_order_detail_page(
|
|
366
|
+
page=page, logger=logger, protocol=protocol, domain=domain, order_id=order_id, timeout=timeout
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
# 2. 更新订单政策代码
|
|
370
|
+
await update_order_policy(
|
|
371
|
+
logger=logger, page=order_detail_po, order_id=order_id, timeout=timeout, policy=policy
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
return order_detail_po
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
async def first_open_page_my_order_unlock(
|
|
378
|
+
*, page: Page, logger: Logger, protocol: str, domain: str, order_id: int, qlv_user_id: str,
|
|
379
|
+
policy: Optional[str] = None, remark: Optional[str] = None, timeout: float = 20.0, is_force: bool = False,
|
|
380
|
+
**kwargs: Any
|
|
381
|
+
) -> OrderDetailPage:
|
|
382
|
+
# 1. 打开页面
|
|
383
|
+
order_detail_po = await open_order_detail_page(
|
|
384
|
+
page=page, logger=logger, protocol=protocol, domain=domain, order_id=order_id, timeout=timeout
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
if policy:
|
|
388
|
+
# 2. 更新订单政策代码
|
|
389
|
+
await update_order_policy(
|
|
390
|
+
logger=logger, page=order_detail_po, order_id=order_id, timeout=timeout, policy=policy
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
if remark:
|
|
394
|
+
# 3. 添加解锁备注
|
|
395
|
+
await add_custom_remark(logger=logger, page=order_detail_po, remark=remark, timeout=timeout)
|
|
396
|
+
|
|
397
|
+
# 4. 获取订单操作锁的状态
|
|
398
|
+
lock_state, lock_btn = await order_detail_po.get_order_lock_state_btn(timeout=timeout)
|
|
399
|
+
if "强制解锁" in lock_state:
|
|
400
|
+
if is_force is False:
|
|
401
|
+
logger.warning(f"订单<{order_id}>,非本账号<{qlv_user_id}>的锁单,暂不处理,即将跳过")
|
|
402
|
+
return order_detail_po
|
|
403
|
+
await lock_btn.click(button="left")
|
|
404
|
+
logger.info(f"订单详情页面,用户操作【{lock_state}】按钮点击完成")
|
|
405
|
+
try:
|
|
406
|
+
confirm_btn = await order_detail_po.get_message_notice_dialog_confirm_btn(timeout=1)
|
|
407
|
+
await confirm_btn.click(button="left")
|
|
408
|
+
logger.info("订单详情页面,强制解锁弹框确认,【确认】按钮点击完成")
|
|
409
|
+
await asyncio.sleep(2)
|
|
410
|
+
except (PlaywrightTimeoutError, PlaywrightError, RuntimeError, Exception):
|
|
411
|
+
pass
|
|
412
|
+
logger.warning(f"订单<{order_id}>,已被用户<{qlv_user_id or '无记录'}>强制解锁")
|
|
413
|
+
# 再次获取订单操作锁的状态
|
|
414
|
+
lock_state, lock_btn = await order_detail_po.get_order_lock_state_btn(timeout=timeout)
|
|
415
|
+
elif "锁定" in lock_state:
|
|
416
|
+
logger.info(f"订单<{order_id}>,处于无锁状态,无需解锁处理")
|
|
417
|
+
return order_detail_po
|
|
418
|
+
elif "操作" in lock_state:
|
|
419
|
+
await lock_btn.click(button="left")
|
|
420
|
+
await asyncio.sleep(2)
|
|
421
|
+
lock_state_temp = lock_state
|
|
422
|
+
lock_state, lock_btn = await order_detail_po.get_order_lock_state_btn(timeout=timeout)
|
|
423
|
+
logger.info(f"订单详情页面,日志记录栏,【{lock_state_temp}】按钮点击完成")
|
|
424
|
+
|
|
425
|
+
# 5. 点击【解锁返回】按钮
|
|
426
|
+
await lock_btn.click(button="left")
|
|
427
|
+
await asyncio.sleep(2)
|
|
428
|
+
logger.info(f"订单详情页面,日志记录栏,【{lock_state}】按钮点击完成")
|
|
429
|
+
return order_detail_po
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
async def fill_procurement_with_http(
|
|
433
|
+
*, order_id: int, qlv_domain: str, amount: float, pre_order_id: str, platform_user_id: str, user_password: str,
|
|
434
|
+
passengers: List[str], fids: str, pids: List[str], transaction_id: str, qlv_protocol: str = "http",
|
|
435
|
+
retry: int = 1, timeout: int = 5, enable_log: bool = True, cookie_jar: Optional[aiohttp.CookieJar] = None,
|
|
436
|
+
playwright_state: Dict[str, Any] = None, data_list: Optional[List[Dict[str, Any]]] = None
|
|
437
|
+
) -> Dict[str, Any]:
|
|
438
|
+
return await fill_procurement_info_with_http(
|
|
439
|
+
order_id=order_id, qlv_domain=qlv_domain, amount=amount, pre_order_id=pre_order_id,
|
|
440
|
+
platform_user_id=platform_user_id, user_password=user_password, passengers=passengers, fids=fids, pids=pids,
|
|
441
|
+
transaction_id=transaction_id, qlv_protocol=qlv_protocol, retry=retry, timeout=timeout, enable_log=enable_log,
|
|
442
|
+
cookie_jar=cookie_jar, playwright_state=playwright_state, data_list=data_list
|
|
443
|
+
)
|
|
@@ -15,7 +15,7 @@ from typing import Optional, Dict, Any, Callable, List
|
|
|
15
15
|
from http_helper.client.async_proxy import HttpClientFactory
|
|
16
16
|
from qlv_helper.utils.html_utils import parse_pagination_info
|
|
17
17
|
from qlv_helper.http.order_table_page import get_domestic_activity_order_page_html, get_domestic_ticket_outed_page_html, \
|
|
18
|
-
parse_order_table
|
|
18
|
+
parse_order_table, get_domestic_unticketed_order_page_html
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
async def _get_paginated_order_table(
|
|
@@ -143,3 +143,19 @@ async def get_domestic_ticket_outed_table(
|
|
|
143
143
|
table_state="completed",
|
|
144
144
|
fetch_page_fn=get_domestic_ticket_outed_page_html
|
|
145
145
|
)
|
|
146
|
+
|
|
147
|
+
async def get_domestic_unticketed_order_table(
|
|
148
|
+
domain: str, protocol: str = "http", retry: int = 1, timeout: int = 5, enable_log: bool = True,
|
|
149
|
+
cookie_jar: Optional[CookieJar] = None, playwright_state: Dict[str, Any] = None
|
|
150
|
+
) -> Dict[str, Any]:
|
|
151
|
+
return await _get_paginated_order_table(
|
|
152
|
+
domain=domain,
|
|
153
|
+
protocol=protocol,
|
|
154
|
+
retry=retry,
|
|
155
|
+
timeout=timeout,
|
|
156
|
+
enable_log=enable_log,
|
|
157
|
+
cookie_jar=cookie_jar,
|
|
158
|
+
playwright_state=playwright_state,
|
|
159
|
+
table_state="proccessing",
|
|
160
|
+
fetch_page_fn=get_domestic_unticketed_order_page_html
|
|
161
|
+
)
|