From 77af9625810729970e6704dc2b1d1d76e3ebe857 Mon Sep 17 00:00:00 2001 From: James Pfluger Date: Thu, 11 Jul 2024 15:22:33 -0700 Subject: [PATCH 1/7] update package versions --- src/Avalara.AvaTax.RestClient.csproj | 18 ++++++++--------- tests/Avalara.AvaTax.RestClient.Test.csproj | 22 ++++++++++----------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Avalara.AvaTax.RestClient.csproj b/src/Avalara.AvaTax.RestClient.csproj index 8a8c95c..9044f94 100644 --- a/src/Avalara.AvaTax.RestClient.csproj +++ b/src/Avalara.AvaTax.RestClient.csproj @@ -74,39 +74,39 @@ - + 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..0fee4b1 100644 --- a/tests/Avalara.AvaTax.RestClient.Test.csproj +++ b/tests/Avalara.AvaTax.RestClient.Test.csproj @@ -1,6 +1,6 @@  - net451;net45;net461;net472;netcoreapp2.2;netcoreapp3.1 + net451;net45;net461;net472;netcoreapp2.2.8;netcoreapp3.1 false @@ -20,10 +20,10 @@ - + - + @@ -31,7 +31,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -53,8 +53,8 @@ - - + + @@ -64,22 +64,22 @@ - + - + TargetFramework=netstandard1.6 - + - + TargetFramework=netstandard2.0 From 1b43e58b50f8867ea471de30eaca23ce51914d9c Mon Sep 17 00:00:00 2001 From: James Pfluger Date: Thu, 11 Jul 2024 15:22:46 -0700 Subject: [PATCH 2/7] add solution --- Avalara.AvaTax.RestClient.sln | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Avalara.AvaTax.RestClient.sln diff --git a/Avalara.AvaTax.RestClient.sln b/Avalara.AvaTax.RestClient.sln new file mode 100644 index 0000000..be14550 --- /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.Test", "tests\Avalara.AvaTax.RestClient.Test.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 From 050038c4686ffaf2110dcb8aa67735ebcaaaf407 Mon Sep 17 00:00:00 2001 From: James Pfluger Date: Thu, 11 Jul 2024 15:39:41 -0700 Subject: [PATCH 3/7] add .NET 6 support --- src/AvaTaxOfflineHelper.cs | 3 ++- src/Avalara.AvaTax.RestClient.csproj | 12 +++++++++++- tests/Avalara.AvaTax.RestClient.Test.csproj | 17 +++++++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) 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 9044f94..48b79a1 100644 --- a/src/Avalara.AvaTax.RestClient.csproj +++ b/src/Avalara.AvaTax.RestClient.csproj @@ -1,7 +1,7 @@  - net20;net45;net461;net472;netstandard1.6;netstandard2.0 false + net20;net45;net461;net472;netstandard1.6;netstandard2.0;net6.0 false true Avalara.AvaTax.RestClient.snk @@ -66,6 +66,16 @@ TRACE;RELEASE;PORTABLE;NETSTANDARD2_0 true + + + TRACE;DEBUG;PORTABLE;NET6_0 + true + + + + TRACE;RELEASE;PORTABLE;NET6_0 + true + diff --git a/tests/Avalara.AvaTax.RestClient.Test.csproj b/tests/Avalara.AvaTax.RestClient.Test.csproj index 0fee4b1..375b88f 100644 --- a/tests/Avalara.AvaTax.RestClient.Test.csproj +++ b/tests/Avalara.AvaTax.RestClient.Test.csproj @@ -1,6 +1,6 @@  - net451;net45;net461;net472;netcoreapp2.2.8;netcoreapp3.1 + net451;net45;net461;net472;netcoreapp2.2.8;netcoreapp3.1;net6.0 false @@ -15,6 +15,8 @@ + + @@ -63,7 +65,7 @@ TargetFramework=net472 - + @@ -85,4 +87,15 @@ TargetFramework=netstandard2.0 + + + + + + + + + TargetFramework=net6.0 + + \ No newline at end of file From aabe0875b9bf64cf5b9b968fd4d593bcf09c912b Mon Sep 17 00:00:00 2001 From: James Pfluger Date: Thu, 11 Jul 2024 15:44:30 -0700 Subject: [PATCH 4/7] add test files for .NET 6 and .NET 8 --- tests/net6.0/BatchTests.cs | 198 +++++++++++++++++++ tests/net6.0/CertificateTests.cs | 144 ++++++++++++++ tests/net6.0/ErrorResultTests.cs | 57 ++++++ tests/net6.0/FreeTaxRatesTest.cs | 97 ++++++++++ tests/net6.0/HttpClientTransactionTests.cs | 204 ++++++++++++++++++++ tests/net6.0/NexusTests.cs | 169 +++++++++++++++++ tests/net6.0/SetUpFixture.cs | 51 +++++ tests/net6.0/TestBase.cs | 103 ++++++++++ tests/net6.0/TransactionTests.cs | 211 +++++++++++++++++++++ tests/net8.0/BatchTests.cs | 198 +++++++++++++++++++ tests/net8.0/CertificateTests.cs | 144 ++++++++++++++ tests/net8.0/ErrorResultTests.cs | 57 ++++++ tests/net8.0/FreeTaxRatesTest.cs | 97 ++++++++++ tests/net8.0/HttpClientTransactionTests.cs | 204 ++++++++++++++++++++ tests/net8.0/NexusTests.cs | 169 +++++++++++++++++ tests/net8.0/SetUpFixture.cs | 51 +++++ tests/net8.0/TestBase.cs | 103 ++++++++++ tests/net8.0/TransactionTests.cs | 211 +++++++++++++++++++++ 18 files changed, 2468 insertions(+) create mode 100644 tests/net6.0/BatchTests.cs create mode 100644 tests/net6.0/CertificateTests.cs create mode 100644 tests/net6.0/ErrorResultTests.cs create mode 100644 tests/net6.0/FreeTaxRatesTest.cs create mode 100644 tests/net6.0/HttpClientTransactionTests.cs create mode 100644 tests/net6.0/NexusTests.cs create mode 100644 tests/net6.0/SetUpFixture.cs create mode 100644 tests/net6.0/TestBase.cs create mode 100644 tests/net6.0/TransactionTests.cs create mode 100644 tests/net8.0/BatchTests.cs create mode 100644 tests/net8.0/CertificateTests.cs create mode 100644 tests/net8.0/ErrorResultTests.cs create mode 100644 tests/net8.0/FreeTaxRatesTest.cs create mode 100644 tests/net8.0/HttpClientTransactionTests.cs create mode 100644 tests/net8.0/NexusTests.cs create mode 100644 tests/net8.0/SetUpFixture.cs create mode 100644 tests/net8.0/TestBase.cs create mode 100644 tests/net8.0/TransactionTests.cs 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); + } + } +} From ee6865c0b6cf1fd0019ea0d27e1608ed907df2ec Mon Sep 17 00:00:00 2001 From: James Pfluger Date: Thu, 11 Jul 2024 15:47:55 -0700 Subject: [PATCH 5/7] add .NET 8 targets --- src/Avalara.AvaTax.RestClient.csproj | 20 +++++++++++++++++++- tests/Avalara.AvaTax.RestClient.Test.csproj | 15 ++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/Avalara.AvaTax.RestClient.csproj b/src/Avalara.AvaTax.RestClient.csproj index 48b79a1..481b52d 100644 --- a/src/Avalara.AvaTax.RestClient.csproj +++ b/src/Avalara.AvaTax.RestClient.csproj @@ -1,7 +1,7 @@  false - net20;net45;net461;net472;netstandard1.6;netstandard2.0;net6.0 + net20;net45;net461;net472;netstandard1.6;netstandard2.0;net6.0;net8.0 false true Avalara.AvaTax.RestClient.snk @@ -76,6 +76,16 @@ TRACE;RELEASE;PORTABLE;NET6_0 true + + + TRACE;DEBUG;PORTABLE;NET8_0 + true + + + + TRACE;RELEASE;PORTABLE;NET8_0 + true + @@ -118,6 +128,14 @@ + + + + + + + + diff --git a/tests/Avalara.AvaTax.RestClient.Test.csproj b/tests/Avalara.AvaTax.RestClient.Test.csproj index 375b88f..23a2e48 100644 --- a/tests/Avalara.AvaTax.RestClient.Test.csproj +++ b/tests/Avalara.AvaTax.RestClient.Test.csproj @@ -1,6 +1,6 @@  - net451;net45;net461;net472;netcoreapp2.2.8;netcoreapp3.1;net6.0 + net451;net45;net461;net472;netcoreapp2.2.8;netcoreapp3.1;net6.0;net8.0 false @@ -17,6 +17,8 @@ + + @@ -98,4 +100,15 @@ TargetFramework=net6.0 + + + + + + + + + TargetFramework=net6.0 + + \ No newline at end of file From c9d52e248bdbfdf661e095e0780708efbab2ad66 Mon Sep 17 00:00:00 2001 From: James Pfluger Date: Thu, 11 Jul 2024 16:03:54 -0700 Subject: [PATCH 6/7] add additional conditions for debug and release --- src/Avalara.AvaTax.RestClient.csproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Avalara.AvaTax.RestClient.csproj b/src/Avalara.AvaTax.RestClient.csproj index 481b52d..59b25ca 100644 --- a/src/Avalara.AvaTax.RestClient.csproj +++ b/src/Avalara.AvaTax.RestClient.csproj @@ -57,32 +57,32 @@ 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 From 638bd984a65c53ea61871175f34ab681c4aad1f1 Mon Sep 17 00:00:00 2001 From: James Pfluger Date: Thu, 11 Jul 2024 16:32:47 -0700 Subject: [PATCH 7/7] clean up project files --- Avalara.AvaTax.RestClient.sln | 2 +- src/Avalara.AvaTax.RestClient.csproj | 101 ++++++++------------ tests/Avalara.AvaTax.RestClient.Test.csproj | 77 ++++----------- 3 files changed, 63 insertions(+), 117 deletions(-) diff --git a/Avalara.AvaTax.RestClient.sln b/Avalara.AvaTax.RestClient.sln index be14550..5cc2f5c 100644 --- a/Avalara.AvaTax.RestClient.sln +++ b/Avalara.AvaTax.RestClient.sln @@ -5,7 +5,7 @@ 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.Test", "tests\Avalara.AvaTax.RestClient.Test.csproj", "{88267F39-00E4-4D70-8E76-EA601E43CCA0}" +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 diff --git a/src/Avalara.AvaTax.RestClient.csproj b/src/Avalara.AvaTax.RestClient.csproj index 59b25ca..ef9e425 100644 --- a/src/Avalara.AvaTax.RestClient.csproj +++ b/src/Avalara.AvaTax.RestClient.csproj @@ -6,7 +6,9 @@ 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,108 +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 23a2e48..3f0176b 100644 --- a/tests/Avalara.AvaTax.RestClient.Test.csproj +++ b/tests/Avalara.AvaTax.RestClient.Test.csproj @@ -3,109 +3,74 @@ 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