diff --git a/e2e_tests/authorization_request_test.py b/e2e_tests/authorization_request_test.py index 002c5e3..9e8f307 100644 --- a/e2e_tests/authorization_request_test.py +++ b/e2e_tests/authorization_request_test.py @@ -41,6 +41,7 @@ def test_card_transaction_authorization_request_dto(): "createdAt": "2021-06-22T13:39:17.018Z", "amount": 2500, "status": "Pending", + "outcome": "WaitTimeout", "partialApprovalAllowed": False, "merchant": { "name": "Apple Inc.", @@ -84,6 +85,7 @@ def test_card_transaction_authorization_request_dto(): assert authorization_request.id == data["id"] assert authorization_request.type == data["type"] assert authorization_request.attributes.get("cardNetwork") == data["attributes"]["cardNetwork"] + assert authorization_request.attributes.get("outcome") == data["attributes"]["outcome"] def test_atm_authorization_request_dto(): @@ -94,6 +96,7 @@ def test_atm_authorization_request_dto(): "createdAt": "2021-06-22T13:39:17.018Z", "amount": 2500, "status": "Pending", + "outcome": "PostTimeout", "partialApprovalAllowed": False, "direction": "Debit", "atmName": "HOME FED SAV BK", @@ -129,6 +132,7 @@ def test_atm_authorization_request_dto(): assert authorization_request.id == data["id"] assert authorization_request.type == data["type"] assert authorization_request.attributes.get("cardNetwork") == data["attributes"]["cardNetwork"] + assert authorization_request.attributes.get("outcome") == data["attributes"]["outcome"] def test_purchase_authorization_request_dto(): @@ -139,6 +143,7 @@ def test_purchase_authorization_request_dto(): "createdAt": "2021-06-22T13:39:17.018Z", "amount": 2500, "status": "Pending", + "outcome": "Approved", "partialApprovalAllowed": False, "merchant": { "name": "Apple Inc.", @@ -179,6 +184,13 @@ def test_purchase_authorization_request_dto(): } } + authorization_request = DtoDecoder.decode(data) + assert type(authorization_request) is PurchaseAuthorizationRequestDTO + assert authorization_request.id == data["id"] + assert authorization_request.type == data["type"] + assert authorization_request.attributes.get("cardNetwork") == data["attributes"]["cardNetwork"] + assert authorization_request.attributes.get("outcome") == data["attributes"]["outcome"] + # # def test_decline_request(): diff --git a/e2e_tests/authorization_test.py b/e2e_tests/authorization_test.py index bc5bd10..31c839f 100644 --- a/e2e_tests/authorization_test.py +++ b/e2e_tests/authorization_test.py @@ -79,6 +79,7 @@ def test_authorization_api_response(): "cardNetwork": "Visa", "paymentMethod": "Swipe", "digitalWallet": "Google", + "cardDecisionSource": "Org", "cashWithdrawalAmount": 150 }, "relationships": { diff --git a/e2e_tests/transaction_test.py b/e2e_tests/transaction_test.py index 1866b36..b4986e8 100644 --- a/e2e_tests/transaction_test.py +++ b/e2e_tests/transaction_test.py @@ -204,7 +204,8 @@ def test_card_transaction(): "cardVerificationData": { "verificationMethod": "CVV2" }, - "cardNetwork": "Visa" + "cardNetwork": "Visa", + "cardDecisionSource": "IssuerStandIn" }, "relationships": { "account": { @@ -233,6 +234,7 @@ def test_card_transaction(): assert transaction.attributes["recurring"] is False assert transaction.attributes["paymentMethod"] == "Contactless" assert transaction.attributes["cardNetwork"] == "Visa" + assert transaction.attributes["cardDecisionSource"] == "IssuerStandIn" assert transaction.attributes["digitalWallet"] == "Apple" assert transaction.attributes["cardVerificationData"]["verificationMethod"] == "CVV2" @@ -252,7 +254,8 @@ def test_atm_transaction(): "atmLocation": "Masontown, PA 15461", "surcharge": 10, "interchange": 15.2, - "cardNetwork": "Allpoint" + "cardNetwork": "Allpoint", + "cardDecisionSource": "TimeoutApprove" }, "relationships": { "account": { @@ -287,6 +290,7 @@ def test_atm_transaction(): assert transaction.attributes["surcharge"] == 10 assert transaction.attributes["interchange"] == 15.2 assert transaction.attributes["cardNetwork"] == "Allpoint" + assert transaction.attributes["cardDecisionSource"] == "TimeoutApprove" def test_purchase_transaction(): purchase_transaction_api_response = { @@ -318,7 +322,8 @@ def test_purchase_transaction(): "cardVerificationData": { "verificationMethod": "CVV2" }, - "cardNetwork": "Visa" + "cardNetwork": "Visa", + "cardDecisionSource": "Unit" }, "relationships": { "account": { @@ -361,6 +366,7 @@ def test_purchase_transaction(): assert transaction.attributes["recurring"] is False assert transaction.attributes["cardPresent"] is True assert transaction.attributes["cardNetwork"] == "Visa" + assert transaction.attributes["cardDecisionSource"] == "Unit" assert transaction.attributes["digitalWallet"] == "Apple" assert transaction.attributes["paymentMethod"] == "Contactless" diff --git a/unit/models/authorization.py b/unit/models/authorization.py index a2726d9..f3b122a 100644 --- a/unit/models/authorization.py +++ b/unit/models/authorization.py @@ -4,6 +4,8 @@ from unit.utils import date_utils AuthorizationStatus = Literal["Authorized", "Completed", "Canceled", "Declined"] +CardDecisionSource = Literal["Org", "Unit", "Network", "TimeoutApprove", "TimeoutDecline", "DefaultApprove", + "InternalError", "IssuerStandIn"] class AuthorizationDTO(object): @@ -14,7 +16,8 @@ def __init__(self, id: str, created_at: datetime, amount: int, card_last_4_digit card_network: Optional[str], tags: Optional[Dict[str, str]], relationships: Optional[Dict[str, Relationship]], merchant_id: Optional[str], decline_reason: Optional[str], cash_withdrawal_amount: Optional[int], summary: Optional[str], - currency_conversion: Optional[CurrencyConversion], rich_merchant_data: Optional[RichMerchantData] + currency_conversion: Optional[CurrencyConversion], rich_merchant_data: Optional[RichMerchantData], + card_decision_source: Optional[CardDecisionSource] = None ): self.id = id self.type = "authorization" @@ -26,7 +29,7 @@ def __init__(self, id: str, created_at: datetime, amount: int, card_last_4_digit "cardVerificationData": card_verification_data, "cardNetwork": card_network, "tags": tags, "declineReason": decline_reason, "cashWithdrawalAmount": cash_withdrawal_amount, "summary": summary, "currencyConversion": currency_conversion, - "richMerchantData": rich_merchant_data} + "richMerchantData": rich_merchant_data, "cardDecisionSource": card_decision_source} self.relationships = relationships @staticmethod @@ -41,7 +44,8 @@ def from_json_api(_id, _type, attributes, relationships): attributes.get("declineReason"), attributes.get("cashWithdrawalAmount"), attributes.get("summary"), CurrencyConversion.from_json_api(attributes.get("currencyConversion")), - RichMerchantData.from_json_api(attributes.get("richMerchantData")) + RichMerchantData.from_json_api(attributes.get("richMerchantData")), + attributes.get("cardDecisionSource") ) diff --git a/unit/models/authorization_request.py b/unit/models/authorization_request.py index 1ca6a08..092cf4f 100644 --- a/unit/models/authorization_request.py +++ b/unit/models/authorization_request.py @@ -8,6 +8,7 @@ from unit.utils import date_utils PurchaseAuthorizationRequestStatus = Literal["Pending", "Approved", "Declined"] +AuthorizationRequestOutcome = Literal["Approved", "Declined", "PostTimeout", "PostError", "WaitTimeout"] DeclineReason = Literal["AccountClosed", "CardExceedsAmountLimit", "DoNotHonor", "InsufficientFunds", "InvalidMerchant", "ReferToCardIssuer", "RestrictedCard", "Timeout", "TransactionNotPermittedToCardholder"] @@ -19,6 +20,7 @@ def __init__(self, id: str, type: str, attributes: Dict[str, object], self.type = type self.attributes = {"createdAt": date_utils.to_datetime(attributes["createdAt"]), "amount": attributes["amount"], "status": attributes["status"], + "outcome": attributes.get("outcome"), "partialApprovalAllowed": attributes.get("partialApprovalAllowed"), "approvedAmount": attributes.get("approvedAmount"), "declineReason": attributes.get("declineReason"), diff --git a/unit/models/transaction.py b/unit/models/transaction.py index 8977e37..6cfe704 100644 --- a/unit/models/transaction.py +++ b/unit/models/transaction.py @@ -135,7 +135,7 @@ def __init__(self, id: str, created_at: datetime, direction: str, amount: int, b card_network: Optional[str], tags: Optional[Dict[str, str]], relationships: Optional[Dict[str, Relationship]], gross_interchange: Optional[str], cash_withdrawal_amount: Optional[int], currency_conversion: Optional[CurrencyConversion], - rich_merchant_data: Optional[RichMerchantData]): + rich_merchant_data: Optional[RichMerchantData], card_decision_source: Optional[str] = None): BaseTransactionDTO.__init__(self, id, created_at, direction, amount, balance, summary, tags, relationships) self.type = 'purchaseTransaction' self.attributes["cardLast4Digits"] = card_last_4_digits @@ -153,6 +153,7 @@ def __init__(self, id: str, created_at: datetime, direction: str, amount: int, b self.attributes["cashWithdrawalAmount"] = cash_withdrawal_amount self.attributes["currencyConversion"] = currency_conversion self.attributes["richMerchantData"] = rich_merchant_data + self.attributes["cardDecisionSource"] = card_decision_source @staticmethod def from_json_api(_id, _type, attributes, relationships): @@ -165,7 +166,7 @@ def from_json_api(_id, _type, attributes, relationships): attributes.get("cardVerificationData"), attributes.get("cardNetwork"), attributes.get("tags"), relationships, attributes.get("grossInterchange"), attributes.get("cashWithdrawalAmount"), CurrencyConversion.from_json_api(attributes.get("currencyConversion")), - RichMerchantData.from_json_api(attributes.get("richMerchantData"))) + RichMerchantData.from_json_api(attributes.get("richMerchantData")), attributes.get("cardDecisionSource")) class AtmTransactionDTO(BaseTransactionDTO): @@ -173,7 +174,8 @@ def __init__(self, id: str, created_at: datetime, direction: str, amount: int, b summary: str, card_last_4_digits: str, atm_name: str, atm_location: Optional[str], surcharge: int, interchange: Optional[int], card_network: Optional[str], tags: Optional[Dict[str, str]], relationships: Optional[Dict[str, Relationship]], - gross_interchange: Optional[str], currency_conversion: Optional[CurrencyConversion]): + gross_interchange: Optional[str], currency_conversion: Optional[CurrencyConversion], + card_decision_source: Optional[str] = None): BaseTransactionDTO.__init__(self, id, created_at, direction, amount, balance, summary, tags, relationships) self.type = 'atmTransaction' self.attributes["cardLast4Digits"] = card_last_4_digits @@ -184,6 +186,7 @@ def __init__(self, id: str, created_at: datetime, direction: str, amount: int, b self.attributes["cardNetwork"] = card_network self.attributes["grossInterchange"] = gross_interchange self.attributes["currencyConversion"] = currency_conversion + self.attributes["cardDecisionSource"] = card_decision_source @staticmethod def from_json_api(_id, _type, attributes, relationships): @@ -192,7 +195,8 @@ def from_json_api(_id, _type, attributes, relationships): attributes["cardLast4Digits"], attributes["atmName"], attributes.get("atmLocation"), attributes["surcharge"], attributes.get("interchange"), attributes.get("cardNetwork"), attributes.get("tags"), relationships, attributes.get("grossInterchange"), - CurrencyConversion.from_json_api(attributes.get("currencyConversion"))) + CurrencyConversion.from_json_api(attributes.get("currencyConversion")), + attributes.get("cardDecisionSource")) class FeeTransactionDTO(BaseTransactionDTO): @@ -214,7 +218,8 @@ def __init__(self, id: str, created_at: datetime, direction: str, amount: int, b interchange: Optional[int], payment_method: Optional[str], digital_wallet: Optional[str], card_verification_data: Optional[Dict], card_network: Optional[str], tags: Optional[Dict[str, str]], relationships: Optional[Dict[str, Relationship]], gross_interchange: Optional[str], - currency_conversion: Optional[CurrencyConversion], rich_merchant_data: Optional[RichMerchantData]): + currency_conversion: Optional[CurrencyConversion], rich_merchant_data: Optional[RichMerchantData], + card_decision_source: Optional[str] = None): BaseTransactionDTO.__init__(self, id, created_at, direction, amount, balance, summary, tags, relationships) self.type = 'cardTransaction' self.attributes["cardLast4Digits"] = card_last_4_digits @@ -228,6 +233,7 @@ def __init__(self, id: str, created_at: datetime, direction: str, amount: int, b self.attributes["grossInterchange"] = gross_interchange self.attributes["currencyConversion"] = currency_conversion self.attributes["richMerchantData"] = rich_merchant_data + self.attributes["cardDecisionSource"] = card_decision_source @staticmethod def from_json_api(_id, _type, attributes, relationships): @@ -239,7 +245,8 @@ def from_json_api(_id, _type, attributes, relationships): attributes.get("cardVerificationData"), attributes.get("cardNetwork"), attributes.get("tags"), relationships, attributes.get("grossInterchange"), CurrencyConversion.from_json_api(attributes.get("currencyConversion")), - RichMerchantData.from_json_api(attributes.get("richMerchantData")) + RichMerchantData.from_json_api(attributes.get("richMerchantData")), + attributes.get("cardDecisionSource") )