python-terminusgps 37.0.0__py3-none-any.whl → 37.1.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 python-terminusgps might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-terminusgps
3
- Version: 37.0.0
3
+ Version: 37.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://docs.terminusgps.com
6
6
  Project-URL: Repository, https://github.com/terminusgps/python-terminusgps
@@ -20,6 +20,8 @@ Requires-Dist: django>=5.1.5
20
20
  Requires-Dist: loguru>=0.7.3
21
21
  Requires-Dist: matplotlib>=3.10.1
22
22
  Requires-Dist: pandas>=2.2.3
23
+ Requires-Dist: pillow-heif>=0.22.0
24
+ Requires-Dist: pillow>=11.2.1
23
25
  Requires-Dist: python-wialon>=1.2.4
24
26
  Requires-Dist: pyzbar>=0.1.9
25
27
  Requires-Dist: twilio>=9.4.5
@@ -2,8 +2,13 @@ terminusgps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  terminusgps/authorizenet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  terminusgps/authorizenet/auth.py,sha256=g2tJPxP9V1nXnUcKzhHSRSs6ruSIHej5_hcf8P7bod8,1262
4
4
  terminusgps/authorizenet/constants.py,sha256=xmulPmiBLhFfZoc7Il3l-DZA9Nq5HSaJmJKU-v-5X-Y,420
5
- terminusgps/authorizenet/controllers.py,sha256=9t62qdGpmAkP4tNyPefd7vBRutXvMWsxql6z_pg52Bg,2146
5
+ terminusgps/authorizenet/controllers.py,sha256=rMuBwSoKJjte7wVuB1ewaqnzfuDXxwus-d5mkqbfnGE,2193
6
6
  terminusgps/authorizenet/utils.py,sha256=vxUTLT4rheWDd_2UprpcI8qo_Gw_zl0oiVHnUwHpNfE,6283
7
+ terminusgps/authorizenet/items/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ terminusgps/authorizenet/items/address_profiles.py,sha256=oiFw2T3TmyhLn8Vw-GWFrAeBbyOEG_dV8LLGr3oH7aI,5669
9
+ terminusgps/authorizenet/items/base.py,sha256=fcO0RRrOXytlSbBDLLFajfdkxYtqmniJ5FWV4z0UkOk,2004
10
+ terminusgps/authorizenet/items/customer_profiles.py,sha256=53cqXooXszTqMv2PuifDsDknuDxGtA73jZkquWZl0zs,9262
11
+ terminusgps/authorizenet/items/payment_profiles.py,sha256=kYvuq1xCmeIUmmXgbOapbA01roQ4k0zOLafcBtG-eM0,10830
7
12
  terminusgps/authorizenet/profiles/__init__.py,sha256=IG4XCEEYtHKqXOatlZlob6J3ukAgF7cFR-RXxOSMS1c,161
8
13
  terminusgps/authorizenet/profiles/addresses.py,sha256=5GudJStBa4P0Hd7G_hRFH2C-WpICAH_k3MT9YJkicKw,6305
9
14
  terminusgps/authorizenet/profiles/base.py,sha256=Pu1NGrvC5Ox2W1oZuVcPqUw3aUoSK191Evexw1U6_3k,3940
@@ -40,7 +45,7 @@ terminusgps/wialon/constants.py,sha256=05pLc_0S-x0tT87cQcxOmr8plesjOQxoXfUdjIHwI
40
45
  terminusgps/wialon/flags.py,sha256=M50EdhxQ8IMnJnU0mrHK7-h8Asc6tvNiTOOfd1dBW6A,12815
41
46
  terminusgps/wialon/session.py,sha256=eWRAWEikYdGr-0xa6yGHfTAxlCx9-1vsZDNwNZUJjZM,13771
42
47
  terminusgps/wialon/utils.py,sha256=ntHLAVJSJBdIgJK704xxFNFRopaFz-No9YZZOMmvWO8,11627
43
- terminusgps/wialon/validators.py,sha256=j5vrtcfClAzRdRkWTvRRAmrne1t0R6cKkmYdE7fAkSs,4247
48
+ terminusgps/wialon/validators.py,sha256=Z2eci8NzKDHU6oXl5ncgeYXmBYg336k-0R2m0DIxsDY,4346
44
49
  terminusgps/wialon/items/__init__.py,sha256=3BVthghekMvhMQSzQgBMlD_phxmKSmp3Zvmo-z0O8Bs,211
45
50
  terminusgps/wialon/items/base.py,sha256=vS8xIo5WLiwzpB81i7aHFnwOHzCf4lQG6azjq79HDM4,11775
46
51
  terminusgps/wialon/items/resource.py,sha256=Rhy2ig-yxznNhi6ZSaUBbu8ViVx0Sg4n_XS08ijgXsA,18280
