From d89b6367ec5abaee397d94d85060173e9e3b30e3 Mon Sep 17 00:00:00 2001 From: Vincent Catalano Date: Sun, 6 Apr 2014 22:29:49 -0700 Subject: [PATCH] Issue 19: Adding x_customer_ip field for CIM and AIM transactions --- README.rst | 2 +- authorize/__init__.py | 12 ++++++++++++ authorize/apis/transaction_api.py | 16 ++++++++++++++++ authorize/schemas.py | 10 +++++++--- authorize/xml_data.py | 2 +- docs/transaction.rst | 14 +++++++++++++- tests/test_live_transaction.py | 9 +++++++++ tests/test_transaction_api.py | 9 +++++++++ 8 files changed, 68 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index be69438..06c92f2 100644 --- a/README.rst +++ b/README.rst @@ -43,7 +43,7 @@ Here is a simple example of a basic credit card transaction. Documentation ------------- -Please visit the `Github Page`_ page for full documentation. +Please visit the `Github Page`_ for full documentation. .. _Github Page: http://vcatalano.github.io/py-authorize/index.html diff --git a/authorize/__init__.py b/authorize/__init__.py index fd3c489..525e3c4 100644 --- a/authorize/__init__.py +++ b/authorize/__init__.py @@ -1,3 +1,5 @@ +import xml.etree.ElementTree as E + from authorize.configuration import Configuration from authorize.address import Address from authorize.bank_account import BankAccount @@ -11,3 +13,13 @@ from authorize.exceptions import AuthorizeInvalidError from authorize.recurring import Recurring from authorize.transaction import Transaction + + +# Monkeypatch the ElementTree module so that we can use CDATA element types +E._original_serialize_xml = E._serialize_xml +def _serialize_xml(write, elem, *args): + if elem.tag == '![CDATA[': + write('' % elem.text) + return + return E._original_serialize_xml(write, elem, *args) +E._serialize_xml = E._serialize['xml'] = _serialize_xml \ No newline at end of file diff --git a/authorize/apis/transaction_api.py b/authorize/apis/transaction_api.py index 9d66a48..b577adb 100644 --- a/authorize/apis/transaction_api.py +++ b/authorize/apis/transaction_api.py @@ -1,5 +1,10 @@ import xml.etree.cElementTree as E +try: + import urllib.parse as urllib +except: + import urllib + from authorize.apis.base_api import BaseAPI from authorize.schemas import AIMTransactionSchema from authorize.schemas import CIMTransactionSchema @@ -88,6 +93,13 @@ def _cim_base_request(self, xact_type, xact={}): if 'recurring' in xact: E.SubElement(xact_type, 'recurringBilling').text = str(xact['recurring']).lower() + if 'extra_options' in xact: + extra_options = {} + if 'customer_ip' in xact['extra_options']: + extra_options['x_customer_ip'] = xact['extra_options']['customer_ip'] + options = E.SubElement(request, 'extraOptions') + E.SubElement(options, '![CDATA[').text = urllib.urlencode(extra_options) + return request def _aim_base_request(self, xact_type, xact={}): @@ -131,6 +143,10 @@ def _aim_base_request(self, xact_type, xact={}): if 'shipping' in xact: xact_elem.append(create_address('shipTo', xact['shipping'])) + if 'extra_options' in xact: + if 'customer_ip' in xact['extra_options']: + E.SubElement(xact_elem, 'customerIP').text = xact['extra_options']['customer_ip'] + return request def _settle_request(self, transaction_id): diff --git a/authorize/schemas.py b/authorize/schemas.py index 41e2393..faa8c76 100644 --- a/authorize/schemas.py +++ b/authorize/schemas.py @@ -163,9 +163,6 @@ class CustomerSchema(AddressSchema): customer_id = colander.SchemaNode(colander.String(), validator=colander.Length(max=20), missing=colander.drop) - # customer_ip = colander.SchemaNode(colander.String(), - # validator=colander.Length(max=20), - # missing=colander.drop) class CreateCustomerSchema(CustomerBaseSchema, CustomerTypeSchema): @@ -228,6 +225,12 @@ class OrderSchema(colander.MappingSchema): missing=colander.drop) +class ExtraOptions(colander.MappingSchema): + customer_ip = colander.SchemaNode(colander.String(), + validator=colander.Length(max=39), + missing=colander.drop) + + class TransactionBaseSchema(colander.MappingSchema): line_items = LineItemsSchema(validator=colander.Length(max=30), missing=colander.drop) @@ -262,6 +265,7 @@ class CIMTransactionSchema(CIMBaseSchema, TransactionBaseSchema): validator=colander.Regex( r'^[0-9]{3,4}$', 'The card code is invalid'), missing=colander.drop) + extra_options = ExtraOptions(missing=colander.drop) class AIMTransactionSchema(TransactionBaseSchema): diff --git a/authorize/xml_data.py b/authorize/xml_data.py index 696d930..0957943 100644 --- a/authorize/xml_data.py +++ b/authorize/xml_data.py @@ -128,4 +128,4 @@ def prettify(elem): """Return a pretty-printed XML string for the Element.""" rough_string = E.tostring(elem, 'utf-8') reparsed = minidom.parseString(rough_string) - return reparsed.toprettyxml(indent=" ").strip() + return reparsed.toprettyxml(indent=' ').strip() diff --git a/docs/transaction.rst b/docs/transaction.rst index cf31e5f..55830b4 100644 --- a/docs/transaction.rst +++ b/docs/transaction.rst @@ -114,7 +114,11 @@ Full Example 'name': 'UPS 2-Day Shipping', 'description': 'Handle with care', }, + 'extra_options': { + 'customer_ip': '100.0.0.1', + }, 'tax_exempt': False, + 'recurring': True, }) result.transaction_response.trans_id @@ -228,7 +232,11 @@ Full Transactions with Bank Accounts 'name': 'UPS 2-Day Shipping', 'description': 'Handle with care', }, + 'extra_options': { + 'customer_ip': '100.0.0.1', + }, 'tax_exempt': False, + 'recurring': True, }) result.transaction_response.trans_id @@ -309,7 +317,11 @@ Full Transactions Example with CIM Data 'name': 'UPS 2-Day Shipping', 'description': 'Handle with care', }, - 'tax_exempt': False, + 'extra_options': { + 'customer_ip': '100.0.0.1', + }, + 'tax_exempt': False,, + 'recurring': True, }) result.transaction_response.trans_id diff --git a/tests/test_live_transaction.py b/tests/test_live_transaction.py index 02dfef8..aedde45 100644 --- a/tests/test_live_transaction.py +++ b/tests/test_live_transaction.py @@ -81,6 +81,9 @@ 'name': 'UPS 2-Day Shipping', 'description': 'Handle with care', }, + 'extra_options': { + 'customer_ip': '100.0.0.1', + }, 'tax_exempt': False, 'recurring': True, } @@ -135,6 +138,9 @@ 'name': 'The amount for duty', 'description': 'I can''t believe you would pay for duty', }, + 'extra_options': { + 'customer_ip': 'fe80::f4b6:2a88:70fa:f09f', + }, 'tax_exempt': False, 'recurring': True, 'card_code': '443', @@ -214,6 +220,9 @@ 'name': 'UPS 2-Day Shipping', 'description': 'Handle with care', }, + 'extra_options': { + 'customer_ip': '100.0.0.1', + }, 'tax_exempt': False, 'recurring': True, } diff --git a/tests/test_transaction_api.py b/tests/test_transaction_api.py index befd2e8..43aeef4 100644 --- a/tests/test_transaction_api.py +++ b/tests/test_transaction_api.py @@ -56,6 +56,9 @@ 'name': 'The amount for duty', 'description': 'I can''t believe you would pay for duty', }, + 'extra_options': { + 'customer_ip': '100.0.0.1', + }, 'tax_exempt': False, 'recurring': True, 'card_code': '443', @@ -135,6 +138,9 @@ 'name': 'UPS 2-Day Shipping', 'description': 'Handle with care', }, + 'extra_options': { + 'customer_ip': '100.0.0.1', + }, 'tax_exempt': False, 'recurring': True, } @@ -206,6 +212,8 @@ true + + ''' @@ -299,6 +307,7 @@ 520-123-4567 520-456-7890 + 100.0.0.1 '''