Skip to content

Commit e245641

Browse files
Merge pull request #888 from recurly/Add-vertex_transaction_type-To-Purchases-endpoint
Adds vertex_transaction_type to purchases invoices and adjustments
2 parents ed22478 + 5e91cf9 commit e245641

File tree

10 files changed

+257
-0
lines changed

10 files changed

+257
-0
lines changed

Library/Adjustment.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ public List<CustomField> CustomFields
9393
}
9494
private List<CustomField> _customFields;
9595

96+
/// <summary>
97+
/// Optional vertex transaction type for tax purposes.
98+
/// </summary>
99+
public string VertexTransactionType { get; set; }
100+
96101
private const string UrlPrefix = "/accounts/";
97102
private const string UrlPostfix = "/adjustments/";
98103

@@ -279,6 +284,10 @@ internal override void ReadXml(XmlTextReader reader)
279284
TaxCode = reader.ReadElementContentAsString();
280285
break;
281286

287+
case "vertex_transaction_type":
288+
VertexTransactionType = reader.ReadElementContentAsString();
289+
break;
290+
282291
case "tax_type":
283292
TaxType = reader.ReadElementContentAsString();
284293
break;
@@ -405,6 +414,8 @@ internal void WriteXml(XmlTextWriter xmlWriter, bool embedded = false)
405414

406415
if (TaxCode != null)
407416
xmlWriter.WriteElementString("tax_code", TaxCode);
417+
if (VertexTransactionType != null)
418+
xmlWriter.WriteElementString("vertex_transaction_type", VertexTransactionType);
408419
if (StartDate != DateTime.MinValue)
409420
xmlWriter.WriteElementString("start_date", StartDate.ToString("s"));
410421
if (EndDate.HasValue)

Library/Invoice.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ public Address Address
140140
public string TermsAndConditions { get; set; }
141141
public string VatReverseChargeNotes { get; set; }
142142
public string GatewayCode { get; set; }
143+
public string VertexTransactionType { get; set; }
143144
public DateTime? AttemptNextCollectionAt { get; set; }
144145
public string RecoveryReason { get; set; }
145146
public string AllLineItemsLink { get; set; }
@@ -793,6 +794,9 @@ internal override void WriteXml(XmlTextWriter xmlWriter)
793794
xmlWriter.WriteElementString("vat_reverse_charge_notes", VatReverseChargeNotes);
794795
xmlWriter.WriteElementString("po_number", PoNumber);
795796

797+
if (VertexTransactionType != null)
798+
xmlWriter.WriteElementString("vertex_transaction_type", VertexTransactionType);
799+
796800
if (CollectionMethod == Collection.Manual)
797801
{
798802
xmlWriter.WriteElementString("collection_method", "manual");

Library/Purchase.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ public List<string> CouponCodes
138138
/// </summary>
139139
public string TransactionType { get; set; }
140140

141+
/// <summary>
142+
/// Optional vertex transaction type for tax purposes.
143+
/// </summary>
144+
public string VertexTransactionType { get; set; }
145+
141146
#region Constructors
142147

143148
internal Purchase()
@@ -281,6 +286,9 @@ internal override void WriteXml(XmlTextWriter xmlWriter)
281286
if (TransactionType != null)
282287
xmlWriter.WriteElementString("transaction_type", TransactionType);
283288

289+
if (VertexTransactionType != null)
290+
xmlWriter.WriteElementString("vertex_transaction_type", VertexTransactionType);
291+
284292
if (NetTerms.HasValue)
285293
xmlWriter.WriteElementString("net_terms", NetTerms.Value.ToString());
286294

Test/AdjustmentTest.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,5 +281,41 @@ public void CheckForRevRecDataOut()
281281
xml.Should().Contain("<revenue_gl_account_id>sxo2b1hpjrye</revenue_gl_account_id>");
282282
xml.Should().Contain("<performance_obligation_id>7pu</performance_obligation_id>");
283283
}
284+
285+
[RecurlyFact(TestEnvironment.Type.Unit)]
286+
public void AdjustmentWithVertexTransactionType()
287+
{
288+
var adjustment = new Adjustment
289+
{
290+
VertexTransactionType = "lease"
291+
};
292+
293+
// Verify the request serializes vertex_transaction_type correctly
294+
var xmlOutput = new System.Text.StringBuilder();
295+
using (var xmlWriter = new XmlTextWriter(new System.IO.StringWriter(xmlOutput)))
296+
{
297+
adjustment.WriteXml(xmlWriter);
298+
}
299+
var xml = xmlOutput.ToString();
300+
Assert.Contains("<vertex_transaction_type>lease</vertex_transaction_type>", xml);
301+
302+
// Verify that vertex_transaction_type can be deserialized from responses
303+
var mockResponse = GetMockAdjustmentResponse();
304+
Assert.NotNull(mockResponse);
305+
Assert.Equal(mockResponse.State, Adjustment.AdjustmentState.Invoiced);
306+
Assert.Equal("lease", mockResponse.VertexTransactionType);
307+
}
308+
309+
private Adjustment GetMockAdjustmentResponse()
310+
{
311+
// Mock the Adjustment response using a fixture with vertex_transaction_type
312+
var adjustment = new Adjustment();
313+
var xmlFixture = FixtureImporter.Get(FixtureType.Adjustments, "show-with-vertex-200").Xml;
314+
using (var reader = new XmlTextReader(new System.IO.StringReader(xmlFixture)))
315+
{
316+
adjustment.ReadXml(reader);
317+
}
318+
return adjustment;
319+
}
284320
}
285321
}