@@ -53,7 +58,7 @@ terminusgps/wialon/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
53
58
  terminusgps/wialon/tests/test_items.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
59
  terminusgps/wialon/tests/test_session.py,sha256=9mBlYchMo9NeqRIZsmxYzrM1zBHorqu4ooxqSNppLpI,1336
55
60
  terminusgps/wialon/tests/test_utils.py,sha256=SK4PxJQGECFnzx_EQeRAQfsQ5_3FLaVcis2W9u_ibuI,1730
56
- python_terminusgps-37.0.0.dist-info/METADATA,sha256=gSJ_ajG7w0h1nKrJnNd2LYwzLOb6XlIiVnL4ibmwO7c,1264
57
- python_terminusgps-37.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
58
- python_terminusgps-37.0.0.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
59
- python_terminusgps-37.0.0.dist-info/RECORD,,
61
+ python_terminusgps-37.1.0.dist-info/METADATA,sha256=0dWu_0SrsHQ1Vv9vaPQ-BBk9rikAnCBl023Jp2Yg4Lg,1329
62
+ python_terminusgps-37.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
63
+ python_terminusgps-37.1.0.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
64
+ python_terminusgps-37.1.0.dist-info/RECORD,,
@@ -1,3 +1,5 @@
1
+ import typing
2
+
1
3
  from authorizenet.apicontrollersbase import APIOperationBase
2
4
 
3
5
  from .auth import get_environment
@@ -7,7 +9,9 @@ class AuthorizenetControllerExecutor:
7
9
  """Allows objects to use :py:meth:`execute_controller` to execute Authorizenet API controllers."""
8
10
 
9
11
  @staticmethod
