Source code for terminusgps.authorizenet.utils
import datetime
import decimal
from authorizenet import apicontractsv1, apicontrollers
from django import forms
from django.conf import settings
from .auth import get_merchant_auth
from .controllers import AuthorizenetControllerExecutor
[docs]
def calculate_amount_plus_tax(
amount: decimal.Decimal, tax_rate: decimal.Decimal | None = None
) -> decimal.Decimal:
"""
Returns the amount + tax. Uses :confval:`DEFAULT_TAX_RATE` if ``tax_rate`` wasn't provided.
:param amount: Amount to add tax to.
:type amount: :py:obj:`~decimal.Decimal`
:param tax_rate: A tax rate to use in the calculation.
:type tax_rate: :py:obj:`~decimal.Decimal` | :py:obj:`None`
:returns: The amount + tax.
:rtype: :py:obj:`~decimal.Decimal`
"""
if tax_rate is None:
tax_rate = settings.DEFAULT_TAX_RATE
return round(amount * (1 + tax_rate), ndigits=2)
[docs]
def get_days_between(start_date: datetime.date, end_date: datetime.date) -> int:
"""
Returns the total number of days between two dates.
:param start_date: Start date.
:type start_date: :py:obj:`~datetime.date`
:param end_date: End date.
:type end_date: :py:obj:`~datetime.date`
:returns: The number of days between the dates as an integer.
:rtype: :py:obj:`int`
"""
return (end_date - start_date).days
[docs]
def get_merchant_details() -> dict | None:
"""
Returns Authorizenet merchant details.
`getMerchantDetailsRequest <http://developer.authorize.net/api/reference/index.html#transaction-reporting-get-merchant-details>`_
:raises AuthorizenetControllerExecutionError: If the API call fails.
:returns: A merchant details object, if found.
:rtype: :py:obj:`dict` | :py:obj:`None`
"""
request = apicontractsv1.getMerchantDetailsRequest(
merchantAuthentication=get_merchant_auth()
)
controller = apicontrollers.getMerchantDetailsController(request)
return AuthorizenetControllerExecutor.execute_controller(controller)
[docs]
def get_transaction(id: int | str) -> dict | None:
"""
Returns Authorizenet transaction details by id.
`getTransactionDetailsRequest <https://developer.authorize.net/api/reference/index.html#transaction-reporting-get-transaction-details>`_
:param id: An Authorizenet transaction id.
:type id: :py:obj:`int` | :py:obj:`str`
:raises ValueError: If ``id`` was provided as a string containing non-digits.
:raises AuthorizenetControllerExecutionError: If the API call fails.
:returns: A transaction object, if found.
:rtype: :py:obj:`dict` | :py:obj:`None`
"""
if isinstance(id, str) and not id.isdigit():
raise ValueError(f"'id' can only contain digits, got '{id}'.")
request = apicontractsv1.getTransactionDetailsRequest(
merchantAuthentication=get_merchant_auth(), transId=str(id)
)
controller = apicontrollers.getTransactionDetailsController(request)
return AuthorizenetControllerExecutor.execute_controller(controller)
def generate_monthly_subscription_schedule(
start_date: datetime.date, total_occurrences: int = 9999, trial_occurrences: int = 0
) -> apicontractsv1.paymentScheduleType:
return apicontractsv1.paymentScheduleType(
interval=apicontractsv1.paymentScheduleTypeInterval(
length=1, unit=apicontractsv1.ARBSubscriptionUnitEnum.months
),
startDate=f"{start_date:%Y-%m-%d}",
totalOccurrences=str(total_occurrences),
trialOccurrences=str(trial_occurrences),
)
[docs]
def get_customer_profile_ids() -> list[int]:
"""
Returns a list of all customer profile ids in Authorizenet.
:raises AuthorizenetControllerExecutionError: If the API call fails.
:returns: A list of all customer profile ids in Authorizenet.
:rtype: :py:obj:`list`
"""
request = apicontractsv1.getCustomerProfileIdsRequest(
merchantAuthentication=get_merchant_auth()
)
controller = apicontrollers.getCustomerProfileIdsController(request)
response = AuthorizenetControllerExecutor.execute_controller(controller)
if response is None or "ids" not in response.getchildren():
return []
return [int(id) for id in response.ids.getchildren()]
[docs]
def generate_customer_address(form: forms.Form) -> apicontractsv1.customerAddressType:
"""
Takes a form and returns a :py:obj:`~authorizenet.apicontractsv1.customerAddressType`.
Required form fields:
+----------------+------------------------------------------------------------+
| name | type |
+================+============================================================+
| ``address`` | :py:obj:`~authorizenet.apicontractsv1.customerAddressType` |
+----------------+------------------------------------------------------------+
| ``first_name`` | :py:obj:`str` |
+----------------+------------------------------------------------------------+
| ``last_name`` | :py:obj:`str` |
+----------------+------------------------------------------------------------+
:param form: A Django form.
:type form: :py:obj:`~django.forms.Form`
:raises ValueError: If ``address`` wasn't in the form.
:raises ValueError: If ``first_name`` wasn't in the form.
:raises ValueError: If ``last_name`` wasn't in the form.
:returns: A customer address object.
:rtype: :py:obj:`~authorizenet.apicontractsv1.customerAddressType`
"""
required_fields: list[str] = ["address", "first_name", "last_name"]
for field in required_fields:
if field not in form.cleaned_data or form.cleaned_data.get(field) is None:
raise ValueError(
f"'{field}' was not provided by the form, got '{form.cleaned_data.get(field)}'."
)
address: apicontractsv1.customerAddressType = form.cleaned_data["address"]
address.firstName = form.cleaned_data["first_name"]
address.lastName = form.cleaned_data["last_name"]
if form.cleaned_data.get("phone"):
address.phone = form.cleaned_data["phone"]
return address
[docs]
def generate_customer_payment(form: forms.Form) -> apicontractsv1.paymentType:
"""
Takes a form and returns a :py:obj:`~authorizenet.apicontractsv1.paymentType`.
Required form fields:
+-----------------+-------------------------------------------------------+
| name | type |
+=================+=======================================================+
| ``credit_card`` | :py:obj:`~authorizenet.apicontractsv1.creditCardType` |
+-----------------+-------------------------------------------------------+
:param form: A Django form.
:type form: :py:obj:`~django.forms.Form`
:raises ValueError: If ``credit_card`` wasn't in the form.
:returns: A payment object.
:rtype: :py:obj:`~authorizenet.apicontractsv1.paymentType`
"""
required_fields: list[str] = ["credit_card"]
for field in required_fields:
if field not in form.cleaned_data or form.cleaned_data.get(field) is None:
raise ValueError(
f"'{field}' was not provided by the form, got '{form.cleaned_data.get(field)}'."
)
credit_card: apicontractsv1.creditCardType = form.cleaned_data["credit_card"]
return apicontractsv1.paymentType(creditCard=credit_card)