- C#
- Python
- NodeJS
FastTax C# Rest Code Snippet
using System.Web;
namespace fast_tax_dot_net.REST
{
/// <summary>
/// Provides functionality to call the ServiceObjects FastTax (FT) REST API's GetBestMatch endpoint,
/// retrieving tax rate information (e.g., total tax rate, city, county, state rates) for a given US address
/// with fallback to a backup endpoint for reliability in live mode.
/// </summary>
public static class GetBestMatchClient
{
// Base URL constants: production, backup, and trial
private const string LiveBaseUrl = "https://sws.serviceobjects.com/ft/web.svc/json/";
private const string BackupBaseUrl = "https://swsbackup.serviceobjects.com/ft/web.svc/json/";
private const string TrialBaseUrl = "https://trial.serviceobjects.com/ft/web.svc/json/";
/// <summary>
/// Synchronously calls the GetBestMatch REST endpoint to retrieve tax rate information,
/// attempting the primary endpoint first and falling back to the backup if the response is invalid
/// (Error.Number == "4") in live mode.
/// </summary>
/// <param name="input">The input parameters including address, city, state, zip, tax type, and license key.</param>
/// <returns>Deserialized <see cref="GetBestMatchResponse"/> containing tax rate data or an error.</returns>
public static GetBestMatchResponse Invoke(GetBestMatchInput input)
{
// Use query string parameters so missing/optional fields don't break the URL
string url = BuildUrl(input, input.IsLive ? LiveBaseUrl : TrialBaseUrl);
GetBestMatchResponse response = Helper.HttpGet<GetBestMatchResponse>(url, input.TimeoutSeconds);
// Fallback on error in live mode
if (input.IsLive && !IsValid(response))
{
string fallbackUrl = BuildUrl(input, BackupBaseUrl);
GetBestMatchResponse fallbackResponse = Helper.HttpGet<GetBestMatchResponse>(fallbackUrl, input.TimeoutSeconds);
return fallbackResponse;
}
return response;
}
/// <summary>
/// Asynchronously calls the GetBestMatch REST endpoint to retrieve tax rate information,
/// attempting the primary endpoint first and falling back to the backup if the response is invalid
/// (Error.Number == "4") in live mode.
/// </summary>
/// <param name="input">The input parameters including address, city, state, zip, tax type, and license key.</param>
/// <returns>Deserialized <see cref="GetBestMatchResponse"/> containing tax rate data or an error.</returns>
public static async Task<GetBestMatchResponse> InvokeAsync(GetBestMatchInput input)
{
// Use query string parameters so missing/optional fields don't break the URL
string url = BuildUrl(input, input.IsLive ? LiveBaseUrl : TrialBaseUrl);
GetBestMatchResponse response = await Helper.HttpGetAsync<GetBestMatchResponse>(url, input.TimeoutSeconds).ConfigureAwait(false);
// Fallback on error in live mode
if (input.IsLive && !IsValid(response))
{
string fallbackUrl = BuildUrl(input, BackupBaseUrl);
GetBestMatchResponse fallbackResponse = await Helper.HttpGetAsync<GetBestMatchResponse>(fallbackUrl, input.TimeoutSeconds).ConfigureAwait(false);
return fallbackResponse;
}
return response;
}
// Build the full request URL, including URL-encoded query string
public static string BuildUrl(GetBestMatchInput input, string baseUrl)
{
// Construct query string with URL-encoded parameters
string qs = $"GetBestMatch?" +
$"Address={HttpUtility.UrlEncode(input.Address)}" +
$"&Address2={HttpUtility.UrlEncode(input.Address2)}" +
$"&City={HttpUtility.UrlEncode(input.City)}" +
$"&State={HttpUtility.UrlEncode(input.State)}" +
$"&Zip={HttpUtility.UrlEncode(input.Zip)}" +
$"&TaxType={HttpUtility.UrlEncode(input.TaxType)}" +
$"&LicenseKey={HttpUtility.UrlEncode(input.LicenseKey)}";
return baseUrl + qs;
}
private static bool IsValid(GetBestMatchResponse response) => response?.Error == null || response.Error.Number != "4";
/// <summary>
/// Input parameters for the GetBestMatch API call. Represents a US address to retrieve tax rates
/// with cascading logic for partial matches.
/// </summary>
/// <param name="Address">Address line of the address to get tax rates for (e.g., "123 Main Street").</param>
/// <param name="Address2">Secondary address line (e.g., "Apt 4B"). Optional.</param>
/// <param name="City">The city of the address (e.g., "New York"). Optional if zip is provided.</param>
/// <param name="State">The state of the address (e.g., "NY"). Optional if zip is provided.</param>
/// <param name="Zip">The ZIP code of the address. Optional if city and state are provided.</param>
/// <param name="TaxType">The type of tax to look for ("sales" or "use").</param>
/// <param name="LicenseKey">The license key to authenticate the API request.</param>
/// <param name="IsLive">Indicates whether to use the live service (true) or trial service (false).</param>
/// <param name="TimeoutSeconds">Timeout duration for the API call, in seconds.</param>
public record GetBestMatchInput(
string Address = "",
string Address2 = "",
string City = "",
string State = "",
string Zip = "",
string TaxType = "",
string LicenseKey = "",
bool IsLive = true,
int TimeoutSeconds = 15
);
}
}
using System.Runtime.Serialization;
using System.Linq;
namespace fast_tax_dot_net.REST
{
/// <summary>
/// Response from GetBestMatch API, containing tax rate information for the best match.
/// </summary>
[DataContract]
public class GetBestMatchResponse
{
public BestMatchTaxInfo[] TaxInfoItems { get; set; }
public string MatchLevel { get; set; }
public Error Error { get; set; }
public string[] Debug { get; set; }
public override string ToString()
{
string taxInfoItemsStr = TaxInfoItems != null
? string.Join("\n", TaxInfoItems.Select(taxInfo => taxInfo.ToString()))
: "null";
string debugStr = Debug != null
? string.Join(", ", Debug)
: "null";
return $"GetBestMatchResponse:\n" +
$"TaxInfoItems:\n{taxInfoItemsStr}\n" +
$"MatchLevel: {MatchLevel}\n" +
$"Error: {(Error != null ? Error.ToString() : "null")}\n" +
$"Debug: [{debugStr}]";
}
}
/// <summary>
/// Tax information for a matched address or ZIP code.
/// </summary>
[DataContract]
public class BestMatchTaxInfo
{
public string Zip { get; set; }
public string City { get; set; }
public string County { get; set; }
public string StateAbbreviation { get; set; }
public string StateName { get; set; }
public string TaxRate { get; set; }
public string StateRate { get; set; }
public string CityRate { get; set; }
public string CountyRate { get; set; }
public string CountyDistrictRate { get; set; }
public string CityDistrictRate { get; set; }
public string SpecialDistrictRate { get; set; }
public InformationComponent[] InformationComponents { get; set; }
public string TotalTaxExempt { get; set; }
public string NotesCodes { get; set; }
public string NotesDesc { get; set; }
public override string ToString()
{
string infoComponentsStr = InformationComponents != null
? string.Join(", ", InformationComponents.Select(ic => ic.ToString()))
: "null";
return $"BestMatchTaxInfo:\n" +
$"Zip: {Zip}\n" +
$"City: {City}\n" +
$"County: {County}\n" +
$"StateAbbreviation: {StateAbbreviation}\n" +
$"StateName: {StateName}\n" +
$"TaxRate: {TaxRate}\n" +
$"StateRate: {StateRate}\n" +
$"CityRate: {CityRate}\n" +
$"CountyRate: {CountyRate}\n" +
$"CountyDistrictRate: {CountyDistrictRate}\n" +
$"CityDistrictRate: {CityDistrictRate}\n" +
$"SpecialDistrictRate: {SpecialDistrictRate}\n" +
$"InformationComponents: [{infoComponentsStr}]\n" +
$"TotalTaxExempt: {TotalTaxExempt}\n" +
$"NotesCodes: {NotesCodes}\n" +
$"NotesDesc: {NotesDesc}";
}
}
/// <summary>
/// Information component containing name-value pairs for additional tax information.
/// </summary>
[DataContract]
public class InformationComponent
{
public string Name { get; set; }
public string Value { get; set; }
public override string ToString()
{
return $"Name: {Name}, Value: {Value}";
}
}
/// <summary>
/// Error object for API responses.
/// </summary>
[DataContract]
public class Error
{
public string Desc { get; set; }
public string Number { get; set; }
public string Location { get; set; }
public override string ToString()
{
return $"Desc: {Desc}, Number: {Number}, Location: {Location}";
}
}
}
using System.Text.Json;
using System.Web;
namespace fast_tax_dot_net.REST
{
public class Helper
{
public static T HttpGet<T>(string url, int timeoutSeconds)
{
using var httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(timeoutSeconds)
};
using var request = new HttpRequestMessage(HttpMethod.Get, url);
using HttpResponseMessage response = httpClient
.SendAsync(request)
.GetAwaiter()
.GetResult();
response.EnsureSuccessStatusCode();
using Stream responseStream = response.Content
.ReadAsStreamAsync()
.GetAwaiter()
.GetResult();
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
object? obj = JsonSerializer.Deserialize(responseStream, typeof(T), options);
T result = (T)obj!;
return result;
}
// Asynchronous HTTP GET and JSON deserialize
public static async Task<T> HttpGetAsync<T>(string url, int timeoutSeconds)
{
HttpClient HttpClient = new HttpClient();
HttpClient.Timeout = TimeSpan.FromSeconds(timeoutSeconds);
using var httpResponse = await HttpClient.GetAsync(url).ConfigureAwait(false);
httpResponse.EnsureSuccessStatusCode();
var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
return JsonSerializer.Deserialize<T>(stream)!;
}
public static string UrlEncode(string value) => HttpUtility.UrlEncode(value ?? string.Empty);
}
}
FastTax Python Rest Code Snippet
from ft_response import GetBestMatchResponse, BestMatchTaxInfo, InformationComponent, Error
import requests
# Endpoint URLs for ServiceObjects FastTax (FT) API
primary_url = "https://sws.serviceobjects.com/ft/web.svc/json/GetBestMatch?"
backup_url = "https://swsbackup.serviceobjects.com/ft/web.svc/json/GetBestMatch?"
trial_url = "https://trial.serviceobjects.com/ft/web.svc/json/GetBestMatch?"
def get_best_match(
address: str,
address2: str,
city: str,
state: str,
zip: str,
tax_type: str,
license_key: str,
is_live: bool = True
) -> GetBestMatchResponse:
"""
Call ServiceObjects FastTax (FT) API's GetBestMatch endpoint
to retrieve tax rate information (e.g., total tax rate, city, county, state rates) for a given US address.
Parameters:
address: Address line of the address to get tax rates for (e.g., "123 Main Street").
address2: Secondary address line (e.g., "Apt 4B"). Optional.
city: The city of the address (e.g., "New York"). Optional if zip is provided.
state: The state of the address (e.g., "NY"). Optional if zip is provided.
zip: The ZIP code of the address. Optional if city and state are provided.
tax_type: The type of tax to look for ("sales" or "use").
license_key: Your ServiceObjects license key.
is_live: Use live or trial servers.
Returns:
GetBestMatchResponse: Parsed JSON response with tax rate results or error details.
Raises:
RuntimeError: If the API returns an error payload.
requests.RequestException: On network/HTTP failures (trial mode).
"""
params = {
"Address": address,
"Address2": address2,
"City": city,
"State": state,
"Zip": zip,
"TaxType": tax_type,
"LicenseKey": license_key,
}
# Select the base URL: production vs trial
url = primary_url if is_live else trial_url
try:
# Attempt primary (or trial) endpoint
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
# If API returned an error in JSON payload, trigger fallback
error = data.get('Error')
if not (error is None or error.get('Number') != "4"):
if is_live:
# Try backup URL
response = requests.get(backup_url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
# If still error, propagate exception
if 'Error' in data:
raise RuntimeError(f"FastTax service error: {data['Error']}")
else:
# Trial mode error is terminal
raise RuntimeError(f"FastTax trial error: {data['Error']}")
# Convert JSON response to GetBestMatchResponse for structured access
error = Error(**data.get("Error", {})) if data.get("Error") else None
return GetBestMatchResponse(
TaxInfoItems=[
BestMatchTaxInfo(
Zip=ti.get("Zip"),
City=ti.get("City"),
County=ti.get("County"),
StateAbbreviation=ti.get("StateAbbreviation"),
StateName=ti.get("StateName"),
TaxRate=ti.get("TaxRate"),
StateRate=ti.get("StateRate"),
CityRate=ti.get("CityRate"),
CountyRate=ti.get("CountyRate"),
CountyDistrictRate=ti.get("CountyDistrictRate"),
CityDistrictRate=ti.get("CityDistrictRate"),
SpecialDistrictRate=ti.get("SpecialDistrictRate"),
InformationComponents=[
InformationComponent(Name=comp.get("Name"), Value=comp.get("Value"))
for comp in ti.get("InformationComponents", [])
] if "InformationComponents" in ti else [],
TotalTaxExempt=ti.get("TotalTaxExempt"),
NotesCodes=ti.get("NotesCodes"),
NotesDesc=ti.get("NotesDesc")
)
for ti in data.get("TaxInfoItems", [])
] if "TaxInfoItems" in data else [],
MatchLevel=data.get("MatchLevel"),
Error=error,
Debug=data.get("Debug", [])
)
except requests.RequestException as req_exc:
# Network or HTTP-level error occurred
if is_live:
try:
# Fallback to backup URL
response = requests.get(backup_url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
if "Error" in data:
raise RuntimeError(f"FastTax backup error: {data['Error']}") from req_exc
error = Error(**data.get("Error", {})) if data.get("Error") else None
return GetBestMatchResponse(
TaxInfoItems=[
BestMatchTaxInfo(
Zip=ti.get("Zip"),
City=ti.get("City"),
County=ti.get("County"),
StateAbbreviation=ti.get("StateAbbreviation"),
StateName=ti.get("StateName"),
TaxRate=ti.get("TaxRate"),
StateRate=ti.get("StateRate"),
CityRate=ti.get("CityRate"),
CountyRate=ti.get("CountyRate"),
CountyDistrictRate=ti.get("CountyDistrictRate"),
CityDistrictRate=ti.get("CityDistrictRate"),
SpecialDistrictRate=ti.get("SpecialDistrictRate"),
InformationComponents=[
InformationComponent(Name=comp.get("Name"), Value=comp.get("Value"))
for comp in ti.get("InformationComponents", [])
] if "InformationComponents" in ti else [],
TotalTaxExempt=ti.get("TotalTaxExempt"),
NotesCodes=ti.get("NotesCodes"),
NotesDesc=ti.get("NotesDesc")
)
for ti in data.get("TaxInfoItems", [])
] if "TaxInfoItems" in data else [],
MatchLevel=data.get("MatchLevel"),
Error=error,
Debug=data.get("Debug", [])
)
except Exception as backup_exc:
raise RuntimeError("FastTax service unreachable on both endpoints") from backup_exc
else:
raise RuntimeError(f"FastTax trial error: {str(req_exc)}") from req_exc
from dataclasses import dataclass
from typing import Optional, List
@dataclass
class GetBestMatchInput:
Address: Optional[str] = None
Address2: Optional[str] = None
City: Optional[str] = None
State: Optional[str] = None
Zip: Optional[str] = None
TaxType: Optional[str] = None
LicenseKey: Optional[str] = None
IsLive: bool = True
TimeoutSeconds: int = 15
def __str__(self) -> str:
return (f"GetBestMatchInput: Address={self.Address}, Address2={self.Address2}, City={self.City}, "
f"State={self.State}, Zip={self.Zip}, TaxType={self.TaxType}, LicenseKey={self.LicenseKey}, "
f"IsLive={self.IsLive}, TimeoutSeconds={self.TimeoutSeconds}")
@dataclass
class InformationComponent:
Name: Optional[str] = None
Value: Optional[str] = None
def __str__(self) -> str:
return f"InformationComponent: Name={self.Name}, Value={self.Value}"
@dataclass
class Error:
Desc: Optional[str] = None
Number: Optional[str] = None
Location: Optional[str] = None
def __str__(self) -> str:
return f"Error: Desc={self.Desc}, Number={self.Number}, Location={self.Location}"
@dataclass
class BestMatchTaxInfo:
Zip: Optional[str] = None
City: Optional[str] = None
County: Optional[str] = None
StateAbbreviation: Optional[str] = None
StateName: Optional[str] = None
TaxRate: Optional[float] = None
StateRate: Optional[float] = None
CityRate: Optional[float] = None
CountyRate: Optional[float] = None
CountyDistrictRate: Optional[float] = None
CityDistrictRate: Optional[float] = None
SpecialDistrictRate: Optional[float] = None
InformationComponents: Optional[List['InformationComponent']] = None
TotalTaxExempt: Optional[str] = None
NotesCodes: Optional[str] = None
NotesDesc: Optional[str] = None
def __post_init__(self):
if self.InformationComponents is None:
self.InformationComponents = []
def __str__(self) -> str:
components_string = ', '.join(str(component) for component in self.InformationComponents) if self.InformationComponents else 'None'
return (f"BestMatchTaxInfo: Zip={self.Zip}, City={self.City}, County={self.County}, "
f"StateAbbreviation={self.StateAbbreviation}, StateName={self.StateName}, "
f"TaxRate={self.TaxRate}, StateRate={self.StateRate}, CityRate={self.CityRate}, "
f"CountyRate={self.CountyRate}, CountyDistrictRate={self.CountyDistrictRate}, "
f"CityDistrictRate={self.CityDistrictRate}, SpecialDistrictRate={self.SpecialDistrictRate}, "
f"InformationComponents=[{components_string}], TotalTaxExempt={self.TotalTaxExempt}, "
f"NotesCodes={self.NotesCodes}, NotesDesc={self.NotesDesc}")
@dataclass
class GetBestMatchResponse:
TaxInfoItems: Optional[List['BestMatchTaxInfo']] = None
MatchLevel: Optional[str] = None
Error: Optional['Error'] = None
Debug: Optional[List[str]] = None
def __post_init__(self):
if self.TaxInfoItems is None:
self.TaxInfoItems = []
if self.Debug is None:
self.Debug = []
def __str__(self) -> str:
tax_info_string = '; '.join(str(tax_info) for tax_info in self.TaxInfoItems) if self.TaxInfoItems else 'None'
debug_string = ', '.join(self.Debug) if self.Debug else 'None'
error = str(self.Error) if self.Error else 'None'
return (f"GetBestMatchResponse: TaxInfoItems=[{tax_info_string}], MatchLevel={self.MatchLevel}, "
f"Error={error}, Debug=[{debug_string}]")
FastTax NodeJS Rest Code Snippet
import axios from 'axios';
import querystring from 'querystring';
import { GetBestMatchResponse } from './ft_response.js';
/**
* @constant
* @type {string}
* @description The base URL for the live ServiceObjects FastTax (FT) API service.
*/
const LiveBaseUrl = 'https://sws.serviceobjects.com/ft/web.svc/json/';
/**
* @constant
* @type {string}
* @description The base URL for the backup ServiceObjects FastTax (FT) API service.
*/
const BackupBaseUrl = 'https://swsbackup.serviceobjects.com/ft/web.svc/json/';
/**
* @constant
* @type {string}
* @description The base URL for the trial ServiceObjects FastTax (FT) API service.
*/
const TrialBaseUrl = 'https://trial.serviceobjects.com/ft/web.svc/json/';
/**
* <summary>
* Checks if a response from the API is valid by verifying that it either has no Error object
* or the Error.Number is not equal to '4'.
* </summary>
* <param name="response" type="Object">The API response object to validate.</param>
* <returns type="boolean">True if the response is valid, false otherwise.</returns>
*/
const isValid = (response) => !response?.Error || response.Error.Number !== '4';
/**
* <summary>
* Constructs a full URL for the GetBestMatch API endpoint by combining the base URL
* with query parameters derived from the input parameters.
* </summary>
* <param name="params" type="Object">An object containing all the input parameters.</param>
* <param name="baseUrl" type="string">The base URL for the API service (live, backup, or trial).</param>
* <returns type="string">The constructed URL with query parameters.</returns>
*/
const buildUrl = (params, baseUrl) =>
`${baseUrl}GetBestMatch?${querystring.stringify(params)}`;
/**
* <summary>
* Performs an HTTP GET request to the specified URL with a given timeout.
* </summary>
* <param name="url" type="string">The URL to send the GET request to.</param>
* <param name="timeoutSeconds" type="number">The timeout duration in seconds for the request.</param>
* <returns type="Promise<GetBestMatchResponse>">A promise that resolves to a GetBestMatchResponse object containing the API response data.</returns>
* <exception cref="Error">Thrown if the HTTP request fails, with a message detailing the error.</exception>
*/
const httpGet = async (url, timeoutSeconds) => {
try {
const response = await axios.get(url, { timeout: timeoutSeconds * 1000 });
return new GetBestMatchResponse(response.data);
} catch (error) {
throw new Error(`HTTP request failed: ${error.message}`);
}
};
/**
* <summary>
* Provides functionality to call the ServiceObjects FastTax (FT) API's GetBestMatch endpoint,
* retrieving tax rate information (e.g., total tax rate, city, county, state rates) for a given US address
* with fallback to a backup endpoint for reliability in live mode.
* </summary>
*/
const GetBestMatchClient = {
/**
* <summary>
* Asynchronously invokes the GetBestMatch API endpoint, attempting the primary endpoint
* first and falling back to the backup if the response is invalid (Error.Number == '4') in live mode.
* </summary>
* @param {string} Address - Address line of the address to get tax rates for (e.g., "123 Main Street").
* @param {string} Address2 - Secondary address line (e.g., "Apt 4B"). Optional.
* @param {string} City - The city of the address (e.g., "New York"). Optional if zip is provided.
* @param {string} State - The state of the address (e.g., "NY"). Optional if zip is provided.
* @param {string} Zip - The ZIP code of the address. Optional if city and state are provided.
* @param {string} TaxType - The type of tax to look for ("sales" or "use").
* @param {string} LicenseKey - Your license key to use the service.
* @param {boolean} isLive - Value to determine whether to use the live or trial servers.
* @param {number} timeoutSeconds - Timeout, in seconds, for the call to the service.
* @returns {Promise<GetBestMatchResponse>} - A promise that resolves to a GetBestMatchResponse object.
*/
async invokeAsync(Address, Address2, City, State, Zip, TaxType, LicenseKey, isLive = true, timeoutSeconds = 15) {
const params = {
Address,
Address2,
City,
State,
Zip,
TaxType,
LicenseKey
};
const url = buildUrl(params, isLive ? LiveBaseUrl : TrialBaseUrl);
let response = await httpGet(url, timeoutSeconds);
if (isLive && !isValid(response)) {
const fallbackUrl = buildUrl(params, BackupBaseUrl);
const fallbackResponse = await httpGet(fallbackUrl, timeoutSeconds);
return fallbackResponse;
}
return response;
},
/**
* <summary>
* Synchronously invokes the GetBestMatch API endpoint by wrapping the async call
* and awaiting its result immediately.
* </summary>
* @param {string} Address - Address line of the address to get tax rates for (e.g., "123 Main Street").
* @param {string} Address2 - Secondary address line (e.g., "Apt 4B"). Optional.
* @param {string} City - The city of the address (e.g., "New York"). Optional if zip is provided.
* @param {string} State - The state of the address (e.g., "NY"). Optional if zip is provided.
* @param {string} Zip - The ZIP code of the address. Optional if city and state are provided.
* @param {string} TaxType - The type of tax to look for ("sales" or "use").
* @param {string} LicenseKey - Your license key to use the service.
* @param {boolean} isLive - Value to determine whether to use the live or trial servers.
* @param {number} timeoutSeconds - Timeout, in seconds, for the call to the service.
* @returns {GetBestMatchResponse} - A GetBestMatchResponse object with tax rate details or an error.
*/
invoke(Address, Address2, City, State, Zip, TaxType, LicenseKey, isLive = true, timeoutSeconds = 15) {
return (async () => await this.invokeAsync(
Address, Address2, City, State, Zip, TaxType, LicenseKey, isLive, timeoutSeconds
))();
}
};
export { GetBestMatchClient, GetBestMatchResponse };
/**
* Input parameters for the GetBestMatch API call.
*/
export class GetBestMatchInput {
constructor(data = {}) {
this.Address = data.Address;
this.Address2 = data.Address2;
this.City = data.City;
this.State = data.State;
this.Zip = data.Zip;
this.TaxType = data.TaxType;
this.LicenseKey = data.LicenseKey;
this.IsLive = data.IsLive !== undefined ? data.IsLive : true;
this.TimeoutSeconds = data.TimeoutSeconds !== undefined ? data.TimeoutSeconds : 15;
}
toString() {
return `GetBestMatchInput: Address = ${this.Address}, Address2 = ${this.Address2}, City = ${this.City}, State = ${this.State}, Zip = ${this.Zip}, TaxType = ${this.TaxType}, LicenseKey = ${this.LicenseKey}, IsLive = ${this.IsLive}, TimeoutSeconds = ${this.TimeoutSeconds}`;
}
}
/**
* Information Component for API responses.
*/
export class InformationComponent {
constructor(data = {}) {
this.Name = data.Name;
this.Value = data.Value;
}
toString() {
return `Name = ${this.Name}, Value = ${this.Value}`;
}
}
/**
* Error object for API responses.
*/
export class Error {
constructor(data = {}) {
this.Desc = data.Desc;
this.Number = data.Number;
this.Location = data.Location;
}
toString() {
return `Error: Desc = ${this.Desc}, Number = ${this.Number}, Location = ${this.Location}`;
}
}
/**
* Tax information for a matched address or ZIP code.
*/
export class BestMatchTaxInfo {
constructor(data = {}) {
this.Zip = data.Zip;
this.City = data.City;
this.County = data.County;
this.StateAbbreviation = data.StateAbbreviation;
this.StateName = data.StateName;
this.TaxRate = data.TaxRate;
this.StateRate = data.StateRate;
this.CityRate = data.CityRate;
this.CountyRate = data.CountyRate;
this.CountyDistrictRate = data.CountyDistrictRate;
this.CityDistrictRate = data.CityDistrictRate;
this.SpecialDistrictRate = data.SpecialDistrictRate;
this.InformationComponents = (data.InformationComponents || []).map(component => new InformationComponent(component));
this.TotalTaxExempt = data.TotalTaxExempt;
this.NotesCodes = data.NotesCodes;
this.NotesDesc = data.NotesDesc;
}
toString() {
const componentsString = this.InformationComponents.length
? this.InformationComponents.map(component => component.toString()).join(', ')
: 'null';
return `BestMatchTaxInfo: Zip = ${this.Zip}, City = ${this.City}, County = ${this.County}, StateAbbreviation = ${this.StateAbbreviation}, StateName = ${this.StateName}, TaxRate = ${this.TaxRate}, StateRate = ${this.StateRate}, CityRate = ${this.CityRate}, CountyRate = ${this.CountyRate}, CountyDistrictRate = ${this.CountyDistrictRate}, CityDistrictRate = ${this.CityDistrictRate}, SpecialDistrictRate = ${this.SpecialDistrictRate}, InformationComponents = [${componentsString}], TotalTaxExempt = ${this.TotalTaxExempt}, NotesCodes = ${this.NotesCodes}, NotesDesc = ${this.NotesDesc}`;
}
}
/**
* Response from GetBestMatch API, containing tax rate information for the best match.
*/
export class GetBestMatchResponse {
constructor(data = {}) {
this.TaxInfoItems = (data.TaxInfoItems || []).map(taxInfo => new BestMatchTaxInfo(taxInfo));
this.MatchLevel = data.MatchLevel;
this.Error = data.Error ? new Error(data.Error) : null;
this.Debug = data.Debug || [];
}
toString() {
const taxInfoItemsString = this.TaxInfoItems.length
? this.TaxInfoItems.map(taxInfo => taxInfo.toString()).join('; ')
: 'null';
const debugString = this.Debug.length
? this.Debug.join(', ')
: 'null';
return `GetBestMatchResponse: TaxInfoItems = [${taxInfoItemsString}], MatchLevel = ${this.MatchLevel}, Error = ${this.Error ? this.Error.toString() : 'null'}, Debug = [${debugString}]`;
}
}
export default GetBestMatchResponse;