python-terminusgps 45.6.1__tar.gz → 45.7.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 (62) hide show
  1. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/.github/workflows/sphinx.yml +19 -2
  2. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/PKG-INFO +1 -1
  3. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/requirements.txt +2 -1
  4. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/authorizenet/constants.rst +4 -1
  5. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/authorizenet/index.rst +4 -5
  6. python_terminusgps-45.7.0/docs/source/authorizenet/service.rst +9 -0
  7. python_terminusgps-45.7.0/docs/source/authorizenet/usage.rst +6 -0
  8. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/conf.py +0 -1
  9. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/pyproject.toml +1 -1
  10. python_terminusgps-45.7.0/terminusgps/authorizenet/api/transactions.py +100 -0
  11. python_terminusgps-45.7.0/terminusgps/authorizenet/service.py +112 -0
  12. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/uv.lock +1 -1
  13. python_terminusgps-45.6.1/docs/source/authorizenet/auth.rst +0 -22
  14. python_terminusgps-45.6.1/docs/source/authorizenet/exceptions.rst +0 -4
  15. python_terminusgps-45.6.1/docs/source/authorizenet/usage.rst +0 -20
  16. python_terminusgps-45.6.1/terminusgps/authorizenet/api/transactions.py +0 -2
  17. python_terminusgps-45.6.1/terminusgps/authorizenet/auth.py +0 -38
  18. python_terminusgps-45.6.1/terminusgps/authorizenet/controllers.py +0 -57
  19. python_terminusgps-45.6.1/terminusgps/authorizenet/services.py +0 -66
  20. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/.gitignore +0 -0
  21. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/.python-version +0 -0
  22. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/COPYING +0 -0
  23. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/README.md +0 -0
  24. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/Makefile +0 -0
  25. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/make.bat +0 -0
  26. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/authorizenet/api.rst +0 -0
  27. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/index.rst +0 -0
  28. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/mixins.rst +0 -0
  29. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/validators.rst +0 -0
  30. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/wialon/constants.rst +0 -0
  31. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/wialon/exceptions.rst +0 -0
  32. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/wialon/index.rst +0 -0
  33. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/wialon/items.rst +0 -0
  34. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/wialon/session.rst +0 -0
  35. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/docs/source/wialon/usage.rst +0 -0
  36. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/__init__.py +0 -0
  37. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/authorizenet/__init__.py +0 -0
  38. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/authorizenet/api/__init__.py +0 -0
  39. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/authorizenet/api/address_profiles.py +0 -0
  40. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/authorizenet/api/customer_profiles.py +0 -0
  41. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/authorizenet/api/payment_profiles.py +0 -0
  42. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/authorizenet/api/subscriptions.py +0 -0
  43. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/authorizenet/constants.py +0 -0
  44. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/default_settings.py +0 -0
  45. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/mixins.py +0 -0
  46. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/validators.py +0 -0
  47. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/__init__.py +0 -0
  48. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/constants.py +0 -0
  49. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/flags.py +0 -0
  50. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/items/__init__.py +0 -0
  51. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/items/account.py +0 -0
  52. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/items/base.py +0 -0
  53. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/items/factory.py +0 -0
  54. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/items/resource.py +0 -0
  55. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/items/retranslator.py +0 -0
  56. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/items/route.py +0 -0
  57. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/items/unit.py +0 -0
  58. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/items/unit_group.py +0 -0
  59. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/items/user.py +0 -0
  60. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/session.py +0 -0
  61. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/utils.py +0 -0
  62. {python_terminusgps-45.6.1 → python_terminusgps-45.7.0}/terminusgps/wialon/validators.py +0 -0
@@ -12,8 +12,25 @@ jobs:
12
12
  with:
13
13
  persist-credentials: false
14
14
 
15
- - name: Build HTML
16
- uses: ammaraskar/sphinx-action@8.2.3
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v6
17
+ with:
18
+ version: "0.8.17"
19
+
20
+ - name: Set up python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version-file: ".python-version"
24
+
25
+ - name: Install project
26
+ run: uv sync --locked --group docs
27
+
28
+ - name: Build docs
29
+ run: |
30
+ source .venv/bin/activate
31
+ cd docs
32
+ make html
33
+ deactivate
17
34
 
18
35
  - name: Upload artifacts
