python-qlv-helper 0.5.7__py3-none-any.whl → 0.7.2__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.5.7
3
+ Version: 0.7.2
4
4
  Summary: qlv helper python package
5
5
  Author-email: ckf10000 <ckf10000@sina.com>
6
6
  License: Apache License
@@ -210,14 +210,16 @@ Project-URL: Issues, https://github.com/ckf10000/qlv-helper/issues
210
210
  Requires-Python: >=3.12
211
211
  Description-Content-Type: text/markdown
212
212
  License-File: LICENSE
213
- Requires-Dist: playwright==1.56.0; python_version >= "3.12" and platform_system == "Windows"
214
- Requires-Dist: playwright-stealth==2.0.0; python_version >= "3.12" and platform_system == "Windows"
215
- Requires-Dist: ddddocr==1.5.6; python_version >= "3.12" and platform_system == "Windows"
213
+ Requires-Dist: playwright==1.56.0; python_version >= "3.12"
214
+ Requires-Dist: playwright-stealth==2.0.0; python_version >= "3.12"
215
+ Requires-Dist: ddddocr==1.5.6; python_version >= "3.12"
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
- Requires-Dist: airtest==1.3.6; python_version >= "3.12" and platform_system == "Windows"
218
+ Requires-Dist: airtest==1.3.6; python_version >= "3.12"
219
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
+ Requires-Dist: python_playwright_helper>=0.3.0; python_version >= "3.12"
221
+ Requires-Dist: python_ocr_helper>=0.0.1; python_version >= "3.12"
222
+ Requires-Dist: flight_helper>=0.2.9
221
223
  Dynamic: license-file
222
224
 
223
225
  # qlv-helper
@@ -1,35 +1,36 @@
1
- python_qlv_helper-0.5.7.dist-info/licenses/LICENSE,sha256=WtjCEwlcVzkh1ziO35P2qfVEkLjr87Flro7xlHz3CEY,11556
1
+ python_qlv_helper-0.7.2.dist-info/licenses/LICENSE,sha256=WtjCEwlcVzkh1ziO35P2qfVEkLjr87Flro7xlHz3CEY,11556
2
2
  qlv_helper/__init__.py,sha256=5DCc5JhfdsgtIuFWgkxPOW5VVKZ8RPikQLGIuyZX6_Y,465
3
3
  qlv_helper/config/__init__.py,sha256=0pKLgui-sC6yMNBBuuTTLkUGhPybiJQSTKTbi66alvg,465
4
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
5
+ qlv_helper/config/url_const.py,sha256=EoLHOtlO3Ob2WSMMv6TBrl7eJCfJCB844dwmD_k86BM,630
6
6
  qlv_helper/controller/__init__.py,sha256=cOJA0xMIytv17oICzPYqWLaSy-Ro2Ceeti0hHhsUj6Y,468
7
7
  qlv_helper/controller/domestic_activity_order.py,sha256=MlmsDVsMBWq2h4Yjh1rhO372Z3p8tu2-4IZGP-nkfr8,1136
8
- qlv_helper/controller/main_page.py,sha256=JtkB6BdKYHoNYZ4fkeALpSmAj-NAuiv1x6BvCcBtpic,1252
9
- qlv_helper/controller/order_detail.py,sha256=tOV80nrL8YDVNjvKi8YQP0hWqAcd8M1J0ToRK5YLWZ0,21701
10
- qlv_helper/controller/order_table.py,sha256=4AgA9EO0_GVuwnW3ltXPoN74U_6YpOqkRJVdeLb6L1o,6082
11
- qlv_helper/controller/user_login.py,sha256=iyyDbOREsXtV5bqAFeXGwurvcCmDHmquh6ReWCfnOBE,5281
8
+ qlv_helper/controller/main_page.py,sha256=p_-nXAIptNrx1SUgma7oPB-cqFFHYdCNvXCfsesIQFc,1855
9
+ qlv_helper/controller/order_detail.py,sha256=pdxN6ahsoeJq2XqBNRUwLrGG12WSy737fU17fhJMjgg,25621
10
+ qlv_helper/controller/order_table.py,sha256=unLL1xMKK1xvm_iewpdMcUPZc6AcBcLq0hAGXAdjdhU,15373
11
+ qlv_helper/controller/user_login.py,sha256=oXO1otTGuK3_r07fKdncQE3Is2w-kiI-mWmJyFvsVyE,5915
12
+ qlv_helper/controller/wechat_login.py,sha256=0u9H6tJiQO28nT5AG2Ot7EWFmpBqFJD_9dd12snsJIQ,2196
12
13
  qlv_helper/http/__init__.py,sha256=yDh1xi_o7ohXqDAzLu62qCWIGk4_aD1dhnUaCon3klM,484
