Page 1 of 2

Tax Provider Integration : Avalara

Posted: Tue Nov 27, 2007 3:16 pm
by jrobgood
We also would like to integrate with a third-party tax provider. If the AC dev team can point us in the right direction in the source code that would be excellent.

Thanks!

Posted: Tue Nov 27, 2007 4:59 pm
by Logan Rhodehamel
Here's a brief overview.

1) Create a class that inherits from CommerceBuilder.Taxes.Providers.TaxProviderBase. This is an abstract class that forms the base of the provider.

2) Implement the required members of the base class. Visual Studio can create method stubs for you.

Calculate This method takes a basket object as input. From there, you can get the billing and shipping addresses as well as line items. What you need to do is determine the tax to charge - then add line items to the basket (BasketItem class) for each line item. The method returns the total tax that was added to the basket.

Commit This method takes an order object as input and commits any taxes that were charged. This may not be required by your integration. Some providers may need to know what taxes were actually charged in order to produce accurate reports on tax liability.

Cancel This method takes a basket object as input. WHen called, it cancels any tax charges currently in progress. Your integration may or may not require this. Some providers may use this to reset the calculations for a particular order in progress.

3) Once your class is implemented and compiled, you need to register it with the store. Since we did not include our tax providers, there is no web based interface to do this. The simplest choice, if available, is to add a record to the database in the ac_TaxGateways table:

TaxGatewayId = auto number ID

StoreId = ID of your store, probably 1

Name = Name of your gateway

ClassId = .NET Class ID used to create an instance of your gateway. For examples, you can look in ac_PaymentGateways (assuming you have a gateway configured).

ConfigData = If you need to provide configuration data it can be stored here in a url encoded string. For example, key1=value&key2=value. The values in the field will be accessible in your integration by using the GetConfigData() method. If you are producing an integration only for yourselves, you don't need to worry about this as any configuration should be hard coded instead.