Test/Fixtures/FixtureImporter.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ public enum FixtureType
9898
PerformanceObligations,
9999
[Description("plans")]
100100
Plans,
101+
[Description("purchases")]
102+
Purchases,
101103
[Description("shipping_methods")]
102104
ShippingMethods,
103105
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
HTTP/1.1 200 OK
2+
Content-Type: application/xml; charset=utf-8
3+
4+
<?xml version="1.0" encoding="UTF-8"?>
5+
<adjustment href="https://api.recurly.com/v2/adjustments/abcdef1234567890" type="charge">
6+
<account href="https://api.recurly.com/v2/accounts/account"/>
7+
<invoice href="https://api.recurly.com/v2/invoices/1234"/>
8+
<subscription href="https://api.recurly.com/v2/subscriptions/1234567890abcdef"/>
9+
<uuid>abcdef1234567890</uuid>
10+
<state>invoiced</state>
11+
<description>$12 Annual Subscription</description>
12+
<item_code></item_code>
13+
<accounting_code></accounting_code>
14+
<product_code nil="nil"></product_code>
15+
<origin>plan</origin>
16+
<unit_amount_in_cents type="integer">1200</unit_amount_in_cents>
17+
<quantity type="integer">1</quantity>
18+
<discount_in_cents type="integer">0</discount_in_cents>
19+
<tax_in_cents type="integer">0</tax_in_cents>
20+
<total_in_cents type="integer">1200</total_in_cents>
21+
<currency>USD</currency>
22+
<taxable type="boolean">false</taxable>
23+
<tax_code></tax_code>
24+
<vertex_transaction_type>lease</vertex_transaction_type>
25+
<start_date type="datetime">2011-04-30T07:00:00Z</start_date>
26+
<end_date type="datetime">2011-04-30T07:00:00Z</end_date>
27+
<created_at type="datetime">2011-08-31T03:30:00Z</created_at>
28+
</adjustment>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
HTTP/1.1 201 Created
2+
Content-Type: application/xml; charset=utf-8
3+
4+
<?xml version="1.0" encoding="UTF-8"?>
5+
<invoice_collection href="https://api.recurly.com/v2/invoice_collections/012345678901234567890123456789ab">
6+
<charge_invoice href="https://api.recurly.com/v2/invoices/012345678901234567890123456789ab">
7+
<account href="https://api.recurly.com/v2/accounts/test-account-123"/>
8+
<uuid>012345678901234567890123456789ab</uuid>
9+
<state>paid</state>
10+
<invoice_number type="integer">1000</invoice_number>
11+
<po_number>PO-12345</po_number>
12+
<vat_number nil="nil"></vat_number>
13+
<subtotal_in_cents type="integer">580</subtotal_in_cents>
14+
<tax_in_cents type="integer">0</tax_in_cents>
15+
<total_in_cents type="integer">580</total_in_cents>
16+
<currency>USD</currency>
17+
<created_at type="datetime">2025-11-25T22:00:00Z</created_at>
18+
<updated_at type="datetime">2025-11-25T22:00:00Z</updated_at>
19+
<line_items type="array">
20+
<adjustment type="charge">
21+
<uuid>adj123456789</uuid>
22+
<description>Test Adjustment</description>
23+
<product_code>test-product</product_code>
24+
<unit_amount_in_cents type="integer">580</unit_amount_in_cents>
25+
<quantity type="integer">1</quantity>
26+
<tax_in_cents type="integer">0</tax_in_cents>
27+
<total_in_cents type="integer">580</total_in_cents>
28+
<currency>USD</currency>
29+
<tax_exempt type="boolean">false</tax_exempt>
30+
<created_at type="datetime">2025-11-25T22:00:00Z</created_at>
31+
<updated_at type="datetime">2025-11-25T22:00:00Z</updated_at>
32+
</adjustment>
33+
</line_items>
34+
<transactions type="array">
35+
<transaction href="https://api.recurly.com/v2/transactions/tx123456789" type="credit_card">
36+
<account href="https://api.recurly.com/v2/accounts/test-account-123"/>
37+
<uuid>tx123456789</uuid>
38+
<action>purchase</action>
39+
<amount_in_cents type="integer">580</amount_in_cents>
40+
<tax_in_cents type="integer">0</tax_in_cents>
41+
<currency>USD</currency>
42+
<status>success</status>
43+
<payment_method>credit_card</payment_method>
44+
<reference nil="nil"></reference>
45+
<source>purchase</source>
46+
<test type="boolean">true</test>
47+
<voidable type="boolean">true</voidable>
48+
<refundable type="boolean">true</refundable>
49+
<created_at type="datetime">2025-11-25T22:00:00Z</created_at>
50+
<updated_at type="datetime">2025-11-25T22:00:00Z</updated_at>
51+
</transaction>
52+
</transactions>
53+
</charge_invoice>
54+
<credit_invoices type="array">
55+
</credit_invoices>
56+
</invoice_collection>

