diff --git a/recurly/__init__.py b/recurly/__init__.py index deea2b07..8469e602 100644 --- a/recurly/__init__.py +++ b/recurly/__init__.py @@ -1055,6 +1055,7 @@ class Adjustment(Resource): 'revenue_gl_account_code', 'revenue_gl_account_id', 'performance_obligation_id', + 'vertex_transaction_type', ) xml_attribute_attributes = ('type',) _classes_for_nodename = { @@ -1138,7 +1139,8 @@ class Invoice(Resource): 'billing_info_uuid', 'dunning_campaign_id', 'refundable_in_cents', - 'used_tax_service' + 'used_tax_service', + 'vertex_transaction_type', ) blacklist_attributes = ( @@ -1406,6 +1408,7 @@ class Purchase(Resource): 'transaction_type', 'billing_info_uuid', 'ramp_intervals', + 'vertex_transaction_type', ) def invoice(self): diff --git a/tests/fixtures/adjustment/charged-with-vertex-transaction-type.xml b/tests/fixtures/adjustment/charged-with-vertex-transaction-type.xml new file mode 100644 index 00000000..19f6ae39 --- /dev/null +++ b/tests/fixtures/adjustment/charged-with-vertex-transaction-type.xml @@ -0,0 +1,31 @@ +POST https://api.recurly.com/v2/accounts/chargemock/adjustments 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 + + + + USD + test charge + 1000 + sale + + +HTTP/1.1 201 Created +Content-Type: application/xml; charset=utf-8 +Location: https://api.recurly.com/v2/adjustments/4ba1531325014b4f969cd13676f514d8 + + + + 4ba1531325014b4f969cd13676f514d8 + chargemock + 1000 + USD + 2009-11-03T23:27:46-08:00 + + test charge + sale + 2009-11-03T23:27:46-08:00 + diff --git a/tests/fixtures/purchase/invoiced-with-invoice-override-vertex-type.xml b/tests/fixtures/purchase/invoiced-with-invoice-override-vertex-type.xml new file mode 100644 index 00000000..e0ff6dc3 --- /dev/null +++ b/tests/fixtures/purchase/invoiced-with-invoice-override-vertex-type.xml @@ -0,0 +1,184 @@ +POST https://api.recurly.com/v2/purchases 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 + + + + + testmock + + + + 500 + sale + + + USD + rental + + +HTTP/1.1 201 Created +Content-Type: application/xml; charset=utf-8 +Location: https://api.recurly.com/v2/invoices/1360 + + + + + + + +
+ + test + mock + + test + + San Francisco + CA + 94016 + US + +
+ 6f4654a0444808153e65594a08b9e7a3 + paid + + 1360 + + 51 + 551 + USD + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + + 2024-02-23T19:55:22Z + + + + 500 + 500 + 0 + 2024-02-23T19:55:22Z + 0 + charge + purchase + + 551 + + + 0 + automatic + + + usst + CA + 0.1025 + true + rental + + + + + + + + + 551 + 6f46549f12d532b7579250425881a3bb + invoiced + + + + debit + 500 + 1 + 0 + 51 + 551 + false + USD + + usst + CA + 0.1025 + false + + 2024-02-23T19:55:20Z + + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + + + + sale + + + + + + + 6f4654a1a6ba44d5272c794d0d9bd5f0 + purchase + 551 + 51 + USD + success + credit_card + 8996823 + transaction + false + true + true + true + 172.22.0.1 + test + api + + Successful test transaction + + + + + Street address and postal code match. + + + 2024-02-23T19:55:21Z + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + false +
+ + testmock + + + + + + test + mock + test + + San Francisco + CA + 94016 + US + + + Visa + 2030 + 12 + 411111 + 1111 + + +
+
+
+ +
+ + +
diff --git a/tests/fixtures/purchase/invoiced-with-multiple-adjustment-vertex-types.xml b/tests/fixtures/purchase/invoiced-with-multiple-adjustment-vertex-types.xml new file mode 100644 index 00000000..9f14064d --- /dev/null +++ b/tests/fixtures/purchase/invoiced-with-multiple-adjustment-vertex-types.xml @@ -0,0 +1,222 @@ +POST https://api.recurly.com/v2/purchases 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 + + + + + testmock + + + + 300 + lease + + + 200 + rental + + + USD + + +HTTP/1.1 201 Created +Content-Type: application/xml; charset=utf-8 +Location: https://api.recurly.com/v2/invoices/1361 + + + + + + + +
+ + test + mock + + test + + San Francisco + CA + 94016 + US + +
+ 6f4654a0444808153e65594a08b9e7a4 + paid + + 1361 + + 51 + 551 + USD + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + + 2024-02-23T19:55:22Z + + + + 500 + 500 + 0 + 2024-02-23T19:55:22Z + 0 + charge + purchase + + 551 + + + 0 + automatic + + + usst + CA + 0.1025 + true + + + + + + + + + 331 + 6f46549f12d532b7579250425881a3bc + invoiced + + + + debit + 300 + 1 + 0 + 31 + 331 + false + USD + + usst + CA + 0.1025 + false + + 2024-02-23T19:55:20Z + + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + + + + lease + + + + + + + + + 220 + 6f46549f12d532b7579250425881a3bd + invoiced + + + + debit + 200 + 1 + 0 + 20 + 220 + false + USD + + usst + CA + 0.1025 + false + + 2024-02-23T19:55:20Z + + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + + + + rental + + + + + + + 6f4654a1a6ba44d5272c794d0d9bd5f1 + purchase + 551 + 51 + USD + success + credit_card + 8996824 + transaction + false + true + true + true + 172.22.0.1 + test + api + + Successful test transaction + + + + + Street address and postal code match. + + + 2024-02-23T19:55:21Z + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + false +
+ + testmock + + + + + + test + mock + test + + San Francisco + CA + 94016 + US + + + Visa + 2030 + 12 + 411111 + 1111 + + +
+
+
+
+ + + + diff --git a/tests/fixtures/purchase/invoiced-with-purchase-level-vertex-transaction-type.xml b/tests/fixtures/purchase/invoiced-with-purchase-level-vertex-transaction-type.xml new file mode 100644 index 00000000..f221e78e --- /dev/null +++ b/tests/fixtures/purchase/invoiced-with-purchase-level-vertex-transaction-type.xml @@ -0,0 +1,182 @@ +POST https://api.recurly.com/v2/purchases 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 + + + + + testmock + + + + 500 + + + USD + sale + + +HTTP/1.1 201 Created +Content-Type: application/xml; charset=utf-8 +Location: https://api.recurly.com/v2/invoices/1360 + + + + + + + +
+ + test + mock + + test + + San Francisco + CA + 94016 + US + +
+ 6f4654a0444808153e65594a08b9e7a3 + paid + + 1360 + + 51 + 551 + USD + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + + 2024-02-23T19:55:22Z + + + + 500 + 500 + 0 + 2024-02-23T19:55:22Z + 0 + charge + purchase + + 551 + + + 0 + automatic + + + usst + CA + 0.1025 + true + + + + + + + + + 551 + 6f46549f12d532b7579250425881a3bb + invoiced + + + + debit + 500 + 1 + 0 + 51 + 551 + false + USD + + usst + CA + 0.1025 + false + + 2024-02-23T19:55:20Z + + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + + + + sale + + + + + + + 6f4654a1a6ba44d5272c794d0d9bd5f0 + purchase + 551 + 51 + USD + success + credit_card + 8996823 + transaction + false + true + true + true + 172.22.0.1 + test + api + + Successful test transaction + + + + + Street address and postal code match. + + + 2024-02-23T19:55:21Z + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + false +
+ + testmock + + + + + + test + mock + test + + San Francisco + CA + 94016 + US + + + Visa + 2030 + 12 + 411111 + 1111 + + +
+
+
+
+ + + + diff --git a/tests/fixtures/purchase/invoiced-with-vertex-transaction-type.xml b/tests/fixtures/purchase/invoiced-with-vertex-transaction-type.xml new file mode 100644 index 00000000..36a76d75 --- /dev/null +++ b/tests/fixtures/purchase/invoiced-with-vertex-transaction-type.xml @@ -0,0 +1,182 @@ +POST https://api.recurly.com/v2/purchases 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 + + + + + testmock + + + + 500 + lease + + + USD + + +HTTP/1.1 201 Created +Content-Type: application/xml; charset=utf-8 +Location: https://api.recurly.com/v2/invoices/1359 + + + + + + + +
+ + test + mock + + test + + San Francisco + CA + 94016 + US + +
+ 6f4654a0444808153e65594a08b9e7a2 + paid + + 1359 + + 51 + 551 + USD + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + + 2024-02-23T19:55:22Z + + + + 500 + 500 + 0 + 2024-02-23T19:55:22Z + 0 + charge + purchase + + 551 + + + 0 + automatic + + + usst + CA + 0.1025 + true + + + + + + + + + 551 + 6f46549f12d532b7579250425881a3ba + invoiced + + + + debit + 500 + 1 + 0 + 51 + 551 + false + USD + + usst + CA + 0.1025 + false + + 2024-02-23T19:55:20Z + + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + + + + lease + + + + + + + 6f4654a1a6ba44d5272c794d0d9bd5ef + purchase + 551 + 51 + USD + success + credit_card + 8996822 + transaction + false + true + true + true + 172.22.0.1 + test + api + + Successful test transaction + + + + + Street address and postal code match. + + + 2024-02-23T19:55:21Z + 2024-02-23T19:55:22Z + 2024-02-23T19:55:22Z + false +
+ + testmock + + + + + + test + mock + test + + San Francisco + CA + 94016 + US + + + Visa + 2030 + 12 + 411111 + 1111 + + +
+
+
+
+ + + + diff --git a/tests/test_resources.py b/tests/test_resources.py index 0fc4aab4..9d28f14d 100644 --- a/tests/test_resources.py +++ b/tests/test_resources.py @@ -473,6 +473,143 @@ def create_purchase(): self.assertEqual(adjustment.revenue_gl_account_code, 'firstrev') self.assertEqual(adjustment.performance_obligation_id, '5') + def test_purchase_with_adjustment_level_vertex_transaction_type(self): + """Test that Adjustment can have vertex_transaction_type within a purchase""" + account_code = 'test%s' % self.test_id + def create_purchase(): + return Purchase( + account = Account( + account_code = account_code, + ), + adjustments = [ + recurly.Adjustment( + currency = 'USD', + vertex_transaction_type='lease', + unit_amount_in_cents=500 + ) + ] + ) + + with self.mock_request('purchase/invoiced-with-vertex-transaction-type.xml'): + collection = create_purchase().invoice() + adjustment = collection.charge_invoice.line_items[0] + + self.assertIsInstance(collection, InvoiceCollection) + self.assertIsInstance(collection.charge_invoice, Invoice) + self.assertEqual(adjustment.vertex_transaction_type, 'lease') + + def test_purchase_with_purchase_level_vertex_transaction_type(self): + """Test that Purchase can accept vertex_transaction_type at the top level""" + account_code = 'test%s' % self.test_id + def create_purchase(): + return Purchase( + account = Account( + account_code = account_code, + ), + adjustments = [ + recurly.Adjustment( + currency = 'USD', + unit_amount_in_cents=500 + ) + ], + vertex_transaction_type='sale' + ) + + with self.mock_request('purchase/invoiced-with-purchase-level-vertex-transaction-type.xml'): + collection = create_purchase().invoice() + adjustment = collection.charge_invoice.line_items[0] + + self.assertIsInstance(collection, InvoiceCollection) + self.assertIsInstance(collection.charge_invoice, Invoice) + # The adjustment inherits the purchase-level vertex_transaction_type + self.assertEqual(adjustment.vertex_transaction_type, 'sale') + + def test_purchase_with_multiple_adjustments_vertex_transaction_type(self): + """Test that each adjustment in a purchase can have its own vertex_transaction_type""" + account_code = 'test%s' % self.test_id + def create_purchase(): + return Purchase( + account = Account( + account_code = account_code, + ), + adjustments = [ + recurly.Adjustment( + currency = 'USD', + vertex_transaction_type='lease', + unit_amount_in_cents=300 + ), + recurly.Adjustment( + currency = 'USD', + vertex_transaction_type='rental', + unit_amount_in_cents=200 + ) + ] + ) + + with self.mock_request('purchase/invoiced-with-multiple-adjustment-vertex-types.xml'): + collection = create_purchase().invoice() + adjustments = collection.charge_invoice.line_items + + self.assertIsInstance(collection, InvoiceCollection) + self.assertIsInstance(collection.charge_invoice, Invoice) + self.assertEqual(len(adjustments), 2) + # Each adjustment has its own vertex_transaction_type + self.assertEqual(adjustments[0].vertex_transaction_type, 'lease') + self.assertEqual(adjustments[1].vertex_transaction_type, 'rental') + + def test_charge_with_vertex_transaction_type(self): + """Test that vertex_transaction_type can be set on a direct adjustment via account.charge()""" + account = Account(account_code='charge%s' % self.test_id) + with self.mock_request('adjustment/account-created.xml'): + account.save() + + charge = Adjustment( + unit_amount_in_cents=1000, + currency='USD', + description='test charge', + type='charge', + vertex_transaction_type='sale' + ) + + with self.mock_request('adjustment/charged-with-vertex-transaction-type.xml'): + account.charge(charge) + + # Verify the charge was created with vertex_transaction_type + self.assertEqual(charge.vertex_transaction_type, 'sale') + + def test_purchase_with_invoice_override_vertex_transaction_type(self): + """Test that invoice-level vertex_transaction_type overrides adjustment-level values. + + This demonstrates the override behavior where an invoice can have its own + vertex_transaction_type that takes precedence over the individual adjustment values. + """ + # Create a purchase with adjustment-level vertex_transaction_type='sale' + # but purchase-level (invoice-level) vertex_transaction_type='rental' + purchase = Purchase( + currency='USD', + account=Account(account_code='testmock'), + adjustments=[ + Adjustment( + unit_amount_in_cents=500, + vertex_transaction_type='sale' # Adjustment-level value + ) + ], + vertex_transaction_type='rental' # Invoice-level value (should override) + ) + + with self.mock_request('purchase/invoiced-with-invoice-override-vertex-type.xml'): + invoice_collection = purchase.invoice() + + invoice = invoice_collection.charge_invoice + adjustments = invoice.line_items + + # Verify the invoice has the invoice-level vertex_transaction_type + self.assertEqual(invoice.vertex_transaction_type, 'rental') + + # The adjustment still has its own value (API preserves both) + # but the invoice-level value is what gets used for tax calculation + self.assertEqual(adjustments[0].vertex_transaction_type, 'sale') + def test_account(self): account_code = 'test%s' % self.test_id with self.mock_request('account/does-not-exist.xml'):