19
36
  uses: actions/upload-artifact@v4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-terminusgps
3
- Version: 45.6.1
3
+ Version: 45.7.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
@@ -1,5 +1,6 @@
1
+ authorizenet>=1.1.5
1
2
  autoclasstoc>=1.7.0
2
3
  django>=5.2.1
3
- furo==2024.04.27
4
4
  python-wialon>=1.2.4
5
+ sphinx>=8.2.3
5
6
  sphinxawesome-theme>=5.3.2
@@ -1,12 +1,15 @@
1
1
  Constants
2
2
  =========
3
3
 
4
- These constants inherit from :py:obj:`~django.db.models.TextChoices`, not the built-in Python :py:obj:`~enum.StrEnum` type.
4
+ These constants inherit from :py:obj:`django.db.models.TextChoices`, not the built-in Python :py:obj:`~enum.StrEnum` type.
5
5
 
6
6
  Django :py:obj:`~django.db.models.TextChoices` provides attributes such as :py:attr:`~django.db.models.TextChoices.choices`, :py:attr:`~django.db.models.TextChoices.values`, :py:attr:`~django.db.models.TextChoices.labels` and more.
7
7
 
8
8
  .. py:currentmodule:: terminusgps.authorizenet.constants
9
9
 
10
+ .. autoclass:: CurrencyCode
11
+ :members:
12
+
10
13
  .. autoclass:: Environment
11
14
  :members:
12
15
 
@@ -1,13 +1,13 @@
1
1
  Authorizenet
2
2
  ============
3
3
 
4
- The :py:mod:`terminusgps.authorizenet` package provides convenient functions for interacting with the Authorizenet API in a Pythonic interface.
4
+ The :py:mod:`terminusgps.authorizenet` package provides a Pythonic interface for interacting with the Authorizenet API.
5
5
 
6
6
  Most `Authorizenet API endpoints <https://developer.authorize.net/api/reference/index.html>`_ are represented as plain Python functions.
7
7
 
8
- .. attention:: These functions require the following settings to be present in your Django project's ``settings.py`` module.
8
+ .. attention:: :py:mod:`terminusgps.authorizenet` requires the following settings to be present in your Django project's ``settings.py`` module.
9
9
 
10
- Using this package without setting these settings will raise :py:exc:`~django.core.exceptions.ImproperlyConfigured`.
10
+ Using the package without setting these settings will raise :py:exc:`~django.core.exceptions.ImproperlyConfigured`.
11
11
 
12
12
  +-----------------------------------+---------------+
13
13
  | setting | type |
