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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python_qlv_helper
3
- Version: 0.2.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==0.1.4; python_version >= "3.12"
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.2.0.dist-info/licenses/LICENSE,sha256=WtjCEwlcVzkh1ziO35P2qfVEkLjr87Flro7xlHz3CEY,11556
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=F6KxZrupitF4EzykHLXxncT1ikmmP89O17E5oCn1XsY,1527
7
- qlv_helper/controller/order_table.py,sha256=rMqdyXrJbbqZmjvOYK1Ot09tR937m-0INU2rgzizjhU,5417
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=VcoDoEPz3R0zHmKNRuRv2vDHkC3XS_bXhBE_uW9wEYw,11852
12
- qlv_helper/http/order_table_page.py,sha256=qDmQXkLcuTkLGPSURGzBKnhirjE8M1Ma9ibehg-mAkk,13135
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/base_po.py,sha256=_Cym-vsrB1kjZeCkKzOj1BYC8pTR-nKlGDj7QaUiLBs,1362
15
- qlv_helper/po/domestic_activity_order_page.py,sha256=ySOrC1Rdc2ApL0FCRwf8xDKQrzTY63OxDC3EHPauvcA,5088
16
- qlv_helper/po/login_page.py,sha256=XcBSvOC_wQ4pInv6w_tDe6iB2UuNG-UUTpUS-mgwUEo,5951
17
- qlv_helper/po/main_page.py,sha256=x4ZJqWdxL6nQdQXDIZB87uDVXfLKs9FIAe0AQqaQO3M,3323
18
- qlv_helper/po/wechat_auth_page.py,sha256=SfZQn_mmfquf7srDs-rPRWKjaDWN7Xtsauk9AnLMMJs,3162
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.2.0.dist-info/METADATA,sha256=irKOAys7QdoUtxIoR1vxZnPT-yiD3zi4k_yF2-CDtf4,14779
30
- python_qlv_helper-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
- python_qlv_helper-0.2.0.dist-info/top_level.txt,sha256=0pYdhD8SfBcC57LzLYGHY7cwwPqdqAkB1twysCJh5OA,11
32
- python_qlv_helper-0.2.0.dist-info/RECORD,,
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
- from typing import Dict, Any, Optional
14
- from qlv_helper.http.order_page import parser_order_info, get_order_page_html, parser_order_flight_table
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, enable_log: bool = True,
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
+ )