airalo-sdk 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of airalo-sdk might be problematic. Click here for more details.
- airalo/__init__.py +29 -0
- airalo/airalo.py +620 -0
- airalo/config.py +146 -0
- airalo/constants/__init__.py +8 -0
- airalo/constants/api_constants.py +49 -0
- airalo/constants/sdk_constants.py +32 -0
- airalo/exceptions/__init__.py +21 -0
- airalo/exceptions/airalo_exception.py +64 -0
- airalo/helpers/__init__.py +9 -0
- airalo/helpers/cached.py +177 -0
- airalo/helpers/cloud_sim_share_validator.py +89 -0
- airalo/helpers/crypt.py +154 -0
- airalo/helpers/date_helper.py +12 -0
- airalo/helpers/signature.py +119 -0
- airalo/resources/__init__.py +8 -0
- airalo/resources/http_resource.py +324 -0
- airalo/resources/multi_http_resource.py +312 -0
- airalo/services/__init__.py +17 -0
- airalo/services/compatibility_devices_service.py +34 -0
- airalo/services/exchange_rates_service.py +69 -0
- airalo/services/future_order_service.py +113 -0
- airalo/services/installation_instructions_service.py +63 -0
- airalo/services/oauth_service.py +186 -0
- airalo/services/order_service.py +463 -0
- airalo/services/packages_service.py +354 -0
- airalo/services/sim_service.py +349 -0
- airalo/services/topup_service.py +127 -0
- airalo/services/voucher_service.py +138 -0
- airalo_sdk-1.0.0.dist-info/METADATA +939 -0
- airalo_sdk-1.0.0.dist-info/RECORD +33 -0
- airalo_sdk-1.0.0.dist-info/WHEEL +5 -0
- airalo_sdk-1.0.0.dist-info/licenses/LICENSE +21 -0
- airalo_sdk-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Topup Service Module
|
|
3
|
+
|
|
4
|
+
This module handles top-up related API operations including creating top-ups.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
|
|
10
|
+
from ..config import Config
|
|
11
|
+
from ..constants.api_constants import ApiConstants
|
|
12
|
+
from ..exceptions.airalo_exception import AiraloException, ValidationError, APIError
|
|
13
|
+
from ..helpers.signature import Signature
|
|
14
|
+
from ..resources.http_resource import HttpResource
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TopupService:
|
|
18
|
+
"""
|
|
19
|
+
Service for managing top-up operations.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
config: Config,
|
|
25
|
+
http_resource: HttpResource,
|
|
26
|
+
signature: Signature,
|
|
27
|
+
access_token: str,
|
|
28
|
+
):
|
|
29
|
+
"""
|
|
30
|
+
Initialize top-up service.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
config: SDK configuration
|
|
34
|
+
http_resource: HTTP client for requests
|
|
35
|
+
signature: Signature generator for request signing
|
|
36
|
+
access_token: API access token
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
AiraloException: If access token is invalid
|
|
40
|
+
"""
|
|
41
|
+
if not access_token:
|
|
42
|
+
raise AiraloException("Invalid access token, please check your credentials")
|
|
43
|
+
|
|
44
|
+
self._config = config
|
|
45
|
+
self._http = http_resource
|
|
46
|
+
self._signature = signature
|
|
47
|
+
self._access_token = access_token
|
|
48
|
+
self._base_url = config.get_url()
|
|
49
|
+
|
|
50
|
+
def create_topup(self, payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
51
|
+
"""
|
|
52
|
+
Create a new top-up.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
payload: Top-up data including:
|
|
56
|
+
- package_id: Package ID to top-up (required)
|
|
57
|
+
- iccid: ICCID of the SIM to top-up (required)
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Top-up response data or None
|
|
61
|
+
|
|
62
|
+
Raises:
|
|
63
|
+
ValidationError: If payload is invalid
|
|
64
|
+
APIError: If API request fails
|
|
65
|
+
"""
|
|
66
|
+
self._validate_topup(payload)
|
|
67
|
+
|
|
68
|
+
# Set headers with signature
|
|
69
|
+
headers = self._get_headers(payload)
|
|
70
|
+
self._http.set_headers(headers)
|
|
71
|
+
|
|
72
|
+
# Make request
|
|
73
|
+
url = self._base_url + ApiConstants.TOPUPS_SLUG
|
|
74
|
+
response = self._http.post(url, payload)
|
|
75
|
+
|
|
76
|
+
if self._http.code != 200:
|
|
77
|
+
raise APIError(
|
|
78
|
+
f"Topup creation failed, status code: {self._http.code}, response: {response}"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
return json.loads(response)
|
|
83
|
+
except json.JSONDecodeError:
|
|
84
|
+
raise APIError("Failed to parse top-up response")
|
|
85
|
+
|
|
86
|
+
def _get_headers(self, payload: Dict[str, Any]) -> Dict[str, str]:
|
|
87
|
+
"""
|
|
88
|
+
Get headers for top-up request with signature.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
payload: Request payload
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
Headers dictionary
|
|
95
|
+
"""
|
|
96
|
+
return {
|
|
97
|
+
"Content-Type": "application/json",
|
|
98
|
+
"Authorization": f"Bearer {self._access_token}",
|
|
99
|
+
"airalo-signature": self._signature.get_signature(payload),
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
def _validate_topup(self, payload: Dict[str, Any]) -> None:
|
|
103
|
+
"""
|
|
104
|
+
Validate top-up payload.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
payload: Top-up data
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
ValidationError: If validation fails
|
|
111
|
+
"""
|
|
112
|
+
if not payload.get("package_id"):
|
|
113
|
+
raise ValidationError(
|
|
114
|
+
f"The package_id is required, payload: {json.dumps(payload)}"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
iccid = payload.get("iccid")
|
|
118
|
+
|
|
119
|
+
if not iccid:
|
|
120
|
+
raise ValidationError(
|
|
121
|
+
f"The iccid is required, payload: {json.dumps(payload)}"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
if len(iccid) < 16 or len(iccid) > 21:
|
|
125
|
+
raise ValidationError(
|
|
126
|
+
f"The iccid must be between 16 and 21 characters, received: {iccid}"
|
|
127
|
+
)
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from airalo.config import Config
|
|
4
|
+
from airalo.constants.api_constants import ApiConstants
|
|
5
|
+
from airalo.constants.sdk_constants import SdkConstants
|
|
6
|
+
from airalo.exceptions.airalo_exception import AiraloException
|
|
7
|
+
from airalo.helpers.signature import Signature
|
|
8
|
+
from airalo.resources.http_resource import HttpResource
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class VoucherService:
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
config: Config,
|
|
15
|
+
curl: HttpResource,
|
|
16
|
+
signature: Signature,
|
|
17
|
+
access_token: str,
|
|
18
|
+
):
|
|
19
|
+
if not access_token:
|
|
20
|
+
raise AiraloException("Invalid access token please check your credentials")
|
|
21
|
+
|
|
22
|
+
self.config = config
|
|
23
|
+
self.curl = curl
|
|
24
|
+
self.signature = signature
|
|
25
|
+
self.access_token = access_token
|
|
26
|
+
|
|
27
|
+
def create_voucher(self, payload: dict) -> dict | None:
|
|
28
|
+
self._validate_voucher(payload)
|
|
29
|
+
|
|
30
|
+
headers = self._get_headers(payload)
|
|
31
|
+
response = self.curl.set_headers(headers).post(
|
|
32
|
+
self.config.get_url() + ApiConstants.VOUCHERS_SLUG, payload
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
if self.curl.code != 200:
|
|
36
|
+
raise AiraloException(
|
|
37
|
+
f"Voucher creation failed, status code: {self.curl.code}, response: {response}"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
return json.loads(response)
|
|
41
|
+
|
|
42
|
+
def create_esim_voucher(self, payload: dict) -> dict | None:
|
|
43
|
+
self._validate_esim_voucher(payload)
|
|
44
|
+
|
|
45
|
+
headers = self._get_headers(payload)
|
|
46
|
+
response = self.curl.set_headers(headers).post(
|
|
47
|
+
self.config.get_url() + ApiConstants.VOUCHERS_ESIM_SLUG, payload
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if self.curl.code != 200:
|
|
51
|
+
raise AiraloException(
|
|
52
|
+
f"Voucher creation failed, status code: {self.curl.code}, response: {response}"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
return json.loads(response)
|
|
56
|
+
|
|
57
|
+
def _get_headers(self, payload: dict) -> list[str]:
|
|
58
|
+
return [
|
|
59
|
+
"Content-Type: application/json",
|
|
60
|
+
f"Authorization: Bearer {self.access_token}",
|
|
61
|
+
f"airalo-signature: {self.signature.get_signature(payload)}",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
def _validate_voucher(self, payload: dict) -> None:
|
|
65
|
+
if "amount" not in payload or payload["amount"] == "" or payload["amount"] < 1:
|
|
66
|
+
raise AiraloException(
|
|
67
|
+
f"The amount is required, payload: {json.dumps(payload)}"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
if payload["amount"] > SdkConstants.VOUCHER_MAX_NUM:
|
|
71
|
+
raise AiraloException(
|
|
72
|
+
f"The amount may not be greater than {SdkConstants.VOUCHER_MAX_NUM}"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
if (
|
|
76
|
+
"voucher_code" in payload
|
|
77
|
+
and isinstance(payload["voucher_code"], str)
|
|
78
|
+
and len(payload["voucher_code"]) > 255
|
|
79
|
+
):
|
|
80
|
+
raise AiraloException("The voucher code may not exceed 255 characters.")
|
|
81
|
+
|
|
82
|
+
if (
|
|
83
|
+
"voucher_code" in payload
|
|
84
|
+
and "quantity" in payload
|
|
85
|
+
and payload["quantity"] > 1
|
|
86
|
+
):
|
|
87
|
+
raise AiraloException(
|
|
88
|
+
"The selected voucher code allows a maximum quantity of 1"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if "usage_limit" in payload and (
|
|
92
|
+
payload["usage_limit"] < 1
|
|
93
|
+
or payload["usage_limit"] > SdkConstants.VOUCHER_MAX_NUM
|
|
94
|
+
):
|
|
95
|
+
raise AiraloException(
|
|
96
|
+
f"The usage_limit may not be greater than {SdkConstants.VOUCHER_MAX_NUM}"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if (
|
|
100
|
+
"quantity" not in payload
|
|
101
|
+
or payload["quantity"] == ""
|
|
102
|
+
or payload["quantity"] < 1
|
|
103
|
+
):
|
|
104
|
+
raise AiraloException(
|
|
105
|
+
f"The quantity is required, payload: {json.dumps(payload)}"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if payload["quantity"] > SdkConstants.VOUCHER_MAX_QUANTITY:
|
|
109
|
+
raise AiraloException(
|
|
110
|
+
f"The quantity may not be greater than {SdkConstants.VOUCHER_MAX_QUANTITY}"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
def _validate_esim_voucher(self, payload: dict) -> None:
|
|
114
|
+
if not payload.get("vouchers"):
|
|
115
|
+
raise AiraloException(
|
|
116
|
+
f"vouchers field is required, payload: {json.dumps(payload)}"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if not isinstance(payload["vouchers"], list):
|
|
120
|
+
raise AiraloException(
|
|
121
|
+
f"vouchers field should be an array, payload: {json.dumps(payload)}"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
for voucher in payload["vouchers"]:
|
|
125
|
+
if not voucher.get("package_id"):
|
|
126
|
+
raise AiraloException(
|
|
127
|
+
f"The vouchers.package_id is required, payload: {json.dumps(payload)}"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
if not voucher.get("quantity"):
|
|
131
|
+
raise AiraloException(
|
|
132
|
+
f"The vouchers.quantity is required and should be greater than 0, payload: {json.dumps(payload)}"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if payload.get("quantity", 0) > SdkConstants.VOUCHER_MAX_QUANTITY:
|
|
136
|
+
raise AiraloException(
|
|
137
|
+
f"The vouchers.quantity may not be greater than {SdkConstants.VOUCHER_MAX_QUANTITY}"
|
|
138
|
+
)
|