Skip to content

Commit

Permalink
Merge pull request #246 from recurly/custom_fields_2_13
Browse files Browse the repository at this point in the history
Add custom fields to Account and Subscription
  • Loading branch information
bhelx committed Jul 6, 2018
2 parents 8896493 + aa1d95b commit 06e4f93
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 6 deletions.
25 changes: 24 additions & 1 deletion recurly/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,27 @@ class AccountAcquisition(Resource):
'updated_at',
)

class CustomField(Resource):

"""A field to store extra data on the account or subscription."""

nodename = 'custom_field'

attributes = (
'name',
'value',
)

def to_element(self, root_name=None):
# Include the field name/value pair when the value changed
if 'value' in self.__dict__:
try:
self.name = self.name # forces name into __dict__
except AttributeError:
pass

return super(CustomField, self).to_element(root_name)

class Account(Resource):

"""A customer account."""
Expand Down Expand Up @@ -160,9 +181,10 @@ class Account(Resource):
'has_paused_subscription',
'has_past_due_invoice',
'preferred_locale',
'custom_fields',
)

_classes_for_nodename = { 'address': Address }
_classes_for_nodename = { 'address': Address, 'custom_field': CustomField }

sensitive_attributes = ('number', 'verification_value',)

Expand Down Expand Up @@ -1016,6 +1038,7 @@ class Subscription(Resource):
'next_bill_date',
'current_term_started_at',
'current_term_ends_at',
'custom_fields',
)
sensitive_attributes = ('number', 'verification_value', 'bulk')

Expand Down
45 changes: 45 additions & 0 deletions tests/fixtures/account/created-with-custom-fields.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
POST https://api.recurly.com/v2/accounts 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"?>
<account>
<account_code>testmock</account_code>
<custom_fields>
<custom_field>
<name>field_1</name>
<value>my field value</value>
</custom_field>
</custom_fields>
</account>

HTTP/1.1 201 Created
Content-Type: application/xml; charset=utf-8
Location: https://api.recurly.com/v2/accounts/testmock

<?xml version="1.0" encoding="UTF-8"?>
<account href="https://api.recurly.com/v2/accounts/testmock">
<adjustments href="https://api.recurly.com/v2/accounts/testmock/adjustments"/>
<billing_info href="https://api.recurly.com/v2/accounts/testmock/billing_info"/>
<invoices href="https://api.recurly.com/v2/accounts/testmock/invoices"/>
<shipping_addresses href="https://api.recurly.com/v2/accounts/testmock/shipping_addresses"/>
<subscriptions href="https://api.recurly.com/v2/accounts/testmock/subscriptions"/>
<transactions href="https://api.recurly.com/v2/accounts/testmock/transactions"/>
<account_code>testmock</account_code>
<username nil="nil"></username>
<email nil="nil"></email>
<first_name nil="nil"></first_name>
<last_name nil="nil"></last_name>
<company_name nil="nil"></company_name>
<vat_number nil="nil"></vat_number>
<accept_language nil="nil"></accept_language>
<custom_fields type="array">
<custom_field>
<name>field_1</name>
<value>my field value</value>
</custom_field>
</custom_fields>
</account>
37 changes: 37 additions & 0 deletions tests/fixtures/account/exists-custom-fields.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
GET https://api.recurly.com/v2/accounts/testmock HTTP/1.1
X-Api-Version: {api-version}
Accept: application/xml
Authorization: Basic YXBpa2V5Og==
User-Agent: {user-agent}


HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8