13
14
  qlv_helper/http/main_page.py,sha256=LTpwrG8H_NqwCa3185irgcGd6JQkChAk7HQsDM-TNTI,1519
14
- qlv_helper/http/order_page.py,sha256=zIUZk1UiinoLQ4Y-Qwcv0ZmNAXtYoOGOYDdwdoA0RBI,13157
15
+ qlv_helper/http/order_page.py,sha256=Sti3dxZIN1U9z0e7NwyJ6_TrNdI-N3mRFnUN8WpN3FM,21674
15
16
  qlv_helper/http/order_table_page.py,sha256=IaXn5wjqPi1aRXHz0kucdHEdZswUWAZfECC13y57y8k,14440
16
17
  qlv_helper/po/__init__.py,sha256=eDr06o0eYapBsYpOhA11bbxzs2F0dsuDjOKmxk_2HVE,480
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
18
+ qlv_helper/po/domestic_activity_order_page.py,sha256=El63U0GI2PU9WGIkGxPgCE1Fp1yCsw2v1H6cZhSaG4c,8509
19
+ qlv_helper/po/login_page.py,sha256=JbapNFwGCei3K3mpfhte1TVNeqzG7yHsCtp5KiKv_6g,4271
20
+ qlv_helper/po/main_page.py,sha256=0_tqZILZnLS6y3chg9ERTHDtg86pW0aIQ1vNuPFLVG8,1752
21
+ qlv_helper/po/order_detail_page.py,sha256=0Xyi9zxnSHv4OfFAlPPz_D0S5S0ZHKLphUUT8R4svzk,14414
21
22
  qlv_helper/po/wechat_auth_page.py,sha256=a4YZlM5JOS0l3CNJm_oJFBhZY7AbNOpdIwilSjAO5bY,3171
22
23
  qlv_helper/utils/__init__.py,sha256=rGzBkUf1tslG4WRPQjVWTVuwWG76pkckuKO_6K4sEus,465
23
24
  qlv_helper/utils/browser_utils.py,sha256=mKoqSEz1vFrVemp9cgI4R5UhA4k7i0Cd9cWsIXJZ6E4,986
24
25
  qlv_helper/utils/datetime_utils.py,sha256=BaDJKuH-yqc2NF9KYN66zUYUEJ9ZRHj09AV4-gILf3o,606
25
26
  qlv_helper/utils/file_handle.py,sha256=_dJ9Yk8esttJYsjdBMZAkjZTDQh5QYVPXjLRRyWUMh0,1087
26
27
  qlv_helper/utils/html_utils.py,sha256=i5oOFYETH3kDS9-rSyGu1SHFTkfZvAPPQ4za76BCdVA,1962
27
- qlv_helper/utils/ocr_helper.py,sha256=IrS4iPTm1SXnVpbHKMowQA2w1bvI0fUVRqEAbmwnjws,2781
28
+ qlv_helper/utils/ocr_helper.py,sha256=vpIokr07Utmpsb78MHF83UcXL90A8BPbLgjMg4kONyA,3343
28
29
  qlv_helper/utils/po_utils.py,sha256=SwQKL58HERGG2Weou_AwY_TQoYSvgi0gvaVCJBput_k,3516
