From f64d6fb89d72ca45de33e49841dea28c49eb8409 Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Tue, 10 May 2011 17:45:35 -0400 Subject: [PATCH] Added support for one time invoices. --- setup.py | 2 +- sharpy/product.py | 37 +++++++++++++++++++ tests/product_tests.py | 81 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 118 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 04ead81..fb63609 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ setup( name='Sharpy', - version='0.6.7', + version='0.6.8', description='Python client for the Cheddar Getter API (http://cheddargetter.com).', author="Sean O'Connor", author_email="sean@saaspire.com", diff --git a/sharpy/product.py b/sharpy/product.py index 8033171..ac7afaf 100644 --- a/sharpy/product.py +++ b/sharpy/product.py @@ -474,6 +474,43 @@ def charge(self, code, each_amount, quantity=1, description=None): data=data, ) return self.load_data_from_xml(response.content) + + def create_one_time_invoice(self, charges): + ''' + Charges should be a list of charges to execute immediately. Each + value in the charges diectionary should be a dictionary with the + following keys: + + code + Your code for this charge. This code will be displayed in the + user's invoice and is limited to 36 characters. + quantity + A positive integer quantity. If not provided this value will + default to 1. + each_amount + Positive or negative integer or decimal with two digit precision. + A positive number will create a charge (debit). A negative number + will create a credit. + description + An optional description for this charge which will be displayed on + the user's invoice. + ''' + data = {} + for n, charge in enumerate(charges): + each_amount = Decimal(charge['each_amount']) + each_amount = each_amount.quantize(Decimal('.01')) + data['charges[%d][chargeCode]' % n ] = charge['code'] + data['charges[%d][quantity]' % n] = charge.get('quantity', 1) + data['charges[%d][eachAmount]' % n] = each_amount + if 'description' in charge.keys(): + data['charges[%d][description]' % n] = charge['description'] + + response = self.product.client.make_request( + path='invoices/new', + params={'code': self.code}, + data=data, + ) + return self.load_data_from_xml(response.content) def __repr__(self): return u'Customer: %s %s (%s)' % ( diff --git a/tests/product_tests.py b/tests/product_tests.py index d2e6813..d9e3eac 100644 --- a/tests/product_tests.py +++ b/tests/product_tests.py @@ -481,4 +481,83 @@ def test_add_charge_with_descriptions(self): @clear_users def test_add_credit(self): - self.assert_charged(code='TEST-CHARGE', each_amount=-1, quantity=1) \ No newline at end of file + self.assert_charged(code='TEST-CHARGE', each_amount=-1, quantity=1) + + def assertCharge(self, customer, code, each_amount, quantity, description='', invoice_type=None): + found_charge = None + for invoice in customer.subscription.invoices: + if invoice_type is None or invoice['type'] == invoice_type: + for charge in invoice['charges']: + if charge['code'] == code: + found_charge = charge + + self.assertAlmostEqual(Decimal(each_amount), found_charge['each_amount'], places=2) + self.assertEqual(quantity, found_charge['quantity']) + self.assertEqual(description, found_charge['description']) + + + def assertOneTimeInvoice(self, charges): + customer = self.get_customer(**self.paid_defaults) + product = self.get_product() + + customer.create_one_time_invoice(charges) + + for charge in charges: + self.assertCharge( + customer, + code = charge['code'], + quantity = charge['quantity'], + each_amount = charge['each_amount'], + description = charge.get('description', ''), + invoice_type = 'one-time', + ) + + fetched_customer = product.get_customer(code=customer.code) + for charge in charges: + self.assertCharge( + fetched_customer, + code = charge['code'], + quantity = charge['quantity'], + each_amount = charge['each_amount'], + description = charge.get('description', ''), + invoice_type = 'one-time', + ) + + @clear_users + def test_add_simple_one_time_invoice(self): + charges = [{ + 'code': 'immediate-test', + 'quantity': 1, + 'each_amount': Decimal(5.23) + },] + + self.assertOneTimeInvoice(charges) + + @clear_users + def test_add_one_time_invoice_with_description(self): + charges = [{ + 'code': 'immediate-test', + 'quantity': 1, + 'each_amount': Decimal(5.23), + 'description': 'This is a test charge' + },] + + self.assertOneTimeInvoice(charges) + + + @clear_users + def test_add_one_time_invoice_with_multiple_charges(self): + charges = [{ + 'code': 'immediate-test', + 'quantity': 1, + 'each_amount': Decimal(5.23), + 'description': 'This is a test charge' + }, + { + 'code': 'immediate-test-2', + 'quantity': 3, + 'each_amount': 15, + 'description': 'This is another test charge' + },] + + self.assertOneTimeInvoice(charges) \ No newline at end of file