textverified 0.1.0a0__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.
- textverified/__init__.py +288 -0
- textverified/account_api.py +32 -0
- textverified/action.py +47 -0
- textverified/billing_cycle_api.py +178 -0
- textverified/data/__init__.py +9 -0
- textverified/data/dtypes.py +1561 -0
- textverified/exceptions.py +13 -0
- textverified/paginated_list.py +111 -0
- textverified/reservations_api.py +669 -0
- textverified/sales_api.py +52 -0
- textverified/services_api.py +48 -0
- textverified/sms_api.py +191 -0
- textverified/textverified.py +167 -0
- textverified/verifications_api.py +338 -0
- textverified/wake_api.py +218 -0
- textverified-0.1.0a0.dist-info/LICENSE +21 -0
- textverified-0.1.0a0.dist-info/METADATA +279 -0
- textverified-0.1.0a0.dist-info/RECORD +20 -0
- textverified-0.1.0a0.dist-info/WHEEL +5 -0
- textverified-0.1.0a0.dist-info/top_level.txt +1 -0
textverified/__init__.py
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TextVerified Python Client
|
|
3
|
+
|
|
4
|
+
This package provides a Python interface to the TextVerified API.
|
|
5
|
+
You can either use the TextVerified class directly to manage multiple credentials
|
|
6
|
+
or access API endpoints statically.
|
|
7
|
+
|
|
8
|
+
Example usage:
|
|
9
|
+
from textverified import services, verifications
|
|
10
|
+
# or
|
|
11
|
+
from textverified import TextVerified
|
|
12
|
+
client = TextVerified(api_key="...", api_username="...")
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
# Import the main TextVerified class and API modules
|
|
20
|
+
from .textverified import TextVerified, BearerToken
|
|
21
|
+
from .account_api import AccountAPI
|
|
22
|
+
from .billing_cycle_api import BillingCycleAPI
|
|
23
|
+
from .reservations_api import ReservationsAPI
|
|
24
|
+
from .sales_api import SalesAPI
|
|
25
|
+
from .services_api import ServicesAPI
|
|
26
|
+
from .sms_api import SMSApi
|
|
27
|
+
from .verifications_api import VerificationsAPI
|
|
28
|
+
from .wake_api import WakeAPI
|
|
29
|
+
from .paginated_list import PaginatedList
|
|
30
|
+
from .exceptions import TextVerifiedError
|
|
31
|
+
|
|
32
|
+
# Import generated enums
|
|
33
|
+
from .data import *
|
|
34
|
+
|
|
35
|
+
# Configurable, lazy-initialized static instance
|
|
36
|
+
_static_instance: Optional[TextVerified] = None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _get_static_instance() -> TextVerified:
|
|
40
|
+
"""Get or create the static TextVerified instance."""
|
|
41
|
+
global _static_instance
|
|
42
|
+
if _static_instance is None:
|
|
43
|
+
api_key = os.environ.get("TEXTVERIFIED_API_KEY")
|
|
44
|
+
api_username = os.environ.get("TEXTVERIFIED_API_USERNAME")
|
|
45
|
+
base_url = os.environ.get("TEXTVERIFIED_BASE_URL", "https://www.textverified.com")
|
|
46
|
+
user_agent = os.environ.get("TEXTVERIFIED_USER_AGENT", "TextVerified-Python-Client/0.1.0")
|
|
47
|
+
|
|
48
|
+
if not api_key or not api_username:
|
|
49
|
+
raise ValueError(
|
|
50
|
+
"TextVerified static instance not configured. "
|
|
51
|
+
"Either call configure() or set TEXTVERIFIED_API_KEY and TEXTVERIFIED_API_USERNAME environment variables."
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
_static_instance = TextVerified(
|
|
55
|
+
api_key=api_key, api_username=api_username, base_url=base_url, user_agent=user_agent
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return _static_instance
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def configure(
|
|
62
|
+
api_key: str,
|
|
63
|
+
api_username: str,
|
|
64
|
+
base_url: str = "https://www.textverified.com",
|
|
65
|
+
user_agent: str = "TextVerified-Python-Client/0.1.0",
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Configure the static TextVerified instance."""
|
|
68
|
+
global _static_instance
|
|
69
|
+
_static_instance = TextVerified(
|
|
70
|
+
api_key=api_key, api_username=api_username, base_url=base_url, user_agent=user_agent
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# Lazy property implementation using __getattr__ at module level
|
|
75
|
+
class _LazyAPI:
|
|
76
|
+
"""
|
|
77
|
+
Lazy wrapper for API endpoints that creates the static TextVerified instance
|
|
78
|
+
only when an API endpoint is actually accessed.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __init__(self, attr_name: str, doc: str = None):
|
|
82
|
+
self.attr_name = attr_name
|
|
83
|
+
if doc:
|
|
84
|
+
self.__doc__ = doc
|
|
85
|
+
|
|
86
|
+
def __getattr__(self, name):
|
|
87
|
+
"""Forward attribute access to the actual API endpoint."""
|
|
88
|
+
api_endpoint = getattr(_get_static_instance(), self.attr_name)
|
|
89
|
+
return getattr(api_endpoint, name)
|
|
90
|
+
|
|
91
|
+
def __call__(self, *args, **kwargs):
|
|
92
|
+
"""Forward method calls to the actual API endpoint."""
|
|
93
|
+
api_endpoint = getattr(_get_static_instance(), self.attr_name)
|
|
94
|
+
return api_endpoint(*args, **kwargs)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# Create lazy API wrappers with documentation
|
|
98
|
+
account = _LazyAPI(
|
|
99
|
+
"account",
|
|
100
|
+
"""
|
|
101
|
+
Static access to account management functionality.
|
|
102
|
+
|
|
103
|
+
Provides methods for retrieving account information, balance, and account settings.
|
|
104
|
+
This is a static wrapper around the AccountAPI class that uses the globally
|
|
105
|
+
configured TextVerified instance.
|
|
106
|
+
|
|
107
|
+
Example:
|
|
108
|
+
from textverified import account
|
|
109
|
+
|
|
110
|
+
# Get account information
|
|
111
|
+
account_info = account.me()
|
|
112
|
+
|
|
113
|
+
# Get account balance
|
|
114
|
+
balance = account.balance()
|
|
115
|
+
""",
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
billing_cycles = _LazyAPI(
|
|
119
|
+
"billing_cycles",
|
|
120
|
+
"""
|
|
121
|
+
Static access to billing cycle management functionality.
|
|
122
|
+
|
|
123
|
+
Provides methods for managing billing cycles, invoices, and payment history.
|
|
124
|
+
This is a static wrapper around the BillingCycleAPI class that uses the globally
|
|
125
|
+
configured TextVerified instance.
|
|
126
|
+
|
|
127
|
+
Example:
|
|
128
|
+
from textverified import billing_cycles
|
|
129
|
+
|
|
130
|
+
# List all billing cycles
|
|
131
|
+
cycles = billing_cycles.list()
|
|
132
|
+
|
|
133
|
+
# Get specific billing cycle
|
|
134
|
+
cycle = billing_cycles.get(cycle_id)
|
|
135
|
+
""",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
reservations = _LazyAPI(
|
|
139
|
+
"reservations",
|
|
140
|
+
"""
|
|
141
|
+
Static access to phone number reservation functionality.
|
|
142
|
+
|
|
143
|
+
Provides methods for creating, managing, and releasing phone number reservations.
|
|
144
|
+
This is a static wrapper around the ReservationsAPI class that uses the globally
|
|
145
|
+
configured TextVerified instance.
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
from textverified import reservations
|
|
149
|
+
|
|
150
|
+
# Create a new reservation
|
|
151
|
+
reservation = reservations.create(service_id=1, area_code="555")
|
|
152
|
+
|
|
153
|
+
# List all reservations
|
|
154
|
+
all_reservations = reservations.list()
|
|
155
|
+
""",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
sales = _LazyAPI(
|
|
159
|
+
"sales",
|
|
160
|
+
"""
|
|
161
|
+
Static access to sales and transaction functionality.
|
|
162
|
+
|
|
163
|
+
Provides methods for retrieving sales history, transaction details, and revenue analytics.
|
|
164
|
+
This is a static wrapper around the SalesAPI class that uses the globally
|
|
165
|
+
configured TextVerified instance.
|
|
166
|
+
|
|
167
|
+
Example:
|
|
168
|
+
from textverified import sales
|
|
169
|
+
|
|
170
|
+
# Get sales history
|
|
171
|
+
sales_history = sales.list()
|
|
172
|
+
|
|
173
|
+
# Get specific sale details
|
|
174
|
+
sale = sales.get(sale_id)
|
|
175
|
+
""",
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
services = _LazyAPI(
|
|
179
|
+
"services",
|
|
180
|
+
"""
|
|
181
|
+
Static access to service management functionality.
|
|
182
|
+
|
|
183
|
+
Provides methods for listing available services, getting service pricing,
|
|
184
|
+
and retrieving service-specific information.
|
|
185
|
+
This is a static wrapper around the ServicesAPI class that uses the globally
|
|
186
|
+
configured TextVerified instance.
|
|
187
|
+
|
|
188
|
+
Example:
|
|
189
|
+
from textverified import services
|
|
190
|
+
|
|
191
|
+
# Get all available services
|
|
192
|
+
available_services = services.list()
|
|
193
|
+
|
|
194
|
+
# Get pricing for rentals
|
|
195
|
+
pricing = services.pricing_rentals()
|
|
196
|
+
""",
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
verifications = _LazyAPI(
|
|
200
|
+
"verifications",
|
|
201
|
+
"""
|
|
202
|
+
Static access to phone verification functionality.
|
|
203
|
+
|
|
204
|
+
Provides methods for creating verification requests, checking verification status,
|
|
205
|
+
and managing the verification process.
|
|
206
|
+
This is a static wrapper around the VerificationsAPI class that uses the globally
|
|
207
|
+
configured TextVerified instance.
|
|
208
|
+
|
|
209
|
+
Example:
|
|
210
|
+
from textverified import verifications
|
|
211
|
+
|
|
212
|
+
# Create a new verification
|
|
213
|
+
verification = verifications.create(service_id=1)
|
|
214
|
+
|
|
215
|
+
# Check verification status
|
|
216
|
+
status = verifications.get(verification_id)
|
|
217
|
+
""",
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
wake_requests = _LazyAPI(
|
|
221
|
+
"wake_requests",
|
|
222
|
+
"""
|
|
223
|
+
Static access to wake request functionality.
|
|
224
|
+
|
|
225
|
+
Provides methods for creating and managing wake requests for phone numbers.
|
|
226
|
+
This is a static wrapper around the WakeAPI class that uses the globally
|
|
227
|
+
configured TextVerified instance.
|
|
228
|
+
|
|
229
|
+
Example:
|
|
230
|
+
from textverified import wake_requests
|
|
231
|
+
|
|
232
|
+
# Create a wake request
|
|
233
|
+
wake = wake_requests.create(phone_number="+1234567890")
|
|
234
|
+
|
|
235
|
+
# List wake requests
|
|
236
|
+
wakes = wake_requests.list()
|
|
237
|
+
""",
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
sms = _LazyAPI(
|
|
241
|
+
"sms",
|
|
242
|
+
"""
|
|
243
|
+
Static access to SMS management functionality.
|
|
244
|
+
|
|
245
|
+
Provides methods for sending, receiving, and managing SMS messages.
|
|
246
|
+
This is a static wrapper around the SMSApi class that uses the globally
|
|
247
|
+
configured TextVerified instance.
|
|
248
|
+
|
|
249
|
+
Example:
|
|
250
|
+
from textverified import sms
|
|
251
|
+
|
|
252
|
+
# Get SMS messages
|
|
253
|
+
messages = sms.list()
|
|
254
|
+
|
|
255
|
+
# Get specific SMS
|
|
256
|
+
message = sms.get(message_id)
|
|
257
|
+
""",
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
# Available for import:
|
|
262
|
+
__all__ = [
|
|
263
|
+
# Main classes
|
|
264
|
+
"TextVerified",
|
|
265
|
+
"BearerToken",
|
|
266
|
+
"PaginatedList",
|
|
267
|
+
"TextVerifiedError",
|
|
268
|
+
# Configuration
|
|
269
|
+
"configure",
|
|
270
|
+
# Static API access
|
|
271
|
+
"account",
|
|
272
|
+
"billing_cycles",
|
|
273
|
+
"reservations",
|
|
274
|
+
"sales",
|
|
275
|
+
"services",
|
|
276
|
+
"verifications",
|
|
277
|
+
"wake_requests",
|
|
278
|
+
"sms",
|
|
279
|
+
# API classes (for direct instantiation if needed)
|
|
280
|
+
"AccountAPI",
|
|
281
|
+
"BillingCycleAPI",
|
|
282
|
+
"ReservationsAPI",
|
|
283
|
+
"SalesAPI",
|
|
284
|
+
"ServicesAPI",
|
|
285
|
+
"SMSApi",
|
|
286
|
+
"VerificationsAPI",
|
|
287
|
+
"WakeAPI",
|
|
288
|
+
] + data.__all__
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from .action import _Action, _ActionPerformer
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from .data import Account
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AccountAPI:
|
|
7
|
+
"""API endpoints related to account management."""
|
|
8
|
+
|
|
9
|
+
def __init__(self, client: _ActionPerformer):
|
|
10
|
+
self.client = client
|
|
11
|
+
|
|
12
|
+
def me(self) -> Account:
|
|
13
|
+
"""
|
|
14
|
+
Returns:
|
|
15
|
+
Account: The current account details.
|
|
16
|
+
"""
|
|
17
|
+
action = _Action(method="GET", href="/api/pub/v2/account/me")
|
|
18
|
+
response = self.client._perform_action(action)
|
|
19
|
+
return Account.from_api(response.data)
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def balance(self) -> float:
|
|
23
|
+
"""Get the current account balance."""
|
|
24
|
+
details = self.me()
|
|
25
|
+
return details.current_balance
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def username(self) -> str:
|
|
29
|
+
"""Get the current account username."""
|
|
30
|
+
# Realistically, this is the only request we could cache
|
|
31
|
+
details = self.me()
|
|
32
|
+
return details.username
|
textverified/action.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any, Dict, Union
|
|
3
|
+
from requests.structures import CaseInsensitiveDict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass(frozen=True)
|
|
7
|
+
class _ActionResponse:
|
|
8
|
+
"""Internal Protocol for API responses."""
|
|
9
|
+
|
|
10
|
+
data: Any
|
|
11
|
+
headers: "CaseInsensitiveDict[str, Union[str, int]]"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class _ActionPerformer:
|
|
15
|
+
"""Internal Protocol for objects that can perform API actions."""
|
|
16
|
+
|
|
17
|
+
def _perform_action(self, action: "_Action", **kwargs) -> _ActionResponse:
|
|
18
|
+
"""
|
|
19
|
+
Perform an API action and return the result.
|
|
20
|
+
:param action: The action to perform
|
|
21
|
+
:return: Dictionary containing the API response
|
|
22
|
+
"""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(frozen=True)
|
|
27
|
+
class _Action:
|
|
28
|
+
"""Single API action. Often returned by the API but also used internally."""
|
|
29
|
+
|
|
30
|
+
method: str
|
|
31
|
+
href: str
|
|
32
|
+
|
|
33
|
+
def to_api(self) -> dict:
|
|
34
|
+
"""
|
|
35
|
+
Convert the Action instance to an API-compatible dictionary.
|
|
36
|
+
:return: Dictionary representation of the Action for API requests.
|
|
37
|
+
"""
|
|
38
|
+
return {"method": self.method, "href": self.href}
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def from_api(cls, data: Dict[str, Any]) -> "_Action":
|
|
42
|
+
"""
|
|
43
|
+
Create an Action instance from API data.
|
|
44
|
+
:param data: Dictionary containing the API data.
|
|
45
|
+
:return: Action instance.
|
|
46
|
+
"""
|
|
47
|
+
return cls(method=data["method"], href=data["href"])
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
from .action import _ActionPerformer, _Action
|
|
2
|
+
from typing import List, Union
|
|
3
|
+
from .data import (
|
|
4
|
+
BillingCycleCompact,
|
|
5
|
+
BillingCycleExpanded,
|
|
6
|
+
BillingCycleUpdateRequest,
|
|
7
|
+
BillingCycleRenewalInvoicePreview,
|
|
8
|
+
BillingCycleRenewalInvoice,
|
|
9
|
+
)
|
|
10
|
+
from .paginated_list import PaginatedList
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BillingCycleAPI:
|
|
14
|
+
"""API endpoints related to billing cycles.
|
|
15
|
+
Renewable rentals are associated with billing cycles and can be manually assigned on rental creation or automatically assigned.
|
|
16
|
+
A single billing cycle can have multiple renewable rentals.
|
|
17
|
+
Billing cycles can be updated, renewed, and queried for invoices."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, client: _ActionPerformer):
|
|
20
|
+
self.client = client
|
|
21
|
+
|
|
22
|
+
def list(self) -> PaginatedList[BillingCycleCompact]:
|
|
23
|
+
"""Fetch all billing cycles associated with this account."""
|
|
24
|
+
action = _Action(method="GET", href="/api/pub/v2/billing-cycles")
|
|
25
|
+
response = self.client._perform_action(action)
|
|
26
|
+
|
|
27
|
+
return PaginatedList(
|
|
28
|
+
request_json=response.data, parse_item=BillingCycleCompact.from_api, api_context=self.client
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def get(self, billing_cycle_id: str) -> BillingCycleExpanded:
|
|
32
|
+
"""Get the details of a billing cycle by ID.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
billing_cycle_id (str): The ID of the billing cycle to retrieve.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
BillingCycleExpanded: The detailed information about the billing cycle.
|
|
39
|
+
"""
|
|
40
|
+
action = _Action(method="GET", href=f"/api/pub/v2/billing-cycles/{billing_cycle_id}")
|
|
41
|
+
response = self.client._perform_action(action)
|
|
42
|
+
|
|
43
|
+
return BillingCycleExpanded.from_api(response.data)
|
|
44
|
+
|
|
45
|
+
def update(
|
|
46
|
+
self,
|
|
47
|
+
billing_cycle: Union[str, BillingCycleCompact, BillingCycleExpanded],
|
|
48
|
+
data: BillingCycleUpdateRequest = None,
|
|
49
|
+
*,
|
|
50
|
+
reminders_enabled: bool = None,
|
|
51
|
+
nickname: str = None,
|
|
52
|
+
) -> bool:
|
|
53
|
+
"""Update a billing cycle.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
billing_cycle (Union[str, BillingCycleCompact, BillingCycleExpanded]): The ID or instance of the billing cycle to update.
|
|
57
|
+
data (BillingCycleUpdateRequest, optional): Data to update. Overwritten by kwargs. Defaults to None.
|
|
58
|
+
reminders_enabled (bool, optional): Whether email reminders are enabled. Defaults to None.
|
|
59
|
+
nickname (str, optional): Your custom string to identify the billing cycle. Defaults to None.
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
ValueError: If billing_cycle is not a valid ID or instance, or if no fields are provided to update.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
bool: True if the update was successful, False otherwise.
|
|
66
|
+
"""
|
|
67
|
+
billing_cycle_id = (
|
|
68
|
+
billing_cycle.id
|
|
69
|
+
if isinstance(billing_cycle, (BillingCycleCompact, BillingCycleExpanded))
|
|
70
|
+
else billing_cycle
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
update_request = (
|
|
74
|
+
BillingCycleUpdateRequest(
|
|
75
|
+
reminders_enabled=reminders_enabled if reminders_enabled is not None else data.reminders_enabled,
|
|
76
|
+
nickname=nickname or data.nickname,
|
|
77
|
+
)
|
|
78
|
+
if data
|
|
79
|
+
else BillingCycleUpdateRequest(reminders_enabled=reminders_enabled, nickname=nickname)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if not billing_cycle_id or not isinstance(billing_cycle_id, str):
|
|
83
|
+
raise ValueError("billing_cycle must be a valid ID or instance of BillingCycleCompact/Expanded.")
|
|
84
|
+
|
|
85
|
+
if not update_request or (not update_request.reminders_enabled and not update_request.nickname):
|
|
86
|
+
raise ValueError("At least one field must be updated: reminders_enabled or nickname.")
|
|
87
|
+
|
|
88
|
+
action = _Action(method="POST", href=f"/api/pub/v2/billing-cycles/{billing_cycle_id}")
|
|
89
|
+
response = self.client._perform_action(action, json=update_request.to_api())
|
|
90
|
+
|
|
91
|
+
return True
|
|
92
|
+
|
|
93
|
+
def invoices(
|
|
94
|
+
self, billing_cycle_id: Union[str, BillingCycleCompact, BillingCycleExpanded]
|
|
95
|
+
) -> PaginatedList[BillingCycleRenewalInvoice]:
|
|
96
|
+
"""Get invoices for a specific billing cycle.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
billing_cycle_id (Union[str, BillingCycleCompact, BillingCycleExpanded]): The ID or instance of the billing cycle to retrieve invoices for.
|
|
100
|
+
|
|
101
|
+
Raises:
|
|
102
|
+
ValueError: If billing_cycle_id is not a valid ID or instance.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
PaginatedList[BillingCycleRenewalInvoice]: A paginated list of billing cycle renewal invoices.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
billing_cycle_id = (
|
|
109
|
+
billing_cycle_id.id
|
|
110
|
+
if isinstance(billing_cycle_id, (BillingCycleCompact, BillingCycleExpanded))
|
|
111
|
+
else billing_cycle_id
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if not billing_cycle_id or not isinstance(billing_cycle_id, str):
|
|
115
|
+
raise ValueError("billing_cycle_id must be a valid ID or instance of BillingCycleCompact/Expanded.")
|
|
116
|
+
|
|
117
|
+
action = _Action(method="GET", href=f"/api/pub/v2/billing-cycles/{billing_cycle_id}/invoices")
|
|
118
|
+
response = self.client._perform_action(action)
|
|
119
|
+
|
|
120
|
+
return PaginatedList(
|
|
121
|
+
request_json=response.data, parse_item=BillingCycleRenewalInvoice.from_api, api_context=self.client
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
def preview(
|
|
125
|
+
self, billing_cycle_id: Union[str, BillingCycleCompact, BillingCycleExpanded]
|
|
126
|
+
) -> BillingCycleRenewalInvoice:
|
|
127
|
+
"""Preview the next billing cycle invoice.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
billing_cycle_id (Union[str, BillingCycleCompact, BillingCycleExpanded]): The ID or instance of the billing cycle to preview.
|
|
131
|
+
|
|
132
|
+
Raises:
|
|
133
|
+
ValueError: If billing_cycle_id is not a valid ID or instance.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
BillingCycleRenewalInvoice: The preview of the next billing cycle invoice.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
billing_cycle_id = (
|
|
140
|
+
billing_cycle_id.id
|
|
141
|
+
if isinstance(billing_cycle_id, (BillingCycleCompact, BillingCycleExpanded))
|
|
142
|
+
else billing_cycle_id
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
if not billing_cycle_id or not isinstance(billing_cycle_id, str):
|
|
146
|
+
raise ValueError("billing_cycle_id must be a valid ID or instance of BillingCycleCompact/Expanded.")
|
|
147
|
+
|
|
148
|
+
action = _Action(method="POST", href=f"/api/pub/v2/billing-cycles/{billing_cycle_id}/next-invoice")
|
|
149
|
+
response = self.client._perform_action(action)
|
|
150
|
+
return BillingCycleRenewalInvoicePreview.from_api(response.data)
|
|
151
|
+
|
|
152
|
+
def renew(self, billing_cycle_id: Union[str, BillingCycleCompact, BillingCycleExpanded]) -> bool:
|
|
153
|
+
"""Renew the active rentals on your billing cycle.
|
|
154
|
+
Will not renew overdue rentals. To renew overdue rentals, you must explicitly call `textverified.reservations.renew_overdue_renewable_reservation` on each overdue rental.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
billing_cycle_id (Union[str, BillingCycleCompact, BillingCycleExpanded]): The ID or instance of the billing cycle to renew.
|
|
158
|
+
|
|
159
|
+
Raises:
|
|
160
|
+
ValueError: If billing_cycle_id is not a valid ID or instance.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
bool: True if the billing cycle was renewed successfully, False otherwise.
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
billing_cycle_id = (
|
|
167
|
+
billing_cycle_id.id
|
|
168
|
+
if isinstance(billing_cycle_id, (BillingCycleCompact, BillingCycleExpanded))
|
|
169
|
+
else billing_cycle_id
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
if not billing_cycle_id or not isinstance(billing_cycle_id, str):
|
|
173
|
+
raise ValueError("billing_cycle_id must be a valid ID or instance of BillingCycleCompact/Expanded.")
|
|
174
|
+
|
|
175
|
+
action = _Action(method="POST", href=f"/api/pub/v2/billing-cycles/{billing_cycle_id}/renew")
|
|
176
|
+
self.client._perform_action(action)
|
|
177
|
+
|
|
178
|
+
return True
|