29
30
  qlv_helper/utils/stealth_browser.py,sha256=srNOYJOboYo30TvW5OP5TaVpg4jgHm9GxqmYnuwcUQU,3140
30
31
  qlv_helper/utils/type_utils.py,sha256=S5FXUje2mbDuq27LU05WymxNu1VGOLBUV3tuqcx51dE,3792
31
32
  qlv_helper/utils/windows_utils.py,sha256=Cvedsk1c2ujgPNVxszz8XWANkvEr8G9kne6povtZRU4,2866
32
- python_qlv_helper-0.5.7.dist-info/METADATA,sha256=QcI93-dpNseb9ie1ciSpmZu2GMC45SVG--lmaK8ZkJ8,14853
33
- python_qlv_helper-0.5.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
- python_qlv_helper-0.5.7.dist-info/top_level.txt,sha256=0pYdhD8SfBcC57LzLYGHY7cwwPqdqAkB1twysCJh5OA,11
35
- python_qlv_helper-0.5.7.dist-info/RECORD,,
33
+ python_qlv_helper-0.7.2.dist-info/METADATA,sha256=LuxKTcs6bOcTbrthW-Q3N35aT9nF7sTKDDZS0uae9bQ,14825
34
+ python_qlv_helper-0.7.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
+ python_qlv_helper-0.7.2.dist-info/top_level.txt,sha256=0pYdhD8SfBcC57LzLYGHY7cwwPqdqAkB1twysCJh5OA,11
36
+ python_qlv_helper-0.7.2.dist-info/RECORD,,
@@ -11,3 +11,5 @@
11
11
  """
12
12
 
13
13
  order_detail_url = "/OrderProcessing/NewTicket_show/{}?&r={}"
14
+ domestic_activity_order_url = "/OrderList/GuoNei_ActivityOrders"
15
+ login_url = "/Home/Login"
@@ -10,13 +10,29 @@
10
10
  # ---------------------------------------------------------------------------------------------------------
11
11
  """
12
12
  import aiohttp
13
+ from logging import Logger
14
+ from playwright.async_api import Page
13
15
  from typing import Dict, Any, Optional
16
+ from qlv_helper.po.main_page import MainPage
14
17
  from qlv_helper.http.main_page import get_main_page_html, parser_head_title
15
18
 
16
19
 
20
+ async def open_main_page(
21
+ *, page: Page, logger: Logger, qlv_protocol: str, qlv_domain: str, timeout: float = 60.0, **kwargs: Any
22
+ ) -> MainPage:
23
+ url_prefix = f"{qlv_protocol}://{qlv_domain}"
24
+ main_url = url_prefix + "/"
25
+ await page.goto(main_url)
26
+
27
+ main_po = MainPage(page=page, url=main_url)
28
+ await main_po.url_wait_for(url=main_url, timeout=timeout)
29
+ logger.info(f"即将进入首页,页面URL<{main_url}>")
30
+ return main_po
31
+
32
+
17
33
  async def get_main_info_with_http(
18
34
  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
35
+ cookie_jar: Optional[aiohttp.CookieJar] = None, playwright_state: Dict[str, Any] = None, **kwargs: Any
20
36
  ) -> Dict[str, Any]:
