flight-helper 0.0.3__tar.gz → 0.3.6__tar.gz
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.
- {flight_helper-0.0.3 → flight_helper-0.3.6}/PKG-INFO +1 -1
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper/models/dto/booking.py +34 -28
- flight_helper-0.3.6/flight_helper/models/dto/http_schema.py +31 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper/models/dto/itinerary.py +4 -6
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper/models/dto/passenger.py +10 -6
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper/models/dto/payment.py +64 -27
- flight_helper-0.3.6/flight_helper/models/dto/procurement.py +56 -0
- flight_helper-0.3.6/flight_helper/utils/__init__.py +11 -0
- flight_helper-0.3.6/flight_helper/utils/exception_utils.py +138 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper.egg-info/PKG-INFO +1 -1
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper.egg-info/SOURCES.txt +3 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/pyproject.toml +1 -1
- flight_helper-0.0.3/flight_helper/models/dto/procurement.py +0 -30
- {flight_helper-0.0.3 → flight_helper-0.3.6}/LICENSE +0 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/README.md +0 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper/__init__.py +0 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper/models/__init__.py +0 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper/models/dto/__init__.py +0 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper/validator/__init__.py +0 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper/validator/type_validator.py +0 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper.egg-info/dependency_links.txt +0 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper.egg-info/requires.txt +0 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/flight_helper.egg-info/top_level.txt +0 -0
- {flight_helper-0.0.3 → flight_helper-0.3.6}/setup.cfg +0 -0
|
@@ -11,17 +11,42 @@
|
|
|
11
11
|
"""
|
|
12
12
|
from typing import Optional
|
|
13
13
|
from flight_helper.validator.type_validator import parse_to_date_str
|
|
14
|
-
from pydantic import BaseModel, model_validator, PositiveInt,
|
|
14
|
+
from pydantic import BaseModel, model_validator, PositiveInt, NonNegativeFloat, Field, field_validator
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
class
|
|
17
|
+
class BookingInputDTO(BaseModel):
|
|
18
18
|
# 平台信息
|
|
19
|
-
book_domain:
|
|
20
|
-
book_protocol:
|
|
19
|
+
book_domain: str = Field(..., description="预订平台域名,例如:www.ceair.com")
|
|
20
|
+
book_protocol: str = Field(..., description="预订平台协议,例如:https")
|
|
21
|
+
|
|
22
|
+
book_login_user: str = Field(..., description="预订平台登录用户")
|
|
23
|
+
book_password: str = Field(..., description="预订平台登录密码")
|
|
24
|
+
|
|
25
|
+
# 产品
|
|
26
|
+
product_type: str = Field(..., description="产品类型,如:经济舱、超级经济舱等")
|
|
27
|
+
product_name: Optional[str] = Field(default=None, description="产品名称,如:C919特惠,老年特惠")
|
|
28
|
+
|
|
29
|
+
sale_increase_threshold: NonNegativeFloat = Field(
|
|
30
|
+
default=0.0, description="涨价上限(相对于 sale_price 的绝对值或百分比?按业务定)"
|
|
31
|
+
)
|
|
32
|
+
sale_reduction_threshold: NonNegativeFloat = Field(
|
|
33
|
+
default=0.0, description="降价上限(相对于 sale_price 的绝对值或百分比?按业务定)"
|
|
34
|
+
)
|
|
35
|
+
standard_increase_threshold: NonNegativeFloat = Field(
|
|
36
|
+
default=0.0, description="涨价上限(相对于 standard_price 的绝对值或百分比?按业务定)"
|
|
37
|
+
)
|
|
38
|
+
standard_reduction_threshold: NonNegativeFloat = Field(
|
|
39
|
+
default=0.0, description="降价上限(相对于 standard_price 的绝对值或百分比?按业务定)"
|
|
40
|
+
)
|
|
21
41
|
|
|
22
|
-
|
|
23
|
-
|
|
42
|
+
# 服务联系人
|
|
43
|
+
specialist_name: Optional[str] = Field(default=None, description="退改联系人姓名")
|
|
44
|
+
specialist_mobile: Optional[str] = Field(default=None, description="电话")
|
|
45
|
+
specialist_email: Optional[str] = Field(default=None, description="邮箱")
|
|
24
46
|
|
|
47
|
+
|
|
48
|
+
class OneWayBookingDTO(BaseModel):
|
|
49
|
+
order_no: PositiveInt = Field(..., description="报表平台的订单号")
|
|
25
50
|
# 航班信息
|
|
26
51
|
dep_city: str = Field(..., description="起飞城市(中文)")
|
|
27
52
|
arr_city: str = Field(..., description="抵达城市(中文)")
|
|
@@ -37,28 +62,9 @@ class OneWayBookingDTO(BaseModel):
|
|
|
37
62
|
children: Optional[PositiveInt] = Field(default=None, description="儿童数量(如提供,必须 ≥1;未提供则视为无儿童)")
|
|
38
63
|
infant: Optional[PositiveInt] = Field(default=None, description="婴儿数量(如提供,必须 ≥1;未提供则视为无婴儿)")
|
|
39
64
|
|
|
40
|
-
#
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
sale_price: Optional[PositiveFloat] = Field(default=None, description="预期销售价")
|
|
44
|
-
standard_price: PositiveFloat = Field(..., description="预期票面价(应 ≥ sale_price)")
|
|
45
|
-
sale_increase_threshold: Optional[NonNegativeFloat] = Field(
|
|
46
|
-
default=0.00, description="涨价上限(相对于 sale_price 的绝对值或百分比?按业务定)"
|
|
47
|
-
)
|
|
48
|
-
sale_reduction_threshold: Optional[NonNegativeFloat] = Field(
|
|
49
|
-
default=0.00, description="降价上限(相对于 sale_price 的绝对值或百分比?按业务定)"
|
|
50
|
-
)
|
|
51
|
-
standard_increase_threshold: Optional[NonNegativeFloat] = Field(
|
|
52
|
-
default=0.00, description="涨价上限(相对于 standard_price 的绝对值或百分比?按业务定)"
|
|
53
|
-
)
|
|
54
|
-
standard_reduction_threshold: Optional[NonNegativeFloat] = Field(
|
|
55
|
-
default=0.00, description="降价上限(相对于 standard_price 的绝对值或百分比?按业务定)"
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
# 服务联系人
|
|
59
|
-
specialist_name: Optional[str] = Field(default=None, description="退改联系人姓名")
|
|
60
|
-
specialist_mobile: Optional[str] = Field(default=None, description="电话")
|
|
61
|
-
specialist_email: Optional[str] = Field(default=None, description="邮箱")
|
|
65
|
+
# 价格
|
|
66
|
+
sale_price: NonNegativeFloat = Field(default=0.0, description="预期销售价")
|
|
67
|
+
standard_price: NonNegativeFloat = Field(default=0.0, description="预期票面价(应 ≥ sale_price)")
|
|
62
68
|
|
|
63
69
|
@field_validator("dep_date")
|
|
64
70
|
@classmethod
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
4
|
+
# ProjectName: python-flight-helper
|
|
5
|
+
# FileName: http_schema.py
|
|
6
|
+
# Description: http请求参数基础模型
|
|
7
|
+
# Author: ASUS
|
|
8
|
+
# CreateDate: 2026/01/13
|
|
9
|
+
# Copyright ©2011-2026. Hunan xxxxxxx Company limited. All rights reserved.
|
|
10
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
11
|
+
"""
|
|
12
|
+
from typing import Optional, Dict, Any
|
|
13
|
+
from pydantic import BaseModel, Field, PositiveInt, NonNegativeInt
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class HTTPRequestDTO(BaseModel):
|
|
17
|
+
# 平台信息
|
|
18
|
+
http_domain: Optional[str] = Field(default=None, description="平台域名,例如:www.ceair.com")
|
|
19
|
+
http_protocol: Optional[str] = Field(default=None, description="平台协议,例如:https")
|
|
20
|
+
storage_state: Optional[Dict[str, Any]] = Field(
|
|
21
|
+
default=None, description="playwright 爬取的用户登录状态没礼貌包含了cookie和origin"
|
|
22
|
+
)
|
|
23
|
+
timeout: Optional[PositiveInt] = Field(default=60, description="请求超时时间")
|
|
24
|
+
retry: Optional[NonNegativeInt] = Field(default=0, description="重试次数")
|
|
25
|
+
enable_log: Optional[bool] = Field(default=True, description="是否打印日志")
|
|
26
|
+
token: Optional[str] = Field(default=None, description="token值")
|
|
27
|
+
json_data: Optional[Dict[str, Any]] = Field(default=None, description="json参数")
|
|
28
|
+
params_data: Optional[Dict[str, Any]] = Field(default=None, description="params参数")
|
|
29
|
+
data: Optional[Dict[str, Any]] = Field(default=None, description="data参数")
|
|
30
|
+
proxy: Optional[Dict[str, Any]] = Field(default=None, description="http的代理配置")
|
|
31
|
+
headers: Optional[Dict[str, Any]] = Field(default=None, description="自定义的http headers")
|
|
@@ -9,9 +9,8 @@
|
|
|
9
9
|
# Copyright ©2011-2026. Hunan xxxxxxx Company limited. All rights reserved.
|
|
10
10
|
# ---------------------------------------------------------------------------------------------------------
|
|
11
11
|
"""
|
|
12
|
-
from aiohttp import CookieJar
|
|
13
12
|
from typing import Optional, List, Dict, Any
|
|
14
|
-
from pydantic import BaseModel, NonNegativeFloat, Field, field_validator
|
|
13
|
+
from pydantic import BaseModel, NonNegativeFloat, Field, field_validator, PositiveInt
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
class ItineraryInfoDTO(BaseModel):
|
|
@@ -23,16 +22,16 @@ class ItineraryInfoDTO(BaseModel):
|
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
class QueryItineraryResponseDTO(BaseModel):
|
|
26
|
-
order_no: Optional[
|
|
25
|
+
order_no: Optional[PositiveInt] = Field(default=None, description="业务平台订单号")
|
|
27
26
|
pre_order_no: str = Field(..., description="采购平台订单号")
|
|
28
27
|
order_status: Optional[str] = Field(default=None, description="采购平台订单状态")
|
|
29
|
-
order_amount:
|
|
28
|
+
order_amount: NonNegativeFloat = Field(default=0.0, description="采购平台订单金额")
|
|
30
29
|
cash_unit: Optional[str] = Field(default=None, description="采购金额的币种")
|
|
31
30
|
itinerary_info: List[ItineraryInfoDTO] = Field(..., description="乘客行程单信息")
|
|
32
31
|
|
|
33
32
|
@field_validator("itinerary_info")
|
|
34
33
|
@classmethod
|
|
35
|
-
def validate_non_empty(cls,
|
|
34
|
+
def validate_non_empty(cls, v: List[ItineraryInfoDTO], info):
|
|
36
35
|
if len(v) == 0:
|
|
37
36
|
raise ValueError("至少需要一个乘客行程")
|
|
38
37
|
# 获取外层的 pre_order_no
|
|
@@ -55,4 +54,3 @@ class QueryItineraryRequestDTO(BaseModel):
|
|
|
55
54
|
user_id: Optional[str] = Field(default=None, description="采购平台登录用户的ID")
|
|
56
55
|
proxy: Optional[Dict[str, Any]] = Field(default=None, description="http的代理配置")
|
|
57
56
|
headers: Optional[Dict[str, Any]] = Field(default=None, description="自定义的http headers")
|
|
58
|
-
cookie_jar: Optional[CookieJar] = Field(default=None, description="自定义的CookieJar对象")
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
# ---------------------------------------------------------------------------------------------------------
|
|
11
11
|
"""
|
|
12
12
|
from typing import Optional, Literal
|
|
13
|
-
from pydantic import BaseModel, Field
|
|
13
|
+
from pydantic import BaseModel, Field, PositiveInt
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class PassengerDTO(BaseModel):
|
|
17
|
+
segment_index: PositiveInt = Field(..., description="航段索引")
|
|
17
18
|
# 乘客基本信息
|
|
18
19
|
passenger_type: Literal["成人", "儿童", "婴儿"] = Field(
|
|
19
20
|
..., description="乘客类型,必须是:成人、儿童 或 婴儿"
|
|
@@ -21,14 +22,17 @@ class PassengerDTO(BaseModel):
|
|
|
21
22
|
passenger_name: str = Field(
|
|
22
23
|
..., description="乘客法定姓名(按证件填写),如:Zhang San 或 张三"
|
|
23
24
|
)
|
|
24
|
-
passenger_alias: Optional[str] = Field(
|
|
25
|
-
default=None,
|
|
26
|
-
description="乘客中文常用名(仅外国人使用),如:汤姆(对应 Tom)"
|
|
27
|
-
)
|
|
28
|
-
|
|
29
25
|
# 性别与证件
|
|
30
26
|
gender: Literal["男", "女"] = Field(..., description='性别,只能是"男"或"女"')
|
|
31
27
|
id_type: Literal["身份证", "港澳通行证", "护照", "军官证", "回乡证"] = Field(
|
|
32
28
|
..., description='证件类型'
|
|
33
29
|
)
|
|
34
30
|
id_number: str = Field(..., description="证件号码(按证件如实填写)")
|
|
31
|
+
|
|
32
|
+
passenger_id: Optional[str] = Field(default=None, description="乘客ID")
|
|
33
|
+
flight_id: Optional[str] = Field(default=None, description="乘客航段ID")
|
|
34
|
+
table_id: Optional[str] = Field(default=None, description="乘客制表ID")
|
|
35
|
+
passenger_alias: Optional[str] = Field(
|
|
36
|
+
default=None,
|
|
37
|
+
description="乘客中文常用名(仅外国人使用),如:汤姆(对应 Tom)"
|
|
38
|
+
)
|
|
@@ -10,28 +10,31 @@
|
|
|
10
10
|
# ---------------------------------------------------------------------------------------------------------
|
|
11
11
|
"""
|
|
12
12
|
from typing import Literal, Optional, Union, Annotated
|
|
13
|
-
from pydantic import BaseModel, Field, TypeAdapter, NonNegativeFloat
|
|
13
|
+
from pydantic import BaseModel, Field, TypeAdapter, NonNegativeFloat, PositiveInt
|
|
14
14
|
|
|
15
|
-
SupportedChannels = Literal["微信", "支付宝", "汇付天下", "易宝支付"]
|
|
15
|
+
SupportedChannels = Literal["微信", "支付宝", "汇付天下", "易宝支付", "空中云汇", "快钱"]
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class __BasePaymentDTO(BaseModel):
|
|
19
|
-
|
|
20
|
-
pay_protocol: Optional[str] = Field(default=None, description="支付在线收银台协议,例如:https")
|
|
21
|
-
|
|
22
|
-
channel_name: SupportedChannels = Field(
|
|
23
|
-
..., description=f'支付渠道,只能是其中之一:{SupportedChannels}'
|
|
24
|
-
)
|
|
19
|
+
channel_name: SupportedChannels = Field(..., description=f'支付渠道,只能是其中之一:{SupportedChannels}')
|
|
25
20
|
payment_type: str = Field(..., description="支付方式")
|
|
26
|
-
order_no: str = Field(..., description="报表平台订单号")
|
|
27
|
-
pre_order_no: Optional[str] = Field(default=None, description="采购平台订单号")
|
|
28
21
|
account: Optional[str] = Field(default=None, description="支付账号")
|
|
29
22
|
password: Optional[str] = Field(default=None, description="账号密码")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PaymentResultDTO(__BasePaymentDTO):
|
|
26
|
+
order_no: PositiveInt = Field(..., description="报表平台订单号")
|
|
27
|
+
pre_order_no: Optional[str] = Field(default=None, description="采购平台订单号")
|
|
30
28
|
pay_transaction: Optional[str] = Field(default=None, description="支付流水")
|
|
31
|
-
pay_amount:
|
|
29
|
+
pay_amount: NonNegativeFloat = Field(default=0.0, description="支付金额")
|
|
32
30
|
|
|
33
31
|
|
|
34
|
-
class
|
|
32
|
+
class __BasePaymentInputDTO(__BasePaymentDTO):
|
|
33
|
+
pay_domain: Optional[str] = Field(default=None, description="支付在线收银台域名,例如:www.ceair.com")
|
|
34
|
+
pay_protocol: Optional[str] = Field(default=None, description="支付在线收银台协议,例如:https")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class YBAccountPaymentInputDTO(__BasePaymentInputDTO):
|
|
35
38
|
"""易宝支付-账号支付"""
|
|
36
39
|
channel_name: Literal["易宝支付"] = Field(..., description="支付渠道")
|
|
37
40
|
payment_type: Literal["账户支付"] = Field(..., description="支付方式")
|
|
@@ -39,17 +42,17 @@ class YBAccountPaymentDTO(__BasePaymentDTO):
|
|
|
39
42
|
password: str = Field(..., description="账号密码")
|
|
40
43
|
|
|
41
44
|
|
|
42
|
-
class
|
|
45
|
+
class WeChatPaymentInputDTO(__BasePaymentInputDTO):
|
|
43
46
|
channel_name: Literal["微信"] = Field(..., description="支付渠道")
|
|
44
47
|
payment_type: Literal["二维码识别"] = Field(..., description="支付方式")
|
|
45
48
|
|
|
46
49
|
|
|
47
|
-
class
|
|
50
|
+
class AlipayPaymentInputDTO(__BasePaymentInputDTO):
|
|
48
51
|
channel_name: Literal["支付宝"] = Field(..., description="支付渠道")
|
|
49
52
|
payment_type: Literal["二维码识别"] = Field(..., description="支付方式")
|
|
50
53
|
|
|
51
54
|
|
|
52
|
-
class
|
|
55
|
+
class HFPaidAccountPaymentInputDTO(__BasePaymentInputDTO):
|
|
53
56
|
"""汇付天下-付款账户支付"""
|
|
54
57
|
channel_name: Literal["汇付天下"] = Field(..., description="支付渠道")
|
|
55
58
|
payment_type: Literal["付款账户支付"] = Field(..., description="支付方式")
|
|
@@ -57,13 +60,48 @@ class HFPaidAccountPaymentDTO(__BasePaymentDTO):
|
|
|
57
60
|
password: str = Field(..., description="操作员交易密码")
|
|
58
61
|
|
|
59
62
|
|
|
63
|
+
class AirwallexVCCPaymentInputDTO(__BasePaymentInputDTO):
|
|
64
|
+
"""空中云汇-VCC支付"""
|
|
65
|
+
channel_name: Literal["空中云汇"] = Field(..., description="支付渠道")
|
|
66
|
+
payment_type: Literal["VCC"] = Field(..., description="支付方式")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Bill99AccountPaymentInputDTO(__BasePaymentInputDTO):
|
|
70
|
+
"""快钱-快钱账户支付"""
|
|
71
|
+
channel_name: Literal["快钱"] = Field(..., description="支付渠道")
|
|
72
|
+
payment_type: Literal["快钱账户"] = Field(..., description="支付方式")
|
|
73
|
+
account: str = Field(..., description="快钱账户")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class AirwallexVCCPaymentInfoDTO(AirwallexVCCPaymentInputDTO):
|
|
77
|
+
first_name: str = Field(..., description="名字")
|
|
78
|
+
last_name: str = Field(..., description="姓氏")
|
|
79
|
+
id_number: str = Field(..., description="证件号码")
|
|
80
|
+
email: str = Field(..., description="电子邮箱")
|
|
81
|
+
mobile: str = Field(..., description="手机号码")
|
|
82
|
+
id_type: str = Field(..., description="证件类型")
|
|
83
|
+
country: str = Field(..., description="国家/地区")
|
|
84
|
+
state: str = Field(..., description="省/州")
|
|
85
|
+
city: str = Field(..., description="城市")
|
|
86
|
+
street: str = Field(..., description="街道名称")
|
|
87
|
+
house_number: str = Field(..., description="门牌号码")
|
|
88
|
+
postal_code: str = Field(..., description="邮编")
|
|
89
|
+
card_number: Optional[str] = Field(default=None, description="卡号")
|
|
90
|
+
expiry_year: Optional[PositiveInt] = Field(default=None, description="有效年份")
|
|
91
|
+
expiry_month: Optional[PositiveInt] = Field(default=None, description="有效月份")
|
|
92
|
+
card_id: Optional[str] = Field(..., description="虚拟卡ID")
|
|
93
|
+
cvv: Optional[str] = Field(..., description="cvv")
|
|
94
|
+
|
|
95
|
+
|
|
60
96
|
# 3. 创建联合类型,并指定 discriminator
|
|
61
|
-
|
|
97
|
+
PaymentInputDTO = Annotated[
|
|
62
98
|
Union[
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
99
|
+
YBAccountPaymentInputDTO,
|
|
100
|
+
WeChatPaymentInputDTO,
|
|
101
|
+
AlipayPaymentInputDTO,
|
|
102
|
+
HFPaidAccountPaymentInputDTO,
|
|
103
|
+
AirwallexVCCPaymentInputDTO,
|
|
104
|
+
Bill99AccountPaymentInputDTO
|
|
67
105
|
# TODO ... 其他支付方式
|
|
68
106
|
],
|
|
69
107
|
Field(discriminator='channel_name') # 或者用 'payment_type',看业务
|
|
@@ -71,27 +109,26 @@ PaymentRuestDTO = Annotated[
|
|
|
71
109
|
|
|
72
110
|
if __name__ == '__main__':
|
|
73
111
|
# 创建适配器
|
|
74
|
-
adapter = TypeAdapter(
|
|
112
|
+
adapter = TypeAdapter(PaymentInputDTO)
|
|
75
113
|
|
|
76
114
|
# 测试 1: 易宝支付
|
|
77
115
|
yb_data = {
|
|
78
|
-
"order_no":
|
|
116
|
+
"order_no": 1312312,
|
|
79
117
|
"channel_name": "易宝支付",
|
|
80
118
|
"payment_type": "账户支付",
|
|
81
119
|
"account": "yb123",
|
|
82
|
-
"password": "pass123"
|
|
120
|
+
"password": "pass123",
|
|
121
|
+
"pay_amount": 0.00
|
|
83
122
|
}
|
|
84
|
-
yb =
|
|
85
|
-
yb.pay_transaction = "112312"
|
|
123
|
+
yb = PaymentResultDTO(**yb_data)
|
|
86
124
|
print(yb)
|
|
87
125
|
yb_payment = adapter.validate_python(yb_data)
|
|
88
|
-
yb_payment.pay_transaction = "123123123"
|
|
89
126
|
print(yb_payment)
|
|
90
127
|
print(type(yb_payment)) # <class '__main__.YBAccountPayment'>
|
|
91
128
|
|
|
92
129
|
# 测试 2: 微信支付
|
|
93
130
|
wx_data = {
|
|
94
|
-
"order_no":
|
|
131
|
+
"order_no": 1312312,
|
|
95
132
|
"channel_name": "微信",
|
|
96
133
|
"payment_type": "二维码识别",
|
|
97
134
|
# account/password 可省略(Optional)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
4
|
+
# ProjectName: python-flight-helper
|
|
5
|
+
# FileName: procurement.py
|
|
6
|
+
# Description: 采购信息数据转换对象
|
|
7
|
+
# Author: ASUS
|
|
8
|
+
# CreateDate: 2026/01/08
|
|
9
|
+
# Copyright ©2011-2026. Hunan xxxxxxx Company limited. All rights reserved.
|
|
10
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
11
|
+
"""
|
|
12
|
+
from typing import Optional, List, Literal
|
|
13
|
+
from pydantic import BaseModel, PositiveInt, NonNegativeFloat, Field
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ProcurementInputDTO(BaseModel):
|
|
17
|
+
# 平台信息
|
|
18
|
+
pl_domain: str = Field(..., description="平台域名,例如:www.ceair.com")
|
|
19
|
+
pl_protocol: str = Field(..., description="平台协议,例如:https")
|
|
20
|
+
out_ticket_platform_type: str = Field(..., description="出票平台类型")
|
|
21
|
+
out_ticket_platform: str = Field(..., description="出票平台")
|
|
22
|
+
account_number: str = Field(..., description="出票账号")
|
|
23
|
+
type_name: str = Field(..., description="采购账号类型")
|
|
24
|
+
purchase_account: str = Field(..., description="采购账号")
|
|
25
|
+
pl_login_user: str = Field(..., description="采购平台登录账号")
|
|
26
|
+
pl_login_password: str = Field(..., description="采购平台登录密码")
|
|
27
|
+
remark: str = Field(..., description="备注,一般是由采购平台登录账号 + 采购平台登录密码拼接而成")
|
|
28
|
+
|
|
29
|
+
out_ticket_account: Optional[str] = Field(default=None, description="账号")
|
|
30
|
+
out_ticket_account_id: Optional[int] = Field(default=None, description="账号ID")
|
|
31
|
+
out_ticket_account_password: Optional[str] = Field(default=None, description="密码")
|
|
32
|
+
purchase_account_id: Optional[int] = Field(default=None, description="采购账号ID")
|
|
33
|
+
out_ticket_platform_type_id: Optional[int] = Field(default=None, description="出票平台类型ID")
|
|
34
|
+
out_ticket_mobile: Optional[str] = Field(default=None, description="出票手机,退改业务需要根据此手机号码来进行操作")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ProcurementReusltDTO(BaseModel):
|
|
38
|
+
# 平台信息
|
|
39
|
+
order_no: PositiveInt = Field(..., description="报表平台的订单号")
|
|
40
|
+
air_co_order_id: str = Field(..., description="官网订单号")
|
|
41
|
+
transaction_amount: NonNegativeFloat = Field(..., description="采购金额")
|
|
42
|
+
passenger_type: Literal["成人", "儿童", "婴儿"] = Field(
|
|
43
|
+
..., description="乘客类型,必须是:成人、儿童 或 婴儿"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
passenger_names: Optional[List[str]] = Field(default=None, description="采购乘客")
|
|
47
|
+
segment_index: Optional[PositiveInt] = Field(default=None, description="航段索引")
|
|
48
|
+
flight_ids: Optional[str] = Field(default=None, description="乘客航段ID")
|
|
49
|
+
passenger_ids: Optional[List[str]] = Field(default=None, description="乘客ID列表")
|
|
50
|
+
pay_transaction: Optional[str] = Field(default=None, description="对账标识")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class FillProcurementInputDTO(ProcurementInputDTO, ProcurementReusltDTO):
|
|
54
|
+
order_no: Optional[PositiveInt] = Field(default=None, description="报表平台的订单号")
|
|
55
|
+
transaction_amount: Optional[NonNegativeFloat] = Field(default=None, description="采购金额")
|
|
56
|
+
air_co_order_id: Optional[str] = Field(default=None, description="官网订单号")
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
4
|
+
# ProjectName: python-flight-helper
|
|
5
|
+
# FileName: __init__.py
|
|
6
|
+
# Description: 工具包
|
|
7
|
+
# Author: ASUS
|
|
8
|
+
# CreateDate: 2026/01/11
|
|
9
|
+
# Copyright ©2011-2026. Hunan xxxxxxx Company limited. All rights reserved.
|
|
10
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
11
|
+
"""
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
4
|
+
# ProjectName: python-flight-helper
|
|
5
|
+
# FileName: exception_utils.py
|
|
6
|
+
# Description: 异常类工具模块
|
|
7
|
+
# Author: ASUS
|
|
8
|
+
# CreateDate: 2026/01/11
|
|
9
|
+
# Copyright ©2011-2026. Hunan xxxxxxx Company limited. All rights reserved.
|
|
10
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
11
|
+
"""
|
|
12
|
+
from typing import Literal
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DuplicatePaymentError(Exception):
|
|
16
|
+
def __init__(self, order_no: int):
|
|
17
|
+
self.order_no = order_no
|
|
18
|
+
super().__init__(f"订单<{order_no}>重复支付")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DuplicateBookingError(Exception):
|
|
22
|
+
def __init__(self, message):
|
|
23
|
+
super().__init__(message)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class NotEnoughTicketsError(Exception):
|
|
27
|
+
def __init__(self, flight_no: str, seats_status: int, passengers: int):
|
|
28
|
+
self.flight_no = flight_no
|
|
29
|
+
self.seats_status = seats_status
|
|
30
|
+
self.passengers = passengers
|
|
31
|
+
super().__init__(f"采购平台显示航班<{flight_no}>的余票<{seats_status}>少于乘客人数<{passengers}>")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ExcessiveProfitdError(Exception):
|
|
35
|
+
def __init__(
|
|
36
|
+
self, flight_no: str, query_price: float, order_price: float, reduction_threshold: float,
|
|
37
|
+
asset: Literal["票面价", "销售价"] = "票面价"
|
|
38
|
+
):
|
|
39
|
+
self.flight_no = flight_no
|
|
40
|
+
self.query_price = query_price
|
|
41
|
+
self.order_price = order_price
|
|
42
|
+
self.reduction_threshold = reduction_threshold
|
|
43
|
+
self.asset = asset
|
|
44
|
+
super().__init__(
|
|
45
|
+
f"航班<{flight_no}>采购平台价:{query_price} 低于:订单{asset}[{order_price}] - 下降阈值[{reduction_threshold}],收益过高"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ExcessiveLossesError(Exception):
|
|
50
|
+
def __init__(
|
|
51
|
+
self, flight_no: str, query_price: float, order_price: float, increase_threshold: float,
|
|
52
|
+
asset: Literal["票面价", "销售价"] = "票面价"
|
|
53
|
+
):
|
|
54
|
+
self.flight_no = flight_no
|
|
55
|
+
self.query_price = query_price
|
|
56
|
+
self.order_price = order_price
|
|
57
|
+
self.increase_threshold = increase_threshold
|
|
58
|
+
self.asset = asset
|
|
59
|
+
super().__init__(
|
|
60
|
+
f"航班<{flight_no}>官网价:{query_price} 高于:订单{asset}[{order_price}] + 上浮阈值[{increase_threshold}],亏损太多"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class PaymentChannelError(Exception):
|
|
65
|
+
def __init__(self, channel_name: str):
|
|
66
|
+
self.channel_name = channel_name
|
|
67
|
+
super().__init__(f"支付渠道<{channel_name}>暂不支持")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class PaymentChannelMissError(Exception):
|
|
71
|
+
def __init__(self):
|
|
72
|
+
super().__init__(f"支付渠道参数丢失")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class PaymentTypeError(Exception):
|
|
76
|
+
def __init__(self, payment_type: str):
|
|
77
|
+
self.payment_type = payment_type
|
|
78
|
+
super().__init__(f"付款方式<{payment_type}>暂不支持")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class PassengerTypeError(Exception):
|
|
82
|
+
def __init__(self, passenger_type: str):
|
|
83
|
+
self.passenger_type = passenger_type
|
|
84
|
+
super().__init__(f"乘客类型<{passenger_type}>暂不支持")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class ProductTypeError(Exception):
|
|
88
|
+
def __init__(self, product_type: str):
|
|
89
|
+
self.product_type = product_type
|
|
90
|
+
super().__init__(f"产品类型<{product_type}>暂不支持")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class HFPaymentTypeError(Exception):
|
|
94
|
+
def __init__(self, payment_type: str):
|
|
95
|
+
self.payment_type = payment_type
|
|
96
|
+
super().__init__(f"汇付天下的付款方式<{payment_type}>暂不支持")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class PaymentFailedError(Exception):
|
|
100
|
+
def __init__(self, pre_order_no: str, order_status: str):
|
|
101
|
+
self.pre_order_no = pre_order_no
|
|
102
|
+
self.order_status = order_status
|
|
103
|
+
super().__init__(f"采购平台订单<{pre_order_no}>支付失败,支付结束后的状态<{order_status}>")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class PaymentFailError(Exception):
|
|
107
|
+
def __init__(self, message: str):
|
|
108
|
+
self.message = message
|
|
109
|
+
super().__init__(message)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class IPBlockError(Exception):
|
|
113
|
+
|
|
114
|
+
def __init__(self, message: str):
|
|
115
|
+
self.message = message
|
|
116
|
+
super().__init__(message)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class RelationOrderConflictError(Exception):
|
|
120
|
+
|
|
121
|
+
def __init__(self, message: str):
|
|
122
|
+
super().__init__(message)
|
|
123
|
+
|
|
124
|
+
class LockedOrderFailedError(Exception):
|
|
125
|
+
|
|
126
|
+
def __init__(self, message: str):
|
|
127
|
+
super().__init__(message)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class OrderLimitError(Exception):
|
|
131
|
+
def __init__(self, user_id: str, message: str):
|
|
132
|
+
self.user_id = user_id
|
|
133
|
+
super().__init__(f"用户<{user_id}>已受限,{message}")
|
|
134
|
+
|
|
135
|
+
class UserNotLoginError(Exception):
|
|
136
|
+
|
|
137
|
+
def __init__(self, message: str):
|
|
138
|
+
super().__init__(message)
|
|
@@ -10,9 +10,12 @@ flight_helper.egg-info/top_level.txt
|
|
|
10
10
|
flight_helper/models/__init__.py
|
|
11
11
|
flight_helper/models/dto/__init__.py
|
|
12
12
|
flight_helper/models/dto/booking.py
|
|
13
|
+
flight_helper/models/dto/http_schema.py
|
|
13
14
|
flight_helper/models/dto/itinerary.py
|
|
14
15
|
flight_helper/models/dto/passenger.py
|
|
15
16
|
flight_helper/models/dto/payment.py
|
|
16
17
|
flight_helper/models/dto/procurement.py
|
|
18
|
+
flight_helper/utils/__init__.py
|
|
19
|
+
flight_helper/utils/exception_utils.py
|
|
17
20
|
flight_helper/validator/__init__.py
|
|
18
21
|
flight_helper/validator/type_validator.py
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
# ---------------------------------------------------------------------------------------------------------
|
|
4
|
-
# ProjectName: python-flight-helper
|
|
5
|
-
# FileName: procurement.py
|
|
6
|
-
# Description: 采购信息数据转换对象
|
|
7
|
-
# Author: ASUS
|
|
8
|
-
# CreateDate: 2026/01/08
|
|
9
|
-
# Copyright ©2011-2026. Hunan xxxxxxx Company limited. All rights reserved.
|
|
10
|
-
# ---------------------------------------------------------------------------------------------------------
|
|
11
|
-
"""
|
|
12
|
-
from typing import Optional
|
|
13
|
-
from pydantic import BaseModel, PositiveInt, NegativeFloat, Field
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class ProcurementDTO(BaseModel):
|
|
17
|
-
# 平台信息
|
|
18
|
-
pl_domain: Optional[str] = Field(default=None, description="平台域名,例如:www.ceair.com")
|
|
19
|
-
pl_protocol: Optional[str] = Field(default=None, description="平台协议,例如:https")
|
|
20
|
-
order_no: PositiveInt = Field(..., description="订单号")
|
|
21
|
-
out_ticket_platform_type: str = Field(..., description="出票平台类型")
|
|
22
|
-
out_ticket_platform: str = Field(..., description="出票平台")
|
|
23
|
-
out_ticket_account: str = Field(..., description="出票账号")
|
|
24
|
-
purchase_account_type: str = Field(..., description="采购账号类型")
|
|
25
|
-
purchase_account: str = Field(..., description="采购账号")
|
|
26
|
-
purchase_amount: NegativeFloat = Field(..., description="采购金额")
|
|
27
|
-
remark: str = Field(..., description="备注,一般是由采购平台账号 + 账号密码拼接而成")
|
|
28
|
-
out_ticket_mobile: str = Field(..., description="出票手机,退改业务需要根据此手机号码来进行操作")
|
|
29
|
-
pay_transaction: str = Field(..., description="支付流水")
|
|
30
|
-
pre_order_no: str = Field(..., description="采购平台订单号")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|