@@ -25,8 +25,7 @@ Most `Authorizenet API endpoints <https://developer.authorize.net/api/reference/
25
25
  :maxdepth: 2
26
26
  :caption: Contents:
27
27
 
28
- auth.rst
29
28
  constants.rst
30
- exceptions.rst
31
29
  api.rst
30
+ service.rst
32
31
  usage.rst
@@ -0,0 +1,9 @@
1
+ Service
2
+ =======
3
+
4
+ .. autoexception:: terminusgps.authorizenet.service.AuthorizenetControllerExecutionError
5
+ :members:
6
+
7
+ .. autoclass:: terminusgps.authorizenet.service.AuthorizenetService
8
+ :autoclasstoc:
9
+ :members:
@@ -0,0 +1,6 @@
1
+ Usage
2
+ =====
3
+
4
+ Check the Authorizenet API documentation for expected attributes in each response.
5
+
6
+ TODO
@@ -33,7 +33,6 @@ intersphinx_mapping = {
33
33
  ),
34
34
  }
35
35
 
36
- templates_path = ["_templates"]
37
36
  exclude_patterns = []
38
37
 
39
38
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-terminusgps"
3
- version = "45.6.1"
3
+ version = "45.7.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" } ]
@@ -0,0 +1,100 @@
1
+ from decimal import Decimal
2
+
3
+ from authorizenet import apicontractsv1, apicontrollers
4
+ from authorizenet.apicontrollersbase import APIOperationBase
5
+ from lxml.objectify import ObjectifiedElement
6
+
7
+ __all__ = []
8
+
9
+
10
+ def build_transaction_request(
11
+ transaction_type: str,
12
+ amount: Decimal,
13
+ payment: apicontractsv1.paymentType | None = None,
14
+ order: apicontractsv1.orderType | None = None,
15
+ address: apicontractsv1.customerAddressType | None = None,
16
+ customer_data: apicontractsv1.customerDataType | None = None,
17
+ settings: apicontractsv1.settingType | None = None,
18
+ line_items: apicontractsv1.ArrayOfLineItem | None = None,
19
+ ) -> apicontractsv1.transactionRequestType:
20
+ request = apicontractsv1.transactionRequestType()
21
+ request.transactionType = transaction_type
22
+ request.amount = amount
23
+
24
+ if payment is not None:
25
+ request.payment = payment
26
+ if order is not None:
27
+ request.order = order
28
+ if address is not None:
29
+ request.billTo = address
30
+ if customer_data is not None:
31
+ request.customer = customer_data
32
+ if settings is not None:
33
+ request.transactionSettings = settings
34
+ if line_items is not None:
35
+ request.lineItems = line_items
36
+ return request
37
+
38
+
39
+ def charge_credit_card(
40
+ amount: Decimal,
41
+ credit_card: apicontractsv1.creditCardType,
42
+ address: apicontractsv1.customerAddressType,
43
+ order: apicontractsv1.orderType | None = None,
44
+ customer_data: apicontractsv1.customerDataType | None = None,
45
+ settings: apicontractsv1.settingType | None = None,
46
+ ) -> tuple[ObjectifiedElement, type[APIOperationBase]]:
47
+ request = apicontractsv1.createTransactionRequest()
48
+ request.transactionRequest = build_transaction_request(
49
+ transaction_type="authCaptureTransaction",
50
+ amount=amount,
51
+ payment=apicontractsv1.paymentType(creditCard=credit_card),
52
+ address=address,
53
+ order=order,
54
+ customer_data=customer_data,
55
+ settings=settings,
56
+ )
57
+ return request, apicontrollers.createTransactionController
58
+
59
+
60
+ def authorize_credit_card(
61
+ amount: Decimal,
62
+ credit_card: apicontractsv1.creditCardType,
63
+ address: apicontractsv1.customerAddressType,
64
+ order: apicontractsv1.orderType | None = None,
65
+ customer_data: apicontractsv1.customerDataType | None = None,
66
+ settings: apicontractsv1.settingType | None = None,
67
+ ) -> tuple[ObjectifiedElement, type[APIOperationBase]]:
68
+ request = apicontractsv1.createTransactionRequest()
69
+ request.transactionRequest = build_transaction_request(
70
+ transaction_type="authOnlyTransaction",
71
+ amount=amount,
72
+ payment=apicontractsv1.paymentType(creditCard=credit_card),
73
+ address=address,
74
+ order=order,
75
+ customer_data=customer_data,
76
+ settings=settings,
77
+ )
78
+ return request, apicontrollers.createTransactionController
79
+
80
+
81
+ def capture_authorized_amount(
82
+ amount: Decimal,
83
+ ) -> tuple[ObjectifiedElement, type[APIOperationBase]]:
84
+ request = apicontractsv1.createTransactionRequest()
85
+ request.transactionRequest = build_transaction_request(
86
+ transaction_type="priorAuthCaptureTransaction", amount=amount
87
+ )
88
+ return request, apicontrollers.createTransactionController
89
+
90
+
91
+ def refund_credit_card(
92
+ amount: Decimal, credit_card: apicontractsv1.creditCardType
93
+ ) -> tuple[ObjectifiedElement, type[APIOperationBase]]:
94
+ request = apicontractsv1.createTransactionRequest()
95
+ request.transactionRequest = build_transaction_request(
96
+ transaction_type="refundTransaction",
97
+ amount=amount,
98
+ payment=apicontractsv1.paymentType(creditCard=credit_card),
99
+ )
100
+ return request, apicontrollers.createTransactionController
@@ -0,0 +1,112 @@
1
+ from functools import cached_property
2
+
3
+ from authorizenet.apicontractsv1 import merchantAuthenticationType
4
+ from authorizenet.apicontrollersbase import APIOperationBase
5
+ from django.conf import settings
6
+ from django.core.exceptions import ImproperlyConfigured
7
+ from lxml.objectify import ObjectifiedElement
8
+
9
+ if not settings.configured:
10
+ from terminusgps import default_settings
11
+
12
+ settings.configure(default_settings)
13
+
14
+
15
+ class AuthorizenetControllerExecutionError(Exception):
16
+ """Raised when an Authorizenet API controller fails to execute."""
17
+
18
+ def __init__(self, message: str, code: str, *args, **kwargs) -> None:
19
+ super().__init__(message, *args, **kwargs)
20
+ self._message: str = message
21
+ self._code: str = code
22
+
23
+ def __str__(self) -> str:
24
+ return f"{self.code}: {self.message}"
25
+
26
+ @property
27
+ def message(self) -> str:
28
+ """An Authorizenet API error message."""
29
+ return self._message
30
+
31
+ @property
32
+ def code(self) -> str:
33
+ """An Authorizenet API error code."""
34
+ return self._code
35
+
36
+
37
+ class AuthorizenetService:
38
+ """A service for safely interacting with the Authorizenet API."""
39
+
40
+ REQUIRED_SETTINGS = (
41
+ "MERCHANT_AUTH_ENVIRONMENT",
42
+ "MERCHANT_AUTH_LOGIN_ID",
43
+ "MERCHANT_AUTH_TRANSACTION_KEY",
44
+ "MERCHANT_AUTH_VALIDATION_MODE",
45
+ )
46
+
47
+ def __init__(self) -> None:
48
+ """Raises :py:exc:`~django.core.exceptions.ImproperlyConfigured` if required settings weren't set."""
49
+ for setting in self.REQUIRED_SETTINGS:
50
+ if not hasattr(settings, setting):
51
+ raise ImproperlyConfigured(f"'{setting}' setting is required.")
52
+
53
+ def call_api(
54
+ self,
55
+ request: ObjectifiedElement,
56
+ controller_cls: type[APIOperationBase],
57
+ reference_id: str | None = None,
58
+ ) -> ObjectifiedElement:
59
+ """
60
+ Adds required authentication data to the request before executing it and returning its response.
61
+
62
+ If ``reference_id`` was provided, it is added to the request before execution.
63
+
64
+ :param request: An Authorizenet API request element.
65
+ :type request: ~lxml.objectify.ObjectifiedElement
66
+ :param controller_cls: An Authorizenet controller class.
67
+ :type controller_cls: type[~authorizenet.apicontrollersbase.APIOperationBase]
68
+ :param reference_id: An optional reference id string for the API call. Default is :py:obj:`None`.
69
+ :type reference_id: str | None
70
+ :raises AuthorizenetControllerExecutionError: If the API call failed.
71
+ :returns: An Authorizenet API response.
72
+ :rtype: ~lxml.objectify.ObjectifiedElement
73
+
74
+ """
75
+ request.merchantAuthentication = self.merchantAuthentication
76
+ if reference_id is not None:
77
+ request.refId = reference_id
78
+
79
+ controller = controller_cls(request)
80
+ controller.setenvironment(self.environment)
81
+ controller.execute()
82
+
83
+ response: ObjectifiedElement | None = controller.getresponse()
84
+ if response is None:
85
+ raise AuthorizenetControllerExecutionError(
86
+ message="No response from the Authorizenet API controller.",
87
+ code="1",
88
+ )
89
+ elif response is not None and response.messages.resultCode != "Ok":
90
+ raise AuthorizenetControllerExecutionError(
91
+ message=response.messages.message[0]["text"].text,
92
+ code=response.messages.message[0]["code"].text,
93
+ )
94
+ return response
95
+
96
+ @cached_property
97
+ def merchantAuthentication(self) -> merchantAuthenticationType:
98
+ """Merchant authentication element for Authorizenet API requests."""
99
+ return merchantAuthenticationType(
100
+ name=str(settings.MERCHANT_AUTH_LOGIN_ID),
101
+ transactionKey=str(settings.MERCHANT_AUTH_TRANSACTION_KEY),
102
+ )
103
+
104
+ @cached_property
105
+ def environment(self) -> str:
106
+ """Environment for Authorizenet API requests."""
107
+ return str(settings.MERCHANT_AUTH_ENVIRONMENT)
108
+
109
+ @cached_property
110
+ def validationMode(self) -> str:
111
+ """Validation mode for Authorizenet API requests."""
112
+ return str(settings.MERCHANT_AUTH_VALIDATION_MODE)
@@ -298,7 +298,7 @@ wheels = [
298
298
 
299
299
  [[package]]
300
300
  name = "python-terminusgps"
301
- version = "45.6.1"
301
+ version = "45.7.0"
302
302
  source = { editable = "." }
303
303
  dependencies = [
304
304
  { name = "authorizenet" },
@@ -1,22 +0,0 @@
1
- Authentication
2
- ==============
3
-
4
- Authentication for each Authorizenet API call is handled by values defined in a Django ``settings.py`` module.
5
-
6
- Required settings:
7
-
8
- +-----------------------------------+---------------+
9
- | setting | type |
10
- +===================================+===============+
11
- | ``MERCHANT_AUTH_ENVIRONMENT`` | :py:obj:`str` |
12
- +-----------------------------------+---------------+
13
- | ``MERCHANT_AUTH_LOGIN_ID`` | :py:obj:`str` |
14
- +-----------------------------------+---------------+
15
- | ``MERCHANT_AUTH_TRANSACTION_KEY`` | :py:obj:`str` |
16
- +-----------------------------------+---------------+
17
- | ``MERCHANT_AUTH_VALIDATION_MODE`` | :py:obj:`str` |
18
- +-----------------------------------+---------------+
19
-
20
- .. automodule:: terminusgps.authorizenet.auth
21
- :synopsis: Provides functions for authenticating Authorizenet API calls.
22
- :members:
@@ -1,4 +0,0 @@
1
- Exceptions
2
- ==========
3
-
4
- .. autoexception:: terminusgps.authorizenet.controllers.AuthorizenetControllerExecutionError
@@ -1,20 +0,0 @@
1
- Usage
2
- =====
3
-
4
- Check the Authorizenet API documentation for expected attributes in each response.
5
-
6
- .. code:: python
7
-
8
- from terminusgps.authorizenet import api as anet
9
-
10
- # An Authorizenet 'createCustomerProfileRequest'
11
- response = anet.create_customer_profile(
12
- merchant_id="1",
13
- email="blake@terminusgps.com",
14
- description="Blake Nall"
15
- )
16
-
17
- # Authorizenet API calls may return None
18
- # Check first before trying to access attributes on it
19
- if response is not None and hasattr(response, "customerProfileId"):
20
- response.customerProfileId
@@ -1,2 +0,0 @@
1
- # TODO
2
- __all__ = []
@@ -1,38 +0,0 @@
1
- from authorizenet.apicontractsv1 import merchantAuthenticationType
2
- from django.conf import settings
3
-
4
-
5
- def get_merchant_auth() -> merchantAuthenticationType:
6
- """
7
- Returns the merchant authentication information for Authorizenet API controller execution.
8
-
9
- :returns: A merchant authentication object.
10
- :rtype: ~authorizenet.apicontractsv1.merchantAuthenticationType
11
-
12
- """
13
- return merchantAuthenticationType(
14
- name=str(settings.MERCHANT_AUTH_LOGIN_ID),
15
- transactionKey=str(settings.MERCHANT_AUTH_TRANSACTION_KEY),
16
- )
17
-
18
-
19
- def get_environment() -> str:
20
- """
21
- Returns the environment for Authorizenet API controller execution.
22
-
23
- :returns: An Authorizenet API environment string.
24
- :rtype: str
25
-
26
- """
27
- return settings.MERCHANT_AUTH_ENVIRONMENT
28
-
29
-
30
- def get_validation_mode() -> str:
31
- """
32
- Returns the validation mode for Authorizenet API controller execution.
33
-
34
- :returns: An Authorizenet API validation string.
35
- :rtype: str
36
-
37
- """
38
- return settings.MERCHANT_AUTH_VALIDATION_MODE
@@ -1,57 +0,0 @@
1
- from authorizenet.apicontrollersbase import APIOperationBase
2
- from lxml.objectify import ObjectifiedElement
3
-
4
-
5
- def execute_controller(
6
- controller: APIOperationBase, environment: str
7
- ) -> ObjectifiedElement:
8
- """
9
- Executes an Authorizenet API controller and returns its response.
10
-
11
- :param controller: An Authorizenet API controller.
12
- :type controller: ~authorizenet.apicontrollersbase.APIOperationBase
13
- :param environment: Authorizenet environment to execute the controller in.
14
- :type environment: :py:obj:`str`
15
- :param merchant_auth: Authorizenet merchant authentication element.
16
- :type merchant_auth: ~authorizenet.apicontractsv1.merchantAuthenticationType
17
- :raises AuthorizenetControllerExecutionError: If the API call fails.
18
- :returns: An Authorizenet API response.
19
- :rtype: ~lxml.objectify.ObjectifiedElement
20
-
21
- """
22
- controller.setenvironment(environment)
23
- controller.execute()
24
- response: ObjectifiedElement | None = controller.getresponse()
25
-
26
- if response is None:
27
- raise AuthorizenetControllerExecutionError(
28
- message="Authorizenet controller response didn't exist.", code="1"
29
- )
30
- elif response is not None and response.messages.resultCode != "Ok":
31
- raise AuthorizenetControllerExecutionError(
32
- message=response.messages.message[0]["text"].text,
33
- code=response.messages.message[0]["code"].text,
34
- )
35
- return response
36
-
37
-
38
- class AuthorizenetControllerExecutionError(Exception):
39
- """Raised when an Authorizenet API controller fails to execute."""
40
-
41
- def __init__(self, message: str, code: str, *args, **kwargs) -> None:
42
- super().__init__(message, *args, **kwargs)
43
- self._message: str = message
44
- self._code: str = code
45
-
46
- def __str__(self) -> str:
47
- return f"{self.code}: {self.message}"
48
-
49
- @property
50
- def message(self) -> str:
51
- """An Authorizenet API error message."""
52
- return self._message
53
-
54
- @property
55
- def code(self) -> str:
56
- """An Authorizenet API error code."""
57
- return self._code
@@ -1,66 +0,0 @@
1
- from functools import cached_property
2
- from typing import Callable
3
-
4
- from authorizenet.apicontractsv1 import merchantAuthenticationType
5
- from django.conf import settings
6
- from django.core.exceptions import ImproperlyConfigured
7
- from lxml.objectify import ObjectifiedElement
8
-
9
- from .auth import get_environment, get_merchant_auth, get_validation_mode
10
- from .controllers import (
11
- AuthorizenetControllerExecutionError,
12
- execute_controller,
13
- )
14
-
15
-
16
- class AuthorizenetService:
17
- """A service for safely interacting with the Authorizenet API."""
18
-
19
- REQUIRED_SETTINGS = (
20
- "MERCHANT_AUTH_ENVIRONMENT",
21
- "MERCHANT_AUTH_LOGIN_ID",
22
- "MERCHANT_AUTH_TRANSACTION_KEY",
23
- "MERCHANT_AUTH_VALIDATION_MODE",
24
- )
25
-
26
- def __init__(self) -> None:
27
- """Raises :py:exc:`~django.core.exceptions.ImproperlyConfigured` if required settings weren't set."""
28
- for setting in self.REQUIRED_SETTINGS:
29
- if not hasattr(settings, setting):
30
- raise ImproperlyConfigured(f"'{setting}' setting is required.")
31
-
32
- def request(self, func: Callable, *args, **kwargs) -> ObjectifiedElement:
33
- """
34
- Calls the Authorizenet API function with arguments and returns the result.
35
-
36
- :param func: An Authorizenet API function.
37
- :type func: ~typing.Callable
38
- :param args: Positional arguments for the API call.
39
- :param kwargs: Keyword arguments for the API call.
40
- :raises ~terminusgps.authorizenet.controllers.AuthorizenetControllerExecutionError: If the API call failed.
41
- :returns: The Authorizenet API call response.
42
- :rtype: ~lxml.objectify.ObjectifiedElement
43
-
44
- """
45
- try:
46
- request, controller_cls = func(*args, **kwargs)
47
- request.merchantAuthentication = self.merchantAuthentication
48
- controller = controller_cls(request)
49
- return execute_controller(controller, self.environment)
50
- except AuthorizenetControllerExecutionError:
51
- raise
52
-
53
- @cached_property
54
- def merchantAuthentication(self) -> merchantAuthenticationType:
55
- """Merchant authentication element for Authorizenet API requests."""
56
- return get_merchant_auth()
57
-
58
- @cached_property
59
- def environment(self) -> str:
60
- """Environment for Authorizenet API requests."""
61
- return get_environment()
62
-
63
- @cached_property
64
- def validationMode(self) -> str:
65
- """Validation mode for Authorizenet API requests."""
66
- return get_validation_mode()