python-terminusgps 49.3.0__tar.gz → 50.1.0__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.
Files changed (58) hide show
  1. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/PKG-INFO +1 -1
  2. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/conf.py +1 -1
  3. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/pyproject.toml +1 -1
  4. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/authorizenet/service.py +2 -3
  5. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/wialon/session.py +1 -2
  6. python_terminusgps-50.1.0/terminusgps/wialon/utils.py +209 -0
  7. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/uv.lock +37 -25
  8. python_terminusgps-49.3.0/terminusgps/tests/authorizenet/__init__.py +0 -0
  9. python_terminusgps-49.3.0/terminusgps/tests/wialon/__init__.py +0 -0
  10. python_terminusgps-49.3.0/terminusgps/wialon/__init__.py +0 -0
  11. python_terminusgps-49.3.0/terminusgps/wialon/items/__init__.py +0 -1
  12. python_terminusgps-49.3.0/terminusgps/wialon/items/account.py +0 -217
  13. python_terminusgps-49.3.0/terminusgps/wialon/items/base.py +0 -272
  14. python_terminusgps-49.3.0/terminusgps/wialon/items/factory.py +0 -126
  15. python_terminusgps-49.3.0/terminusgps/wialon/items/resource.py +0 -126
  16. python_terminusgps-49.3.0/terminusgps/wialon/items/retranslator.py +0 -39
  17. python_terminusgps-49.3.0/terminusgps/wialon/items/route.py +0 -35
  18. python_terminusgps-49.3.0/terminusgps/wialon/items/unit.py +0 -152
  19. python_terminusgps-49.3.0/terminusgps/wialon/items/unit_group.py +0 -55
  20. python_terminusgps-49.3.0/terminusgps/wialon/items/user.py +0 -135
  21. python_terminusgps-49.3.0/terminusgps/wialon/utils.py +0 -417
  22. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/.github/workflows/sphinx.yml +0 -0
  23. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/.gitignore +0 -0
  24. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/.python-version +0 -0
  25. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/COPYING +0 -0
  26. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/README.md +0 -0
  27. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/Makefile +0 -0
  28. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/make.bat +0 -0
  29. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/requirements.txt +0 -0
  30. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/authorizenet/api.rst +0 -0
  31. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/authorizenet/constants.rst +0 -0
  32. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/authorizenet/index.rst +0 -0
  33. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/authorizenet/service.rst +0 -0
  34. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/index.rst +0 -0
  35. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/mixins.rst +0 -0
  36. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/validators.rst +0 -0
  37. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/wialon/constants.rst +0 -0
  38. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/wialon/exceptions.rst +0 -0
  39. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/wialon/index.rst +0 -0
  40. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/wialon/items.rst +0 -0
  41. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/wialon/session.rst +0 -0
  42. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/wialon/usage.rst +0 -0
  43. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/docs/source/wialon/utils.rst +0 -0
  44. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/__init__.py +0 -0
  45. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/authorizenet/__init__.py +0 -0
  46. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/authorizenet/api/__init__.py +0 -0
  47. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/authorizenet/api/address_profiles.py +0 -0
  48. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/authorizenet/api/customer_profiles.py +0 -0
  49. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/authorizenet/api/payment_profiles.py +0 -0
  50. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/authorizenet/api/subscriptions.py +0 -0
  51. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/authorizenet/api/transactions.py +0 -0
  52. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/authorizenet/constants.py +0 -0
  53. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/default_settings.py +0 -0
  54. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/mixins.py +0 -0
  55. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/validators.py +0 -0
  56. {python_terminusgps-49.3.0/terminusgps/tests → python_terminusgps-50.1.0/terminusgps/wialon}/__init__.py +0 -0
  57. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/wialon/constants.py +0 -0
  58. {python_terminusgps-49.3.0 → python_terminusgps-50.1.0}/terminusgps/wialon/flags.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-terminusgps
3
- Version: 49.3.0
3
+ Version: 50.1.0
4
4
  Summary: Provides abstractions/utilities for working with Wialon API, Authorize.NET API, AWS API, and more.
5
5
  Project-URL: Documentation, https://terminusgps.github.io/python-terminusgps
6
6
  Project-URL: Repository, https://github.com/terminusgps/python-terminusgps
