Skip to content

Commit

Permalink
Merge pull request #225 from recurly/api_version_2_9
Browse files Browse the repository at this point in the history
API version 2.9
  • Loading branch information
bhelx authored Nov 20, 2017
2 parents c24c2b3 + 5b16f4d commit 1c49f51
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 5 deletions.
17 changes: 16 additions & 1 deletion recurly/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
API_KEY = None
"""The API key to use when authenticating API requests."""

API_VERSION = '2.8'
API_VERSION = '2.9'
"""The API version to use when making API requests."""

CA_CERTS_FILE = None
Expand Down Expand Up @@ -365,6 +365,7 @@ class BillingInfo(Resource):
'account_number',
'currency',
'updated_at',
'external_hpp_type',
)
sensitive_attributes = ('number', 'verification_value', 'account_number')
xml_attribute_attributes = ('type',)
Expand Down Expand Up @@ -853,6 +854,20 @@ def preview(self):
url = urljoin(recurly.base_uri(), self.collection_path + '/preview')
return self.__invoice(url)

def authorize(self):
"""
Will generate an authorized invoice for the purchase. Runs validations
but does not run any transactions. This endpoint will create a
pending purchase that can be activated at a later time once payment
has been completed on an external source (e.g. Adyen's Hosted
Payment Pages).
Returns:
Invoice: The authorized invoice
"""
url = recurly.base_uri() + self.collection_path + '/authorize'
return self.__invoice(url)

def __invoice(self, url):
# We must null out currency in subscriptions and adjustments
# TODO we should deprecate and remove default currency support
Expand Down
15 changes: 11 additions & 4 deletions recurly/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
from six.moves import http_client
from six.moves.urllib.parse import urlencode, urlsplit, quote

def urlencode_params(args):
# Need to make bools lowercase
for k, v in six.iteritems(args):
if isinstance(v, bool):
args[k] = str(v).lower()
return urlencode(args)

class Money(object):

"""An amount of money in one or more currencies."""
Expand Down Expand Up @@ -514,7 +521,7 @@ def update_from_element(self, elem):
def _make_actionator(self, url, method, extra_handler=None):
def actionator(*args, **kwargs):
if kwargs:
full_url = '%s?%s' % (url, urlencode(kwargs))
full_url = '%s?%s' % (url, urlencode_params(kwargs))
else:
full_url = url

Expand Down Expand Up @@ -574,7 +581,7 @@ def __getattr__(self, name):
def make_relatitator(url):
def relatitator(**kwargs):
if kwargs:
full_url = '%s?%s' % (url, urlencode(kwargs))
full_url = '%s?%s' % (url, urlencode_params(kwargs))
else:
full_url = url

Expand Down Expand Up @@ -608,7 +615,7 @@ def all(cls, **kwargs):
"""
url = recurly.base_uri() + cls.collection_path
if kwargs:
url = '%s?%s' % (url, urlencode(kwargs))
url = '%s?%s' % (url, urlencode_params(kwargs))
return Page.page_for_url(url)

@classmethod
Expand All @@ -618,7 +625,7 @@ def count(cls, **kwargs):
"""
url = recurly.base_uri() + cls.collection_path
if kwargs:
url = '%s?%s' % (url, urlencode(kwargs))
url = '%s?%s' % (url, urlencode_params(kwargs))
return Page.count_for_url(url)

def save(self):
Expand Down
152 changes: 152 additions & 0 deletions tests/fixtures/purchase/authorized.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
POST https://api.recurly.com/v2/purchases/authorize HTTP/1.1
X-Api-Version: {api-version}
Accept: application/xml
Authorization: Basic YXBpa2V5Og==
User-Agent: {user-agent}
Content-Type: application/xml; charset=utf-8

<?xml version="1.0" encoding="UTF-8"?>
<purchase>
<account>
<account_code>testmock</account_code>
<email>[email protected]</email>
<billing_info>
<first_name>Verena</first_name>
<last_name>Example</last_name>
<number>4111-1111-1111-1111</number>
<verification_value>123</verification_value>
<year type="integer">2020</year>
<month type="integer">11</month>
<address1>123 Main St</address1>
<city>New Orleans</city>
<state>LA</state>
<zip>70114</zip>
<country>US</country>
<currency>USD</currency>
<external_hpp_type>adyen</external_hpp_type>
</billing_info>
</account>
<adjustments>
<adjustment>
<description>Item 1</description>
<quantity type="integer">1</quantity>
<unit_amount_in_cents type="integer">1000</unit_amount_in_cents>
</adjustment>
<adjustment>
<description>Item 2</description>
<quantity type="integer">2</quantity>
<unit_amount_in_cents type="integer">2000</unit_amount_in_cents>
</adjustment>
</adjustments>
<currency>USD</currency>
<subscriptions>
<subscription>
<plan_code>gold</plan_code>
</subscription>
</subscriptions>
</purchase>

HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8
Location: https://api.recurly.com/v2/invoices/1021

