Source code for terminusgps.authorizenet.service

from abc import ABC
from functools import cached_property

from authorizenet.apicontractsv1 import merchantAuthenticationType
from authorizenet.apicontrollersbase import APIOperationBase
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from lxml.objectify import ObjectifiedElement

if not settings.configured:
    from terminusgps import default_settings

    settings.configure(default_settings)


[docs] class AuthorizenetControllerExecutionError(Exception): """Raised when an Authorizenet API controller fails to execute.""" def __init__(self, message: str, code: str, *args, **kwargs) -> None: super().__init__(message, *args, **kwargs) self._message: str = message self._code: str = code def __str__(self) -> str: return f"{self.code}: {self.message}" @property def message(self) -> str: """An Authorizenet API error message.""" return self._message @property def code(self) -> str: """An Authorizenet API error code.""" return self._code
[docs] class AuthorizenetService(ABC): """Base service for safely interacting with the Authorizenet API.""" REQUIRED_SETTINGS = ( "MERCHANT_AUTH_ENVIRONMENT", "MERCHANT_AUTH_LOGIN_ID", "MERCHANT_AUTH_TRANSACTION_KEY", "MERCHANT_AUTH_VALIDATION_MODE", ) def __init__(self) -> None: """Raises :py:exc:`~django.core.exceptions.ImproperlyConfigured` if required settings weren't set.""" for setting in self.REQUIRED_SETTINGS: if not hasattr(settings, setting): raise ImproperlyConfigured(f"'{setting}' setting is required.")
[docs] def execute( self, request_tuple: tuple[ObjectifiedElement, type[APIOperationBase]], reference_id: str | None = None, ) -> ObjectifiedElement: """ Adds required authentication data to the Authorizenet API request before executing it and returning its response. If ``reference_id`` was provided, it is added to the request before execution. :param request_tuple: A tuple containing an Authorizenet API request contract and a controller class to execute it with. :type request_tuple: tuple[~lxml.objectify.ObjectifiedElement, type[~authorizenet.apicontrollersbase.APIOperationBase]] :param reference_id: An optional reference id string for the API call. Default is :py:obj:`None`. :type reference_id: str | None :raises AuthorizenetControllerExecutionError: If the API call failed. :returns: An Authorizenet API response. :rtype: ~lxml.objectify.ObjectifiedElement """ request, controller_cls = request_tuple[0], request_tuple[1] request.merchantAuthentication = self.merchantAuthentication if reference_id is not None: request.refId = reference_id controller = controller_cls(request) controller.setenvironment(self.environment) controller.execute() response = controller.getresponse() if response is None: raise AuthorizenetControllerExecutionError( message="No response from the Authorizenet API controller.", code="1", ) elif response is not None and response.messages.resultCode != "Ok": raise AuthorizenetControllerExecutionError( message=response.messages.message[0]["text"].text, code=response.messages.message[0]["code"].text, ) return response
@cached_property def merchantAuthentication(self) -> merchantAuthenticationType: """Merchant authentication element for Authorizenet API requests.""" return merchantAuthenticationType( name=str(settings.MERCHANT_AUTH_LOGIN_ID), transactionKey=str(settings.MERCHANT_AUTH_TRANSACTION_KEY), ) @cached_property def environment(self) -> str: """Environment for Authorizenet API requests.""" return str(settings.MERCHANT_AUTH_ENVIRONMENT) @cached_property def validationMode(self) -> str: """Validation mode for Authorizenet API requests.""" return str(settings.MERCHANT_AUTH_VALIDATION_MODE)