@@ -12,7 +12,7 @@ sys.path.insert(0, os.path.abspath("../../"))
12
12
  project = "python-terminusgps"
13
13
  copyright = "2025, Terminus GPS, LLC"
14
14
  author = "Terminus GPS, LLC"
15
- release = "49.3.0"
15
+ release = "50.1.0"
16
16
 
17
17
  # -- General configuration ---------------------------------------------------
18
18
  # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-terminusgps"
3
- version = "49.3.0"
3
+ version = "50.1.0"
4
4
  description = "Provides abstractions/utilities for working with Wialon API, Authorize.NET API, AWS API, and more."
5
5
  readme = "README.md"
6
6
  authors = [ {name = "Blake Nall", email = "blake@terminusgps.com" } ]
@@ -1,4 +1,3 @@
1
- from abc import ABC
2
1
  from functools import cached_property
3
2
 
4
3
  from authorizenet.apicontractsv1 import merchantAuthenticationType
@@ -35,8 +34,8 @@ class AuthorizenetControllerExecutionError(Exception):
35
34
  return self._code
36
35
 
37
36
 
38
- class AuthorizenetService(ABC):
39
- """Base service for safely interacting with the Authorizenet API."""
37
+ class AuthorizenetService:
38
+ """Service for safely interacting with the Authorizenet API."""
40
39
 
