from __future__ import annotations
import stripe
[docs]
class DatatransPaymentError(Exception):
pass
[docs]
class DatatransApiError(DatatransPaymentError):
def __init__(self, code: str, message: str, terminal: bool) -> None:
super().__init__(f'{code}: {message}')
[docs]
self.terminal = terminal
[docs]
class SaferpayPaymentError(Exception):
pass
[docs]
class SaferpayApiError(SaferpayPaymentError):
# the following errors should be fine to ignore on our end
# full list of names: https://saferpay.github.io/jsonapi/#errorhandling
[docs]
EXPECTED_ERROR_NAMES = frozenset((
'BLOCKED_BY_RISK_MANAGEMENT',
'CARD_CHECK_FAILED',
'CARD_CVC_INVALID',
'CARD_CVC_REQUIRED',
'COMMUNICATION_FAILED',
'COMMUNICATION_TIMEOUT',
'GENERAL_DECLINED',
'PAYER_AUTHENTICATION_REQUIRED',
'PAYMENTMEANS_INVALID',
'PAYMENTMEANS_NOT_SUPPORTED',
'3DS_AUTHENTICATION_FAILED',
'TRANSACTION_ABORTED',
'TRANSACTION_DECLINED',
'UNEXPECTED_ERROR_BY_ACQUIRER',
'UPDATE_CARD_INFORMATION',
))
def __init__(
self,
name: str,
message: str,
behavior: str,
detail: list[str] | None = None
) -> None:
details = tuple(detail) if detail else ()
super().__init__('\n'.join((
f'{name}: {message}',
*details,
)))
[docs]
self.behavior = behavior
@property
[docs]
def is_expected_failure(self) -> bool:
return self.name in self.EXPECTED_ERROR_NAMES
# the following exceptions should be caught and logged - the user should be
# informed that the payment failed, but not why
[docs]
CARD_ERRORS = (
stripe.error.CardError,
DatatransPaymentError,
SaferpayPaymentError,
)