10
- def execute_controller(controller: APIOperationBase) -> dict | None:
12
+ def execute_controller(
13
+ controller: APIOperationBase,
14
+ ) -> dict[str, typing.Any] | None:
11
15
  """
12
16
  Executes an Authorizenet API controller and returns its response.
13
17
 
File without changes
@@ -0,0 +1,126 @@
1
+ import typing
2
+
3
+ from authorizenet import apicontractsv1, apicontrollers
4
+
5
+ from .base import AuthorizenetBase
6
+
7
+
8
+ class AuthorizenetAddressProfile(AuthorizenetBase):
9
+ """An Authorizenet address profile."""
10
+
11
+ def __init__(self, customerProfileId: int | str, *args, **kwargs) -> None:
12
+ super().__init__(*args, **kwargs)
13
+ if isinstance(customerProfileId, str) and not customerProfileId.isdigit():
14
+ raise ValueError(
15
+ f"'customerProfileId' can only contain digits, got '{customerProfileId}'."
16
+ )
17
+ self.customerProfileId = customerProfileId
18
+
19
+ def _authorizenet_create_customer_shipping_address(
20
+ self, address: apicontractsv1.customerAddressType, default: bool = False
21
+ ) -> dict[str, typing.Any] | None:
22
+ """
23
+ Executes a :py:obj:`~authorizenet.apicontractsv1.createCustomerShippingAddressRequest` using the Authorizenet API.
24
+
25
+ `createCustomerShippingAddressRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-create-customer-shipping-address>`_
26
+
27
+ :param address: A customer address object.
28
+ :type address: :py:obj:`~authorizenet.apicontractsv1.customerAddressType`
29
+ :param default: Whether or not to set the address profile as default.
30
+ :type default: :py:obj:`bool`
31
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
32
+ :returns: An Authorizenet API response, if any.
33
+ :rtype: :py:obj:`dict` | :py:obj:`None`
34
+
35
+ """
36
+
37
+ request = apicontractsv1.createCustomerShippingAddressRequest()
38
+ request.merchantAuthentication = self.merchantAuthentication
39
+ request.customerProfileId = self.customerProfileId
40
+ request.address = address
41
+ request.defaultShippingAddress = str(default).lower()
42
+
43
+ return self.execute_controller(
44
+ apicontrollers.createCustomerShippingAddressController(request)
45
+ )
46
+
47
+ def _authorizenet_get_customer_shipping_address(
48
+ self,
49
+ ) -> dict[str, typing.Any] | None:
50
+ """
51
+ Executes a :py:obj:`~authorizenet.apicontractsv1.getCustomerShippingAddressRequest` using the Authorizenet API.
52
+
53
+ `getCustomerShippingAddressRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-get-customer-shipping-address>`_
54
+
55
+ :raises AssertionError: If :py:attr:`id` wasn't set.
56
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
57
+ :returns: An Authorizenet API response, if any.
58
+ :rtype: :py:obj:`dict` | :py:obj:`None`
59
+
60
+ """
61
+
62
+ assert self.id, "Address profile id wasn't set."
63
+
64
+ request = apicontractsv1.getCustomerShippingAddressRequest()
65
+ request.merchantAuthentication = self.merchantAuthentication
66
+ request.customerProfileId = self.customerProfileId
67
+ request.customerAddressId = self.id
68
+
69
+ return self.execute_controller(
70
+ apicontrollers.getCustomerShippingAddressController(request)
71
+ )
72
+
73
+ def _authorizenet_update_customer_shipping_address(
74
+ self, address: apicontractsv1.customerAddressType, default: bool = False
75
+ ) -> dict[str, typing.Any] | None:
76
+ """
77
+ Executes a :py:obj:`~authorizenet.apicontractsv1.updateCustomerShippingAddress` using the Authorizenet API.
78
+
79
+ `updateCustomerShippingAddressRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-update-customer-shipping-address>`_
80
+
81
+ :param address: A customer address object.
82
+ :type address: :py:obj:`~authorizenet.apicontractsv1.customerAddressType`
83
+ :param default: Whether or not to set the address profile as default.
84
+ :type default: :py:obj:`bool`
85
+ :raises AssertionError: If :py:attr:`id` wasn't set.
86
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
87
+ :returns: An Authorizenet API response, if any.
88
+ :rtype: :py:obj:`dict` | :py:obj:`None`
89
+
90
+ """
91
+ request = apicontractsv1.updateCustomerShippingAddressRequest()
92
+ request.merchantAuthentication = self.merchantAuthentication
93
+ request.customerProfileId = self.customerProfileId
94
+ request.address = address
95
+ request.address.customerAddressId = self.id
96
+ request.defaultShippingAddress = str(default).lower()
97
+
98
+ return self.execute_controller(
99
+ apicontrollers.updateCustomerShippingAddressController(request)
100
+ )
101
+
102
+ def _authorizenet_delete_customer_shipping_address(
103
+ self,
104
+ ) -> dict[str, typing.Any] | None:
105
+ """
106
+ Executes a :py:obj:`~authorizenet.apicontractsv1.deleteCustomerShippingAddress` using the Authorizenet API.
107
+
108
+ `deleteCustomerShippingAddressRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-delete-customer-shipping-address>`_
109
+
110
+ :raises AssertionError: If :py:attr:`id` wasn't set.
111
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
112
+ :returns: An Authorizenet API response, if any.
113
+ :rtype: :py:obj:`dict` | :py:obj:`None`
114
+
115
+ """
116
+
117
+ assert self.id, "Address profile id wasn't set."
118
+
119
+ request = apicontractsv1.deleteCustomerShippingAddressRequest()
120
+ request.merchantAuthentication = self.merchantAuthentication
121
+ request.customerProfileId = self.customerProfileId
122
+ request.customerAddressId = self.id
123
+
124
+ return self.execute_controller(
125
+ apicontrollers.deleteCustomerShippingAddressController(request)
126
+ )
@@ -0,0 +1,68 @@
1
+ from authorizenet import apicontractsv1
2
+
3
+ from terminusgps.authorizenet.auth import get_merchant_auth, get_validation_mode
4
+ from terminusgps.authorizenet.controllers import AuthorizenetControllerExecutor
5
+
6
+
7
+ class AuthorizenetBase(AuthorizenetControllerExecutor):
8
+ """Base class for Authorizenet objects."""
9
+
10
+ def __init__(self, id: int | str | None = None, *args, **kwargs) -> None:
11
+ """
12
+ Sets :py:attr:`id` if provided.
13
+
14
+ :returns: Nothing.
15
+ :rtype: :py:obj:`None`
16
+
17
+ """
18
+ self.id = id
19
+
20
+ def __str__(self) -> str:
21
+ """Returns the object in format: '#<ID>' if :py:attr:`id` is set."""
22
+ return f"#{self.id}" if self.id else ""
23
+
24
+ @property
25
+ def id(self) -> str | None:
26
+ """
27
+ An Authorizenet generated id.
28
+
29
+ :type: :py:obj:`str` | :py:obj:`None`
30
+
31
+ """
32
+ return self._id
33
+
34
+ @id.setter
35
+ def id(self, other: int | str | None) -> None:
36
+ """
37
+ Sets :py:attr:`id` to ``other``.
38
+
39
+ :raises ValueError: If ``other`` was provided as a string containing non-digit characters.
40
+ :returns: Nothing.
41
+ :rtype: :py:obj:`None`
42
+
43
+ """
44
+ if isinstance(other, str) and not other.isdigit():
45
+ raise ValueError(f"'id' can only contain digit characters, got '{other}'.")
46
+ self._id = str(other) if other is not None else None
47
+
48
+ @property
49
+ def merchantAuthentication(self) -> apicontractsv1.merchantAuthenticationType:
50
+ """
51
+ Current merchant authentication object to authenticate Authorizenet API calls.
52
+
53
+ :returns: A merchant authentication object.
54
+ :rtype: :py:obj:`~authorizenet.apicontractsv1.merchantAuthenticationType`
55
+
56
+ """
57
+ return get_merchant_auth()
58
+
59
+ @property
60
+ def validationMode(self) -> str:
61
+ """
62
+ Current Authorizenet API validation mode.
63
+
64
+ :returns: An Authorizenet API validation mode string.
65
+ :rtype: :py:obj:`str`
66
+
67
+ """
68
+ return get_validation_mode()
@@ -0,0 +1,227 @@
1
+ import typing
2
+
3
+ from authorizenet import apicontractsv1, apicontrollers
4
+
5
+ from .base import AuthorizenetBase
6
+
7
+
8
+ class AuthorizenetCustomerProfile(AuthorizenetBase):
9
+ """An Authorizenet customer profile."""
10
+
11
+ def __init__(self, email: str, merchant_id: str, *args, **kwargs) -> None:
12
+ """
13
+ Sets :py:attr:`_email` and :py:attr:`_merchant_id`.
14
+
15
+ :param email: An email address.
16
+ :type email: :py:obj:`str`
17
+ :param merchant_id: A merchant designated id string.
18
+ :type merchant_id: :py:obj:`str`
19
+ :returns: Nothing.
20
+ :rtype: :py:obj:`None`
21
+
22
+ """
23
+ super().__init__(*args, **kwargs)
24
+ self._email = email
25
+ self._merchant_id = merchant_id
26
+
27
+ @property
28
+ def email(self) -> str:
29
+ """An email address assigned to the customer profile."""
30
+ return str(self._email)
31
+
32
+ @property
33
+ def merchant_id(self) -> str:
34
+ """A merchant designated id assigned to the customer profile."""
35
+ return str(self._merchant_id)
36
+
37
+ @email.setter
38
+ def email(self, other: str) -> None:
39
+ """Sets :py:attr:`email` to ``other``."""
40
+ self._email = str(other)
41
+
42
+ @merchant_id.setter
43
+ def merchant_id(self, other: str) -> None:
44
+ """Sets :py:attr:`merchant_id` to ``other``."""
45
+ self._merchant_id = str(other)
46
+
47
+ def create(self, desc: str | None = None, validate: bool = False) -> int:
48
+ """
49
+ Creates an Authorizenet customer profile and returns its id as an integer.
50
+
51
+ If successfully created, sets :py:attr:`id` to the new customer profile id.
52
+
53
+ :param desc: An optional customer profile description. Default is :py:obj:`None`
54
+ :type desc: :py:obj:`str` | :py:obj:`None`
55
+ :param validate: Whether or not to validate a payment on the new customer profile. Default is :py:obj:`False`.
56
+ :type validate: :py:obj:`bool`
57
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
58
+ :returns: A customer profile id integer.
59
+ :rtype: :py:obj:`int`
60
+
61
+ """
62
+
63
+ profile = apicontractsv1.customerProfileType()
64
+ profile.merchantCustomerId = self.merchant_id
65
+ if desc:
66
+ profile.description = desc
67
+
68
+ response = self._authorizenet_create_customer_profile(profile, validate)
69
+ profile_id = int(response.customerProfileId)
70
+ self.id = profile_id
71
+
72
+ return profile_id
73
+
74
+ def delete(self) -> None:
75
+ """
76
+ Deletes the Authorizenet customer profile.
77
+
78
+ If successfully deleted, sets :py:attr:`id` to :py:obj:`None`.
79
+
80
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
81
+ :returns: Nothing.
82
+ :rtype: :py:obj:`None`
83
+
84
+ """
85
+
86
+ if self.id:
87
+ self._authorizenet_delete_customer_profile()
88
+ self._id = None
89
+
90
+ def update(self, desc: str | None = None, validate: bool = False) -> None:
91
+ """
92
+ Updates the Authorizenet customer profile if :py:attr:`id` is set.
93
+
94
+ :param desc: An optional customer profile description. Default is :py:obj:`None`
95
+ :type desc: :py:obj:`str` | :py:obj:`None`
96
+ :param validate: Whether or not to validate a payment on the customer profile. Default is :py:obj:`False`.
97
+ :type validate: :py:obj:`bool`
98
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
99
+ :returns: Nothing.
100
+ :rtype: :py:obj:`None`
101
+
102
+ """
103
+
104
+ if self.id:
105
+ profile = apicontractsv1.customerProfileExType()
106
+ profile.customerProfileId = self.id
107
+ profile.merchantCustomerId = self.merchant_id
108
+ profile.email = self.email
109
+ if desc is not None:
110
+ profile.description = desc
111
+
112
+ self._authorizenet_update_customer_profile(profile, validate)
113
+
114
+ def _authorizenet_get_customer_profile(
115
+ self, issuer_info: bool = False
116
+ ) -> dict[str, typing.Any] | None:
117
+ """
118
+ Executes a :py:obj:`~authorizenet.apicontractsv1.getCustomerProfileRequest` using the Authorizenet API.
119
+
120
+ `getCustomerProfileRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-get-customer-profile>`_
121
+
122
+ :param issuer_info: Whether or not to include issuer information in the response. Default is :py:obj:`False`.
123
+ :type issuer_info: :py:obj:`bool`
124
+ :raises AssertionError: If none of :py:attr:`id`, :py:attr:`email` or :py:attr:`merchant_id` were set.
125
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
126
+ :returns: An Authorizenet API response, if any.
127
+ :rtype: :py:obj:`dict` | :py:obj:`None`
128
+
129
+ """
130
+
131
+ assert any([self.id, self.email, self.merchant_id]), (
132
+ "At least one of 'id', 'email' or 'merchant_id' must be set."
133
+ )
134
+
135
+ request = apicontractsv1.getCustomerProfileRequest()
136
+ request.merchantAuthentication = self.merchantAuthentication
137
+ request.includeIssuerInfo = str(issuer_info).lower()
138
+
139
+ if self.id:
140
+ request.customerProfileId = self.id
141
+ if self.email:
142
+ request.email = self.email
143
+ if self.merchant_id:
144
+ request.customerMerchantId = self.merchant_id
145
+
146
+ return self.execute_controller(
147
+ apicontrollers.getCustomerProfileController(request)
148
+ )
149
+
150
+ def _authorizenet_create_customer_profile(
151
+ self, profile: apicontractsv1.customerProfileType, validate: bool = False
152
+ ) -> dict[str, typing.Any] | None:
153
+ """
154
+ Executes a :py:obj:`~authorizenet.apicontractsv1.createCustomerProfileRequest` using the Authorizenet API.
155
+
156
+ `createCustomerProfileRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-create-customer-profile>`_
157
+
158
+ :param profile: A customer profile object.
159
+ :type profile: :py:obj:`~authorizenet.apicontractsv1.customerProfileType`
160
+ :param validate: Whether or not to validate a payment profile for the customer profile. Default is :py:obj:`False`.
161
+ :type validate: :py:obj:`bool`
162
+ :raises AuthorizenetControllerExecutionError: If ``validate`` was :py:obj:`True` but validation was forbidden.
163
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
164
+ :returns: An Authorizenet API response, if any.
165
+ :rtype: :py:obj:`dict` | :py:obj:`None`
166
+
167
+ """
168
+ request = apicontractsv1.createCustomerProfileRequest()
169
+ request.merchantAuthentication = self.merchantAuthentication
170
+ request.profile = profile
171
+ if validate:
172
+ request.validationMode = self.validationMode
173
+
174
+ return self.execute_controller(
175
+ apicontrollers.createCustomerProfileController(request)
176
+ )
177
+
178
+ def _authorizenet_update_customer_profile(
179
+ self, profile: apicontractsv1.customerProfileExType, validate: bool = False
180
+ ) -> dict[str, typing.Any] | None:
181
+ """
182
+ Executes a :py:obj:`~authorizenet.apicontractsv1.updateCustomerProfileRequest` using the Authorizenet API.
183
+
184
+ `updateCustomerProfileRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-update-customer-profile>`_
185
+
186
+ :param profile: A customer profile ex object.
187
+ :type profile: :py:obj:`~authorizenet.apicontractsv1.customerProfileExType`
188
+ :param validate: Whether or not to validate a payment profile for the customer profile. Default is :py:obj:`False`.
189
+ :type validate: :py:obj:`bool`
190
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
191
+ :returns: An Authorizenet API response, if any.
192
+ :rtype: :py:obj:`dict` | :py:obj:`None`
193
+
194
+ """
195
+
196
+ request = apicontractsv1.updateCustomerProfileRequest()
197
+ request.merchantAuthentication = self.merchantAuthentication
198
+ request.profile = profile
199
+ if validate:
200
+ request.validationMode = self.validationMode
201
+
202
+ return self.execute_controller(
203
+ apicontrollers.updateCustomerProfileController(request)
204
+ )
205
+
206
+ def _authorizenet_delete_customer_profile(self) -> dict[str, typing.Any] | None:
207
+ """
208
+ Executes a :py:obj:`~authorizenet.apicontractsv1.deleteCustomerProfileRequest` using the Authorizenet API.
209
+
210
+ `deleteCustomerProfileRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-delete-customer-profile>`_
211
+
212
+ :raises AssertionError: If :py:attr:`id` wasn't set.
213
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
214
+ :returns: An Authorizenet API response, if any.
215
+ :rtype: :py:obj:`dict` | :py:obj:`None`
216
+
217
+ """
218
+
219
+ assert self.id, "Customer profile id wasn't set."
220
+
221
+ request = apicontractsv1.deleteCustomerProfileRequest()
222
+ request.merchantAuthentication = self.merchantAuthentication
223
+ request.customerProfileId = self.id
224
+
225
+ return self.execute_controller(
226
+ apicontrollers.deleteCustomerProfileController(request)
227
+ )
@@ -0,0 +1,253 @@
1
+ import typing
2
+
3
+ from authorizenet import apicontractsv1, apicontrollers
4
+
5
+ from .base import AuthorizenetBase
6
+
7
+
8
+ class AuthorizenetPaymentProfile(AuthorizenetBase):
9
+ """An Authorizenet payment profile."""
10
+
11
+ def __init__(self, customerProfileId: int | str, *args, **kwargs) -> None:
12
+ super().__init__(*args, **kwargs)
13
+ if isinstance(customerProfileId, str) and not customerProfileId.isdigit():
14
+ raise ValueError(
15
+ f"'customerProfileId' can only contain digits, got '{customerProfileId}'."
16
+ )
17
+ self.customerProfileId = customerProfileId
18
+
19
+ def create(
20
+ self,
21
+ payment: apicontractsv1.paymentType,
22
+ address: apicontractsv1.customerAddressType,
23
+ default: bool = False,
24
+ validate: bool = False,
25
+ ) -> int:
26
+ """
27
+ Creates an Authorizenet payment profile and returns its id as an integer.
28
+
29
+ If successfully created, sets :py:attr:`id` to the new payment profile id.
30
+
31
+ :param payment: A payment object.
32
+ :type payment: :py:obj:`~authorizenet.apicontractsv1.paymentType`
33
+ :param address: A customer address object.
34
+ :type address: :py:obj:`~authorizenet.apicontractsv1.customerAddressType`
35
+ :param default: Whether or not to set the payment profile as default.
36
+ :type default: :py:obj:`bool`
37
+ :param validate: Whether or not to validate the payment profile.
38
+ :type validate: :py:obj:`bool`
39
+ :raises AuthorizenetControllerExecutionError: If something went wrong during an Authorizenet API call.
40
+ :returns: The new payment profile id.
41
+ :rtype: :py:obj:`int`
42
+
43
+ """
44
+ response = self._authorizenet_create_customer_payment_profile(
45
+ payment=payment, address=address, default=default, validate=validate
46
+ )
47
+
48
+ payment_id = int(response.customerPaymentProfileId)
49
+ self.id = payment_id
50
+
51
+ return payment_id
52
+
53
+ def update(
54
+ self,
55
+ payment: apicontractsv1.paymentType,
56
+ address: apicontractsv1.customerAddressType,
57
+ default: bool = False,
58
+ validate: bool = False,
59
+ ) -> None:
60
+ """
61
+ Updates the Authorizenet payment profile if :py:attr:`id` is set.
62
+
63
+ :param payment: A payment object.
64
+ :type payment: :py:obj:`~authorizenet.apicontractsv1.paymentType`
65
+ :param address: A customer address object.
66
+ :type address: :py:obj:`~authorizenet.apicontractsv1.customerAddressType`
67
+ :param default: Whether or not to set the payment profile as default.
68
+ :type default: :py:obj:`bool`
69
+ :param validate: Whether or not to validate the payment profile.
70
+ :type validate: :py:obj:`bool`
71
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
72
+ :returns: Nothing.
73
+ :rtype: :py:obj:`None`
74
+
75
+ """
76
+ if self.id:
77
+ self._authorizenet_update_customer_payment_profile(
78
+ payment=payment, address=address, default=default, validate=validate
79
+ )
80
+
81
+ def delete(self) -> None:
82
+ """
83
+ Deletes the Authorizenet payment profile.
84
+
85
+ If successfully deleted, sets :py:attr:`id` to :py:obj:`None`.
86
+
87
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
88
+ :returns: Nothing.
89
+ :rtype: :py:obj:`None`
90
+
91
+ """
92
+
93
+ if self.id:
94
+ self._authorizenet_delete_customer_payment_profile()
95
+ self.id = None
96
+
97
+ def _authorizenet_create_customer_payment_profile(
98
+ self,
99
+ payment: apicontractsv1.paymentType,
100
+ address: apicontractsv1.customerAddressType,
101
+ default: bool = False,
102
+ validate: bool = False,
103
+ ) -> dict[str, typing.Any] | None:
104
+ """
105
+ Executes a :py:obj:`~authorizenet.apicontractsv1.createCustomerPaymentProfileRequest` using the Authorizenet API.
106
+
107
+ `createCustomerPaymentProfileRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-create-customer-payment-profile>`_
108
+
109
+ :param payment: A payment object.
110
+ :type payment: :py:obj:`~authorizenet.apicontractsv1.paymentType`
111
+ :param address: A customer address object.
112
+ :type address: :py:obj:`~authorizenet.apicontractsv1.customerAddressType`
113
+ :param default: Whether or not to set the payment profile as default.
114
+ :type default: :py:obj:`bool`
115
+ :param validate: Whether or not to validate the payment profile in Authorizenet.
116
+ :type validate: :py:obj:`bool`
117
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
118
+ :returns: An Authorizenet API response, if any.
119
+ :rtype: :py:obj:`dict` | :py:obj:`None`
120
+
121
+ """
122
+
123
+ request = apicontractsv1.createCustomerPaymentProfileRequest()
124
+ request.merchantAuthentication = self.merchantAuthentication
125
+ request.paymentProfile = apicontractsv1.customerPaymentProfileType()
126
+ request.paymentProfile.payment = payment
127
+ request.paymentProfile.address = address
128
+ request.paymentProfile.defaultPaymentProfile = str(default).lower()
129
+
130
+ if validate:
131
+ request.validationMode = self.validationMode
132
+
133
+ return self.execute_controller(
134
+ apicontrollers.createCustomerPaymentProfileController(request)
135
+ )
136
+
137
+ def _authorizenet_get_customer_payment_profile(
138
+ self, issuer_info: bool = False
139
+ ) -> dict[str, typing.Any] | None:
140
+ """
141
+ Executes a :py:obj:`~authorizenet.apicontractsv1.getCustomerPaymentProfileRequest` using the Authorizenet API.
142
+
143
+ `getCustomerPaymentProfileRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-get-customer-payment-profile>`_
144
+
145
+ :param issuer_info: Whether or not to include issuer information in the response.
146
+ :type issuer_info: :py:obj:`bool`
147
+ :raises AssertionError: If :py:attr:`id` wasn't set.
148
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
149
+ :returns: An Authorizenet API response, if any.
150
+ :rtype: :py:obj:`dict` | :py:obj:`None`
151
+
152
+ """
153
+
154
+ assert self.id, "Customer payment profile id wasn't set."
155
+
156
+ request = apicontractsv1.getCustomerPaymentProfileRequest()
157
+ request.merchantAuthentication = self.merchantAuthentication
158
+ request.customerProfileId = self.customerProfileId
159
+ request.customerPaymentProfileId = self.id
160
+ request.includeIssuerInfo = str(issuer_info).lower()
161
+
162
+ return self.execute_controller(
163
+ apicontrollers.getCustomerPaymentProfileController(request)
164
+ )
165
+
166
+ def _authorizenet_validate_customer_payment_profile(
167
+ self,
168
+ ) -> dict[str, typing.Any] | None:
169
+ """
170
+ Executes a :py:obj:`~authorizenet.apicontractsv1.validateCustomerPaymentProfileRequest` using the Authorizenet API.
171
+
172
+ `validateCustomerPaymentProfileRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-validate-customer-payment-profile>`_
173
+
174
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
175
+ :returns: An Authorizenet API response, if any.
176
+ :rtype: :py:obj:`dict` | :py:obj:`None`
177
+
178
+ """
179
+
180
+ request = apicontractsv1.validateCustomerPaymentProfileRequest()
181
+ request.merchantAuthentication = self.merchantAuthentication
182
+ request.customerProfileId = self.customerProfileId
183
+ request.customerPaymentProfileId = self.id
184
+ request.validationMode = self.validationMode
185
+
186
+ return self.execute_controller(
187
+ apicontrollers.validateCustomerPaymentProfileController(request)
188
+ )
189
+
190
+ def _authorizenet_update_customer_payment_profile(
191
+ self,
192
+ payment: apicontractsv1.paymentType,
193
+ address: apicontractsv1.customerAddressType,
194
+ default: bool = False,
195
+ validate: bool = False,
196
+ ) -> dict[str, typing.Any] | None:
197
+ """
198
+ Executes a :py:obj:`~authorizenet.apicontractsv1.updateCustomerPaymentProfileRequest` using the Authorizenet API.
199
+
200
+ `updateCustomerPaymentProfileRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-update-customer-payment-profile>`_
201
+
202
+ :param payment: A payment object.
203
+ :type payment: :py:obj:`~authorizenet.apicontractsv1.paymentType`
204
+ :param address: A customer address object.
205
+ :type address: :py:obj:`~authorizenet.apicontractsv1.customerAddressType`
206
+ :param default: Whether or not to set the payment profile as default.
207
+ :type default: :py:obj:`bool`
208
+ :param validate: Whether or not to validate the payment profile in Authorizenet.
209
+ :type validate: :py:obj:`bool`
210
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
211
+ :returns: An Authorizenet API response, if any.
212
+ :rtype: :py:obj:`dict` | :py:obj:`None`
213
+
214
+ """
215
+
216
+ request = apicontractsv1.updateCustomerPaymentProfileRequest()
217
+ request.merchantAuthentication = self.merchantAuthentication
218
+ request.customerProfileId = self.customerProfileId
219
+
220
+ request.paymentProfile = apicontractsv1.customerPaymentProfileType()
221
+ request.paymentProfile.payment = payment
222
+ request.paymentProfile.address = address
223
+ request.paymentProfile.defaultPaymentProfile = str(default).lower()
224
+ request.paymentProfile.customerPaymentProfileId = self.id
225
+
226
+ if validate:
227
+ request.validationMode = self.validationMode
228
+
229
+ return self.execute_controller(
230
+ apicontrollers.updateCustomerPaymentProfileController(request)
231
+ )
232
+
233
+ def _authorizenet_delete_customer_payment_profile(
234
+ self,
235
+ ) -> dict[str, typing.Any] | None:
236
+ """
237
+ Executes a :py:obj:`~authorizenet.apicontractsv1.deleteCustomerPaymentProfileRequest` using the Authorizenet API.
238
+
239
+ `deleteCustomerPaymentProfileRequest <https://developer.authorize.net/api/reference/index.html#customer-profiles-delete-customer-payment-profile>`_
240
+
241
+ :raises AuthorizenetControllerExecutionError: If something goes wrong during an Authorizenet API call.
242
+ :returns: An Authorizenet API response, if any.
243
+ :rtype: :py:obj:`dict` | :py:obj:`None`
244
+
245
+ """
246
+ request = apicontractsv1.deleteCustomerPaymentProfileRequest()
247
+ request.merchantAuthentication = self.merchantAuthentication
248
+ request.customerProfileId = self.customerProfileId
249
+ request.customerPaymentProfileId = self.id
250
+
251
+ return self.execute_controller(
252
+ apicontrollers.deleteCustomerPaymentProfileController(request)
253
+ )
@@ -4,7 +4,7 @@ from django.conf import settings
4
4
  from django.core.exceptions import ImproperlyConfigured, ValidationError
5
5
  from django.utils.translation import gettext_lazy as _
6
6
 
7
- from .session import WialonSession
7
+ from .session import WialonSessionManager
8
8
 
9
9
  if settings.configured and not hasattr(settings, "WIALON_TOKEN"):
10
10
  raise ImproperlyConfigured("'WIALON_TOKEN' setting is required.")
@@ -12,8 +12,7 @@ if settings.configured and not hasattr(settings, "WIALON_TOKEN"):
12
12
 
13
13
  class WialonValidatorBase:
14
14
  def __init__(self) -> None:
15
- self.session: WialonSession = WialonSession()
16
- self.session.login(settings.WIALON_TOKEN)
15
+ self.session_manager = WialonSessionManager(token=settings.WIALON_TOKEN)
17
16
 
18
17
  def __call__(self, value: str) -> None:
19
18
  raise NotImplementedError("Subclasses must implement this method.")
@@ -21,10 +20,11 @@ class WialonValidatorBase:
21
20
 
22
21
  class WialonVinNumberValidator(WialonValidatorBase):
23
22
  def __call__(self, value: str) -> None:
24
- response = self.session.wialon_api.unit_get_vin_info(vin=value)
23
+ session = self.session_manager.get_session(sid=None)
24
+ response = session.wialon_api.unit_get_vin_info(vin=value)
25
25
  if "error" in response["vin_lookup_result"].keys():
26
26
  raise ValidationError(
27
- _("Failed to get info for VIN '%(value)s': '%(message)s'"),
27
+ _("Failed to get info for VIN # '%(value)s': '%(message)s'"),
28
28
  code="invalid",
29
29
  params={
30
30
  "value": value,
@@ -35,7 +35,8 @@ class WialonVinNumberValidator(WialonValidatorBase):
35
35
 
36
36
  class WialonImeiNumberValidator(WialonValidatorBase):
37
37
  def __call__(self, value: str) -> None:
38
- response = self.session.wialon_api.core_search_items(
38
+ session = self.session_manager.get_session(sid=None)
39
+ response = session.wialon_api.core_search_items(
39
40
  **{
40
41
  "spec": {
41
42
  "itemsType": "avl_unit",
@@ -51,7 +52,7 @@ class WialonImeiNumberValidator(WialonValidatorBase):
51
52
  )
52
53
  if response is None or not response.get("items"):
53
54
  raise ValidationError(
54
- _("IMEI '%(value)s' was not found in Wialon."),
55
+ _("IMEI # '%(value)s' wasn't found in Wialon."),
55
56
  code="invalid",
56
57
  params={"value": value},
57
58
  )