41
40
  REQUIRED_SETTINGS = (
42
41
  "MERCHANT_AUTH_ENVIRONMENT",
@@ -15,8 +15,7 @@ class WialonAPIError(Exception):
15
15
  try:
16
16
  self._code = int(message._code)
17
17
  except ValueError:
18
- # 6 = 'Unknown Error' according to Wialon
19
- self._code = 6
18
+ self._code = 6 # 'Unknown Error' according to Wialon
20
19
  return super().__init__(message, *args, **kwargs)
21
20
 
22
21
  @property
@@ -0,0 +1,209 @@
1
+ import secrets
2
+ import string
3
+ import typing
4
+
5
+ from terminusgps.wialon.session import WialonSession
6
+
7
+ __all__ = [
8
+ "generate_wialon_password",
9
+ "get_unit_from_iccid",
10
+ "get_unit_from_imei",
11
+ "get_units_from_carrier",
12
+ ]
13
+
14
+
15
+ def generate_wialon_password(length: int = 32) -> str:
16
+ """
17
+ Generates a Wialon compliant password between ``8`` and ``64`` characters.
18
+
19
+ The generated password will contain:
20
+
21
+ - At least one uppercase letter.
22
+ - At least one lowercase letter.
23
+ - At least one special symbol.
24
+ - At least three digits.
25
+
26
+ :param length: Length of the generated password. Default is ``32``.
27
+ :type length: int
28
+ :raises ValueError: If ``length`` was less than ``8`` or greater than ``64``.
29
+ :returns: A Wialon compliant password.
30
+ :rtype: str
31
+
32
+ """
33
+ if length > 64:
34
+ raise ValueError(
35
+ f"Password cannot be greater than 64 characters in length, got {length}."
36
+ )
37
+ elif length < 8:
38
+ raise ValueError(
39
+ f"Password cannot be less than 8 characters in length, got {length}."
40
+ )
41
+
42
+ s0 = list(string.ascii_uppercase)
43
+ s1 = list(string.ascii_lowercase)
44
+ s2 = list(string.digits)
45
+ s3 = list("!@#$%^*()[]-_+")
46
+
47
+ while True:
48
+ password = "".join(
49
+ [secrets.choice(s0 + s1 + s2 + s3) for _ in range(length)]
50
+ )
51
+ if (
52
+ any(c.islower() for c in password)
53
+ and any(c.isupper() for c in password)
54
+ and sum(c.isdigit() for c in password) >= 3
55
+ and any(c in s3 for c in password)
56
+ ):
57
+ break
58
+ return password
59
+
60
+
61
+ def get_unit_from_iccid(
62
+ iccid: str,
63
+ session: WialonSession,
64
+ *,
65
+ flags: int = 1,
66
+ use_cache: bool = True,
67
+ afield_key: str = "iccid",
68
+ ) -> dict[str, typing.Any]:
69
+ """
70
+ Returns a Wialon unit from a telecom iccid.
71
+
72
+ :param iccid: A telecom iccid number.
73
+ :type iccid: str
74
+ :param session: A valid Wialon API session.
75
+ :type session: ~terminusgps.wialon.session.WialonSession
76
+ :param flags: Wialon API response format flags. Default is ``1``.
77
+ :type flags: int
78
+ :param use_cache: Whether to use a cached Wialon API response or force a Wialon API call. Default is :py:obj:`True`.
79
+ :type use_cache: bool
80
+ :param afield_key: Admin field key to search against. Default is ``"iccid"``.
81
+ :type afield_key: str
82
+ :raises ValueError: If multiple units were found with the provided iccid.
83
+ :raises ValueError: If zero units were found with the provided iccid.
84
+ :raises WialonAPIError: If something went wrong calling the Wialon API.
85
+ :returns: A Wialon unit dictionary.
86
+ :rtype: dict[str, ~typing.Any]
87
+
88
+ """
89
+ response = session.wialon_api.core_search_items(
90
+ **{
91
+ "spec": {
92
+ "itemsType": "avl_unit",
93
+ "propName": "rel_adminfield_name,rel_adminfield_value",
94
+ "propValueMask": f"{afield_key},{iccid}",
95
+ "sortType": "sys_name",
96
+ "propType": "admin_fields,admin_fields",
97
+ },
98
+ "force": int(not use_cache),
99
+ "flags": flags,
100
+ "from": 0,
101
+ "to": 0,
102
+ }
103
+ )
104
+ if int(response["totalItemsCount"]) > 1:
105
+ raise ValueError(f"Multiple units found for iccid #{iccid}.")
106
+ elif int(response["totalItemsCount"]) == 0:
107
+ raise ValueError(f"No units found for iccid #{iccid}.")
108
+ return response["items"][0]
109
+
110
+
111
+ def get_unit_from_imei(
112
+ imei: str,
113
+ session: WialonSession,
114
+ *,
115
+ flags: int = 1,
116
+ use_cache: bool = True,
117
+ ) -> dict[str, typing.Any]:
118
+ """
119
+ Returns a Wialon unit ID from an IMEI (sys_unique_id) number.
120
+
121
+ :param imei: An IMEI number.
122
+ :type imei: str
123
+ :param session: A valid Wialon API session.
124
+ :type session: ~terminusgps.wialon.session.WialonSession
125
+ :param flags: Wialon API response format flags. Default is ``1``.
126
+ :type flags: int
127
+ :param use_cache: Whether to use a cached Wialon API response or force a Wialon API call. Default is :py:obj:`True`.
128
+ :type use_cache: bool
129
+ :raises ValueError: If multiple units were found with the provided IMEI number.
130
+ :raises ValueError: If zero units were found with the provided IMEI number.
131
+ :raises WialonAPIError: If something went wrong calling the Wialon API.
132
+ :returns: A Wialon unit dictionary.
133
+ :rtype: dict[str, ~typing.Any]
134
+
135
+ """
136
+ response = session.wialon_api.core_search_items(
137
+ **{
138
+ "spec": {
139
+ "itemsType": "avl_unit",
140
+ "propName": "sys_unique_id",
141
+ "propValueMask": imei,
142
+ "sortType": "sys_name",
143
+ "propType": "property",
144
+ },
145
+ "force": int(not use_cache),
146
+ "flags": flags,
147
+ "from": 0,
148
+ "to": 0,
149
+ }
150
+ )
151
+ if int(response["totalItemsCount"]) > 1:
152
+ raise ValueError(f"Multiple units found for IMEI #{imei}.")
153
+ elif int(response["totalItemsCount"]) == 0:
154
+ raise ValueError(f"No units found for IMEI #{imei}.")
155
+ return response["items"][0]
156
+
157
+
158
+ def get_units_from_carrier(
159
+ carrier: str,
160
+ session: WialonSession,
161
+ *,
162
+ use_cache: bool = True,
163
+ afield_key: str = "carrier",
164
+ flags: int = 1,
165
+ start: int = 0,
166
+ end: int = 0,
167
+ ) -> list[dict[str, typing.Any]]:
168
+ """
169
+ Returns a list of Wialon unit IDs by telecom carrier name.
170
+
171
+ The list may be empty if no units were found.
172
+
173
+ :param carrier: A telecom carrier name.
174
+ :type carrier: str
175
+ :param session: A valid Wialon API session.
176
+ :type session: ~terminusgps.wialon.session.WialonSession
177
+ :param use_cache: Whether to use a cached Wialon API response or force a Wialon API call. Default is :py:obj:`True`.
178
+ :type use_cache: bool
179
+ :param afield_key: Admin field key to search against. Default is ``"carrier"``.
180
+ :type afield_key: str
181
+ :param flags: Wialon API response flags. Default is ``1``.
182
+ :type flags: int
183
+ :param start: Start index. Default is ``0``.
184
+ :type start: int
185
+ :param end: End index. Default is ``0``.
186
+ :type end: int
187
+ :raises WialonAPIError: If something went wrong calling the Wialon API.
188
+ :returns: A list of Wialon unit dictionaries.
189
+ :rtype: list[dict[str, ~typing.Any]]
190
+
191
+ """
192
+ response = session.wialon_api.core_search_items(
193
+ **{
194
+ "spec": {
195
+ "itemsType": "avl_unit",
196
+ "propName": "rel_adminfield_name,rel_adminfield_value",
197
+ "propValueMask": f"{afield_key},{carrier}",
198
+ "sortType": "sys_name",
199
+ "propType": "admin_fields,admin_fields",
200
+ },
201
+ "force": int(not use_cache),
202
+ "flags": flags,
203
+ "from": start,
204
+ "to": end,
205
+ }
206
+ )
207
+ if int(response["totalItemsCount"]) == 0:
208
+ return []
209
+ return response["items"]
@@ -180,15 +180,15 @@ wheels = [
180
180
 
181
181
  [[package]]
182
182
  name = "beautifulsoup4"
183
- version = "4.14.2"
183
+ version = "4.14.3"
184
184
  source = { registry = "https://pypi.org/simple" }
185
185
  dependencies = [
186
186
  { name = "soupsieve" },
187
187
  { name = "typing-extensions" },
188
188
  ]
189
- sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822 }
189
+ sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737 }
190
190
  wheels = [
191
- { url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392 },
191
+ { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721 },
192
192
  ]