<?xml version="1.0" encoding="UTF-8"?>
<account href="https://api.recurly.com/v2/accounts/testmock">
<adjustments href="https://api.recurly.com/v2/accounts/testmock/adjustments"/>
<billing_info href="https://api.recurly.com/v2/accounts/testmock/billing_info"/>
<invoices href="https://api.recurly.com/v2/accounts/testmock/invoices"/>
<subscriptions href="https://api.recurly.com/v2/accounts/testmock/subscriptions"/>
<transactions href="https://api.recurly.com/v2/accounts/testmock/transactions"/>
<account_balance href="https://api.recurly.com/v2/accounts/testmock/balance"/>
<account_code>testmock</account_code>
<username nil="nil"></username>
<email nil="nil"></email>
<first_name nil="nil"></first_name>
<last_name nil="nil"></last_name>
<company_name nil="nil"></company_name>
<entity_use_code>I</entity_use_code>
<accept_language nil="nil"></accept_language>
<custom_fields type="array">
<custom_field>
<name>field1</name>
<value>original value1</value>
</custom_field>
<custom_field>
<name>field2</name>
<value>original value2</value>
</custom_field>
</custom_fields>
</account>
37 changes: 37 additions & 0 deletions tests/fixtures/account/updated-custom-fields.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
PUT https://api.recurly.com/v2/accounts/testmock 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"?>
<account>
<custom_fields>
<custom_field />
<custom_field>
<name>field2</name>
<value>new value2</value>
</custom_field>
</custom_fields>
<account_code>testmock</account_code>
</account>

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

<?xml version="1.0" encoding="UTF-8"?>
<account href="https://api.recurly.com/v2/accounts/testmock">
<account_code>testmock</account_code>
<custom_fields type="array">
<custom_field>
<name>field1</name>
<value>original value1</value>
</custom_field>
<custom_field>
<name>field2</name>
<value>new value2</value>
</custom_field>
</custom_fields>
</account>
75 changes: 75 additions & 0 deletions tests/fixtures/subscription/subscribe-custom-fields.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
POST https://api.recurly.com/v2/subscriptions 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"?>
<subscription>
<plan_code>basicplan</plan_code>
<currency>USD</currency>
<account>
<account_code>subscribe-mock-2</account_code>
<custom_fields>
<custom_field>
<name>my_account_field</name>
<value>here is the account value you seek</value>
</custom_field>
</custom_fields>
<billing_info type="credit_card">
<first_name>Verena</first_name>
<last_name>Example</last_name>
<number>4111 1111 1111 1111</number>
<verification_value>7777</verification_value>
<year>2015</year>
<month>12</month>
<address1>123 Main St</address1>
<city>San José</city>
<state>CA</state>
<zip>94105</zip>
<country>US</country>
<currency>USD</currency>
</billing_info>
</account>
<custom_fields>
<custom_field>
<name>my_sub_field</name>
<value>definitely sub value</value>
</custom_field>
</custom_fields>
</subscription>

HTTP/1.1 201 Created
Content-Type: application/xml; charset=utf-8
Location: https://api.recurly.com/v2/plans/basicplan

<?xml version="1.0" encoding="UTF-8"?>
<subscription
href="https://api.recurly.com/v2/subscriptions/123456789012345678901234567890ab">
<uuid>123456789012345678901234567890ab</uuid>
<account href="https://api.recurly.com/v2/accounts/subscribe-mock-2"/>
<plan href="https://api.recurly.com/v2/plans/basicplan">
<plan_code>basicplan</plan_code>
<name>Basic Plan</name>
</plan>
<state>active</state>
<quantity type="integer">1</quantity>
<currency>EUR</currency>
<unit_amount_in_cents type="integer">1000</unit_amount_in_cents>
<activated_at type="datetime">2011-05-27T07:00:00Z</activated_at>
<canceled_at nil="nil"></canceled_at>
<expires_at nil="nil"></expires_at>
<current_period_started_at type="datetime">2011-06-27T07:00:00Z</current_period_started_at>
<current_period_ends_at type="datetime">2010-07-27T07:00:00Z</current_period_ends_at>
<trial_started_at nil="nil"></trial_started_at>
<trial_ends_at nil="nil"></trial_ends_at>
<subscription_add_ons type="array">
</subscription_add_ons>
<custom_fields type="array">
<custom_field>
<name>my_sub_field</name>
<value>definitely sub value</value>
</custom_field>
</custom_fields>
</subscription>
74 changes: 69 additions & 5 deletions tests/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from six.moves import urllib, http_client
from six.moves.urllib.parse import urljoin