Test/InvoiceTest.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.Linq;
3+
using System.Xml;
34
using FluentAssertions;
5+
using Recurly.Test.Fixtures;
46
using Xunit;
57

68
namespace Recurly.Test
@@ -587,5 +589,24 @@ public void CreateInvoiceWithEOMNetTerms()
587589
Assert.Equal(response.NetTerms, 45);
588590
Assert.Equal(response.NetTermsType, NetTermsType.EOM);
589591
}
592+
593+
[RecurlyFact(TestEnvironment.Type.Unit)]
594+
public void InvoiceWithVertexTransactionType()
595+
{
596+
var invoice = new Invoice
597+
{
598+
VertexTransactionType = "lease"
599+
};
600+
601+
// Verify the request serializes vertex_transaction_type correctly (create only, not update)
602+
var xmlOutput = new System.Text.StringBuilder();
603+
using (var xmlWriter = new XmlTextWriter(new System.IO.StringWriter(xmlOutput)))
604+
{
605+
invoice.WriteXml(xmlWriter);
606+
}
607+
var xml = xmlOutput.ToString();
608+
Assert.Contains("<vertex_transaction_type>lease</vertex_transaction_type>", xml);
609+
}
590610
}
591611
}
612+

Test/PurchaseTest.cs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Xml;
45
using FluentAssertions;
6+
using Recurly.Test.Fixtures;
57
using Xunit;
68