193
193
 
194
194
  [[package]]
@@ -268,21 +268,21 @@ wheels = [
268
268
 
269
269
  [[package]]
270
270
  name = "django"
271
- version = "5.2.8"
271
+ version = "6.0"
272
272
  source = { registry = "https://pypi.org/simple" }
273
273
  dependencies = [
274
274
  { name = "asgiref" },
275
275
  { name = "sqlparse" },
276
276
  { name = "tzdata", marker = "sys_platform == 'win32'" },
277
277
  ]
278
- sdist = { url = "https://files.pythonhosted.org/packages/05/a2/933dbbb3dd9990494960f6e64aca2af4c0745b63b7113f59a822df92329e/django-5.2.8.tar.gz", hash = "sha256:23254866a5bb9a2cfa6004e8b809ec6246eba4b58a7589bc2772f1bcc8456c7f", size = 10849032 }
278
+ sdist = { url = "https://files.pythonhosted.org/packages/15/75/19762bfc4ea556c303d9af8e36f0cd910ab17dff6c8774644314427a2120/django-6.0.tar.gz", hash = "sha256:7b0c1f50c0759bbe6331c6a39c89ae022a84672674aeda908784617ef47d8e26", size = 10932418 }
279
279
  wheels = [
280
- { url = "https://files.pythonhosted.org/packages/5e/3d/a035a4ee9b1d4d4beee2ae6e8e12fe6dee5514b21f62504e22efcbd9fb46/django-5.2.8-py3-none-any.whl", hash = "sha256:37e687f7bd73ddf043e2b6b97cfe02fcbb11f2dbb3adccc6a2b18c6daa054d7f", size = 8289692 },
280
+ { url = "https://files.pythonhosted.org/packages/d7/ae/f19e24789a5ad852670d6885f5480f5e5895576945fcc01817dfd9bc002a/django-6.0-py3-none-any.whl", hash = "sha256:1cc2c7344303bbfb7ba5070487c17f7fc0b7174bbb0a38cebf03c675f5f19b6d", size = 8339181 },
281
281
  ]
282
282
 
283
283
  [[package]]
284
284
  name = "django-stubs"
285
- version = "5.2.7"
285
+ version = "5.2.8"
286
286
  source = { registry = "https://pypi.org/simple" }
287
287
  dependencies = [
288
288
  { name = "django" },
@@ -290,22 +290,22 @@ dependencies = [
290
290
  { name = "types-pyyaml" },
291
291
  { name = "typing-extensions" },
292
292
  ]
293
- sdist = { url = "https://files.pythonhosted.org/packages/5d/a8/bc8c55212978f1e666486b60a4bfb0bc3a066de8212fa7389ff0f3dca639/django_stubs-5.2.7.tar.gz", hash = "sha256:2a07e47a8a867836a763c6bba8bf3775847b4fd9555bfa940360e32d0ee384a1", size = 257339 }
293
+ sdist = { url = "https://files.pythonhosted.org/packages/6c/75/97626224fd8f1787bb6f7f06944efcfddd5da7764bf741cf7f59d102f4a0/django_stubs-5.2.8.tar.gz", hash = "sha256:9bba597c9a8ed8c025cae4696803d5c8be1cf55bfc7648a084cbf864187e2f8b", size = 257709 }
294
294
  wheels = [
295
- { url = "https://files.pythonhosted.org/packages/ad/66/1c8063eee88a943f01d073dbbbda34ed093bf6e19738178506a66abbd5ad/django_stubs-5.2.7-py3-none-any.whl", hash = "sha256:2864e74b56ead866ff1365a051f24d852f6ed02238959664f558a6c9601c95bf", size = 507733 },
295
+ { url = "https://files.pythonhosted.org/packages/7d/3f/7c9543ad5ade5ce1d33d187a3abd82164570314ebee72c6206ab5c044ebf/django_stubs-5.2.8-py3-none-any.whl", hash = "sha256:a3c63119fd7062ac63d58869698d07c9e5ec0561295c4e700317c54e8d26716c", size = 508136 },
296
296
  ]
297
297
 
298
298
  [[package]]
299
299
  name = "django-stubs-ext"
300
- version = "5.2.7"
300
+ version = "5.2.8"
301
301
  source = { registry = "https://pypi.org/simple" }
302
302
  dependencies = [
303
303
  { name = "django" },
304
304
  { name = "typing-extensions" },
305
305
  ]
306
- sdist = { url = "https://files.pythonhosted.org/packages/9b/6f/a0bab0e6a7676ab3ca02d51b459444e9bd6dd747e3a43b9c24cae6d0a1c6/django_stubs_ext-5.2.7.tar.gz", hash = "sha256:b690655bd4cb8a44ae57abb314e0995dc90414280db8f26fff0cb9fb367d1cac", size = 6524 }
306
+ sdist = { url = "https://files.pythonhosted.org/packages/14/a2/d67f4a5200ff7626b104eddceaf529761cba4ed318a73ffdb0677551be73/django_stubs_ext-5.2.8.tar.gz", hash = "sha256:b39938c46d7a547cd84e4a6378dbe51a3dd64d70300459087229e5fee27e5c6b", size = 6487 }
307
307
  wheels = [
308
- { url = "https://files.pythonhosted.org/packages/f8/c9/60445606e26706d3fccadf3b80ee1a9f32c1012683ff2ada7580937b2da9/django_stubs_ext-5.2.7-py3-none-any.whl", hash = "sha256:0466a7132587d49c5bbe12082ac9824d117a0dedcad5d0ada75a6e0d3aca6f60", size = 9979 },
308
+ { url = "https://files.pythonhosted.org/packages/da/2d/cb0151b780c3730cf0f2c0fcb1b065a5e88f877cf7a9217483c375353af1/django_stubs_ext-5.2.8-py3-none-any.whl", hash = "sha256:1dd5470c9675591362c78a157a3cf8aec45d0e7a7f0cf32f227a1363e54e0652", size = 9949 },
309
309
  ]
310
310
 
311
311
  [[package]]
@@ -748,7 +748,7 @@ wheels = [
748
748
 
749
749
  [[package]]
750
750
  name = "python-terminusgps"
751
- version = "49.3.0"
751
+ version = "50.1.0"
752
752
  source = { editable = "." }
753
753
  dependencies = [
754
754
  { name = "authorizenet" },
@@ -820,13 +820,25 @@ wheels = [
820
820
  { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738 },
821
821
  ]
822
822
 
823
+ [[package]]
824
+ name = "roman-numerals"
825
+ version = "4.0.0"
826
+ source = { registry = "https://pypi.org/simple" }
827
+ sdist = { url = "https://files.pythonhosted.org/packages/6b/20/a6b20239f54814de5c34bf3f504e553b11780c2aad3677ad2daf989f1fb3/roman_numerals-4.0.0.tar.gz", hash = "sha256:231287018a8788bf8c0718482a08c15b90458523ea1d840a18a791a86d4583b3", size = 9027 }
828
+ wheels = [
829
+ { url = "https://files.pythonhosted.org/packages/ad/9d/ad950fd3b65cf0974c633862320829f3d461aef125b981504277c8409a93/roman_numerals-4.0.0-py3-none-any.whl", hash = "sha256:4131feb23ba1a542494873e4cee7844ec8d226a750134efc65ceb20939ed33c9", size = 7668 },
830
+ ]
831
+
823
832
  [[package]]
824
833
  name = "roman-numerals-py"
825
- version = "3.1.0"
834
+ version = "4.0.0"
826
835
  source = { registry = "https://pypi.org/simple" }
827
- sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017 }
836
+ dependencies = [
837
+ { name = "roman-numerals" },
838
+ ]
839
+ sdist = { url = "https://files.pythonhosted.org/packages/7e/02/6cb667fc1872c5fe814971be2973317f0747d86f1c0aac37d0e1a1df1ecc/roman_numerals_py-4.0.0.tar.gz", hash = "sha256:f7fa8dff5b7b7251d3a7586b97c57a0698e2e28898fa42c23bcc0cf51b02aee9", size = 1119 }
828
840
  wheels = [
829
- { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742 },
841
+ { url = "https://files.pythonhosted.org/packages/d2/b7/c0aa3b0154e022faa8e8b4eadda0c49f53b09b6b8d55ed3b7cd311abfd92/roman_numerals_py-4.0.0-py3-none-any.whl", hash = "sha256:dfcecf6e0cddbf2ee1112e7e2ebf58ba771984f075cb57a30e1811cee4f06332", size = 1244 },
830
842
  ]
831
843
 
832
844
  [[package]]
@@ -979,11 +991,11 @@ wheels = [
979
991
 
980
992
  [[package]]
981
993
  name = "sqlparse"
982
- version = "0.5.3"
994
+ version = "0.5.4"
983
995
  source = { registry = "https://pypi.org/simple" }
984
- sdist = { url = "https://files.pythonhosted.org/packages/e5/40/edede8dd6977b0d3da179a342c198ed100dd2aba4be081861ee5911e4da4/sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272", size = 84999 }
996
+ sdist = { url = "https://files.pythonhosted.org/packages/18/67/701f86b28d63b2086de47c942eccf8ca2208b3be69715a1119a4e384415a/sqlparse-0.5.4.tar.gz", hash = "sha256:4396a7d3cf1cd679c1be976cf3dc6e0a51d0111e87787e7a8d780e7d5a998f9e", size = 120112 }
985
997
  wheels = [
986
- { url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415 },
998
+ { url = "https://files.pythonhosted.org/packages/25/70/001ee337f7aa888fb2e3f5fd7592a6afc5283adb1ed44ce8df5764070f22/sqlparse-0.5.4-py3-none-any.whl", hash = "sha256:99a9f0314977b76d776a0fcb8554de91b9bb8a18560631d6bc48721d07023dcb", size = 45933 },
987
999
  ]
988
1000
 
989
1001
  [[package]]
@@ -1006,20 +1018,20 @@ wheels = [
1006
1018
 
1007
1019
  [[package]]
1008
1020
  name = "tzdata"
1009
- version = "2025.2"
1021
+ version = "2025.3"
1010
1022
  source = { registry = "https://pypi.org/simple" }
1011
- sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380 }
1023
+ sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772 }
1012
1024
  wheels = [
1013
- { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839 },
1025
+ { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521 },
1014
1026
  ]
1015
1027
 
1016
1028
  [[package]]
1017
1029
  name = "urllib3"
1018
- version = "2.5.0"
1030
+ version = "2.6.2"
1019
1031
  source = { registry = "https://pypi.org/simple" }
1020
- sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185 }
1032
+ sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930 }
1021
1033
  wheels = [
1022
- { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795 },
1034
+ { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182 },
1023
1035
  ]
1024
1036
 
1025
1037
  [[package]]
File without changes
@@ -1 +0,0 @@
1
- from .factory import WialonObjectFactory
@@ -1,217 +0,0 @@
1
- import collections.abc
2
- import decimal
3
- import typing
4
-
5
- from terminusgps.wialon.items.base import WialonObject, requires_id
6
-
7
-
8
- class WialonAccount(WialonObject):
9
- """A Wialon `account <https://help.wialon.com/en/wialon-hosting/user-guide/management-system/accounts-and-resources>`_."""
10
-
11
- def create(
12
- self, resource_id: int | str, billing_plan: str
13
- ) -> dict[str, str]:
14
- """
15
- Creates the account in Wialon and sets its id.
16
-
17
- :param resource_id: A Wialon resource id.
18
- :type creator_id: int | str
19
- :param billing_plan: A Wialon account billing plan.
20
- :type billing_plan: str
21
- :raises ValueError: If ``resource_id`` wasn't a digit.
22
- :raises ~terminusgps.wialon.session.WialonAPIError: If something went wrong calling the Wialon API.
23
- :returns: A Wialon object dictionary.
24
- :rtype: dict[str, str]
25
-
26
- """
27
- if isinstance(resource_id, str) and not resource_id.isdigit():
28
- raise ValueError(
29
- f"'resource_id' must be a digit, got '{resource_id}'."
30
- )
31
- response = self.session.wialon_api.account_create_account(
32
- **{"itemId": resource_id, "plan": billing_plan}
33
- )
34
- self.id = resource_id
35
- return response
36
-
37
- @typing.override
38
- @requires_id
39
- def delete(
40
- self, reasons: collections.abc.Collection[str] | None = None
41
- ) -> dict[str, str]:
42
- """
43
- Deletes the account in Wialon.
44
-
45
- :param reasons: An optional collection of reason strings. Default is :py:obj:`None`.
46
- :type reasons: ~collections.abc.Collection[str] | None
47
- :raises AssertionError: If the Wialon account id wasn't set.
48
- :raises ~terminusgps.wialon.session.WialonAPIError: If something went wrong calling the Wialon API.
49
- :returns: An empty dictionary.
50
- :rtype: dict[str, str]
51
-
52
- """
53
- return self.session.wialon_api.account_delete_account(
54
- **{"itemId": self.id, "reasons": reasons}
55
- if reasons is not None
56
- else {"itemId": self.id}
57
- )
58
-
59
- @requires_id
60
- def activate(self) -> dict[str, str]:
61
- """
62
- Enables the account in Wialon.
63
-
64
- :raises AssertionError: If the Wialon account id wasn't set.
65
- :raises ~terminusgps.wialon.session.WialonAPIError: If something went wrong calling the Wialon API.
66
- :returns: An empty dictionary.
67
- :rtype: dict[str, str]
68
-
69
- """
70
- return self.session.wialon_api.account_enable_account(
71
- **{"itemId": self.id, "enable": 1}
72
- )
73
-
74
- @requires_id
75
- def deactivate(self) -> dict[str, str]:
76
- """
77
- Disables the account in Wialon.
78
-
79
- :raises AssertionError: If the Wialon account id wasn't set.
80
- :raises ~terminusgps.wialon.session.WialonAPIError: If something went wrong calling the Wialon API.
81
- :returns: An empty dictionary.
82
- :rtype: dict[str, str]
83
-
84
- """
85
- return self.session.wialon_api.account_enable_account(
86
- **{"itemId": self.id, "enable": 0}
87
- )
88
-
89
- @requires_id
90
- def do_payment(
91
- self,
92
- balance_update: decimal.Decimal,
93
- days_update: int,
94
- description: str,
95
- ) -> dict[str, str]:
96
- """
97
- Makes an account payment in Wialon.
98
-
99
- :param balance_update: Amount to update the account balance by. Can be negative.
100
- :type balance_update: ~decimal.Decimal
101
- :param days_update: Amount of days to add to the account.
102
- :type days_update: str
103
- :param description: A description for the payment.
104
- :type description: str
105
- :raises AssertionError: If the Wialon account id wasn't set.
106
- :raises ~terminusgps.wialon.session.WialonAPIError: If something went wrong calling the Wialon API.
107
- :returns: An empty dictionary.
108
- :rtype: dict[str, str]
109
-
110
- """
111
- return self.session.wialon_api.account_do_payment(
112
- **{
113
- "itemId": self.id,
114
- "balanceUpdate": str(balance_update),
115
- "daysUpdate": days_update,
116
- "description": description,
117
- }
118
- )
119
-
120
- @requires_id
121
- def set_dealer_rights(self, enabled: bool) -> dict[str, str]:
122
- """
123
- Enables or disables the account's dealer rights in Wialon.
124
-
125
- :param enabled: Whether to set the account as a dealer or not.
126
- :type enabled: bool
127
- :raises AssertionError: If the Wialon account id wasn't set.
128
- :raises ~terminusgps.wialon.session.WialonAPIError: If something went wrong calling the Wialon API.
129
- :returns: An empty dictionary.
130
- :rtype: dict[str, str]
131
-
132
- """
133
- return self.session.wialon_api.account_update_dealer_rights(
134
- **{"itemId": self.id, "enable": int(enabled)}
135
- )
136
-
137
- @requires_id
138
- def set_flags(
139
- self,
140
- flags: int,
141
- block_balance: decimal.Decimal = decimal.Decimal("0.00"),
142
- deny_balance: decimal.Decimal = decimal.Decimal("0.00"),
143
- ) -> dict[str, str]:
144
- """
145
- Sets settings flags for the account in Wialon.
146
-
147
- :param flags: A Wialon account settings flag integer.
148
- :type flags: int
149
- :param block_balance: Balance required for account blocking. Default is ``0.00``.
150
- :type block_balance: ~decimal.Decimal
151
- :param deny_balance: Balance required for service denial. Default is ``0.00``.
152
- :type deny_balance: ~decimal.Decimal
153
- :raises AssertionError: If the Wialon account id wasn't set.
154
- :raises ~terminusgps.wialon.session.WialonAPIError: If something went wrong calling the Wialon API.
155
- :returns: An empty dictionary.
156
- :rtype: dict[str, str]
157
-
158
- """
159
- return self.session.wialon_api.account_update_flags(
160
- **{
161
- "itemId": self.id,
162
- "flags": flags,
163
- "blockBalance": block_balance,
164
- "denyBalance": deny_balance,
165
- }
166
- )
167
-
168
- @requires_id
169
- def set_plan(self, name: str) -> dict[str, str]:
170
- """
171
- Sets the account's billing plan to ``name``.
172
-
173
- :param name: A Wialon billing plan name.
174
- :type name: str
175
- :raises AssertionError: If the Wialon account id wasn't set.
176
- :raises ~terminusgps.wialon.session.WialonAPIError: If something went wrong calling the Wialon API.
177
- :returns: An empty dictionary.
178
- :rtype: dict[str, str]
179
-
180
- """
181
- return self.session.wialon_api.account_update_plan(
182
- **{"itemId": self.id, "plan": name}
183
- )
184
-
185
- @requires_id
186
- def set_minimum_days(self, days: int) -> dict[str, str]:
187
- """
188
- Sets the account's minimum days to ``days`` in Wialon.
189
-
190
- :param days: Minimum number of days as an integer.
191
- :type days: int
192
- :raises AssertionError: If the Wialon account id wasn't set.
193
- :raises ~terminusgps.wialon.session.WialonAPIError: If something went wrong calling the Wialon API.
194
- :returns: An empty dictionary.
195
- :rtype: dict[str, str]
196
-
197
- """
198
- return self.session.wialon_api.account_update_min_days(
199
- **{"itemId": self.id, "minDays": days}
200
- )
201
-
202
- @requires_id
203
- def get_data(self, response_type: int = 1) -> dict[str, str]:
204
- """
205
- Returns account data from Wialon.
206
-
207
- :param response_type: A response flag integer. Default is ``1``.
208
- :type response_type: int
209
- :raises AssertionError: If the Wialon account id wasn't set.
210
- :raises ~terminusgps.wialon.session.WialonAPIError: If something went wrong calling the Wialon API.
211
- :returns: A dictionary containing the account's data from Wialon.
212
- :rtype: dict[str, str]
213
-
214
- """
215
- return self.session.wialon_api.account_get_account_data(
216
- **{"itemId": self.id, "type": response_type}
217
- )