-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a Callback object for easy callback parsing
As described in both #20, #21 and #22, it is annoying to parse the callbacks. This adds the callback object, which can be used to easily parse the callback, and also map the underlying transactions in Transaction objects.
- Loading branch information
1 parent
3f01848
commit 7086e76
Showing
9 changed files
with
335 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
from __future__ import absolute_import, unicode_literals | ||
|
||
from xml.etree import ElementTree | ||
|
||
from . import utils | ||
from .resource import Resource | ||
from .transaction import Transaction | ||
|
||
|
||
class Callback(Resource): | ||
def transactions(self, auth_type=''): | ||
""" | ||
List all of the transactions returned by the callback. | ||
:param auth_type: the authentication type you wish to filter. | ||
Defaults to empty string, which means no filter will be made. | ||
:rtype: List of :py:class:`altapay.Transaction` objects. | ||
""" | ||
data = self.__data__['transactions']['transaction'] | ||
|
||
if not isinstance(data, list): | ||
data = [data] | ||
|
||
transaction_set = data | ||
if auth_type: | ||
transaction_set = [ | ||
transaction for transaction in data | ||
if transaction['AuthType'] == auth_type | ||
] | ||
|
||
return [ | ||
Transaction(self.version, self.__header__, transaction) | ||
for transaction in transaction_set] | ||
|
||
@classmethod | ||
def from_xml_callback(cls, callback): | ||
""" | ||
Instantiate a :py:class:`altapay.Callback` object from an XML response. | ||
:rtype: :py:class:`altapay.Callback` instance. | ||
""" | ||
if not isinstance(callback, ElementTree.Element): | ||
callback = ElementTree.XML(callback) | ||
|
||
response = utils.etree_to_dict(callback)['APIResponse'] | ||
|
||
return cls( | ||
response['@version'], response['Header'], | ||
response['Body']) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
.. _api-callback: | ||
|
||
Callback | ||
======== | ||
|
||
.. py:module:: altapay | ||
.. autoclass:: Callback | ||
:show-inheritance: | ||
:members: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
.. _guide-callback-handling: | ||
|
||
Callback Handling | ||
================= | ||
|
||
To make it easy to parse callbacks received from AltaPay, the special :py:class:`altapay.Callback` class can be used. Note that when you receive callbacks from AltaPay, it comes as an HTTP POST. Within this is a field called :samp:`xml`, and this is the response you should use for the :py:class:`altapay.Callback` class. | ||
|
||
Given a callback response in the variable :samp:`xml`, this is how a callback instance can be instantiated: | ||
|
||
.. code :: python | ||
from altapay import Callback | ||
xml = '' # XML response here | ||
callback = Callback.from_xml_callback(xml) | ||
if callback.result == 'Success': | ||
for transaction in callback.transactions(): | ||
print(transaction) | ||
else: | ||
raise Exception('Callback not successful') | ||
:py:func:`altapay.Callback.transactions` will contain a list of :py:class:`altapay.Transaction` objects. Note that even if there is only one transaction in the callback, you will have a list of just one :py:class:`altapay.Transaction`. | ||
|
||
Using :py:func:`altapay.Callback.transactions` it is possible to filter based on a authentication type (this will depend on what you chose for the payment type). This can be useful if you have chosen to make a subscription and reservation in the same payment; in this case you can receive a callback with two transactions, and in some cases you might want to process a specific of them ahead of the other one. | ||
|
||
This example extends the usecase described above, and filters out the subscription portion of the payment: | ||
|
||
.. code :: python | ||
from altapay import Callback | ||
xml = '' # XML response here | ||
callback = Callback.from_xml_callback(xml) | ||
if callback.result == 'Success': | ||
transactions = callback.transactions(auth_type=subscription_payment) | ||
for transaction in transactions: | ||
# Will only show transactions of the authentication type | ||
# subscription_payment | ||
print(transaction) | ||
else: | ||
raise Exception('Callback not successful') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from __future__ import absolute_import, unicode_literals | ||
|
||
from xml.etree import ElementTree | ||
|
||
import responses | ||
from altapay import API, Callback, Transaction | ||
|
||
from .test_cases import TestCase | ||
|
||
|
||
class PaymentTest(TestCase): | ||
def setUp(self): | ||
self.api = API(mode='test', auto_login=False) | ||
self.response_as_str = self.load_xml_response( | ||
'200_callback_multiple.xml') | ||
self.response_as_etree = ElementTree.XML(self.response_as_str) | ||
self.response_single_as_str = self.load_xml_response( | ||
'200_callback_single.xml') | ||
|
||
@responses.activate | ||
def test_load_from_str(self): | ||
callback = Callback.from_xml_callback(self.response_as_str) | ||
|
||
self.assertEqual(callback.result, 'Success') | ||
|
||
def test_load_from_etree(self): | ||
callback = Callback.from_xml_callback(self.response_as_etree) | ||
|
||
self.assertEqual(callback.result, 'Success') | ||
|
||
def test_transaction_set(self): | ||
callback = Callback.from_xml_callback(self.response_as_etree) | ||
|
||
transactions = callback.transactions() | ||
|
||
self.assertEqual(len(transactions), 2) | ||
for transaction in transactions: | ||
self.assertIsInstance(transaction, Transaction) | ||
|
||
def test_transaction_set_filter(self): | ||
callback = Callback.from_xml_callback(self.response_as_etree) | ||
|
||
transactions = callback.transactions(auth_type='subscription_payment') | ||
|
||
self.assertEqual(len(transactions), 1) | ||
self.assertIsInstance(transactions[0], Transaction) | ||
|
||
def test_transaction_set_single(self): | ||
callback = Callback.from_xml_callback(self.response_single_as_str) | ||
|
||
transactions = callback.transactions() | ||
|
||
self.assertIsInstance(transactions, list) | ||
self.assertEqual(len(transactions), 1) | ||
self.assertIsInstance(transactions[0], Transaction) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
<?xml version="1.0"?> | ||
<APIResponse version="20151228"> | ||
<Header> | ||
<Date>2016-01-12T11:13:11+01:00</Date> | ||
<Path>API/reservationOfFixedAmount?pid=c80919f5-0b6d-4679-872a-980162e9cbf1</Path> | ||
<ErrorCode>0</ErrorCode> | ||
<ErrorMessage/> | ||
</Header> | ||
<Body> | ||
<Result>Success</Result> | ||
<CardHolderMessageMustBeShown>false</CardHolderMessageMustBeShown> | ||
<Transactions> | ||
<Transaction> | ||
<TransactionId>8140142</TransactionId> | ||
<PaymentId>d4a66206-881e-4d1c-b41a-55e27828ab70</PaymentId> | ||
<AuthType>subscriptionAndReserve</AuthType> | ||
<CardStatus>InvalidLuhn</CardStatus> | ||
<CreditCardExpiry> | ||
<Year>2016</Year> | ||
<Month>01</Month> | ||
</CreditCardExpiry> | ||
<CreditCardToken>e48a3bb37ab9e2aeb935b42a3c37d1dd42be768b</CreditCardToken> | ||
<CreditCardMaskedPan>500000******0000</CreditCardMaskedPan> | ||
<ThreeDSecureResult>Not_Attempted</ThreeDSecureResult> | ||
<LiableForChargeback>Merchant</LiableForChargeback> | ||
<CVVCheckResult>Not_Attempted</CVVCheckResult> | ||
<BlacklistToken>cf9d894c143b3448697726523d3fec4ab73d2da3</BlacklistToken> | ||
<ShopOrderId>8000011</ShopOrderId> | ||
<Shop>Test Shop</Shop> | ||
<Terminal>Test Terminal</Terminal> | ||
<TransactionStatus>recurring_confirmed</TransactionStatus> | ||
<ReasonCode>NONE</ReasonCode> | ||
<MerchantCurrency>208</MerchantCurrency> | ||
<MerchantCurrencyAlpha>DKK</MerchantCurrencyAlpha> | ||
<CardHolderCurrency>208</CardHolderCurrency> | ||
<CardHolderCurrencyAlpha>DKK</CardHolderCurrencyAlpha> | ||
<ReservedAmount>13.29</ReservedAmount> | ||
<CapturedAmount>0.00</CapturedAmount> | ||
<RefundedAmount>0.00</RefundedAmount> | ||
<CreditedAmount>0.00</CreditedAmount> | ||
<RecurringDefaultAmount>13.29</RecurringDefaultAmount> | ||
<SurchargeAmount>0.00</SurchargeAmount> | ||
<CreatedDate>2016-01-12 11:13:10</CreatedDate> | ||
<UpdatedDate>2016-01-12 11:13:11</UpdatedDate> | ||
<PaymentNature>CreditCard</PaymentNature> | ||
<PaymentSchemeName>Maestro</PaymentSchemeName> | ||
<PaymentNatureService name="SoapTestAcquirer"> | ||
<SupportsRefunds>true</SupportsRefunds> | ||
<SupportsRelease>true</SupportsRelease> | ||
<SupportsMultipleCaptures>true</SupportsMultipleCaptures> | ||
<SupportsMultipleRefunds>true</SupportsMultipleRefunds> | ||
</PaymentNatureService> | ||
<AddressVerification>L</AddressVerification> | ||
<AddressVerificationDescription>Invalid address verification response code</AddressVerificationDescription> | ||
<ChargebackEvents/> | ||
<PaymentInfos> | ||
<PaymentInfo name="0"><![CDATA[COOL]]></PaymentInfo> | ||
</PaymentInfos> | ||
<ReconciliationIdentifiers/> | ||
</Transaction> | ||
<Transaction> | ||
<TransactionId>8140152</TransactionId> | ||
<PaymentId>d851583c-bdbd-489b-a237-bc153916028c</PaymentId> | ||
<AuthType>subscription_payment</AuthType> | ||
<CardStatus>InvalidLuhn</CardStatus> | ||
<CreditCardExpiry> | ||
<Year>2016</Year> | ||
<Month>01</Month> | ||
</CreditCardExpiry> | ||
<CreditCardToken>e48a3bb37ab9e2aeb935b42a3c37d1dd42be768b</CreditCardToken> | ||
<CreditCardMaskedPan>500000******0000</CreditCardMaskedPan> | ||
<ThreeDSecureResult>Not_Applicable</ThreeDSecureResult> | ||
<LiableForChargeback>Merchant</LiableForChargeback> | ||
<CVVCheckResult>Not_Applicable</CVVCheckResult> | ||
<BlacklistToken>cf9d894c143b3448697726523d3fec4ab73d2da3</BlacklistToken> | ||
<ShopOrderId>8000011</ShopOrderId> | ||
<Shop>Test Shop</Shop> | ||
<Terminal>Test Terminal</Terminal> | ||
<TransactionStatus>preauth</TransactionStatus> | ||
<ReasonCode>NONE</ReasonCode> | ||
<MerchantCurrency>208</MerchantCurrency> | ||
<MerchantCurrencyAlpha>DKK</MerchantCurrencyAlpha> | ||
<CardHolderCurrency>208</CardHolderCurrency> | ||
<CardHolderCurrencyAlpha>DKK</CardHolderCurrencyAlpha> | ||
<ReservedAmount>13.29</ReservedAmount> | ||
<CapturedAmount>0.00</CapturedAmount> | ||
<RefundedAmount>0.00</RefundedAmount> | ||
<CreditedAmount>0.00</CreditedAmount> | ||
<RecurringDefaultAmount>0.00</RecurringDefaultAmount> | ||
<SurchargeAmount>0.00</SurchargeAmount> | ||
<CreatedDate>2016-01-12 11:13:11</CreatedDate> | ||
<UpdatedDate>2016-01-12 11:13:11</UpdatedDate> | ||
<PaymentNature>CreditCard</PaymentNature> | ||
<PaymentSchemeName>Maestro</PaymentSchemeName> | ||
<PaymentNatureService name="SoapTestAcquirer"> | ||
<SupportsRefunds>true</SupportsRefunds> | ||
<SupportsRelease>true</SupportsRelease> | ||
<SupportsMultipleCaptures>true</SupportsMultipleCaptures> | ||
<SupportsMultipleRefunds>true</SupportsMultipleRefunds> | ||
</PaymentNatureService> | ||
<AddressVerification>L</AddressVerification> | ||
<AddressVerificationDescription>Invalid address verification response code</AddressVerificationDescription> | ||
<ChargebackEvents/> | ||
<PaymentInfos/> | ||
<ReconciliationIdentifiers/> | ||
</Transaction> | ||
</Transactions> | ||
</Body> | ||
</APIResponse> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?xml version="1.0"?> | ||
<APIResponse version="20151228"> | ||
<Header> | ||
<Date>2016-01-12T11:13:11+01:00</Date> | ||
<Path>API/reservationOfFixedAmount?pid=c80919f5-0b6d-4679-872a-980162e9cbf1</Path> | ||
<ErrorCode>0</ErrorCode> | ||
<ErrorMessage/> | ||
</Header> | ||
<Body> | ||
<Result>Success</Result> | ||
<CardHolderMessageMustBeShown>false</CardHolderMessageMustBeShown> | ||
<Transactions> | ||
<Transaction> | ||
<TransactionId>8140152</TransactionId> | ||
<PaymentId>d851583c-bdbd-489b-a237-bc153916028c</PaymentId> | ||
<AuthType>subscription_payment</AuthType> | ||
<CardStatus>InvalidLuhn</CardStatus> | ||
<CreditCardExpiry> | ||
<Year>2016</Year> | ||
<Month>01</Month> | ||
</CreditCardExpiry> | ||
<CreditCardToken>e48a3bb37ab9e2aeb935b42a3c37d1dd42be768b</CreditCardToken> | ||
<CreditCardMaskedPan>500000******0000</CreditCardMaskedPan> | ||
<ThreeDSecureResult>Not_Applicable</ThreeDSecureResult> | ||
<LiableForChargeback>Merchant</LiableForChargeback> | ||
<CVVCheckResult>Not_Applicable</CVVCheckResult> | ||
<BlacklistToken>cf9d894c143b3448697726523d3fec4ab73d2da3</BlacklistToken> | ||
<ShopOrderId>8000011</ShopOrderId> | ||
<Shop>Test Shop</Shop> | ||
<Terminal>Test Terminal</Terminal> | ||
<TransactionStatus>preauth</TransactionStatus> | ||
<ReasonCode>NONE</ReasonCode> | ||
<MerchantCurrency>208</MerchantCurrency> | ||
<MerchantCurrencyAlpha>DKK</MerchantCurrencyAlpha> | ||
<CardHolderCurrency>208</CardHolderCurrency> | ||
<CardHolderCurrencyAlpha>DKK</CardHolderCurrencyAlpha> | ||
<ReservedAmount>13.29</ReservedAmount> | ||
<CapturedAmount>0.00</CapturedAmount> | ||
<RefundedAmount>0.00</RefundedAmount> | ||
<CreditedAmount>0.00</CreditedAmount> | ||
<RecurringDefaultAmount>0.00</RecurringDefaultAmount> | ||
<SurchargeAmount>0.00</SurchargeAmount> | ||
<CreatedDate>2016-01-12 11:13:11</CreatedDate> | ||
<UpdatedDate>2016-01-12 11:13:11</UpdatedDate> | ||
<PaymentNature>CreditCard</PaymentNature> | ||
<PaymentSchemeName>Maestro</PaymentSchemeName> | ||
<PaymentNatureService name="SoapTestAcquirer"> | ||
<SupportsRefunds>true</SupportsRefunds> | ||
<SupportsRelease>true</SupportsRelease> | ||
<SupportsMultipleCaptures>true</SupportsMultipleCaptures> | ||
<SupportsMultipleRefunds>true</SupportsMultipleRefunds> | ||
</PaymentNatureService> | ||
<AddressVerification>L</AddressVerification> | ||
<AddressVerificationDescription>Invalid address verification response code</AddressVerificationDescription> | ||
<ChargebackEvents/> | ||
<PaymentInfos/> | ||
<ReconciliationIdentifiers/> | ||
</Transaction> | ||
</Transactions> | ||
</Body> | ||
</APIResponse> |