79
namespace Recurly.Test
@@ -278,5 +280,88 @@ public void PurchaseWithEOMNetTerms()
278280
Assert.Equal(response.ChargeInvoice.NetTerms, 45);
279281
response.ChargeInvoice.NetTermsType.Should().Be(NetTermsType.EOM);
280282
}
283+
284+
[RecurlyFact(TestEnvironment.Type.Unit)]
285+
public void PurchaseWithVertexTransactionType()
286+
{
287+
// Create an actual purchase with vertex_transaction_type
288+
var account = NewAccountWithBillingInfo();
289+
290+
var adjustment = account.NewAdjustment("Test Adjustment", 580);
291+
adjustment.Currency = "USD";
292+
adjustment.Quantity = 1;
293+
adjustment.UnitAmountInCents = 580;
294+
295+
var purchase = new Purchase(account.AccountCode, "USD");
296+
purchase.Account = account;
297+
purchase.VertexTransactionType = "lease";
298+
purchase.Adjustments.Add(adjustment);
299+
300+
// Verify the request serializes vertex_transaction_type correctly
301+
var xmlOutput = new System.Text.StringBuilder();
302+
using (var xmlWriter = new XmlTextWriter(new System.IO.StringWriter(xmlOutput)))
303+
{
304+
purchase.WriteXml(xmlWriter);
305+
}
306+
var xml = xmlOutput.ToString();
307+
Assert.Contains("<vertex_transaction_type>lease</vertex_transaction_type>", xml);
308+
309+
// Verify that a valid InvoiceCollection can be deserialized
310+
// (vertex_transaction_type is only sent in requests, not returned in responses)
311+
var mockResponse = GetMockInvoiceCollectionResponse();
312+
Assert.NotNull(mockResponse.ChargeInvoice);
313+
Assert.Equal(mockResponse.ChargeInvoice.State, Invoice.InvoiceState.Paid);
314+
}
315+
316+
[RecurlyFact(TestEnvironment.Type.Unit)]
317+
public void PurchaseWithAdjustmentsContainingVertexTransactionType()
318+
{
319+
// Create a purchase with adjustments that have vertex_transaction_type
320+
var account = NewAccountWithBillingInfo();
321+
322+
var adjustment1 = account.NewAdjustment("Adjustment with lease type", 580);
323+
adjustment1.Currency = "USD";
324+
adjustment1.Quantity = 1;
325+
adjustment1.VertexTransactionType = "lease";
326+
327+
var adjustment2 = account.NewAdjustment("Adjustment with rental type", 1200);
328+
adjustment2.Currency = "USD";
329+
adjustment2.Quantity = 2;
330+
adjustment2.UnitAmountInCents = 600;
331+
adjustment2.VertexTransactionType = "rental";
332+
333+
var purchase = new Purchase(account.AccountCode, "USD");
334+
purchase.Account = account;
335+
purchase.Adjustments.Add(adjustment1);
336+
purchase.Adjustments.Add(adjustment2);
337+
338+
// Verify the request serializes vertex_transaction_type correctly for each adjustment
339+
var xmlOutput = new System.Text.StringBuilder();
340+
using (var xmlWriter = new XmlTextWriter(new System.IO.StringWriter(xmlOutput)))
341+
{
342+
purchase.WriteXml(xmlWriter);
343+
}
344+
var xml = xmlOutput.ToString();
345+
346+
// Should contain vertex_transaction_type for both adjustments
347+
Assert.Contains("<vertex_transaction_type>lease</vertex_transaction_type>", xml);
348+
Assert.Contains("<vertex_transaction_type>rental</vertex_transaction_type>", xml);
349+
350+
// Verify both adjustments are in the XML with their properties
351+
Assert.Contains("<unit_amount_in_cents>580</unit_amount_in_cents>", xml);
352+
Assert.Contains("<unit_amount_in_cents>600</unit_amount_in_cents>", xml);
353+
}
354+
355+
private InvoiceCollection GetMockInvoiceCollectionResponse()
356+
{
357+
// Mock the Purchase.Invoice response using a fixture
358+
var collection = new InvoiceCollection();
359+
var xmlFixture = FixtureImporter.Get(FixtureType.Purchases, "invoice-with-vertex-201").Xml;
360+
using (var reader = new XmlTextReader(new System.IO.StringReader(xmlFixture)))
361+
{
362+
collection.ReadXml(reader);
363+
}
364+
return collection;
365+
}
281366
}
282367
}

Test/Recurly.Test.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@
134134
<Content Include="Fixtures\adjustments\show-404.xml">
135135
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
136136
</Content>
137+
<Content Include="Fixtures\adjustments\show-with-vertex-200.xml">
138+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
139+
</Content>
137140
<Content Include="Fixtures\billinginfo\destroy-204.xml">
138141
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
139142
</Content>
@@ -224,6 +227,9 @@
224227
<Content Include="Fixtures\plans\show-200.xml">
225228
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
226229
</Content>
230+
<Content Include="Fixtures\purchases\invoice-with-vertex-201.xml">
231+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
232+
</Content>
227233
<Content Include="Fixtures\subscriptions\show-200-inactive.xml">
228234
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
229235
</Content>

0 commit comments

Comments
 (0)