Hope this helps. Feel free to ask questions... We can answer until we have a formal doc and example. (We only have CCH integration completed and I can't release source for that as is...)

Posted: Wed Dec 19, 2007 2:04 am
by brian.sutherland
Hey Logan, thanks for the quick response on the original message.

We've finally gotten to the point where we are about to roll this sucker out, and I was able to implement some of what you explained, but I have a couple of questions still.

Our tax provider has some carry over from Calculate to Commit (it's basically the OrderID). For Calculate, since it takes a basket object, I was using basketId, and for Commit, since it takes an order, I was using OrderId. Is this correct? I unfortunately don't have a debugger on our server where we have AC installed, so I can't look at it myself on here, and I was unsuccessful in finding a data dictionary showing any coorelation between baskets and orders.

When looking at our web server, I cracked open SQLServer management studio, opened up SQLExpress, but I didn't see any DB's installed. Is there a default name that I should be seeing in here? I could just be tired and not seeing things straight here, but the site is working, so I know we have data in there.

Thanks in advance, and I'm sure I'll have another question before this is all said and done.

Posted: Wed Dec 19, 2007 10:03 am
by Logan Rhodehamel
brian.sutherland wrote:Our tax provider has some carry over from Calculate to Commit (it's basically the OrderID). For Calculate, since it takes a basket object, I was using basketId, and for Commit, since it takes an order, I was using OrderId. Is this correct? I unfortunately don't have a debugger on our server where we have AC installed, so I can't look at it myself on here, and I was unsuccessful in finding a data dictionary showing any coorelation between baskets and orders.
Let me think about that one. You need to correlate the basket to the final order, in order to commit the transaction. Is that correct?
brian.sutherland wrote:When looking at our web server, I cracked open SQLServer management studio, opened up SQLExpress, but I didn't see any DB's installed. Is there a default name that I should be seeing in here? I could just be tired and not seeing things straight here, but the site is working, so I know we have data in there.
I am guessing you installed using the included SQL express database? If so this is called a 'user instance' and the database is not linked up to studio in the traditional way. There are a lot of examples online of how to link up to your data:

http://blogs.msdn.com/sqlexpress/archiv ... tudio.aspx

There is also a way to attach the database to SQL Server so that it will be treated like a traditional database.

Posted: Thu Dec 20, 2007 1:07 am
by brian.sutherland
For the first part, yes, I think you have it. When you calculate, you need to pass in an ID number, that ends up saving that record to their server. When you commit, you need that same number in order to then "finalize" that record that was saved off in the calculate call. Likewise, with cancel, you pass in that same number too. I didn't see anything that stood out to me that I could use in both the basket object and in the order object. With your hesitation there, unfortunately maybe I stumbled across something that's gonna cause us a problem.

Thanks for the msdn article. I'll dig into this next, and try to start adding those other records that are needed to get this tax class integrated into our AC site.


You know, I just thought of something that may work...
I could use the calculate with different parameters on their side, which actually doesn't save a record, just gives back the value. Then, inside of commit, I could call calculate with the value that will save the record, then immediately call commit after, which would prevent us from having to have that value floating across both objects. Unless you can see something else that would work, I think this will be the way we have to end up going with it.

Posted: Thu Dec 20, 2007 9:08 am
by Logan Rhodehamel
brian.sutherland wrote:With your hesitation there, unfortunately maybe I stumbled across something that's gonna cause us a problem.
But we may have the same concern for our own integrations. We made a change to our database architecture - previously there was something in place to deal with this.

I will check this out today.

Posted: Mon Dec 24, 2007 2:45 am
by brian.sutherland
Alright, I neede a little more hand holding here, because the user instance doesn't seem to want to play nicely with me...

I downloaded SSEUtil, which, as I understand it, will allow me to change the heart_beat state of the instnaces to alive rather than dead.

When I log into MY account on the server, I see 2 lines... (names have been changed to protect the innocent)
1. NT AUTHORITY\NETWORK SERVICE \\.\pipe\blah1\tsql\query dead
2. MYDOMAIN\myusername \\.\pipe\blah2\tsql\query alive

As you can see, using SSEUtil, I was able to get mine to alive. However, when I look through the databases, I only see master, model (read only), msdb, and tempdb after I connect to my pipe in the object explorer.

So I was lucky enough to have the admin password shared with me from my customer, (which is where they installed the AC package from). I ran it, and this time, I see 3 entries...

1. NT AUTHORITY\NETWORK SERVICE \\.\pipe\blah1\tsql\query dead
2. MYDOMAIN\adminaccount \\.\pipe\blah3\tsql\query alive
3. MYDOMAIN\myusername \\.\pipe\blah2\tsql\query alive

Again, I was able to use SSEUtil to activate the adminaccount pipe here, but I looking through that, again, I'm coming up with nothing. So I'm now pretty sure NT AUTHORITY is the sucker I need to get started, but I havent' been able to get that to work, and don't want to waste more time than I already have this weekend and not ask for some help here.

I tried passing in the username in sseutil, with the following command
sseutil -child 'NT AUTHORITY\NETWORK SERVICE', and with the -user flag as well, but I get nothing.

Any hand holding you can provide on this would be extremly helpful. The deadline has pretty much passed, and this is pretty much the last piece I need to get in there, so if there are any other docs or things I need to know about, I'm all ears. Thanks in advance.

~Brian

Posted: Mon Dec 31, 2007 1:28 pm
by brian.sutherland
Just checking in to make sure I didn't slip through the cracks. I still haven't had any success adding those values into the db.

Posted: Wed Jan 02, 2008 3:46 pm
by Logan Rhodehamel
I have never had to use SSEUtil to turn the user instance on. Instead, just make a web request to the site that is using the database. The user instance will then be turned on.

Then run this query against the master database on the server:

SELECT owning_principal_name, instance_pipe_name, heart_beat FROM sys.dm_os_child_instances

Find the user instance that is showing as "alive" and connect to that one from object explorer.

Posted: Thu Jan 03, 2008 12:52 am
by brian.sutherland
OK, good deal. I was able to get it running doing your method rather than trying to fire it up with SSEUtil.

Now, just to be clear on the values to put in...

TaxGatewayId: auto numbered, I do nothing for it.

StoreId: 1, since that is the store value

Name: something like AvalaraGateway

ClassId: I saw that the PaymentGateway was named CommerceBuilder.Payments.Providers.GiftCertificatePaymentProvider, CommerceBuilder

I have a namespace of AvalaraTaxProvider
and the class declaration of public class MyTaxClass : CommerceBuilder.Taxes.Providers.TaxProviderBase

The output is a dll called AvalaraTaxProvider.dll

I'm a little confused as to what I should make the ClassId

ConfigData: I have none, so it should be good.

Looks like we're in the home stretch here, so if there is anything else that I didn't think of, please let me know.

Posted: Thu Jan 03, 2008 10:26 am
by Logan Rhodehamel
I'm a little confused as to what I should make the ClassId
I think something like

AvalaraTaxProvider.MyTaxClass, AvalaraTaxProvider

Posted: Sun Jan 06, 2008 3:30 pm
by brian.sutherland
Logan, you've been a life saver, thanks a bunch.

It's now in there, and being called, but it's not updating the order with the tax.

The tax provider is getting the correct values in there, but it's not reflected in the checkout process. I made sure the product was set to taxable, but I don't see a way to have that point to a custom tax provider. I have the rule and tax code set, but it's now just adding the value I put in tax rule that I created.

So close to having this wrapped up. Thanks a bunch for all the help you've provided so far.

Posted: Tue Jan 08, 2008 9:11 am
by Logan Rhodehamel
Tax calculators are a bit different from shipping and payment in the sense that they are expected to add items to the basket. I didn't realize this - I haven't worked on tax gateways in a long time.

Within our CertiTAX integration, calls to the "Calculate" method go something like this:

send CertiTAX request
receive CertiTAX response
check response for taxes
add tax line items to basket
return total tax added to basket

The last step uses this code:

Code: Select all

        private void CreateTaxLineItem(Basket basket, int shipmentId, string authorityName, string certiTaxTransactionId, LSDecimal amount)
        {
            BasketItem taxLineItem = new BasketItem();
            taxLineItem.BasketId = basket.BasketId;
            taxLineItem.OrderItemType = OrderItemType.Tax;
            taxLineItem.BasketShipmentId = shipmentId;
            taxLineItem.Name = authorityName;
            taxLineItem.Sku = string.Format("CT:" + certiTaxTransactionId);
            taxLineItem.Price = amount;
            taxLineItem.Quantity = 1;
            taxLineItem.Save();
            basket.Items.Add(taxLineItem);
        }
The parameter "shipmentId" may or may not apply to your integration. In the case of CertiTAX, some taxes are dependent on either the shipping origin or destination address. So we may associate a tax to a particular shipment. Setting this to 0 means the tax applies to the order as a whole and is not dependent on one of these addresses.

The authority name is what CertiTAX calls the tax jurisdiction. Like it might return "Clark County" or something like that.

You can modify this code as needed. I think this is the piece you are missing - instead you are thinking we will add tax line items based on the value you return.

Also, you should not need to set a tax rule for this to work. Tax rules are only used by the built in AbleCommerce tax engine.

Posted: Tue Jan 08, 2008 9:14 am
by Logan Rhodehamel
Also, notice that we use the SKU field to track the CertiTAX transaction ID. We use this during hte "Commit" phase, by searching through the order items to locate any Tax item types having a SKU that begins with "CT:". I don't know if this matters to you, but it's a field that can be used to store a little piece of arbitrary info.

Posted: Tue Jan 08, 2008 10:20 am
by brian.sutherland
OK, I think I got it...

So in my call to calculate, I'm going to add the value that is returned in their response, to the basket object that was passed in to my Calculate method.

I'll give that a shot tonight and let you know how it goes. Thanks a bunch.

Posted: Sun Jan 13, 2008 2:40 am
by brian.sutherland
Everything is hooked up now, and looking to be running good, except for the fact that Calculate is called when I add an item to my basket when the AddToBasketButton_Click is launched. (it could be elsewhere, but this is the event that fires off). Because I don't yet have the shipping address, my webservice cant calculate the tax properly, and I get an exception. I've stubbed it out for now, but I see this is going to be a problem. What I am doing now in the meantime is to just call the calculate code when the commit is called, which then gives me back the correct tax, I throw it into the order.Items, and it's working good that way. However, I don't have a way to show the user what the total price is before they actually hit the purchase button, so that's not ideal.

Any ideas on this? I'm hoping I just missed where the call was being made.

Posted: Tue Jan 15, 2008 9:09 pm
by brian.sutherland
I ended up catching the exception that was being thrown, and returning 0 for those calls.

After the address is put in, it seems the calculate call is called again, which since we then have the address, it's able to calculate it.

So I have it working, but had to add a few extra checks in there (I'm actually checking the SKU for the string "TAX" becasue that's what I was putting in there)

If this seems way off, let me know and I'll do it properly if there is something I'm missing here.

Thanks a bunch.

Has anyone completed this integration

Posted: Mon Mar 10, 2008 9:21 am
by mianders
If so, then would you be willing to share the code. We are trying to perform that same integration.

Avalara Provider service

Posted: Sun Mar 16, 2008 11:41 pm
by jrobgood
OK, here's the code that Brian built for us, sharing as promised. No warranty of usability, data protection, liability, your mileage may vary, etc etc.

http://files.brand-up.com/get/AvalaraTaxProvider.zip
Link updated 7/20/2008

Re: Avalara intergration

Posted: Fri May 09, 2008 5:30 pm
by mianders
I cannot get the download links to work. Can you repost the files. I need to get sales tax running on my site as soon as possible.

Re: Avalara intergration

Posted: Mon Jul 14, 2008 12:32 pm
by ajseltzer
Does anyone have access to the tester application? I cannot seem to download it.

Re: Avalara intergration

Posted: Mon Jul 21, 2008 8:01 pm
by trozzi
I see the solution for the classId of "AvalaraTaxProvider.MyTaxClass, AvalaraTaxProvider".

Does the second AvalaraTaxProvider reference the namespace or the name of the .dll?

Thanks
Thomas

Re: Avalara intergration

Posted: Tue Jul 22, 2008 7:19 am
by keats76
Anyone have an idea of the annual licensing costs for Alavara and a small order volume installation of AC7 (<1000 /yr)?

Their site doesn't make it very clear. Also, when they say "per transaction" does that mean per actual sale, or per web service call for tax lookup?

Thanks!
Mike

Re: Avalara intergration

Posted: Tue Jul 22, 2008 10:03 am
by jrobgood
keats76 wrote:Anyone have an idea of the annual licensing costs for Alavara and a small order volume installation of AC7 (<1000 /yr)?

Their site doesn't make it very clear. Also, when they say "per transaction" does that mean per actual sale, or per web service call for tax lookup?

Thanks!
Mike
Avalara. It costs us about $1800 a year including filing taxes in a few states.

Transactions aren't booked into their system until it's completed on the AC7 cart, so it keeps an accurate log of tax liability for us.

-Rob.

Re: Avalara integration

Posted: Thu Jul 24, 2008 2:16 am
by brian.sutherland
After being away from this project for a while, I'm now back to try to help out a little. We've updated to the latest version of AbleCommerce, changed around our Avalara to be a class within the appcode folder rather than a seperate dll, to try to clean things up, but are now having some problems.

We get a NullReferenceException when basket.Recalculate() is called. I'm thinking we have something wrong in the registration of our class. It seems a few of the things have changed since I last saw them, and I need one more (hopefully) little push to get it rolling again.
Before, we were told...
TaxGatewayId = auto number ID
StoreId = ID of your store, probably 1
Name = Name of your gateway
ClassId = .NET Class ID used to create an instance of your gateway. For examples, you can look in ac_PaymentGateways (assuming you have a gateway configured).

I had created my own gateway before (AvalaraGateway), but now we are using Authorize.Net. Should I put in "Authorize.Net" for that value?

Our classID is now namespace.classname, so it's AvalaraTaxProvider.MyTaxClass. (this is in the appcode folder, using the TaxProvider.cs file)

Is there anything obvious I'm missing here? This feels like the lamest post ever, getting everyting done already, then having to circle back and ask some of the things again, but there seem to have been a number of chagnes since I last used it (it was in beta then, too), and I'm hoping there are some easy lines that will connect this thing back up both on the server and in my head again.

Thanks a bunch.