21
37
  response = await get_main_page_html(
22
38
  domain=domain, protocol=protocol, retry=retry, timeout=timeout, enable_log=enable_log,
@@ -27,4 +43,4 @@ async def get_main_info_with_http(
27
43
 
28
44
  html = response.get("data")
29
45
  response["message"] = parser_head_title(html=html)
30
- return response
46
+ return response
@@ -16,7 +16,9 @@ from datetime import datetime
16
16
  import qlv_helper.config.url_const as url_const
17
17
  from typing import Dict, Any, List, cast, Optional
18
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
19
+ from flight_helper.models.dto.procurement import FillProcurementInputDTO
20
+ from qlv_helper.http.order_page import parser_order_info, get_order_page_html, parser_order_flight_table, \
21
+ fill_procurement_info_with_http, fill_itinerary_info_with_http, fill_procurement_dto_with_http
20
22
  from playwright.async_api import Page, Locator, Error as PlaywrightError, TimeoutError as PlaywrightTimeoutError
21
23
 
22
24
 
@@ -95,7 +97,7 @@ async def order_unlock(
95
97
  lock_state, lock_btn = await page.get_order_lock_state_btn(timeout=timeout)
96
98
  if "强制解锁" in lock_state:
97
99
  if is_force is False:
98
- raise EnvironmentError(f"订单<{order_id}>,被他人锁定,无需解锁处理")
100
+ raise EnvironmentError(f"被他人锁定,无需解锁处理")
99
101
  await lock_btn.click(button="left")
100
102
  logger.info(f"订单详情页面,用户操作【{lock_state}】按钮点击完成")
101
103
  try:
@@ -135,7 +137,7 @@ async def order_locked(
135
137
  lock_state, lock_btn = await page.get_order_lock_state_btn(timeout=timeout)
136
138
  if "强制解锁" in lock_state:
137
139
  if is_force is False:
138
- raise EnvironmentError(f"订单<{order_id}>,被他人锁定,不做加锁处理")
140
+ raise EnvironmentError(f"被他人锁定,不做加锁处理")
139
141
  await lock_btn.click(button="left")
140
142
  logger.info(f"订单详情页面,用户操作【{lock_state}】按钮点击完成")
141
143
  try:
@@ -317,7 +319,7 @@ async def fill_itinerary(
317
319
  diff = kwargs_passengers.difference(current_passengers)
318
320
  if diff:
319
321
  raise RuntimeError(
320
- f"订单<{order_id}>,传递回填票号的乘客证件信息<{kwargs_passengers}>与订单实际乘客信息<{current_passengers}>不一致"
322
+ f"传递回填票号的乘客证件信息<{kwargs_passengers}>与订单实际乘客信息<{current_passengers}>不一致"
321
323
  )
322
324
  passenger_itinerary_locator = cast(Locator, None)
323
325
  for passenger_locator in passenger_itinerary_locators:
@@ -333,7 +335,7 @@ async def fill_itinerary(
333
335
  await passenger_itinerary_locator.press("Enter")
334
336
  logger.info(f"订单<{order_id}>,本次的票号回填完成")
335
337
  else:
336
- raise RuntimeError(f"订单<{order_id}>,回填票号过程异常,回填失败")
338
+ raise RuntimeError(f"回填票号过程异常,回填失败")
337
339
 
338
340
 
339
341
  async def first_open_page_fill_itinerary(
@@ -413,6 +415,7 @@ async def first_open_page_my_order_unlock(
413
415
  lock_state, lock_btn = await order_detail_po.get_order_lock_state_btn(timeout=timeout)
414
416
  elif "锁定" in lock_state:
415
417
  logger.info(f"订单<{order_id}>,处于无锁状态,无需解锁处理")
418
+ return order_detail_po
416
419
  elif "操作" in lock_state:
417
420
  await lock_btn.click(button="left")
418
421
  await asyncio.sleep(2)
@@ -425,3 +428,69 @@ async def first_open_page_my_order_unlock(
425
428
  await asyncio.sleep(2)
426
429
  logger.info(f"订单详情页面,日志记录栏,【{lock_state}】按钮点击完成")
427
430
  return order_detail_po
431
+
432
+
433
+ async def fill_procurement_with_http(
434
+ *, order_id: int, qlv_domain: str, amount: float, pre_order_id: str, platform_user_id: str, user_password: str,
435
+ passengers: List[str], fids: str, pids: List[str], transaction_id: str, qlv_protocol: str = "http",
436
+ retry: int = 1, timeout: int = 5, enable_log: bool = True, cookie_jar: Optional[aiohttp.CookieJar] = None,
437
+ playwright_state: Dict[str, Any] = None, data_list: Optional[List[Dict[str, Any]]] = None, **kwargs: Any
438
+ ) -> Dict[str, Any]:
439
+ return await fill_procurement_info_with_http(
440
+ order_id=order_id, qlv_domain=qlv_domain, amount=amount, pre_order_id=pre_order_id,
441
+ platform_user_id=platform_user_id, user_password=user_password, passengers=passengers, fids=fids, pids=pids,
442
+ transaction_id=transaction_id, qlv_protocol=qlv_protocol, retry=retry, timeout=timeout, enable_log=enable_log,
443
+ cookie_jar=cookie_jar, playwright_state=playwright_state, data_list=data_list
444
+ )
445
+
446
+
447
+ async def fill_procurement_with_http_callback(
448
+ *, fill_procurement_dto: FillProcurementInputDTO, retry: int = 1, timeout: int = 5, enable_log: bool = True,
449
+ cookie_jar: Optional[aiohttp.CookieJar] = None, playwright_state: Dict[str, Any] = None,
450
+ data_list: Optional[List[Dict[str, Any]]] = None, **kwargs: Any
451
+ ) -> Dict[str, Any]:
452
+ return await fill_procurement_dto_with_http(
453
+ fill_procurement_dto=fill_procurement_dto, retry=retry, timeout=timeout, enable_log=enable_log,
454
+ cookie_jar=cookie_jar, playwright_state=playwright_state, data_list=data_list
455
+ )
456
+
457
+
458
+ async def fill_itinerary_with_http(
459
+ *, page: Page, logger: Logger, qlv_protocol: str, qlv_domain: str, order_id: int, retry: int = 1,
460
+ passengers: List[Dict[str, Any]], timeout: float = 20.0, cookie_jar: Optional[aiohttp.CookieJar] = None,
461
+ playwright_state: Dict[str, Any] = None, enable_log: bool = True, **kwargs: Any
462
+ ) -> bool:
463
+ # 1. 打开页面
464
+ order_detail_po = await open_order_detail_page(
465
+ page=page, logger=logger, protocol=qlv_protocol, domain=qlv_domain, order_id=order_id, timeout=timeout
466
+ )
467
+
468
+ # 2. 获取采购信息的流水id
469
+ purchase_transaction_ids = await order_detail_po.get_purchase_info_transaction_id(timeout=timeout)
470
+ purchase_transaction_ids = [x for x in purchase_transaction_ids if x != "0"]
471
+ if purchase_transaction_ids:
472
+ flag = True
473
+ purchase_transaction_ids.sort()
474
+ purchase_transaction_id = purchase_transaction_ids[0]
475
+ for passenger in passengers:
476
+ pid = passenger.get("pid")
477
+ tid = passenger.get("tid")
478
+ p_name = passenger.get("p_name")
479
+ itinerary_id = passenger.get("itinerary_id")
480
+ try:
481
+ response = await fill_itinerary_info_with_http(
482
+ order_id=order_id, qlv_domain=qlv_domain, pid=pid, tid=tid, transaction_id=purchase_transaction_id,
483
+ itinerary_id=itinerary_id, retry=retry, qlv_protocol=qlv_protocol, timeout=int(timeout),
484
+ enable_log=enable_log, cookie_jar=cookie_jar, playwright_state=playwright_state
485
+ )
486
+ if response == 200 or "OK" in response.get("data"):
487
+ logger.info(f"订单<{order_id}>,乘客<{p_name}>票号<{itinerary_id}>回填成功")
488
+ else:
489
+ logger.warning(
490
+ f'订单<{order_id}>,乘客<{p_name}>票号<{itinerary_id}>回填失败:{response.get("data")}')
491
+ flag = False
492
+ except (Exception,):
493
+ flag = False
494
+ return flag
495
+ else:
496
+ raise EnvironmentError("还未填写采购信息,暂时不能回填票号")
@@ -10,10 +10,17 @@
10
10
  # ---------------------------------------------------------------------------------------------------------
11
11
  """
12
12
  import asyncio
13
+ from copy import deepcopy
14
+ from logging import Logger
13
15
  from aiohttp import CookieJar
14
- from typing import Optional, Dict, Any, Callable, List
16
+ from datetime import datetime, timedelta
17
+ from playwright.async_api import Page, Locator
18
+ import qlv_helper.config.url_const as url_const
15
19
  from http_helper.client.async_proxy import HttpClientFactory
16
20
  from qlv_helper.utils.html_utils import parse_pagination_info
21
+ from qlv_helper.utils.type_utils import safe_convert_advanced
22
+ from typing import Optional, Dict, Any, Callable, List, cast, Tuple
23
+ from qlv_helper.po.domestic_activity_order_page import DomesticActivityOrderPage
17
24
  from qlv_helper.http.order_table_page import get_domestic_activity_order_page_html, get_domestic_ticket_outed_page_html, \
18
25
  parse_order_table, get_domestic_unticketed_order_page_html
19
26
 
@@ -28,7 +35,7 @@ async def _get_paginated_order_table(
28
35
  cookie_jar: Optional[CookieJar],
29
36
  playwright_state: Dict[str, Any],
30
37
  table_state: str,
31
- fetch_page_fn: Callable[..., Any], # 拿到第一页/分页 HTML 的函数
38
+ fetch_page_fn: Callable[..., Any], # 拿到第一页/分页 HTML 的函数
32
39
  ) -> Dict[str, Any]:
33
40
  """通用分页表格抓取(支持并发)"""
34
41
 
@@ -79,7 +86,7 @@ async def _get_paginated_order_table(
79
86
  )
80
87
  if resp.get("code") == 200:
81
88
  return parse_order_table(html=resp["data"], table_state=table_state)
82
- except (Exception, ):
89
+ except (Exception,):
83
90
  return list() # 抓取失败则返回空,不影响整体
84
91
  return list()
85
92
 
@@ -111,6 +118,7 @@ async def _get_paginated_order_table(
111
118
  response["data"] = pagination_info
112
119
  return response
113
120
 
121
+
114
122
  async def get_domestic_activity_order_table(
115
123
  domain: str, protocol: str = "http", retry: int = 1, timeout: int = 5, enable_log: bool = True,
116
124
  cookie_jar: Optional[CookieJar] = None, playwright_state: Dict[str, Any] = None
@@ -144,6 +152,7 @@ async def get_domestic_ticket_outed_table(
144
152
  fetch_page_fn=get_domestic_ticket_outed_page_html
145
153
  )
146
154
 
155
+
147
156
  async def get_domestic_unticketed_order_table(
148
157
  domain: str, protocol: str = "http", retry: int = 1, timeout: int = 5, enable_log: bool = True,
149
158
  cookie_jar: Optional[CookieJar] = None, playwright_state: Dict[str, Any] = None
@@ -158,4 +167,164 @@ async def get_domestic_unticketed_order_table(
158
167
  playwright_state=playwright_state,
159
168
  table_state="proccessing",
160
169
  fetch_page_fn=get_domestic_unticketed_order_page_html
161
- )
170
+ )
171
+
172
+
173
+ async def open_domestic_activity_order_page(
174
+ *, page: Page, logger: Logger, qlv_protocol: str, qlv_domain: str, timeout: float = 20.0
175
+ ) -> DomesticActivityOrderPage:
176
+ url_prefix = f"{qlv_protocol}://{qlv_domain}"
177
+ domestic_activity_order_url = url_prefix + url_const.domestic_activity_order_url
178
+ await page.goto(domestic_activity_order_url)
179
+
180
+ domestic_activity_order_po = DomesticActivityOrderPage(page=page, url=domestic_activity_order_url)
181
+ await domestic_activity_order_po.url_wait_for(url=domestic_activity_order_url, timeout=timeout)
182
+ logger.info(f"即将进入国内活动订单页面,页面URL<{domestic_activity_order_url}>")
183
+ return domestic_activity_order_po
184
+
185
+
186
+ async def pop_will_expire_domestic_activity_order(
187
+ *, page: Page, logger: Logger, qlv_protocol: str, qlv_domain: str, last_minute_threshold: int,
188
+ timeout: float = 20.0, **kwargs: Any
189
+ ) -> Tuple[List[Dict[str, Any]], bool]:
190
+ # 1. 打开国内活动订单页面
191
+ domestic_activity_order_po = await open_domestic_activity_order_page(
192
+ page=page, logger=logger, qlv_protocol=qlv_protocol, qlv_domain=qlv_domain, timeout=timeout
193
+ )
194
+
195
+ # TODO 暂时不考虑分页的情况
196
+ # 2. 获取table所有tr的Locator对象
197
+ trs_locator = await domestic_activity_order_po.get_flight_table_trs_locator(timeout=timeout)
198
+ trs_locator = await trs_locator.all()
199
+ table_data = list()
200
+ feilds = {
201
+ "to_from": "", "urgant_state": "", "order_id": 0, "pre_order_id": "", "aduit_pnr": "", "child_pnr": "",
202
+ "payment_time": "", "last_time_ticket": "", "dat_dep": "", "code_dep": "", "code_arr": "", "flight_no": "",
203
+ "cabin": "", "policy": "", "total_people": 0, "total_adult": 0, "total_child": 0, "receipted": 0.00,
204
+ "stat_opration": "", "more_seats": "", "operation_info": "", "substitute_btn_locator": ""
205
+ }
206
+ pre_pop_orders = list()
207
+ is_pop = False
208
+ for tr_locator in trs_locator[1:]:
209
+ row_locator = await domestic_activity_order_po.get_flight_table_trs_td(locator=tr_locator, timeout=timeout)
210
+ tds_locators = await row_locator.all()
211
+ sub_feilds = list()
212
+ copy_feilds = deepcopy(feilds)
213
+ for index, td_locator in enumerate(tds_locators):
214
+ try:
215
+ text = (await td_locator.inner_text()).strip()
216
+ if index == 0:
217
+ copy_feilds["to_from"] = text
218
+ sub_feilds.append("to_from")
219
+ elif index == 1:
220
+ order_id = await domestic_activity_order_po.get_flight_table_td_order_id(
221
+ locator=td_locator, timeout=timeout
222
+ )
223
+ urgant_state = await domestic_activity_order_po.get_flight_table_td_urgant(
224
+ locator=td_locator, timeout=timeout
225
+ )
226
+ copy_feilds["order_id"] = safe_convert_advanced(value=order_id)
227
+ copy_feilds["urgant_state"] = urgant_state
228
+ sub_feilds.extend(["order_id", "urgant_state"])
229
+ elif index == 2:
230
+ copy_feilds["pre_order_id"] = text
231
+ sub_feilds.append("pre_order_id")
232
+ elif index == 3:
233
+ text = text.replace("\xa0", "")
234
+ text_slice = text.split("|")
235
+ copy_feilds["aduit_pnr"] = text_slice[0].strip()
236
+ copy_feilds["child_pnr"] = text_slice[1].strip()
237
+ sub_feilds.extend(["aduit_pnr", "child_pnr"])
238
+ elif index == 4:
239
+ copy_feilds["payment_time"] = text
240
+ sub_feilds.append("payment_time")
241
+ elif index == 5:
242
+ continue
243
+ elif index == 6:
244
+ copy_feilds["last_time_ticket"] = text
245
+ sub_feilds.append("last_time_ticket")
246
+ elif index == 7:
247
+ continue
248
+ elif index == 8:
249
+ text = text.replace("\xa0", "|")
250
+ text_slice = [i for i in text.split("|") if i.strip()]
251
+ ctrip = text_slice[1].split("-")
252
+ copy_feilds["dat_dep"] = text_slice[0].strip()
253
+ copy_feilds["code_dep"] = ctrip[0].strip()
254
+ copy_feilds["code_arr"] = ctrip[1].strip()
255
+ copy_feilds["flight_no"] = text_slice[2].strip()
256
+ copy_feilds["cabin"] = text_slice[3].strip()
257
+ sub_feilds.extend(["dat_dep", "code_dep", "code_arr", "flight_no", "cabin"])
258
+ elif index == 9:
259
+ text = text.replace("\xa0", "")
260
+ text = text.replace(">", "")
261
+ text = text.replace("<", "")
262
+ text = text.replace("&", "")
263
+ text = text.replace("<br>", "\n")
264
+ copy_feilds["policy"] = text
265
+ sub_feilds.append("policy")
266
+ elif index == 10:
267
+ text = text.replace("【 ", "|")
268
+ text = text.replace("/", "|")
269
+ text = text.replace("】", "")
270
+ text_slice = text.split("|")
271
+ copy_feilds["total_people"] = safe_convert_advanced(value=text_slice[0].strip())
272
+ copy_feilds["total_adult"] = safe_convert_advanced(value=text_slice[1].strip())
273
+ copy_feilds["total_child"] = safe_convert_advanced(value=text_slice[2].strip())
274
+ sub_feilds.extend(["total_people", "total_adult", "total_child"])
275
+ elif index == 11:
276
+ copy_feilds["receipted"] = safe_convert_advanced(value=text)
277
+ sub_feilds.append("receipted")
278
+ elif index == 12:
279
+ copy_feilds["stat_opration"] = text
280
+ sub_feilds.append("stat_opration")
281
+ elif index == 13:
282
+ copy_feilds["more_seats"] = safe_convert_advanced(value=text)
283
+ sub_feilds.append("more_seats")
284
+ elif index == 14:
285
+ text_slice = text.split(" ")
286
+ operation_info = dict(
287
+ lock_btn_locator=cast(Locator, None), pop_btn_locator=cast(Locator, None), locked=""
288
+ )
289
+ if "锁定" in text_slice[0]:
290
+ lock_btn_locator = await domestic_activity_order_po.get_flight_table_td_operation_lock_btn(
291
+ locator=td_locator, timeout=timeout
292
+ )
293
+ operation_info["lock_btn_locator"] = lock_btn_locator
294
+ else:
295
+ operation_info["locked"] = text_slice[0].strip()
296
+ if "踢出" in text:
297
+ pop_btn_locator = await domestic_activity_order_po.get_flight_table_td_operation_pop_btn(
298
+ locator=td_locator, timeout=timeout
299
+ )
300
+ operation_info["pop_btn_locator"] = pop_btn_locator
301
+ copy_feilds["operation_info"] = operation_info
302
+ sub_feilds.append("operation_info")
303
+ elif index == 15:
304
+ copy_feilds[
305
+ "substitute_btn_locator"
306
+ ] = await domestic_activity_order_po.get_flight_table_td_operation_substitute_btn(
307
+ locator=td_locator, timeout=timeout)
308
+ sub_feilds.append("substitute_btn_locator")
309
+ except (Exception,) as e:
310
+ logger.error(f"第<{index + 1}>列数据处理异常,原因:{e}")
311
+ if len(sub_feilds) == 22:
312
+ table_data.append(copy_feilds)
313
+ if datetime.strptime(
314
+ copy_feilds.get("last_time_ticket"), "%Y-%m-%d %H:%M:%S"
315
+ ) < datetime.now() + timedelta(minutes=last_minute_threshold):
316
+ pre_pop_orders.append(copy_feilds)
317
+ for pre_pop_order in pre_pop_orders:
318
+ order_id = pre_pop_order.get("order_id")
319
+ operation_info = pre_pop_order.get("operation_info")
320
+ pop_btn_locator = operation_info.get("pop_btn_locator")
321
+ last_time_ticket = pre_pop_order.get("last_time_ticket")
322
+ if pop_btn_locator and isinstance(pop_btn_locator, Locator):
323
+ minute = (datetime.strptime(last_time_ticket, "%Y-%m-%d %H:%M:%S") - datetime.now()).total_seconds() / 60
324
+ await pop_btn_locator.click()
325
+ if is_pop is False:
326
+ is_pop = True
327
+ logger.info(
328
+ f"订单<{order_id}>,距离最晚出票时限: {last_time_ticket},仅剩<{minute}>分钟,已将工单剔出活动订单"
329
+ )
330
+ return table_data, is_pop