<?xml version="1.0" encoding="UTF-8"?>
<invoice href="">
<account href="https://api.recurly.com/v2/accounts/03f2dad7-e0d3-4856-acbb-fa7a7ce26683"/>
<address>
<address1>123 Main St</address1>
<address2 nil="nil"></address2>
<city>New Orleans</city>
<state>LA</state>
<zip>70114</zip>
<country>US</country>
<phone nil="nil"></phone>
</address>
<uuid>40625fd700c1c2d90060744092b4a1b1</uuid>
<state>open</state>
<invoice_number_prefix></invoice_number_prefix>
<invoice_number nil="nil"></invoice_number>
<po_number nil="nil"></po_number>
<vat_number nil="nil"></vat_number>
<subtotal_in_cents type="integer">6000</subtotal_in_cents>
<tax_in_cents type="integer">0</tax_in_cents>
<total_in_cents type="integer">6000</total_in_cents>
<subtotal_after_discount_in_cents type="integer">6000</subtotal_after_discount_in_cents>
<currency>USD</currency>
<created_at nil="nil"></created_at>
<updated_at nil="nil"></updated_at>
<attempt_next_collection_at type="datetime">2017-10-06T21:25:55Z</attempt_next_collection_at>
<closed_at nil="nil"></closed_at>
<terms_and_conditions nil="nil"></terms_and_conditions>
<customer_notes nil="nil"></customer_notes>
<recovery_reason nil="nil"></recovery_reason>
<net_terms type="integer">0</net_terms>
<collection_method>automatic</collection_method>
<line_items type="array">
<adjustment href="" type="charge">
<account href="https://api.recurly.com/v2/accounts/03f2dad7-e0d3-4856-acbb-fa7a7ce26683"/>
<uuid>40625fd6fc46181e2f15044db38c1c82</uuid>
<state>pending</state>
<description>gold</description>
<accounting_code nil="nil"></accounting_code>
<product_code>gold</product_code>
<origin>plan</origin>
<unit_amount_in_cents type="integer">1000</unit_amount_in_cents>
<quantity type="integer">1</quantity>
<discount_in_cents type="integer">0</discount_in_cents>
<tax_in_cents type="integer">0</tax_in_cents>
<total_in_cents type="integer">1000</total_in_cents>
<currency>USD</currency>
<taxable type="boolean">false</taxable>
<start_date type="datetime">2017-10-06T21:25:55Z</start_date>
<end_date type="datetime">2017-11-06T21:25:55Z</end_date>
<created_at nil="nil"></created_at>
<updated_at nil="nil"></updated_at>
<revenue_schedule_type>evenly</revenue_schedule_type>
</adjustment>
<adjustment href="" type="charge">
<account href="https://api.recurly.com/v2/accounts/03f2dad7-e0d3-4856-acbb-fa7a7ce26683"/>
<uuid>40625fd6e6a5817b59a2174b72a92fea</uuid>
<state>pending</state>
<description>Item 1</description>
<accounting_code nil="nil"></accounting_code>
<product_code nil="nil"></product_code>
<origin>debit</origin>
<unit_amount_in_cents type="integer">1000</unit_amount_in_cents>
<quantity type="integer">1</quantity>
<discount_in_cents type="integer">0</discount_in_cents>
<tax_in_cents type="integer">0</tax_in_cents>
<total_in_cents type="integer">1000</total_in_cents>
<currency>USD</currency>
<taxable type="boolean">false</taxable>
<start_date type="datetime">2017-10-06T21:25:55Z</start_date>
<end_date nil="nil"></end_date>
<created_at nil="nil"></created_at>
<updated_at nil="nil"></updated_at>
<revenue_schedule_type></revenue_schedule_type>
</adjustment>
<adjustment href="" type="charge">
<account href="https://api.recurly.com/v2/accounts/03f2dad7-e0d3-4856-acbb-fa7a7ce26683"/>
<uuid>40625fd6e9096c9922b52646e29f6d5e</uuid>
<state>pending</state>
<description>Item 2</description>
<accounting_code nil="nil"></accounting_code>
<product_code nil="nil"></product_code>
<origin>debit</origin>
<unit_amount_in_cents type="integer">2000</unit_amount_in_cents>
<quantity type="integer">2</quantity>
<discount_in_cents type="integer">0</discount_in_cents>
<tax_in_cents type="integer">0</tax_in_cents>
<total_in_cents type="integer">4000</total_in_cents>
<currency>USD</currency>
<taxable type="boolean">false</taxable>
<start_date type="datetime">2017-10-06T21:25:55Z</start_date>
<end_date nil="nil"></end_date>
<created_at nil="nil"></created_at>
<updated_at nil="nil"></updated_at>
<revenue_schedule_type></revenue_schedule_type>
</adjustment>
</line_items>
<transactions type="array">
</transactions>
</invoice>
5 changes: 5 additions & 0 deletions tests/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ def test_purchase(self):
with self.mock_request('purchase/previewed.xml'):
preview_invoice = purchase.preview()
self.assertIsInstance(preview_invoice, Invoice)
with self.mock_request('purchase/authorized.xml'):
purchase.account.email = '[email protected]'
purchase.account.billing_info.external_hpp_type = 'adyen'
authorized_invoice = purchase.authorize()
self.assertIsInstance(authorized_invoice, Invoice)

def test_account(self):
account_code = 'test%s' % self.test_id
Expand Down

0 comments on commit 1c49f51

Please sign in to comment.