GetPaid authorize.net payment processor functionality
Project description
This package provides authorizedotnet payment processor functionality for the getpaid framework.
=======
CHANGES
=======
0.6.1 (2011-06-21)
------------------
- Fix to use the correct getSite in Zope 2.10.
[davisagli]
0.6.0 (2011-06-15)
------------------
- Record the response received from authorize.net on an annotation on the
order, for debugging purposes.
[davisagli]
- Add option to enable setting the x_test_request flag when one of the known
test credit card numbers is used. This makes it possible to test the
integration even if the processor is using the production server.
[davisagli]
- Patch zc.authorizedotnet to make sure that the correct root certificates
are checked.
[davisagli]
0.5.1 (2011-05-18)
------------------
- Send the credit card CVC code to authorize.net.
[davisagli]
- Provide additional root certificates needed to validate the SSL certificate
used by api.authorize.net
[davisagli]
0.5.0 (2010-05-18)
------------------
- Added support for Authorize.net's Automated Recurring Billing (API)
for managing subscription-based payments.
[davisagli]
- Added tests.
[davisagli]
0.4.0 (2010-04-07)
------------------
- Use zope.annotation instead of zope.app.annotation
[davisagli]
0.3.3 (2009-08-19)
------------------
- Record the transaction id returned by authorize.net
0.3.2 (2009-07-22)
------------------
- Handle expiration date as a string.
0.3.1 (2009-03-13)
------------------
- added M2Crypto in the setup.py dependencies [lucielejard]
0.3 (2008-08-29)
----------------
- Added buildout files and general text documents to project root.
- Removed setup.cfg
0.2 (2008-08-21)
----------------
- Eggified package
Detailed Documentation
**********************
GetPaid Authorize.Net Payment Processor
=======================================
The AuthorizeNetAdapter is an implementation of a GetPaid payment processor
that can process payments via the Authorize.net APIs.
Test Setup
----------
In order to use the AuthorizeNetAdapter, we first need a context that can be
adapted to IAuthorizeNetOptions to get the keys for accessing the Authorize.net
API. (LOGIN and KEY are initialized in tests.py based on environment variables.
Use the login Authorize.net)
>>> from zope.interface import implements
>>> from getpaid.authorizedotnet.interfaces import IAuthorizeNetOptions
>>> class DummyAuthContext(object):
... implements(IAuthorizeNetOptions)
... server_url = 'Test'
... merchant_id = LOGIN
... merchant_key = KEY
We also need an order that we want to process payments for.
>>> import time
>>> from getpaid.core import order, item, cart, options, interfaces, payment
>>> my_cart = cart.ShoppingCart()
>>> my_cart['abc'] = abc = item.LineItem()
>>> abc.cost = 22.20; abc.name = 'abc'; abc.quantity = 3
>>> order = order.Order()
>>> order.setOrderId('test%s' % int(time.time()))
>>> order.shopping_cart = my_cart
>>> order.contact_information = contact = payment.ContactInformation()
>>> contact.name = 'Harvey Frank'
>>> contact.phone_number = '2062681235'
>>> contact.email = 'harvey@example.com'
>>> order.billing_address = billing = payment.BillingAddress()
>>> billing.bill_first_line = '1402 3rd Ave.'
>>> billing.bill_city = 'Seattle'
>>> billing.bill_state = 'WA'
>>> billing.bill_postal_code = '98101'
And a property bag with details about the payment.
>>> from datetime import datetime, timedelta
>>> BillingInfo = options.PropertyBag.makeclass(interfaces.IUserPaymentInformation)
>>> payment = BillingInfo(
... name_on_card = 'Harvey Frank',
... bill_phone_number = '2062861235',
... credit_card_type = 'Visa',
... credit_card = '4007000000027',
... cc_expiration = datetime.now() + timedelta(365),
... cc_cvc = '111',
... )
Authorizing an Order
--------------------
Authorization confirms that an order may be processed using the given billing
information.
>>> from getpaid.authorizedotnet.authorizenet import AuthorizeNetAdapter
>>> authnet = AuthorizeNetAdapter(DummyAuthContext())
>>> authnet.authorize(order, payment) == interfaces.keys.results_success
True
Capturing/Charging an Order
---------------------------
Capturing an order tells Authorize.net to queue payment for settlement. (Actual
settlement happens in a daily batch process.)
>>> authnet.capture(order, order.getTotalPrice()) == interfaces.keys.results_success
True
Refunding an Order
------------------
Refunding an order tells Authorize.net to return the payment to the customer.
Refunds cannot be issued until the original payment has been captured and settled,
so we don't expect this to succeed in the test.
>>> authnet.refund(order, order.getTotalPrice())
'The referenced transaction does not meet the criteria for issuing a credit.'
Voiding an Order
----------------
Orders with recurring line items
--------------------------------
If an order whose cart contains a recurring line item is authorized, it will
result in the creation of a subscription-based payment using Authorize.net's
Automated Recurring Billing (ARB) API. The subscriptionId will be recorded
on the order as its transaction ID.
Note that the creation of the subscription happens during the call to
``authorize``, not ``capture``, because it needs access to the billing
information which is passed to ``authorize`` but not ``capture``.
>>> import copy
>>> from zope.annotation.interfaces import IAnnotations
>>> order2 = copy.deepcopy(order)
>>> cart2 = cart.ShoppingCart()
>>> cart2['abc'] = abc = item.RecurringLineItem()
>>> abc.cost = 22.20; abc.name = 'abc'; abc.quantity = 1
>>> abc.interval = 1; abc.total_occurrences = 3; abc.unit = 'months'
>>> order2.shopping_cart = cart2
>>> order2._order_id = 'recur%s' % int(time.time())
>>> authnet.authorize(order2, payment) == interfaces.keys.results_success
True
>>> subscriptionId = IAnnotations(order2)[interfaces.keys.processor_txn_id]
>>> subscriptionId is not None
True
In the case of a recurring order ``capture`` is basically a no-op, but still
needs to succeed, because it will get called by the order workflow.
>>> authnet.capture(order2, order2.getTotalPrice()) == interfaces.keys.results_success
True
Orders with multiple recurring line items, or with a mixture of recurring and
non-recurring line items, are not currently supported.
A recurring order will first be authorized using the standard AIM API,
to make sure that valid CC info was provided.
>>> payment2 = copy.deepcopy(payment)
>>> payment2.credit_card = '1111111111111'
>>> authnet.authorize(order2, payment2)
'The credit card number is invalid.'
Canceling a recurring payment subscription
------------------------------------------
If an order has a subscriptionId, its subscription can be canceled.
>>> authnet.cancel_subscription(order2) == interfaces.keys.results_success
True
Authorize.Net ARB Integration
=============================
The ARBProcessor provides support for Authorize.net's Automated Recurring
Billing (ARB) API, which makes it possible to manage subscription-based
payments via an XML API.
See http://www.authorize.net/support/ARB_guide.pdf for API documentation
including prerequisites for using ARB, and details of what parameters may
be specified.
Transaction Keys
----------------
Each ARB transaction must be accompanied by a merchant login and a
"transaction key". This key is obtained from the merchant interface. After
importing the ARBProcessor class you must pass it your login and transaction
key:
>>> from getpaid.authorizedotnet.subscription import ARBProcessor
>>> arb = ARBProcessor(server=SERVER_NAME, login=LOGIN, key=KEY)
Creating a subscription
-----------------------
To create a new subscription, use the ``create`` method.
>>> from time import gmtime, strftime
>>> today = strftime("%Y-%m-%d", gmtime())
>>> exp_date = strftime("%Y-%m", gmtime())
>>> import random
>>> amount = '%.2f' % random.uniform(0,100)
>>> result = arb.create(refId = '1234',
... subscription = {
... 'name': '1234',
... 'paymentSchedule': {
... 'interval': {
... 'length': 1,
... 'unit': 'months', },
... 'startDate': today,
... 'totalOccurrences': 12,
... 'trialOccurrences': 0, },
... 'amount': amount,
... 'trialAmount': '0',
... 'payment': {
... 'creditCard': {
... 'cardNumber': '4007000000027',
... 'expirationDate': exp_date,
... 'cardCode': '111', },
... },
... 'billTo': {
... 'firstName': 'Harvey',
... 'lastName': 'Frank', },
... },
... )
It returns a dictionary which contains details about the transaction.
>>> result['refId']
'1234'
>>> result['messages']['resultCode']
'Ok'
>>> result['messages']['message']['code']
'123456'
>>> result['messages']['message']['text']
'Successful.'
>>> subscriptionId = result['subscriptionId']
>>> subscriptionId
'123456'
Updating a subscription
-----------------------
To update an existing subscription, use the ``update`` method. This accepts
the same parameters as ``create``, but all are optional except for the
subscriptionId.
>>> result = arb.update(subscriptionId = subscriptionId,
... subscription = {
... 'paymentSchedule': {
... 'totalOccurrences': 6, },
... },
... )
>>> result['messages']['resultCode']
'Ok'
Trying to update a non-existent subscription results in an error code.
>>> result = arb.update(subscriptionId = '1',
... subscription = {
... 'paymentSchedule': {
... 'totalOccurrences': 6, },
... },
... )
>>> result['messages']['resultCode']
'Error'
>>> result['messages']['message']['text']
'The subscription cannot be found.'
Canceling a subscription
------------------------
To cancel an existing subscription, use the ``cancel`` method.
>>> result = arb.cancel(subscriptionId = subscriptionId)
>>> result['messages']['resultCode']
'Ok'
Trying to cancel a non-existent subscription results in an error code.
>>> result = arb.cancel(subscriptionId = '1')
>>> result['messages']['resultCode']
'Error'
>>> result['messages']['message']['text']
'The subscription cannot be found.'
=======
CHANGES
=======
0.6.1 (2011-06-21)
------------------
- Fix to use the correct getSite in Zope 2.10.
[davisagli]
0.6.0 (2011-06-15)
------------------
- Record the response received from authorize.net on an annotation on the
order, for debugging purposes.
[davisagli]
- Add option to enable setting the x_test_request flag when one of the known
test credit card numbers is used. This makes it possible to test the
integration even if the processor is using the production server.
[davisagli]
- Patch zc.authorizedotnet to make sure that the correct root certificates
are checked.
[davisagli]
0.5.1 (2011-05-18)
------------------
- Send the credit card CVC code to authorize.net.
[davisagli]
- Provide additional root certificates needed to validate the SSL certificate
used by api.authorize.net
[davisagli]
0.5.0 (2010-05-18)
------------------
- Added support for Authorize.net's Automated Recurring Billing (API)
for managing subscription-based payments.
[davisagli]
- Added tests.
[davisagli]
0.4.0 (2010-04-07)
------------------
- Use zope.annotation instead of zope.app.annotation
[davisagli]
0.3.3 (2009-08-19)
------------------
- Record the transaction id returned by authorize.net
0.3.2 (2009-07-22)
------------------
- Handle expiration date as a string.
0.3.1 (2009-03-13)
------------------
- added M2Crypto in the setup.py dependencies [lucielejard]
0.3 (2008-08-29)
----------------
- Added buildout files and general text documents to project root.
- Removed setup.cfg
0.2 (2008-08-21)
----------------
- Eggified package
Detailed Documentation
**********************
GetPaid Authorize.Net Payment Processor
=======================================
The AuthorizeNetAdapter is an implementation of a GetPaid payment processor
that can process payments via the Authorize.net APIs.
Test Setup
----------
In order to use the AuthorizeNetAdapter, we first need a context that can be
adapted to IAuthorizeNetOptions to get the keys for accessing the Authorize.net
API. (LOGIN and KEY are initialized in tests.py based on environment variables.
Use the login Authorize.net)
>>> from zope.interface import implements
>>> from getpaid.authorizedotnet.interfaces import IAuthorizeNetOptions
>>> class DummyAuthContext(object):
... implements(IAuthorizeNetOptions)
... server_url = 'Test'
... merchant_id = LOGIN
... merchant_key = KEY
We also need an order that we want to process payments for.
>>> import time
>>> from getpaid.core import order, item, cart, options, interfaces, payment
>>> my_cart = cart.ShoppingCart()
>>> my_cart['abc'] = abc = item.LineItem()
>>> abc.cost = 22.20; abc.name = 'abc'; abc.quantity = 3
>>> order = order.Order()
>>> order.setOrderId('test%s' % int(time.time()))
>>> order.shopping_cart = my_cart
>>> order.contact_information = contact = payment.ContactInformation()
>>> contact.name = 'Harvey Frank'
>>> contact.phone_number = '2062681235'
>>> contact.email = 'harvey@example.com'
>>> order.billing_address = billing = payment.BillingAddress()
>>> billing.bill_first_line = '1402 3rd Ave.'
>>> billing.bill_city = 'Seattle'
>>> billing.bill_state = 'WA'
>>> billing.bill_postal_code = '98101'
And a property bag with details about the payment.
>>> from datetime import datetime, timedelta
>>> BillingInfo = options.PropertyBag.makeclass(interfaces.IUserPaymentInformation)
>>> payment = BillingInfo(
... name_on_card = 'Harvey Frank',
... bill_phone_number = '2062861235',
... credit_card_type = 'Visa',
... credit_card = '4007000000027',
... cc_expiration = datetime.now() + timedelta(365),
... cc_cvc = '111',
... )
Authorizing an Order
--------------------
Authorization confirms that an order may be processed using the given billing
information.
>>> from getpaid.authorizedotnet.authorizenet import AuthorizeNetAdapter
>>> authnet = AuthorizeNetAdapter(DummyAuthContext())
>>> authnet.authorize(order, payment) == interfaces.keys.results_success
True
Capturing/Charging an Order
---------------------------
Capturing an order tells Authorize.net to queue payment for settlement. (Actual
settlement happens in a daily batch process.)
>>> authnet.capture(order, order.getTotalPrice()) == interfaces.keys.results_success
True
Refunding an Order
------------------
Refunding an order tells Authorize.net to return the payment to the customer.
Refunds cannot be issued until the original payment has been captured and settled,
so we don't expect this to succeed in the test.
>>> authnet.refund(order, order.getTotalPrice())
'The referenced transaction does not meet the criteria for issuing a credit.'
Voiding an Order
----------------
Orders with recurring line items
--------------------------------
If an order whose cart contains a recurring line item is authorized, it will
result in the creation of a subscription-based payment using Authorize.net's
Automated Recurring Billing (ARB) API. The subscriptionId will be recorded
on the order as its transaction ID.
Note that the creation of the subscription happens during the call to
``authorize``, not ``capture``, because it needs access to the billing
information which is passed to ``authorize`` but not ``capture``.
>>> import copy
>>> from zope.annotation.interfaces import IAnnotations
>>> order2 = copy.deepcopy(order)
>>> cart2 = cart.ShoppingCart()
>>> cart2['abc'] = abc = item.RecurringLineItem()
>>> abc.cost = 22.20; abc.name = 'abc'; abc.quantity = 1
>>> abc.interval = 1; abc.total_occurrences = 3; abc.unit = 'months'
>>> order2.shopping_cart = cart2
>>> order2._order_id = 'recur%s' % int(time.time())
>>> authnet.authorize(order2, payment) == interfaces.keys.results_success
True
>>> subscriptionId = IAnnotations(order2)[interfaces.keys.processor_txn_id]
>>> subscriptionId is not None
True
In the case of a recurring order ``capture`` is basically a no-op, but still
needs to succeed, because it will get called by the order workflow.
>>> authnet.capture(order2, order2.getTotalPrice()) == interfaces.keys.results_success
True
Orders with multiple recurring line items, or with a mixture of recurring and
non-recurring line items, are not currently supported.
A recurring order will first be authorized using the standard AIM API,
to make sure that valid CC info was provided.
>>> payment2 = copy.deepcopy(payment)
>>> payment2.credit_card = '1111111111111'
>>> authnet.authorize(order2, payment2)
'The credit card number is invalid.'
Canceling a recurring payment subscription
------------------------------------------
If an order has a subscriptionId, its subscription can be canceled.
>>> authnet.cancel_subscription(order2) == interfaces.keys.results_success
True
Authorize.Net ARB Integration
=============================
The ARBProcessor provides support for Authorize.net's Automated Recurring
Billing (ARB) API, which makes it possible to manage subscription-based
payments via an XML API.
See http://www.authorize.net/support/ARB_guide.pdf for API documentation
including prerequisites for using ARB, and details of what parameters may
be specified.
Transaction Keys
----------------
Each ARB transaction must be accompanied by a merchant login and a
"transaction key". This key is obtained from the merchant interface. After
importing the ARBProcessor class you must pass it your login and transaction
key:
>>> from getpaid.authorizedotnet.subscription import ARBProcessor
>>> arb = ARBProcessor(server=SERVER_NAME, login=LOGIN, key=KEY)
Creating a subscription
-----------------------
To create a new subscription, use the ``create`` method.
>>> from time import gmtime, strftime
>>> today = strftime("%Y-%m-%d", gmtime())
>>> exp_date = strftime("%Y-%m", gmtime())
>>> import random
>>> amount = '%.2f' % random.uniform(0,100)
>>> result = arb.create(refId = '1234',
... subscription = {
... 'name': '1234',
... 'paymentSchedule': {
... 'interval': {
... 'length': 1,
... 'unit': 'months', },
... 'startDate': today,
... 'totalOccurrences': 12,
... 'trialOccurrences': 0, },
... 'amount': amount,
... 'trialAmount': '0',
... 'payment': {
... 'creditCard': {
... 'cardNumber': '4007000000027',
... 'expirationDate': exp_date,
... 'cardCode': '111', },
... },
... 'billTo': {
... 'firstName': 'Harvey',
... 'lastName': 'Frank', },
... },
... )
It returns a dictionary which contains details about the transaction.
>>> result['refId']
'1234'
>>> result['messages']['resultCode']
'Ok'
>>> result['messages']['message']['code']
'123456'
>>> result['messages']['message']['text']
'Successful.'
>>> subscriptionId = result['subscriptionId']
>>> subscriptionId
'123456'
Updating a subscription
-----------------------
To update an existing subscription, use the ``update`` method. This accepts
the same parameters as ``create``, but all are optional except for the
subscriptionId.
>>> result = arb.update(subscriptionId = subscriptionId,
... subscription = {
... 'paymentSchedule': {
... 'totalOccurrences': 6, },
... },
... )
>>> result['messages']['resultCode']
'Ok'
Trying to update a non-existent subscription results in an error code.
>>> result = arb.update(subscriptionId = '1',
... subscription = {
... 'paymentSchedule': {
... 'totalOccurrences': 6, },
... },
... )
>>> result['messages']['resultCode']
'Error'
>>> result['messages']['message']['text']
'The subscription cannot be found.'
Canceling a subscription
------------------------
To cancel an existing subscription, use the ``cancel`` method.
>>> result = arb.cancel(subscriptionId = subscriptionId)
>>> result['messages']['resultCode']
'Ok'
Trying to cancel a non-existent subscription results in an error code.
>>> result = arb.cancel(subscriptionId = '1')
>>> result['messages']['resultCode']
'Error'
>>> result['messages']['message']['text']
'The subscription cannot be found.'
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
getpaid.authorizedotnet-0.6.1.zip
(32.4 kB
view hashes)
Close
Hashes for getpaid.authorizedotnet-0.6.1.zip
Algorithm | Hash digest | |
---|---|---|
SHA256 | b91aca885518668cbc55580ee3bcdfe1dd27c33a37fcd951c34264a3bddad73a |
|
MD5 | aa22a81352654874093fbb0350db12bb |
|
BLAKE2b-256 | 41c3631bc85cd1b7e9d52ffaa87b9ca7ce1d39fc95658cc3a5b3173b794e4101 |