airalo-sdk 1.0.1__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.
@@ -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
+ )