from recurly import Account, AddOn, Address, Adjustment, BillingInfo, Coupon, Plan, Redemption, Subscription, SubscriptionAddOn, Transaction, MeasuredUnit, Usage, GiftCard, Delivery, ShippingAddress, AccountAcquisition, Purchase, Invoice, InvoiceCollection, CreditPayment
from recurly import Account, AddOn, Address, Adjustment, BillingInfo, Coupon, Plan, Redemption, Subscription, SubscriptionAddOn, Transaction, MeasuredUnit, Usage, GiftCard, Delivery, ShippingAddress, AccountAcquisition, Purchase, Invoice, InvoiceCollection, CreditPayment, CustomField
from recurly import Money, NotFoundError, ValidationError, BadRequestError, PageError
from recurlytests import RecurlyTest, xml

Expand Down Expand Up @@ -230,6 +230,13 @@ def test_account(self):
with self.mock_request('account/numeric-deleted.xml'):
account.delete()

"""Get taxed account"""
with self.mock_request('account/show-taxed.xml'):
account = Account.get(account_code)
self.assertTrue(account.tax_exempt)

def test_account_addresses(self):
account_code = 'test%s' % self.test_id
"""Create an account with an account level address"""
account = Account(account_code=account_code)
account.address.address1 = '123 Main St'
Expand Down Expand Up @@ -276,10 +283,34 @@ def test_account(self):
with self.mock_request('shipping_addresses/created-on-existing-account.xml'):
shipping_address = account.create_shipping_address(shipping_address)

"""Get taxed account"""
with self.mock_request('account/show-taxed.xml'):
account = Account.get(account_code)
self.assertTrue(account.tax_exempt)
def test_account_custom_fields(self):
account_code = 'test%s' % self.test_id
"""Create an account with a custom field"""
account = Account(
account_code=account_code,
custom_fields=[
CustomField(name="field_1", value="my field value")
]
)
with self.mock_request('account/created-with-custom-fields.xml'):
account.save()

self.assertEquals(account.custom_fields[0].name, 'field_1')
self.assertEquals(account.custom_fields[0].value, 'my field value')

"""Update custom fields on an account"""
with self.mock_request('account/exists-custom-fields.xml'):
existing_account = Account.get(account_code)
fields = existing_account.custom_fields
fields[1].value = "new value2"
existing_account.custom_fields = fields
with self.mock_request('account/updated-custom-fields.xml'):
existing_account.save()

self.assertEquals(existing_account.custom_fields[0].name, 'field1')
self.assertEquals(existing_account.custom_fields[0].value, 'original value1')
self.assertEquals(existing_account.custom_fields[1].name, 'field2')
self.assertEquals(existing_account.custom_fields[1].value, 'new value2')

def test_account_acquisition(self):
account_code = 'test%s' % self.test_id
Expand Down Expand Up @@ -1320,6 +1351,39 @@ def test_subscribe_add_on(self):
with self.mock_request('subscribe-add-on/plan-deleted.xml'):
plan.delete()

def test_subscription_custom_fields(self):
account_code = 'subscribe-%s-2' % self.test_id
sub = Subscription(
plan_code='basicplan',
currency='USD',
account=Account(
account_code=account_code,
billing_info=BillingInfo(
first_name='Verena',
last_name='Example',
address1='123 Main St',
city=six.u('San Jos\xe9'),
state='CA',
zip='94105',
country='US',
type='credit_card',
number='4111 1111 1111 1111',
verification_value='7777',
year='2015',
month='12',
),
custom_fields=[CustomField(name='my_account_field', value='here is the account value you seek')],
),
custom_fields=[CustomField(name='my_sub_field', value='definitely sub value')],
)

with self.mock_request('subscription/subscribe-custom-fields.xml'):
sub.save()

self.assertTrue(sub._url)
self.assertEquals(sub.custom_fields[0].name, 'my_sub_field')
self.assertEquals(sub.custom_fields[0].value, 'definitely sub value')

def test_account_notes(self):
account1 = Account(account_code='note%s' % self.test_id)
account2 = Account(account_code='note%s' % self.test_id)
Expand Down

0 comments on commit 06e4f93

Please sign in to comment.