diff --git a/Avalara.AvaTax.RestClient.sln b/Avalara.AvaTax.RestClient.sln
new file mode 100644
index 0000000..5cc2f5c
--- /dev/null
+++ b/Avalara.AvaTax.RestClient.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.10.35004.147
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalara.AvaTax.RestClient", "src\Avalara.AvaTax.RestClient.csproj", "{F0EEC671-76CD-47C3-8671-FA178139B2A9}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalara.AvaTax.RestClient.Tests", "tests\Avalara.AvaTax.RestClient.Tests.csproj", "{88267F39-00E4-4D70-8E76-EA601E43CCA0}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F0EEC671-76CD-47C3-8671-FA178139B2A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F0EEC671-76CD-47C3-8671-FA178139B2A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F0EEC671-76CD-47C3-8671-FA178139B2A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F0EEC671-76CD-47C3-8671-FA178139B2A9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {88267F39-00E4-4D70-8E76-EA601E43CCA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {88267F39-00E4-4D70-8E76-EA601E43CCA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {88267F39-00E4-4D70-8E76-EA601E43CCA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {88267F39-00E4-4D70-8E76-EA601E43CCA0}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {EF80143E-E986-4C4B-9401-395AF44EF2FE}
+ EndGlobalSection
+EndGlobal
diff --git a/src/AvaTaxOfflineHelper.cs b/src/AvaTaxOfflineHelper.cs
index 14f2806..42d1f1b 100644
--- a/src/AvaTaxOfflineHelper.cs
+++ b/src/AvaTaxOfflineHelper.cs
@@ -145,7 +145,8 @@ private static void WriteZipRateFile(TaxRateModel zipRate, string zip, string pa
TextWriter writer = null;
try {
- Directory.GetAccessControl(path);
+ DirectoryInfo directory = new DirectoryInfo(path);
+ directory.GetAccessControl();
var content = JsonConvert.SerializeObject(zipRate);
writer = new StreamWriter(Path.Combine(path, zip + ".json"));
writer.Write(content);
diff --git a/src/Avalara.AvaTax.RestClient.csproj b/src/Avalara.AvaTax.RestClient.csproj
index 8a8c95c..ef9e425 100644
--- a/src/Avalara.AvaTax.RestClient.csproj
+++ b/src/Avalara.AvaTax.RestClient.csproj
@@ -1,12 +1,14 @@
- net20;net45;net461;net472;netstandard1.6;netstandard2.0
false
+ net20;net45;net461;net472;netstandard1.6;netstandard2.0;net6.0;net8.0
false
true
Avalara.AvaTax.RestClient.snk
+
+
NETFRAMEWORK;TRACE;DEBUG;NET20
false
@@ -15,8 +17,9 @@
NETFRAMEWORK;TRACE;RELEASE;NET20
true
-
-
+
+
+
NETFRAMEWORK;TRACE;DEBUG;PORTABLE;NET45
false
@@ -25,8 +28,9 @@
NETFRAMEWORK;TRACE;RELEASE;PORTABLE;NET45
true
+
-
+
NETFRAMEWORK;TRACE;DEBUG;PORTABLE;NET461
true
@@ -35,80 +39,85 @@
NETFRAMEWORK;TRACE;RELEASE;PORTABLE;NET461
true
+
-
+
NETFRAMEWORK;TRACE;DEBUG;PORTABLE;NET472
true
-
NETFRAMEWORK;TRACE;RELEASE;PORTABLE;NET472
true
-
+
+
+
TRACE;DEBUG;PORTABLE;NETSTANDARD1_6
true
-
TRACE;RELEASE;PORTABLE;NETSTANDARD1_6
true
+
-
+
+
TRACE;DEBUG;PORTABLE;NETSTANDARD2_0
true
-
-
+
TRACE;RELEASE;PORTABLE;NETSTANDARD2_0
true
+
+
+ TRACE;DEBUG;PORTABLE;NET6_0
+ true
+
+
+ TRACE;RELEASE;PORTABLE;NET6_0
+ true
+
+
+
+
+
+ TRACE;DEBUG;PORTABLE;NET8_0
+ true
+
+
+ TRACE;RELEASE;PORTABLE;NET8_0
+ true
+
+
+
-
+
+
-
-
-
- Properties\GlobalAssemblyInfo.cs
-
-
-
-
-
-
- Properties\GlobalAssemblyInfo.cs
-
-
-
-
-
-
- Properties\GlobalAssemblyInfo.cs
-
-
-
-
-
-
- Properties\GlobalAssemblyInfo.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ Properties\GlobalAssemblyInfo.cs
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Avalara.AvaTax.RestClient.Test.csproj b/tests/Avalara.AvaTax.RestClient.Test.csproj
index 1864a8a..3f0176b 100644
--- a/tests/Avalara.AvaTax.RestClient.Test.csproj
+++ b/tests/Avalara.AvaTax.RestClient.Test.csproj
@@ -1,88 +1,79 @@
- net451;net45;net461;net472;netcoreapp2.2;netcoreapp3.1
+ net451;net45;net461;net472;netcoreapp2.2.8;netcoreapp3.1;net6.0;net8.0
false
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
-
-
+
+
+
+
+
+
+
TargetFramework=net20
+
+
-
-
-
-
-
TargetFramework=net45
+
+
-
-
-
-
-
TargetFramework=net461
+
+
-
-
-
-
-
TargetFramework=net472
-
-
-
-
-
-
+
+
+
TargetFramework=netstandard1.6
+
+
-
-
-
-
-
TargetFramework=netstandard2.0
+
+
+
+
+
+ TargetFramework=net6.0
+
+
+
+
+
+
+
+ TargetFramework=net6.0
+
+
\ No newline at end of file
diff --git a/tests/net6.0/BatchTests.cs b/tests/net6.0/BatchTests.cs
new file mode 100644
index 0000000..dceff99
--- /dev/null
+++ b/tests/net6.0/BatchTests.cs
@@ -0,0 +1,198 @@
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Avalara.AvaTax.RestClient.Test.net60
+{
+ [TestFixture]
+ public class BatchTests
+ {
+ public AvaTaxClient Client { get; set; }
+ public string CompanyCode { get; set; }
+ public CompanyModel TestCompany { get; set; }
+
+ #region Setup / TearDown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try
+ {
+ // Create a client and set up authentication
+ Client = new AvaTaxClient(typeof(TransactionTests).Name,
+ typeof(TransactionTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = Client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ // Create a basic company with nexus in the state of Washington
+ TestCompany = Client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = Guid.NewGuid().ToString("N").Substring(0, 25),
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Hardware Store",
+ title = "Owner/CEO"
+ });
+
+ // Add a delay after creating a company
+ System.Threading.Thread.Sleep(6 * 1000);
+
+ // Assert that company setup succeeded
+ Assert.NotNull(TestCompany, "Test company should be created");
+ Assert.True(TestCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(TestCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try
+ {
+ // Re-fetch the company
+ var company = Client.GetCompany(TestCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = Client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in TearDown: " + ex);
+ }
+ }
+ #endregion
+
+ ///
+ ///
+ ///
+ [Test]
+ public async Task BatchesWorkflow()
+ {
+ // Raw batch CSV string.
+ const string transactionImport = @"ProcessCode,DocCode,DocType,DocDate,CompanyCode,CustomerCode,EntityUseCode,LineNo,TaxCode,TaxDate,ItemCode,Description,Qty,Amount,Discount,Ref1,Ref2,ExemptionNo,RevAcct,DestAddress,DestCity,DestRegion,DestPostalCode,DestCountry,OrigAddress,OrigCity,OrigRegion,OrigPostalCode,OrigCountry,LocationCode,SalesPersonCode,PurchaseOrderNo,CurrencyCode,ExchangeRate,ExchangeRateEffDate,PaymentDate,TaxIncluded,DestTaxRegion,OrigTaxRegion,Taxable,TaxType,TotalTax,CountryName,CountryCode,CountryRate,CountryTax,StateName,StateCode,StateRate,StateTax,CountyName,CountyCode,CountyRate,CountyTax,CityName,CityCode,CityRate,CityTax,Other1Name,Other1Code,Other1Rate,Other1Tax,Other2Name,Other2Code,Other2Rate,Other2Tax,Other3Name,Other3Code,Other3Rate,Other3Tax,Other4Name,Other4Code,Other4Rate,Other4Tax,ReferenceCode,BuyersVATNo
+3,BS1323154187029MG10,2,16-Apr-14,,029MG10,,0000000001,SR060100,06-May-14,6500,REPAIRS & MAINTENANCE,,1980,,,0,,6500,119 N. 72nd St.,Omaha,NE,68114,,6923 MAPLE ST,OMAHA,NE,68104,,029,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS1323158772194036MAC1,2,04-Apr-14,,036MAC1,,0000000001,SC150158,06-May-14,6505,R&M HEAT / VENT / AIR COND,,322.26,,,0,,6505,1200 E. Mall Drive,Holland,OH,43528,,2875 CRANE WAY,NORTHWOOD,OH,43619,,036,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS1323159W206409036MLK,2,25-Mar-14,,036MLK,,0000000001,SR060100,06-May-14,6507,R&M OTHER,,449,,,31.43,,6507,1200 E. Mall Drive,Holland,OH,43528,,1214 JEFFERSON AVE,TOLEDO,OH,43604,,036,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231601596048MRP2,2,02-May-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,60,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231631591048MRP2,2,02-May-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,58,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231611594048MRP2,2,01-May-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,65,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231621593048MRP2,2,01-May-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,75,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231641587048MRP2,2,01-May-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,60,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231651582048MRP2,2,15-Mar-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,47,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,";
+
+ // Let's Create the file portion of the batch request.
+ var batchFileModel = new BatchFileModel
+ {
+ name = "TransactionImport.csv",
+ content = Encoding.UTF8.GetBytes(transactionImport),
+ contentType = "text/csv",
+ fileExtension = "csv"
+ };
+
+ // Create the bare-minimum batch header info.
+ var batchRequest = new BatchModel
+ {
+ name = "AutomationTestBatch",
+ type = BatchType.TransactionImport,
+ files = new List { batchFileModel }
+ };
+
+ // Send the batch!
+ try
+ {
+ var batchResult = Client.CreateBatches(TestCompany.id, new List { batchRequest });
+ Assert.NotNull(batchResult, "Batch not sent.");
+ Assert.True(batchResult.Count > 0, "No batches created.");
+
+ // Check that the batch comes out of Waiting state using a linear backoff strategy.
+ var waiting = true;
+ BatchModel batchFetchResult = null;
+ for (var i = 1; i < 6; ++i)
+ {
+ await Task.Delay(i * 1000);
+
+ batchFetchResult = Client.GetBatch(TestCompany.id, batchResult[0].id.Value);
+ Assert.NotNull(batchFetchResult, "Batch fetch unsuccessful.");
+ if (batchFetchResult.status.Value == BatchStatus.Waiting) continue;
+ waiting = false;
+ break;
+ }
+ Assert.True(waiting == false, $"Batch waiting too long. Check BatchId: {batchResult[0].id}");
+
+ // This batch is no longer in the Waiting state. Let's see it process.
+ var processing = true;
+ for (var i = 1; i < 11; ++i)
+ {
+ await Task.Delay(i * 1000);
+
+ batchFetchResult = Client.GetBatch(TestCompany.id, batchResult[0].id.Value);
+ Assert.NotNull(batchFetchResult, "Batch fetch unsuccessful.");
+ if (batchFetchResult.status.Value == BatchStatus.Processing) continue;
+ processing = false;
+ break;
+ }
+ Assert.True(processing == false, $"Batch processing too long. Check BatchId: {batchResult[0].id}");
+
+ // This batch is done processing.
+ Assert.True((batchFetchResult.status.Value == BatchStatus.Errors || batchFetchResult.status.Value == BatchStatus.Completed),
+ $"BatchId: {batchResult[0].id} should either complete or error out.");
+ // Ensure that the number of records matches what we sent in.
+ Assert.AreEqual(9, batchFetchResult.currentRecord.Value);
+
+ // Alright. Time to download the sent batch file.
+ var fileResult = Client.DownloadBatch(TestCompany.id, batchFetchResult.id.Value, batchFetchResult.files[0].id.Value);
+ Assert.NotNull(fileResult);
+
+ // Compare what we got back with what we sent.
+ Assert.AreEqual(batchFetchResult.name + ".Input.CSV; filename*=UTF-8''" + batchFetchResult.name + ".Input.CSV", fileResult.Filename);
+ Assert.AreEqual(batchFileModel.content, fileResult.Data);
+ Assert.AreEqual(batchFileModel.contentType, fileResult.ContentType);
+ } catch (AvaTaxError e)
+ {
+ Assert.True(false, $"AvaTaxError: {e.error.error.details?[0].message}");
+ } catch (Exception e)
+ {
+ Assert.True(false, $"Unknown Exception! {e.Message}");
+ }
+ }
+ }
+}
diff --git a/tests/net6.0/CertificateTests.cs b/tests/net6.0/CertificateTests.cs
new file mode 100644
index 0000000..be1739f
--- /dev/null
+++ b/tests/net6.0/CertificateTests.cs
@@ -0,0 +1,144 @@
+using Avalara.AvaTax.RestClient;
+using Newtonsoft.Json;
+using NUnit.Framework;
+using System;
+using System.IO;
+using System.Net;
+using System.Reflection;
+
+namespace Avalara.AvaTax.RestClient.Test.net60
+{
+ [TestFixture]
+ public class CertificateTests
+ {
+ public AvaTaxClient Client { get; set; }
+ public string CompanyCode { get; set; }
+ public int DefaultCompanyId { get; set; }
+ public CompanyModel TestCompany { get; set; }
+
+ #region Setup / TearDown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try {
+ // Create a client and set up authentication
+ Client = new AvaTaxClient(typeof(CertificateTests).Name,
+ typeof(CertificateTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = Client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ //Get the default company.
+ var defaultCompanyModel = Client.QueryCompanies(string.Empty, "isDefault EQ true", null, null, string.Empty).value[0];
+
+ DefaultCompanyId = defaultCompanyModel.id;
+
+ // Create a basic company with nexus in the state of Washington
+ TestCompany = Client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = Guid.NewGuid().ToString().Substring(0, 25),
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Greatest Popcorn",
+ title = "Owner/CEO"
+ });
+
+ // Add a delay
+ System.Threading.Thread.Sleep(6 * 1000);
+
+ // Assert that company setup succeeded
+ Assert.NotNull(TestCompany, "Test company should be created");
+ Assert.True(TestCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(TestCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ } catch (Exception ex) {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try {
+
+ // Re-fetch the company
+ var company = Client.GetCompany(TestCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = Client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ } catch (Exception ex) {
+ Assert.Fail("Exception in TearDown: " + ex);
+ }
+ }
+ #endregion
+
+ ///
+ /// Tests the upload certificate image endpoint.
+ ///
+ [Test]
+ [Ignore("Ignore CertificateImageUploadTest")]
+ public void CertificateImageUploadTest()
+ {
+ //Get the cert number. The account needs to have CertCapture
+ //be provisioned, already have a certificate created, and the
+ //certificate needs to be valid.
+ var certs = Client.QueryCertificates(DefaultCompanyId, string.Empty, "valid EQ true", null, null, string.Empty).value;
+ var certId = certs[0].id.Value;
+
+ //Get an image.
+ byte[] jpegByteArr = File.ReadAllBytes(Environment.GetEnvironmentVariable("TEST_IMAGE_PATH"));
+
+ FileResult fileResult = new FileResult()
+ {
+ ContentType = "multipart/form-data",
+ Filename = "test_cert_image.jpg",
+ Data = jpegByteArr
+ };
+
+ //Send request.
+ var certUploadResult = Client.UploadCertificateImage(DefaultCompanyId, certId, fileResult);
+
+ //Response should be "OK"
+ Assert.True(string.Equals(certUploadResult, "\"OK\""));
+
+ //Test download of image attachment.
+ var certAttachment = Client.DownloadCertificateImage(DefaultCompanyId, certId, null, CertificatePreviewType.Pdf);
+ Assert.NotNull(certAttachment);
+ Assert.True(string.Equals(certAttachment.ContentType, "application/pdf"));
+ Assert.True(certAttachment.Data.Length > 1000);
+
+ }
+ }
+}
diff --git a/tests/net6.0/ErrorResultTests.cs b/tests/net6.0/ErrorResultTests.cs
new file mode 100644
index 0000000..6626028
--- /dev/null
+++ b/tests/net6.0/ErrorResultTests.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+
+namespace Avalara.AvaTax.RestClient.Test.net60
+{
+ [TestFixture]
+ public class ErrorResultTests : TestBase
+ {
+ [Test]
+ public async Task NonJsonErrorResult()
+ {
+ AvaTaxError avataxError = null;
+ try
+ {
+ // make a client that points to a server that will give a 404 for ping
+ var client = new AvaTaxClient(GetType().Name,
+ GetType().GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName, new Uri("https://www.google.com"));
+
+ var result = await client.PingAsync().ConfigureAwait(false);
+ }
+ catch (AvaTaxError e)
+ {
+ avataxError = e;
+ }
+
+ Assert.NotNull(avataxError);
+ Assert.True(avataxError.error.error.message.Contains("the response is in an unexpected format"));
+ Assert.True(avataxError.error.error.details[0].description.ToLower().Contains("not found"));
+ }
+
+ [Test]
+ public async Task JsonErrorResult()
+ {
+ AvaTaxError avataxError = null;
+ try
+ {
+ var result = await _client.ChangePasswordAsync(new PasswordChangeModel
+ {
+ }).ConfigureAwait(false);
+ }
+ catch (AvaTaxError e)
+ {
+ avataxError = e;
+ }
+
+ Assert.NotNull(avataxError);
+ Assert.True(avataxError.error.error.message.Contains("Field oldPassword is required"));
+ }
+ }
+}
diff --git a/tests/net6.0/FreeTaxRatesTest.cs b/tests/net6.0/FreeTaxRatesTest.cs
new file mode 100644
index 0000000..1b0ff67
--- /dev/null
+++ b/tests/net6.0/FreeTaxRatesTest.cs
@@ -0,0 +1,97 @@
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalara.AvaTax.RestClient.Test.net60
+{
+ [TestFixture]
+ class FreeTaxRatesTest
+ {
+ public AvaTaxClient _client;
+
+ #region Setup / Teardown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try {
+ // Create a client and set up authentication
+ _client = new AvaTaxClient(typeof(TransactionTests).Name,
+ typeof(TransactionTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+ } catch (Exception ex) {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+ #endregion
+
+ [Test]
+ public async Task FreeTaxRates()
+ {
+ // Call TaxRates for a few addresses and verify that the rates are nonzero
+ var tr = await _client.TaxRatesByAddressAsync("123 Main Street", null, null, "Irvine", "CA", "92615", "US");
+ Assert.NotNull(tr);
+ Assert.True(tr.totalRate > 0.05m);
+
+ // Washington
+ tr = await _client.TaxRatesByAddressAsync("522 Stadium Pl S", null, null, "Seattle", "WA", "98104", "US");
+ Assert.NotNull(tr);
+ Assert.True(tr.totalRate > 0.05m);
+
+ // By postal code for New York
+ tr = await _client.TaxRatesByPostalCodeAsync("US", "10010");
+ Assert.NotNull(tr);
+ Assert.True(tr.totalRate > 0.05m);
+ }
+
+ ///
+ /// Test the local rate by ZIP storage and retrieval.
+ ///
+ [Test]
+ [Ignore("This test will fail in Travis")]
+ public void StoreRatesByZipTest()
+ {
+ string path = Environment.GetEnvironmentVariable("ZIP_RATE_FILE_STORAGE_PATH");
+ List zips = new List() { "12590", "98104" };
+
+ //Call the content caching helper.
+ AvaTaxOfflineHelper.StoreZipRateContent(_client, "US", zips, path);
+
+ //Verify that the files were stored locally.
+ bool zipRateExists = AvaTaxOfflineHelper.VerifyLocalZipRateAvailable(zips[0], path);
+ Assert.True(zipRateExists);
+ zipRateExists = AvaTaxOfflineHelper.VerifyLocalZipRateAvailable(zips[1], path);
+ Assert.True(zipRateExists);
+
+ //Verify that a bogus file does not exist locally.
+ zipRateExists = AvaTaxOfflineHelper.VerifyLocalZipRateAvailable("bogusZipFile.json", path);
+ Assert.False(zipRateExists);
+
+ //Verify that the local file can be used for rate calculation.
+ var zipTaxRate = AvaTaxOfflineHelper.GetLocalTaxRateByZip(zips[1], path);
+ Assert.NotNull(zipTaxRate);
+ decimal result = 9.99m * zipTaxRate.totalRate.Value;
+ Assert.NotZero(result);
+
+ //Test AvaTaxOfflineHelper Exception handling.
+ path = @"n:\someBadPath";
+ try {
+ AvaTaxOfflineHelper.StoreZipRateContent(_client, "US", zips, path);
+ } catch (AvaTaxOfflineHelperException exc) {
+#if PORTABLE
+ Assert.True(string.Equals(exc.InnerException.Message, "Could not find a part of the path 'n:\\someBadPath\\12590.json'."));
+#else
+ Assert.True(string.Equals(exc.Message, "An error occurred retrieving or storing the rate content. Please see inner exception for details."));
+#endif
+ }
+ }
+ }
+}
diff --git a/tests/net6.0/HttpClientTransactionTests.cs b/tests/net6.0/HttpClientTransactionTests.cs
new file mode 100644
index 0000000..80af650
--- /dev/null
+++ b/tests/net6.0/HttpClientTransactionTests.cs
@@ -0,0 +1,204 @@
+using Avalara.AvaTax.RestClient;
+using Newtonsoft.Json;
+using NUnit.Framework;
+using System;
+using System.Net;
+using System.Reflection;
+
+namespace Avalara.AvaTax.RestClient.Test.net60
+{
+ [TestFixture]
+ public class HttpClientTransactionTests
+ {
+ public AvaTaxClient Client { get; set; }
+ public string CompanyCode { get; set; }
+ public CompanyModel TestCompany { get; set; }
+
+ #region Setup / TearDown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try
+ {
+ var httpClient = new System.Net.Http.HttpClient() { Timeout = TimeSpan.FromMinutes(20) };
+ // Create a client and set up authentication
+ Client = new AvaTaxClient(httpClient, typeof(HttpClientTransactionTests).Name,
+ typeof(HttpClientTransactionTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = Client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ // Create a basic company with nexus in the state of Washington
+ TestCompany = Client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = Guid.NewGuid().ToString().Substring(0, 25),
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Greatest Popcorn",
+ title = "Owner/CEO"
+ });
+
+ // Add a delay
+ System.Threading.Thread.Sleep(6 * 1000);
+
+ // Assert that company setup succeeded
+ Assert.NotNull(TestCompany, "Test company should be created");
+ Assert.True(TestCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(TestCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try
+ {
+
+ // Re-fetch the company
+ var company = Client.GetCompany(TestCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = Client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in TearDown: " + ex);
+ }
+ }
+ #endregion
+
+ ///
+ /// To debug this application, call app must be called with args[0] as username and args[1] as password
+ ///
+ [Test]
+ public void TransactionWorkflow()
+ {
+ Client.CallCompleted += Client_CallCompleted;
+ var tfn = System.IO.Path.GetTempFileName();
+ Client.LogToFile(tfn);
+
+ // Execute a transaction
+ var transaction = new TransactionBuilder(Client, TestCompany.companyCode, DocumentType.SalesInvoice, "ABC")
+ .WithAddress(TransactionAddressType.SingleLocation, "521 S Weller St", null, null, "Seattle", "WA",
+ "98104", "US")
+ .WithLine(100.0m, 1, "P0000000")
+ .WithLine(200m)
+ .WithExemptLine(50m, "NT")
+ .WithLineReference("Special Line Reference!", "Also this!")
+ .Create();
+
+ // Verify that the call was captured and logged
+ Assert.NotNull(lastEvent);
+ Assert.True(String.Equals(lastEvent.HttpVerb, "POST", StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(String.Equals(lastEvent.RequestUri.ToString(), "https://sandbox-rest.avatax.com/api/v2/transactions/create", StringComparison.CurrentCultureIgnoreCase));
+ Assert.AreEqual(lastEvent.Code, HttpStatusCode.Created);
+
+ // Verify that the log file was created
+ Assert.True(System.IO.File.Exists(tfn));
+
+ // Ensure this transaction was created, and has three lines, and has some tax
+ Assert.NotNull(transaction, "Transaction should have been created");
+ Assert.True(transaction.totalTax > 0.0m, "Transaction should have had some tax");
+ Assert.True(transaction.lines.Count == 3, "Transaction should have three lines");
+ Assert.True(transaction.lines[2].ref1.Contains("Reference!"), "Line3 should have had a Ref1.");
+
+ // Now commit that transaction
+ var commitResult = Client.CommitTransaction(TestCompany.companyCode, transaction.code, null, null, new CommitTransactionModel() { commit = true });
+
+ // Ensure that this transaction was committed
+ Assert.NotNull(commitResult, "Should have been able to call CommitTransaction");
+ Assert.True(commitResult.status == DocumentStatus.Committed, "Transaction should have been committed");
+
+ // Now void the transaction
+ var voidResult = Client.VoidTransaction(TestCompany.companyCode, transaction.code, null, null, new VoidTransactionModel()
+ {
+ code = VoidReasonCode.DocVoided
+ });
+
+ // Ensure that the transaction was voided
+ Assert.NotNull(voidResult, "Should have been able to call VoidTransactoin");
+ Assert.True(voidResult.status == DocumentStatus.Cancelled, "Transaction should have been voided");
+ }
+
+ private AvaTaxCallEventArgs lastEvent = null;
+ private void Client_CallCompleted(object sender, EventArgs e)
+ {
+ lastEvent = e as AvaTaxCallEventArgs;
+ }
+
+ [Test]
+
+ public void TaxOverrideExample()
+ {
+ // Create base transaction.
+ var builder = new TransactionBuilder(Client, TestCompany.companyCode, DocumentType.SalesInvoice,
+ "TaxOverrideCustomerCode")
+ .WithAddress(TransactionAddressType.SingleLocation, "521 S Weller St", null, null, "Seattle", "WA",
+ "98104", "US")
+ .WithLine(100.0m, 1, "P0000000")
+ .WithLine(200m);
+
+ var transaction = builder.Create();
+
+ // Ensure this transaction was created.
+ Assert.NotNull(transaction, "Transaction should have been created");
+
+ // Add Line-level TaxOverride.
+ var overrideTransaction = builder
+ .WithLineTaxOverride(TaxOverrideType.TaxAmount, "Tax Override Reason", 1)
+ .Create();
+
+ // Ensure this transaction was created.
+ Assert.NotNull(overrideTransaction, "Transaction should have been created");
+
+ // Compare the two transactions.
+ Assert.AreEqual(overrideTransaction.totalTaxCalculated, transaction.totalTaxCalculated, "Total Tax Calculated should be the same.");
+ Assert.True(overrideTransaction.totalTax < transaction.totalTax, "Total Tax should not be the same. Overridden transaction should be smaller.");
+
+ // Compare the transaction lines.
+ var overrideLine = overrideTransaction.lines[1];
+ var line = transaction.lines[1];
+ Assert.AreEqual(overrideLine.isItemTaxable, line.isItemTaxable);
+ Assert.AreEqual(overrideLine.taxCalculated, line.taxCalculated);
+ Assert.AreEqual(overrideLine.lineAmount, line.lineAmount);
+ Assert.AreEqual(1, overrideLine.tax);
+ Assert.True(overrideLine.tax < line.tax);
+ Assert.AreEqual(TaxOverrideType.TaxAmount, overrideLine.taxOverrideType);
+ }
+ }
+}
diff --git a/tests/net6.0/NexusTests.cs b/tests/net6.0/NexusTests.cs
new file mode 100644
index 0000000..39e3c81
--- /dev/null
+++ b/tests/net6.0/NexusTests.cs
@@ -0,0 +1,169 @@
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace Avalara.AvaTax.RestClient.Test.net60
+{
+ [TestFixture]
+ [Ignore("This test is not yet implemented")]
+ public class NexusTests
+ {
+ public AvaTaxClient Client { get; set; }
+ public string CompanyCode { get; set; }
+ public CompanyModel TestCompany { get; set; }
+
+ #region Setup / TearDown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try {
+ // Create a client and set up authentication
+ Client = new AvaTaxClient(typeof(TransactionTests).Name,
+ typeof(TransactionTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = Client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ // Create a basic company with nexus in the state of Washington
+ TestCompany = Client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = Guid.NewGuid().ToString().Substring(0, 25),
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Greatest Popcorn",
+ title = "Owner/CEO"
+ });
+
+ // Assert that company setup succeeded
+ Assert.NotNull(TestCompany, "Test company should be created");
+ Assert.True(TestCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(TestCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ } catch (Exception ex) {
+ Assert.Fail("Exception in SetUp: " + ex.ToString());
+ }
+ }
+
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try {
+
+ // Re-fetch the company
+ var company = Client.GetCompany(TestCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = Client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ } catch (Exception ex) {
+ Assert.Fail("Exception in TearDown: " + ex.ToString());
+ }
+ }
+ #endregion
+
+ [Test]
+ public void CreateAndDeleteNexus()
+ {
+ var nexusModels = new List();
+
+ var stateNexus = new NexusModel
+ {
+ id = 0,
+ companyId = TestCompany.id,
+ country = "US",
+ region = "AL",
+ jurisTypeId = JurisTypeId.STA,
+ jurisCode = "01",
+ jurisName = "ALABAMA",
+ shortName = "AL",
+ signatureCode = "",
+ stateAssignedNo = "",
+ nexusTypeId = NexusTypeId.SalesOrSellersUseTax,
+ hasLocalNexus = true,
+ hasPermanentEstablishment = true,
+ effectiveDate = new DateTime(2008, 07, 01),
+ endDate = new DateTime(2019, 07, 01)
+ };
+
+ var cityNexus = new NexusModel
+ {
+ id = 0,
+ companyId = TestCompany.id,
+ country = "US",
+ region = "AL",
+ jurisTypeId = JurisTypeId.CIT,
+ jurisCode = "00124",
+ jurisName = "ABBEVILLE",
+ shortName = "ABBEVILLE",
+ signatureCode = "",
+ stateAssignedNo = "9356",
+ nexusTypeId = NexusTypeId.SalesTax,
+ hasLocalNexus = true,
+ hasPermanentEstablishment = false,
+ effectiveDate = new DateTime(2008, 07, 01),
+ endDate = new DateTime(2018, 07, 01)
+ };
+
+ nexusModels.Add(stateNexus);
+ nexusModels.Add(cityNexus);
+
+ var nexusModelsAdded = Client.CreateNexus(TestCompany.id, new List { stateNexus, cityNexus });
+
+ // Get State nexus
+ NexusModel getALNexus = null;
+ try {
+ getALNexus = Client.GetNexus(TestCompany.id, nexusModelsAdded[0].id.Value, null);
+ } catch (Exception) { }
+ Assert.NotNull(getALNexus);
+
+ var fetchedUSNexus = new List { getALNexus };
+
+ // Get City Nexus
+ NexusModel getCityNexus = null;
+ try {
+ getCityNexus = Client.GetNexus(TestCompany.id, nexusModelsAdded[1].id.Value, null);
+ } catch (Exception) { }
+ Assert.NotNull(getALNexus);
+
+ fetchedUSNexus.Add(getCityNexus);
+
+ // Delete Nexus
+ var errorResult = Client.DeleteNexus(TestCompany.id, nexusModelsAdded[1].id.Value, null);
+ Assert.NotNull(errorResult);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/net6.0/SetUpFixture.cs b/tests/net6.0/SetUpFixture.cs
new file mode 100644
index 0000000..0f5ddb7
--- /dev/null
+++ b/tests/net6.0/SetUpFixture.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Versioning;
+using System.Text;
+using System.Threading.Tasks;
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+
+namespace Avalara.AvaTax.RestClient.Test.net60
+{
+ [SetUpFixture]
+ public class SetUpFixture
+ {
+ [OneTimeSetUp]
+ public void RunBeforeAnyTests()
+ {
+ var stringBuilder = new StringBuilder();
+
+ stringBuilder
+ .AppendLine($"Hosting Framework Runtime Version: {GetRuntimeFrameworkVersion(GetType().Assembly)}")
+ .AppendLine($"Hosting Framework Version: {GetFrameworkVersion(GetType().Assembly)}")
+ .AppendLine($"Target Framework Runtime Version: {GetRuntimeFrameworkVersion(typeof(AvaTaxClient).Assembly)}")
+ .AppendLine($"Target Framework Version: {GetFrameworkVersion(typeof(AvaTaxClient).Assembly)}");
+
+ TestContext.Progress.WriteLine(stringBuilder);
+ }
+
+ private static string GetRuntimeFrameworkVersion(Assembly assembly)
+ {
+ var imageRuntimeVersion = assembly
+ .ImageRuntimeVersion;
+
+ return imageRuntimeVersion;
+ }
+
+ private static string GetFrameworkVersion(Assembly assembly)
+ {
+ var targetFrameAttribute = assembly.GetCustomAttributes(true)
+ .OfType().FirstOrDefault();
+ if (targetFrameAttribute == null)
+ {
+ return ".NET 2, 3 or 3.5";
+ }
+
+ return targetFrameAttribute.FrameworkName;
+ }
+ }
+}
diff --git a/tests/net6.0/TestBase.cs b/tests/net6.0/TestBase.cs
new file mode 100644
index 0000000..2c50898
--- /dev/null
+++ b/tests/net6.0/TestBase.cs
@@ -0,0 +1,103 @@
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+namespace Avalara.AvaTax.RestClient.Test.net60
+{
+ public class TestBase
+ {
+ protected AvaTaxClient _client;
+ protected string _companyCode;
+ protected CompanyModel _testCompany;
+
+ [SetUp]
+ public void Setup()
+ {
+ _client = null;
+ _testCompany = null;
+ try
+ {
+ // Create a client and set up authentication
+ _client = new AvaTaxClient(GetType().Name,
+ GetType().GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = _client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ _companyCode = Guid.NewGuid().ToString("N").Substring(0, 25);
+ // Create a basic company with nexus in the state of Washington
+ _testCompany = _client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = _companyCode,
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Hardware Store",
+ title = "Owner/CEO"
+ });
+
+ // Add a delay after creating a company
+ System.Threading.Thread.Sleep(6 * 1000);
+
+ // Assert that company setup succeeded
+ Assert.NotNull(_testCompany, "Test company should be created");
+ Assert.True(_testCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(_testCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try
+ {
+ // Re-fetch the company
+ var company = _client.GetCompany(_testCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = _client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail("Exception in TearDown: " + ex);
+ }
+ }
+ }
+}
diff --git a/tests/net6.0/TransactionTests.cs b/tests/net6.0/TransactionTests.cs
new file mode 100644
index 0000000..36a0e94
--- /dev/null
+++ b/tests/net6.0/TransactionTests.cs
@@ -0,0 +1,211 @@
+using Avalara.AvaTax.RestClient;
+using Newtonsoft.Json;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Reflection;
+
+namespace Avalara.AvaTax.RestClient.Test.net60
+{
+ [TestFixture]
+ public class TransactionTests
+ {
+ public AvaTaxClient Client { get; set; }
+ public string CompanyCode { get; set; }
+ public CompanyModel TestCompany { get; set; }
+
+ #region Setup / TearDown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try
+ {
+ // Create a client and set up authentication
+ Client = new AvaTaxClient(typeof(TransactionTests).Name,
+ typeof(TransactionTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = Client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ // Create a basic company with nexus in the state of Washington
+ TestCompany = Client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = Guid.NewGuid().ToString().Substring(0, 25),
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Greatest Popcorn",
+ title = "Owner/CEO"
+ });
+
+ // Add a delay
+ System.Threading.Thread.Sleep(6 * 1000);
+
+ // Assert that company setup succeeded
+ Assert.NotNull(TestCompany, "Test company should be created");
+ Assert.True(TestCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(TestCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try
+ {
+
+ // Re-fetch the company
+ var company = Client.GetCompany(TestCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = Client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in TearDown: " + ex);
+ }
+ }
+ #endregion
+
+ ///
+ /// To debug this application, call app must be called with args[0] as username and args[1] as password
+ ///
+ [Test]
+ public void TransactionWorkflow()
+ {
+ Client.CallCompleted += Client_CallCompleted;
+ var tfn = System.IO.Path.GetTempFileName();
+ Client.LogToFile(tfn);
+
+ // Execute a transaction
+ var transaction = new TransactionBuilder(Client, TestCompany.companyCode, DocumentType.SalesInvoice, "ABC")
+ .WithAddress(TransactionAddressType.SingleLocation, "521 S Weller St", null, null, "Seattle", "WA",
+ "98104", "US")
+ .WithLine(100.0m, 1, "P0000000")
+ .WithLine(200m)
+ .WithExemptLine(50m, "NT")
+ .WithLineReference("Special Line Reference!", "Also this!")
+ .Create();
+
+ // Verify that the call was captured and logged
+ Assert.NotNull(lastEvent);
+ Assert.True(String.Equals(lastEvent.HttpVerb, "POST", StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(String.Equals(lastEvent.RequestUri.ToString(), "https://sandbox-rest.avatax.com/api/v2/transactions/create", StringComparison.CurrentCultureIgnoreCase));
+ Assert.AreEqual(lastEvent.Code, HttpStatusCode.Created);
+
+ // Verify that the log file was created
+ Assert.True(System.IO.File.Exists(tfn));
+
+ // Ensure this transaction was created, and has three lines, and has some tax
+ Assert.NotNull(transaction, "Transaction should have been created");
+ Assert.True(transaction.totalTax > 0.0m, "Transaction should have had some tax");
+ Assert.True(transaction.lines.Count == 3, "Transaction should have three lines");
+ Assert.True(transaction.lines[2].ref1.Contains("Reference!"), "Line3 should have had a Ref1.");
+
+ // Now commit that transaction
+ var commitResult = Client.CommitTransaction(TestCompany.companyCode, transaction.code, null, null, new CommitTransactionModel() { commit = true });
+
+ // Ensure that this transaction was committed
+ Assert.NotNull(commitResult, "Should have been able to call CommitTransaction");
+ Assert.True(commitResult.status == DocumentStatus.Committed, "Transaction should have been committed");
+
+ // Now void the transaction
+ var voidResult = Client.VoidTransaction(TestCompany.companyCode, transaction.code, null, null, new VoidTransactionModel()
+ {
+ code = VoidReasonCode.DocVoided
+ });
+
+ // Ensure that the transaction was voided
+ Assert.NotNull(voidResult, "Should have been able to call VoidTransactoin");
+ Assert.True(voidResult.status == DocumentStatus.Cancelled, "Transaction should have been voided");
+ }
+
+ private AvaTaxCallEventArgs lastEvent = null;
+ private void Client_CallCompleted(object sender, EventArgs e)
+ {
+ lastEvent = e as AvaTaxCallEventArgs;
+ }
+ [Ignore("Ignore Override")]
+ [Test]
+ public void TaxOverrideExample()
+ {
+ // Create base transaction.
+ var builder = new TransactionBuilder(Client, TestCompany.companyCode, DocumentType.SalesInvoice,
+ "TaxOverrideCustomerCode")
+ .WithAddress(TransactionAddressType.SingleLocation, "521 S Weller St", null, null, "Seattle", "WA",
+ "98104", "US")
+ .WithLine(100.0m, 1, "P0000000")
+ .WithLine(200m);
+
+ var transaction = builder.Create();
+
+ // Ensure this transaction was created.
+ Assert.NotNull(transaction, "Transaction should have been created");
+
+ var taxOverrideList = new List();
+ var item = new TransactionLineTaxAmountByTaxTypeModel();
+ item.taxTypeId = "123";
+ item.taxAmount = 10;
+ taxOverrideList.Add(item);
+ // Add Line-level TaxOverride.
+ var overrideTransaction = builder
+ .WithLineTaxOverride(TaxOverrideType.TaxAmount, "Tax Override Reason", 1)
+ .WithLine(300m, 1)
+ .WithLineTaxOverride(TaxOverrideType.TaxAmountByTaxType, "Another reason", 10, null, taxOverrideList)
+ .Create();
+
+
+ // Ensure this transaction was created.
+ Assert.NotNull(overrideTransaction, "Transaction should have been created");
+
+ // Compare the two transactions.
+ Assert.AreEqual(overrideTransaction.totalTaxCalculated, transaction.totalTaxCalculated, "Total Tax Calculated should be the same.");
+ Assert.True(overrideTransaction.totalTax < transaction.totalTax, "Total Tax should not be the same. Overridden transaction should be smaller.");
+
+ // Compare the transaction lines.
+ var overrideLine = overrideTransaction.lines[1];
+ var line = transaction.lines[1];
+ Assert.AreEqual(overrideLine.isItemTaxable, line.isItemTaxable);
+ Assert.AreEqual(overrideLine.taxCalculated, line.taxCalculated);
+ Assert.AreEqual(overrideLine.lineAmount, line.lineAmount);
+ Assert.AreEqual(1, overrideLine.tax);
+ Assert.True(overrideLine.tax < line.tax);
+ Assert.AreEqual(TaxOverrideType.TaxAmount, overrideLine.taxOverrideType);
+ }
+ }
+}
diff --git a/tests/net8.0/BatchTests.cs b/tests/net8.0/BatchTests.cs
new file mode 100644
index 0000000..9c74c53
--- /dev/null
+++ b/tests/net8.0/BatchTests.cs
@@ -0,0 +1,198 @@
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Avalara.AvaTax.RestClient.Test.net80
+{
+ [TestFixture]
+ public class BatchTests
+ {
+ public AvaTaxClient Client { get; set; }
+ public string CompanyCode { get; set; }
+ public CompanyModel TestCompany { get; set; }
+
+ #region Setup / TearDown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try
+ {
+ // Create a client and set up authentication
+ Client = new AvaTaxClient(typeof(TransactionTests).Name,
+ typeof(TransactionTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = Client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ // Create a basic company with nexus in the state of Washington
+ TestCompany = Client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = Guid.NewGuid().ToString("N").Substring(0, 25),
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Hardware Store",
+ title = "Owner/CEO"
+ });
+
+ // Add a delay after creating a company
+ System.Threading.Thread.Sleep(6 * 1000);
+
+ // Assert that company setup succeeded
+ Assert.NotNull(TestCompany, "Test company should be created");
+ Assert.True(TestCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(TestCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try
+ {
+ // Re-fetch the company
+ var company = Client.GetCompany(TestCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = Client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in TearDown: " + ex);
+ }
+ }
+ #endregion
+
+ ///
+ ///
+ ///
+ [Test]
+ public async Task BatchesWorkflow()
+ {
+ // Raw batch CSV string.
+ const string transactionImport = @"ProcessCode,DocCode,DocType,DocDate,CompanyCode,CustomerCode,EntityUseCode,LineNo,TaxCode,TaxDate,ItemCode,Description,Qty,Amount,Discount,Ref1,Ref2,ExemptionNo,RevAcct,DestAddress,DestCity,DestRegion,DestPostalCode,DestCountry,OrigAddress,OrigCity,OrigRegion,OrigPostalCode,OrigCountry,LocationCode,SalesPersonCode,PurchaseOrderNo,CurrencyCode,ExchangeRate,ExchangeRateEffDate,PaymentDate,TaxIncluded,DestTaxRegion,OrigTaxRegion,Taxable,TaxType,TotalTax,CountryName,CountryCode,CountryRate,CountryTax,StateName,StateCode,StateRate,StateTax,CountyName,CountyCode,CountyRate,CountyTax,CityName,CityCode,CityRate,CityTax,Other1Name,Other1Code,Other1Rate,Other1Tax,Other2Name,Other2Code,Other2Rate,Other2Tax,Other3Name,Other3Code,Other3Rate,Other3Tax,Other4Name,Other4Code,Other4Rate,Other4Tax,ReferenceCode,BuyersVATNo
+3,BS1323154187029MG10,2,16-Apr-14,,029MG10,,0000000001,SR060100,06-May-14,6500,REPAIRS & MAINTENANCE,,1980,,,0,,6500,119 N. 72nd St.,Omaha,NE,68114,,6923 MAPLE ST,OMAHA,NE,68104,,029,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS1323158772194036MAC1,2,04-Apr-14,,036MAC1,,0000000001,SC150158,06-May-14,6505,R&M HEAT / VENT / AIR COND,,322.26,,,0,,6505,1200 E. Mall Drive,Holland,OH,43528,,2875 CRANE WAY,NORTHWOOD,OH,43619,,036,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS1323159W206409036MLK,2,25-Mar-14,,036MLK,,0000000001,SR060100,06-May-14,6507,R&M OTHER,,449,,,31.43,,6507,1200 E. Mall Drive,Holland,OH,43528,,1214 JEFFERSON AVE,TOLEDO,OH,43604,,036,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231601596048MRP2,2,02-May-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,60,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231631591048MRP2,2,02-May-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,58,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231611594048MRP2,2,01-May-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,65,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231621593048MRP2,2,01-May-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,75,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231641587048MRP2,2,01-May-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,60,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+3,BS13231651582048MRP2,2,15-Mar-14,,048MRP2,,0000000001,SR060100,06-May-14,6520,FURNITURE REPAIRS,,47,,,0,,6520,2201 Hwy 75 North,Sherman,TX,75090,,P.O. BOX 125,POTTSBORO,TX,75076,,048,,,USD,,,,0,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,";
+
+ // Let's Create the file portion of the batch request.
+ var batchFileModel = new BatchFileModel
+ {
+ name = "TransactionImport.csv",
+ content = Encoding.UTF8.GetBytes(transactionImport),
+ contentType = "text/csv",
+ fileExtension = "csv"
+ };
+
+ // Create the bare-minimum batch header info.
+ var batchRequest = new BatchModel
+ {
+ name = "AutomationTestBatch",
+ type = BatchType.TransactionImport,
+ files = new List { batchFileModel }
+ };
+
+ // Send the batch!
+ try
+ {
+ var batchResult = Client.CreateBatches(TestCompany.id, new List { batchRequest });
+ Assert.NotNull(batchResult, "Batch not sent.");
+ Assert.True(batchResult.Count > 0, "No batches created.");
+
+ // Check that the batch comes out of Waiting state using a linear backoff strategy.
+ var waiting = true;
+ BatchModel batchFetchResult = null;
+ for (var i = 1; i < 6; ++i)
+ {
+ await Task.Delay(i * 1000);
+
+ batchFetchResult = Client.GetBatch(TestCompany.id, batchResult[0].id.Value);
+ Assert.NotNull(batchFetchResult, "Batch fetch unsuccessful.");
+ if (batchFetchResult.status.Value == BatchStatus.Waiting) continue;
+ waiting = false;
+ break;
+ }
+ Assert.True(waiting == false, $"Batch waiting too long. Check BatchId: {batchResult[0].id}");
+
+ // This batch is no longer in the Waiting state. Let's see it process.
+ var processing = true;
+ for (var i = 1; i < 11; ++i)
+ {
+ await Task.Delay(i * 1000);
+
+ batchFetchResult = Client.GetBatch(TestCompany.id, batchResult[0].id.Value);
+ Assert.NotNull(batchFetchResult, "Batch fetch unsuccessful.");
+ if (batchFetchResult.status.Value == BatchStatus.Processing) continue;
+ processing = false;
+ break;
+ }
+ Assert.True(processing == false, $"Batch processing too long. Check BatchId: {batchResult[0].id}");
+
+ // This batch is done processing.
+ Assert.True((batchFetchResult.status.Value == BatchStatus.Errors || batchFetchResult.status.Value == BatchStatus.Completed),
+ $"BatchId: {batchResult[0].id} should either complete or error out.");
+ // Ensure that the number of records matches what we sent in.
+ Assert.AreEqual(9, batchFetchResult.currentRecord.Value);
+
+ // Alright. Time to download the sent batch file.
+ var fileResult = Client.DownloadBatch(TestCompany.id, batchFetchResult.id.Value, batchFetchResult.files[0].id.Value);
+ Assert.NotNull(fileResult);
+
+ // Compare what we got back with what we sent.
+ Assert.AreEqual(batchFetchResult.name + ".Input.CSV; filename*=UTF-8''" + batchFetchResult.name + ".Input.CSV", fileResult.Filename);
+ Assert.AreEqual(batchFileModel.content, fileResult.Data);
+ Assert.AreEqual(batchFileModel.contentType, fileResult.ContentType);
+ } catch (AvaTaxError e)
+ {
+ Assert.True(false, $"AvaTaxError: {e.error.error.details?[0].message}");
+ } catch (Exception e)
+ {
+ Assert.True(false, $"Unknown Exception! {e.Message}");
+ }
+ }
+ }
+}
diff --git a/tests/net8.0/CertificateTests.cs b/tests/net8.0/CertificateTests.cs
new file mode 100644
index 0000000..11915bb
--- /dev/null
+++ b/tests/net8.0/CertificateTests.cs
@@ -0,0 +1,144 @@
+using Avalara.AvaTax.RestClient;
+using Newtonsoft.Json;
+using NUnit.Framework;
+using System;
+using System.IO;
+using System.Net;
+using System.Reflection;
+
+namespace Avalara.AvaTax.RestClient.Test.net80
+{
+ [TestFixture]
+ public class CertificateTests
+ {
+ public AvaTaxClient Client { get; set; }
+ public string CompanyCode { get; set; }
+ public int DefaultCompanyId { get; set; }
+ public CompanyModel TestCompany { get; set; }
+
+ #region Setup / TearDown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try {
+ // Create a client and set up authentication
+ Client = new AvaTaxClient(typeof(CertificateTests).Name,
+ typeof(CertificateTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = Client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ //Get the default company.
+ var defaultCompanyModel = Client.QueryCompanies(string.Empty, "isDefault EQ true", null, null, string.Empty).value[0];
+
+ DefaultCompanyId = defaultCompanyModel.id;
+
+ // Create a basic company with nexus in the state of Washington
+ TestCompany = Client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = Guid.NewGuid().ToString().Substring(0, 25),
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Greatest Popcorn",
+ title = "Owner/CEO"
+ });
+
+ // Add a delay
+ System.Threading.Thread.Sleep(6 * 1000);
+
+ // Assert that company setup succeeded
+ Assert.NotNull(TestCompany, "Test company should be created");
+ Assert.True(TestCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(TestCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ } catch (Exception ex) {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try {
+
+ // Re-fetch the company
+ var company = Client.GetCompany(TestCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = Client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ } catch (Exception ex) {
+ Assert.Fail("Exception in TearDown: " + ex);
+ }
+ }
+ #endregion
+
+ ///
+ /// Tests the upload certificate image endpoint.
+ ///
+ [Test]
+ [Ignore("Ignore CertificateImageUploadTest")]
+ public void CertificateImageUploadTest()
+ {
+ //Get the cert number. The account needs to have CertCapture
+ //be provisioned, already have a certificate created, and the
+ //certificate needs to be valid.
+ var certs = Client.QueryCertificates(DefaultCompanyId, string.Empty, "valid EQ true", null, null, string.Empty).value;
+ var certId = certs[0].id.Value;
+
+ //Get an image.
+ byte[] jpegByteArr = File.ReadAllBytes(Environment.GetEnvironmentVariable("TEST_IMAGE_PATH"));
+
+ FileResult fileResult = new FileResult()
+ {
+ ContentType = "multipart/form-data",
+ Filename = "test_cert_image.jpg",
+ Data = jpegByteArr
+ };
+
+ //Send request.
+ var certUploadResult = Client.UploadCertificateImage(DefaultCompanyId, certId, fileResult);
+
+ //Response should be "OK"
+ Assert.True(string.Equals(certUploadResult, "\"OK\""));
+
+ //Test download of image attachment.
+ var certAttachment = Client.DownloadCertificateImage(DefaultCompanyId, certId, null, CertificatePreviewType.Pdf);
+ Assert.NotNull(certAttachment);
+ Assert.True(string.Equals(certAttachment.ContentType, "application/pdf"));
+ Assert.True(certAttachment.Data.Length > 1000);
+
+ }
+ }
+}
diff --git a/tests/net8.0/ErrorResultTests.cs b/tests/net8.0/ErrorResultTests.cs
new file mode 100644
index 0000000..41fd7af
--- /dev/null
+++ b/tests/net8.0/ErrorResultTests.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+
+namespace Avalara.AvaTax.RestClient.Test.net80
+{
+ [TestFixture]
+ public class ErrorResultTests : TestBase
+ {
+ [Test]
+ public async Task NonJsonErrorResult()
+ {
+ AvaTaxError avataxError = null;
+ try
+ {
+ // make a client that points to a server that will give a 404 for ping
+ var client = new AvaTaxClient(GetType().Name,
+ GetType().GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName, new Uri("https://www.google.com"));
+
+ var result = await client.PingAsync().ConfigureAwait(false);
+ }
+ catch (AvaTaxError e)
+ {
+ avataxError = e;
+ }
+
+ Assert.NotNull(avataxError);
+ Assert.True(avataxError.error.error.message.Contains("the response is in an unexpected format"));
+ Assert.True(avataxError.error.error.details[0].description.ToLower().Contains("not found"));
+ }
+
+ [Test]
+ public async Task JsonErrorResult()
+ {
+ AvaTaxError avataxError = null;
+ try
+ {
+ var result = await _client.ChangePasswordAsync(new PasswordChangeModel
+ {
+ }).ConfigureAwait(false);
+ }
+ catch (AvaTaxError e)
+ {
+ avataxError = e;
+ }
+
+ Assert.NotNull(avataxError);
+ Assert.True(avataxError.error.error.message.Contains("Field oldPassword is required"));
+ }
+ }
+}
diff --git a/tests/net8.0/FreeTaxRatesTest.cs b/tests/net8.0/FreeTaxRatesTest.cs
new file mode 100644
index 0000000..7302654
--- /dev/null
+++ b/tests/net8.0/FreeTaxRatesTest.cs
@@ -0,0 +1,97 @@
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalara.AvaTax.RestClient.Test.net80
+{
+ [TestFixture]
+ class FreeTaxRatesTest
+ {
+ public AvaTaxClient _client;
+
+ #region Setup / Teardown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try {
+ // Create a client and set up authentication
+ _client = new AvaTaxClient(typeof(TransactionTests).Name,
+ typeof(TransactionTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+ } catch (Exception ex) {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+ #endregion
+
+ [Test]
+ public async Task FreeTaxRates()
+ {
+ // Call TaxRates for a few addresses and verify that the rates are nonzero
+ var tr = await _client.TaxRatesByAddressAsync("123 Main Street", null, null, "Irvine", "CA", "92615", "US");
+ Assert.NotNull(tr);
+ Assert.True(tr.totalRate > 0.05m);
+
+ // Washington
+ tr = await _client.TaxRatesByAddressAsync("522 Stadium Pl S", null, null, "Seattle", "WA", "98104", "US");
+ Assert.NotNull(tr);
+ Assert.True(tr.totalRate > 0.05m);
+
+ // By postal code for New York
+ tr = await _client.TaxRatesByPostalCodeAsync("US", "10010");
+ Assert.NotNull(tr);
+ Assert.True(tr.totalRate > 0.05m);
+ }
+
+ ///
+ /// Test the local rate by ZIP storage and retrieval.
+ ///
+ [Test]
+ [Ignore("This test will fail in Travis")]
+ public void StoreRatesByZipTest()
+ {
+ string path = Environment.GetEnvironmentVariable("ZIP_RATE_FILE_STORAGE_PATH");
+ List zips = new List() { "12590", "98104" };
+
+ //Call the content caching helper.
+ AvaTaxOfflineHelper.StoreZipRateContent(_client, "US", zips, path);
+
+ //Verify that the files were stored locally.
+ bool zipRateExists = AvaTaxOfflineHelper.VerifyLocalZipRateAvailable(zips[0], path);
+ Assert.True(zipRateExists);
+ zipRateExists = AvaTaxOfflineHelper.VerifyLocalZipRateAvailable(zips[1], path);
+ Assert.True(zipRateExists);
+
+ //Verify that a bogus file does not exist locally.
+ zipRateExists = AvaTaxOfflineHelper.VerifyLocalZipRateAvailable("bogusZipFile.json", path);
+ Assert.False(zipRateExists);
+
+ //Verify that the local file can be used for rate calculation.
+ var zipTaxRate = AvaTaxOfflineHelper.GetLocalTaxRateByZip(zips[1], path);
+ Assert.NotNull(zipTaxRate);
+ decimal result = 9.99m * zipTaxRate.totalRate.Value;
+ Assert.NotZero(result);
+
+ //Test AvaTaxOfflineHelper Exception handling.
+ path = @"n:\someBadPath";
+ try {
+ AvaTaxOfflineHelper.StoreZipRateContent(_client, "US", zips, path);
+ } catch (AvaTaxOfflineHelperException exc) {
+#if PORTABLE
+ Assert.True(string.Equals(exc.InnerException.Message, "Could not find a part of the path 'n:\\someBadPath\\12590.json'."));
+#else
+ Assert.True(string.Equals(exc.Message, "An error occurred retrieving or storing the rate content. Please see inner exception for details."));
+#endif
+ }
+ }
+ }
+}
diff --git a/tests/net8.0/HttpClientTransactionTests.cs b/tests/net8.0/HttpClientTransactionTests.cs
new file mode 100644
index 0000000..c0c79e1
--- /dev/null
+++ b/tests/net8.0/HttpClientTransactionTests.cs
@@ -0,0 +1,204 @@
+using Avalara.AvaTax.RestClient;
+using Newtonsoft.Json;
+using NUnit.Framework;
+using System;
+using System.Net;
+using System.Reflection;
+
+namespace Avalara.AvaTax.RestClient.Test.net80
+{
+ [TestFixture]
+ public class HttpClientTransactionTests
+ {
+ public AvaTaxClient Client { get; set; }
+ public string CompanyCode { get; set; }
+ public CompanyModel TestCompany { get; set; }
+
+ #region Setup / TearDown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try
+ {
+ var httpClient = new System.Net.Http.HttpClient() { Timeout = TimeSpan.FromMinutes(20) };
+ // Create a client and set up authentication
+ Client = new AvaTaxClient(httpClient, typeof(HttpClientTransactionTests).Name,
+ typeof(HttpClientTransactionTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = Client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ // Create a basic company with nexus in the state of Washington
+ TestCompany = Client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = Guid.NewGuid().ToString().Substring(0, 25),
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Greatest Popcorn",
+ title = "Owner/CEO"
+ });
+
+ // Add a delay
+ System.Threading.Thread.Sleep(6 * 1000);
+
+ // Assert that company setup succeeded
+ Assert.NotNull(TestCompany, "Test company should be created");
+ Assert.True(TestCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(TestCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try
+ {
+
+ // Re-fetch the company
+ var company = Client.GetCompany(TestCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = Client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in TearDown: " + ex);
+ }
+ }
+ #endregion
+
+ ///
+ /// To debug this application, call app must be called with args[0] as username and args[1] as password
+ ///
+ [Test]
+ public void TransactionWorkflow()
+ {
+ Client.CallCompleted += Client_CallCompleted;
+ var tfn = System.IO.Path.GetTempFileName();
+ Client.LogToFile(tfn);
+
+ // Execute a transaction
+ var transaction = new TransactionBuilder(Client, TestCompany.companyCode, DocumentType.SalesInvoice, "ABC")
+ .WithAddress(TransactionAddressType.SingleLocation, "521 S Weller St", null, null, "Seattle", "WA",
+ "98104", "US")
+ .WithLine(100.0m, 1, "P0000000")
+ .WithLine(200m)
+ .WithExemptLine(50m, "NT")
+ .WithLineReference("Special Line Reference!", "Also this!")
+ .Create();
+
+ // Verify that the call was captured and logged
+ Assert.NotNull(lastEvent);
+ Assert.True(String.Equals(lastEvent.HttpVerb, "POST", StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(String.Equals(lastEvent.RequestUri.ToString(), "https://sandbox-rest.avatax.com/api/v2/transactions/create", StringComparison.CurrentCultureIgnoreCase));
+ Assert.AreEqual(lastEvent.Code, HttpStatusCode.Created);
+
+ // Verify that the log file was created
+ Assert.True(System.IO.File.Exists(tfn));
+
+ // Ensure this transaction was created, and has three lines, and has some tax
+ Assert.NotNull(transaction, "Transaction should have been created");
+ Assert.True(transaction.totalTax > 0.0m, "Transaction should have had some tax");
+ Assert.True(transaction.lines.Count == 3, "Transaction should have three lines");
+ Assert.True(transaction.lines[2].ref1.Contains("Reference!"), "Line3 should have had a Ref1.");
+
+ // Now commit that transaction
+ var commitResult = Client.CommitTransaction(TestCompany.companyCode, transaction.code, null, null, new CommitTransactionModel() { commit = true });
+
+ // Ensure that this transaction was committed
+ Assert.NotNull(commitResult, "Should have been able to call CommitTransaction");
+ Assert.True(commitResult.status == DocumentStatus.Committed, "Transaction should have been committed");
+
+ // Now void the transaction
+ var voidResult = Client.VoidTransaction(TestCompany.companyCode, transaction.code, null, null, new VoidTransactionModel()
+ {
+ code = VoidReasonCode.DocVoided
+ });
+
+ // Ensure that the transaction was voided
+ Assert.NotNull(voidResult, "Should have been able to call VoidTransactoin");
+ Assert.True(voidResult.status == DocumentStatus.Cancelled, "Transaction should have been voided");
+ }
+
+ private AvaTaxCallEventArgs lastEvent = null;
+ private void Client_CallCompleted(object sender, EventArgs e)
+ {
+ lastEvent = e as AvaTaxCallEventArgs;
+ }
+
+ [Test]
+
+ public void TaxOverrideExample()
+ {
+ // Create base transaction.
+ var builder = new TransactionBuilder(Client, TestCompany.companyCode, DocumentType.SalesInvoice,
+ "TaxOverrideCustomerCode")
+ .WithAddress(TransactionAddressType.SingleLocation, "521 S Weller St", null, null, "Seattle", "WA",
+ "98104", "US")
+ .WithLine(100.0m, 1, "P0000000")
+ .WithLine(200m);
+
+ var transaction = builder.Create();
+
+ // Ensure this transaction was created.
+ Assert.NotNull(transaction, "Transaction should have been created");
+
+ // Add Line-level TaxOverride.
+ var overrideTransaction = builder
+ .WithLineTaxOverride(TaxOverrideType.TaxAmount, "Tax Override Reason", 1)
+ .Create();
+
+ // Ensure this transaction was created.
+ Assert.NotNull(overrideTransaction, "Transaction should have been created");
+
+ // Compare the two transactions.
+ Assert.AreEqual(overrideTransaction.totalTaxCalculated, transaction.totalTaxCalculated, "Total Tax Calculated should be the same.");
+ Assert.True(overrideTransaction.totalTax < transaction.totalTax, "Total Tax should not be the same. Overridden transaction should be smaller.");
+
+ // Compare the transaction lines.
+ var overrideLine = overrideTransaction.lines[1];
+ var line = transaction.lines[1];
+ Assert.AreEqual(overrideLine.isItemTaxable, line.isItemTaxable);
+ Assert.AreEqual(overrideLine.taxCalculated, line.taxCalculated);
+ Assert.AreEqual(overrideLine.lineAmount, line.lineAmount);
+ Assert.AreEqual(1, overrideLine.tax);
+ Assert.True(overrideLine.tax < line.tax);
+ Assert.AreEqual(TaxOverrideType.TaxAmount, overrideLine.taxOverrideType);
+ }
+ }
+}
diff --git a/tests/net8.0/NexusTests.cs b/tests/net8.0/NexusTests.cs
new file mode 100644
index 0000000..d144b07
--- /dev/null
+++ b/tests/net8.0/NexusTests.cs
@@ -0,0 +1,169 @@
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace Avalara.AvaTax.RestClient.Test.net80
+{
+ [TestFixture]
+ [Ignore("This test is not yet implemented")]
+ public class NexusTests
+ {
+ public AvaTaxClient Client { get; set; }
+ public string CompanyCode { get; set; }
+ public CompanyModel TestCompany { get; set; }
+
+ #region Setup / TearDown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try {
+ // Create a client and set up authentication
+ Client = new AvaTaxClient(typeof(TransactionTests).Name,
+ typeof(TransactionTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = Client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ // Create a basic company with nexus in the state of Washington
+ TestCompany = Client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = Guid.NewGuid().ToString().Substring(0, 25),
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Greatest Popcorn",
+ title = "Owner/CEO"
+ });
+
+ // Assert that company setup succeeded
+ Assert.NotNull(TestCompany, "Test company should be created");
+ Assert.True(TestCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(TestCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ } catch (Exception ex) {
+ Assert.Fail("Exception in SetUp: " + ex.ToString());
+ }
+ }
+
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try {
+
+ // Re-fetch the company
+ var company = Client.GetCompany(TestCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = Client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ } catch (Exception ex) {
+ Assert.Fail("Exception in TearDown: " + ex.ToString());
+ }
+ }
+ #endregion
+
+ [Test]
+ public void CreateAndDeleteNexus()
+ {
+ var nexusModels = new List();
+
+ var stateNexus = new NexusModel
+ {
+ id = 0,
+ companyId = TestCompany.id,
+ country = "US",
+ region = "AL",
+ jurisTypeId = JurisTypeId.STA,
+ jurisCode = "01",
+ jurisName = "ALABAMA",
+ shortName = "AL",
+ signatureCode = "",
+ stateAssignedNo = "",
+ nexusTypeId = NexusTypeId.SalesOrSellersUseTax,
+ hasLocalNexus = true,
+ hasPermanentEstablishment = true,
+ effectiveDate = new DateTime(2008, 07, 01),
+ endDate = new DateTime(2019, 07, 01)
+ };
+
+ var cityNexus = new NexusModel
+ {
+ id = 0,
+ companyId = TestCompany.id,
+ country = "US",
+ region = "AL",
+ jurisTypeId = JurisTypeId.CIT,
+ jurisCode = "00124",
+ jurisName = "ABBEVILLE",
+ shortName = "ABBEVILLE",
+ signatureCode = "",
+ stateAssignedNo = "9356",
+ nexusTypeId = NexusTypeId.SalesTax,
+ hasLocalNexus = true,
+ hasPermanentEstablishment = false,
+ effectiveDate = new DateTime(2008, 07, 01),
+ endDate = new DateTime(2018, 07, 01)
+ };
+
+ nexusModels.Add(stateNexus);
+ nexusModels.Add(cityNexus);
+
+ var nexusModelsAdded = Client.CreateNexus(TestCompany.id, new List { stateNexus, cityNexus });
+
+ // Get State nexus
+ NexusModel getALNexus = null;
+ try {
+ getALNexus = Client.GetNexus(TestCompany.id, nexusModelsAdded[0].id.Value, null);
+ } catch (Exception) { }
+ Assert.NotNull(getALNexus);
+
+ var fetchedUSNexus = new List { getALNexus };
+
+ // Get City Nexus
+ NexusModel getCityNexus = null;
+ try {
+ getCityNexus = Client.GetNexus(TestCompany.id, nexusModelsAdded[1].id.Value, null);
+ } catch (Exception) { }
+ Assert.NotNull(getALNexus);
+
+ fetchedUSNexus.Add(getCityNexus);
+
+ // Delete Nexus
+ var errorResult = Client.DeleteNexus(TestCompany.id, nexusModelsAdded[1].id.Value, null);
+ Assert.NotNull(errorResult);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/net8.0/SetUpFixture.cs b/tests/net8.0/SetUpFixture.cs
new file mode 100644
index 0000000..8586be1
--- /dev/null
+++ b/tests/net8.0/SetUpFixture.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Versioning;
+using System.Text;
+using System.Threading.Tasks;
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+
+namespace Avalara.AvaTax.RestClient.Test.net80
+{
+ [SetUpFixture]
+ public class SetUpFixture
+ {
+ [OneTimeSetUp]
+ public void RunBeforeAnyTests()
+ {
+ var stringBuilder = new StringBuilder();
+
+ stringBuilder
+ .AppendLine($"Hosting Framework Runtime Version: {GetRuntimeFrameworkVersion(GetType().Assembly)}")
+ .AppendLine($"Hosting Framework Version: {GetFrameworkVersion(GetType().Assembly)}")
+ .AppendLine($"Target Framework Runtime Version: {GetRuntimeFrameworkVersion(typeof(AvaTaxClient).Assembly)}")
+ .AppendLine($"Target Framework Version: {GetFrameworkVersion(typeof(AvaTaxClient).Assembly)}");
+
+ TestContext.Progress.WriteLine(stringBuilder);
+ }
+
+ private static string GetRuntimeFrameworkVersion(Assembly assembly)
+ {
+ var imageRuntimeVersion = assembly
+ .ImageRuntimeVersion;
+
+ return imageRuntimeVersion;
+ }
+
+ private static string GetFrameworkVersion(Assembly assembly)
+ {
+ var targetFrameAttribute = assembly.GetCustomAttributes(true)
+ .OfType().FirstOrDefault();
+ if (targetFrameAttribute == null)
+ {
+ return ".NET 2, 3 or 3.5";
+ }
+
+ return targetFrameAttribute.FrameworkName;
+ }
+ }
+}
diff --git a/tests/net8.0/TestBase.cs b/tests/net8.0/TestBase.cs
new file mode 100644
index 0000000..332d184
--- /dev/null
+++ b/tests/net8.0/TestBase.cs
@@ -0,0 +1,103 @@
+using Avalara.AvaTax.RestClient;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+namespace Avalara.AvaTax.RestClient.Test.net80
+{
+ public class TestBase
+ {
+ protected AvaTaxClient _client;
+ protected string _companyCode;
+ protected CompanyModel _testCompany;
+
+ [SetUp]
+ public void Setup()
+ {
+ _client = null;
+ _testCompany = null;
+ try
+ {
+ // Create a client and set up authentication
+ _client = new AvaTaxClient(GetType().Name,
+ GetType().GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = _client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ _companyCode = Guid.NewGuid().ToString("N").Substring(0, 25);
+ // Create a basic company with nexus in the state of Washington
+ _testCompany = _client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = _companyCode,
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Hardware Store",
+ title = "Owner/CEO"
+ });
+
+ // Add a delay after creating a company
+ System.Threading.Thread.Sleep(6 * 1000);
+
+ // Assert that company setup succeeded
+ Assert.NotNull(_testCompany, "Test company should be created");
+ Assert.True(_testCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(_testCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try
+ {
+ // Re-fetch the company
+ var company = _client.GetCompany(_testCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = _client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail("Exception in TearDown: " + ex);
+ }
+ }
+ }
+}
diff --git a/tests/net8.0/TransactionTests.cs b/tests/net8.0/TransactionTests.cs
new file mode 100644
index 0000000..ab5ef12
--- /dev/null
+++ b/tests/net8.0/TransactionTests.cs
@@ -0,0 +1,211 @@
+using Avalara.AvaTax.RestClient;
+using Newtonsoft.Json;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Reflection;
+
+namespace Avalara.AvaTax.RestClient.Test.net80
+{
+ [TestFixture]
+ public class TransactionTests
+ {
+ public AvaTaxClient Client { get; set; }
+ public string CompanyCode { get; set; }
+ public CompanyModel TestCompany { get; set; }
+
+ #region Setup / TearDown
+ ///
+ /// Create a company for use with these tests
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ try
+ {
+ // Create a client and set up authentication
+ Client = new AvaTaxClient(typeof(TransactionTests).Name,
+ typeof(TransactionTests).GetTypeInfo().Assembly.ImageRuntimeVersion.ToString(),
+ Environment.MachineName,
+ AvaTaxEnvironment.Sandbox)
+ .WithSecurity(Environment.GetEnvironmentVariable("SANDBOX_USERNAME"), Environment.GetEnvironmentVariable("SANDBOX_PASSWORD"));
+
+ // Verify that we can ping successfully
+ var pingResult = Client.Ping();
+
+ // Assert that ping succeeded
+ Assert.NotNull(pingResult, "Should be able to call Ping");
+ Assert.True(pingResult.authenticated, "Environment variables should provide correct authentication");
+
+ // Create a basic company with nexus in the state of Washington
+ TestCompany = Client.CompanyInitialize(new CompanyInitializationModel()
+ {
+ city = "Bainbridge Island",
+ companyCode = Guid.NewGuid().ToString().Substring(0, 25),
+ country = "US",
+ email = "bob@example.org",
+ faxNumber = null,
+ firstName = "Bob",
+ lastName = "McExample",
+ line1 = "100 Ravine Lane",
+ mobileNumber = "206 555 1212",
+ phoneNumber = "206 555 1212",
+ postalCode = "98110",
+ region = "WA",
+ taxpayerIdNumber = "123456789",
+ name = "Bob's Greatest Popcorn",
+ title = "Owner/CEO"
+ });
+
+ // Add a delay
+ System.Threading.Thread.Sleep(6 * 1000);
+
+ // Assert that company setup succeeded
+ Assert.NotNull(TestCompany, "Test company should be created");
+ Assert.True(TestCompany.nexus.Count > 0, "Test company should have nexus");
+ Assert.True(TestCompany.locations.Count > 0, "Test company should have locations");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in SetUp: " + ex);
+ }
+ }
+
+
+ ///
+ /// Any cleanup required goes here
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ try
+ {
+
+ // Re-fetch the company
+ var company = Client.GetCompany(TestCompany.id, null);
+
+ // Flag this company as inactive
+ company.isActive = false;
+ var disableResult = Client.UpdateCompany(company.id, company);
+
+ // Assert that it succeeded
+ Assert.NotNull(disableResult, "Should have been able to update this company");
+ Assert.False(disableResult.isActive, "Company should have been deactivated");
+
+ // Shouldn't fail
+ } catch (Exception ex)
+ {
+ Assert.Fail("Exception in TearDown: " + ex);
+ }
+ }
+ #endregion
+
+ ///
+ /// To debug this application, call app must be called with args[0] as username and args[1] as password
+ ///
+ [Test]
+ public void TransactionWorkflow()
+ {
+ Client.CallCompleted += Client_CallCompleted;
+ var tfn = System.IO.Path.GetTempFileName();
+ Client.LogToFile(tfn);
+
+ // Execute a transaction
+ var transaction = new TransactionBuilder(Client, TestCompany.companyCode, DocumentType.SalesInvoice, "ABC")
+ .WithAddress(TransactionAddressType.SingleLocation, "521 S Weller St", null, null, "Seattle", "WA",
+ "98104", "US")
+ .WithLine(100.0m, 1, "P0000000")
+ .WithLine(200m)
+ .WithExemptLine(50m, "NT")
+ .WithLineReference("Special Line Reference!", "Also this!")
+ .Create();
+
+ // Verify that the call was captured and logged
+ Assert.NotNull(lastEvent);
+ Assert.True(String.Equals(lastEvent.HttpVerb, "POST", StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(String.Equals(lastEvent.RequestUri.ToString(), "https://sandbox-rest.avatax.com/api/v2/transactions/create", StringComparison.CurrentCultureIgnoreCase));
+ Assert.AreEqual(lastEvent.Code, HttpStatusCode.Created);
+
+ // Verify that the log file was created
+ Assert.True(System.IO.File.Exists(tfn));
+
+ // Ensure this transaction was created, and has three lines, and has some tax
+ Assert.NotNull(transaction, "Transaction should have been created");
+ Assert.True(transaction.totalTax > 0.0m, "Transaction should have had some tax");
+ Assert.True(transaction.lines.Count == 3, "Transaction should have three lines");
+ Assert.True(transaction.lines[2].ref1.Contains("Reference!"), "Line3 should have had a Ref1.");
+
+ // Now commit that transaction
+ var commitResult = Client.CommitTransaction(TestCompany.companyCode, transaction.code, null, null, new CommitTransactionModel() { commit = true });
+
+ // Ensure that this transaction was committed
+ Assert.NotNull(commitResult, "Should have been able to call CommitTransaction");
+ Assert.True(commitResult.status == DocumentStatus.Committed, "Transaction should have been committed");
+
+ // Now void the transaction
+ var voidResult = Client.VoidTransaction(TestCompany.companyCode, transaction.code, null, null, new VoidTransactionModel()
+ {
+ code = VoidReasonCode.DocVoided
+ });
+
+ // Ensure that the transaction was voided
+ Assert.NotNull(voidResult, "Should have been able to call VoidTransactoin");
+ Assert.True(voidResult.status == DocumentStatus.Cancelled, "Transaction should have been voided");
+ }
+
+ private AvaTaxCallEventArgs lastEvent = null;
+ private void Client_CallCompleted(object sender, EventArgs e)
+ {
+ lastEvent = e as AvaTaxCallEventArgs;
+ }
+ [Ignore("Ignore Override")]
+ [Test]
+ public void TaxOverrideExample()
+ {
+ // Create base transaction.
+ var builder = new TransactionBuilder(Client, TestCompany.companyCode, DocumentType.SalesInvoice,
+ "TaxOverrideCustomerCode")
+ .WithAddress(TransactionAddressType.SingleLocation, "521 S Weller St", null, null, "Seattle", "WA",
+ "98104", "US")
+ .WithLine(100.0m, 1, "P0000000")
+ .WithLine(200m);
+
+ var transaction = builder.Create();
+
+ // Ensure this transaction was created.
+ Assert.NotNull(transaction, "Transaction should have been created");
+
+ var taxOverrideList = new List();
+ var item = new TransactionLineTaxAmountByTaxTypeModel();
+ item.taxTypeId = "123";
+ item.taxAmount = 10;
+ taxOverrideList.Add(item);
+ // Add Line-level TaxOverride.
+ var overrideTransaction = builder
+ .WithLineTaxOverride(TaxOverrideType.TaxAmount, "Tax Override Reason", 1)
+ .WithLine(300m, 1)
+ .WithLineTaxOverride(TaxOverrideType.TaxAmountByTaxType, "Another reason", 10, null, taxOverrideList)
+ .Create();
+
+
+ // Ensure this transaction was created.
+ Assert.NotNull(overrideTransaction, "Transaction should have been created");
+
+ // Compare the two transactions.
+ Assert.AreEqual(overrideTransaction.totalTaxCalculated, transaction.totalTaxCalculated, "Total Tax Calculated should be the same.");
+ Assert.True(overrideTransaction.totalTax < transaction.totalTax, "Total Tax should not be the same. Overridden transaction should be smaller.");
+
+ // Compare the transaction lines.
+ var overrideLine = overrideTransaction.lines[1];
+ var line = transaction.lines[1];
+ Assert.AreEqual(overrideLine.isItemTaxable, line.isItemTaxable);
+ Assert.AreEqual(overrideLine.taxCalculated, line.taxCalculated);
+ Assert.AreEqual(overrideLine.lineAmount, line.lineAmount);
+ Assert.AreEqual(1, overrideLine.tax);
+ Assert.True(overrideLine.tax < line.tax);
+ Assert.AreEqual(TaxOverrideType.TaxAmount, overrideLine.taxOverrideType);
+ }
+ }
+}