Jump to content

Archived

This topic is now archived and is closed to further replies.

kidsngarden

WA state destination based sales tax

Recommended Posts

I'll bet this is going to wreak havoc with my CreditClassandGiftVouchers install......you think this is a pain, it took me about a year to make it work and EVERYTHING messes it up, but it is so embedded in the code it is easier to fix it than get rid of it. Sorry...little rant there.

 

lildog

Share this post


Link to post
Share on other sites
I got the response working quickly using curl, I will also look at your code and see what I can figure.

 

Ah, yes - works now. I'm embarrassed to say that I thought curl was something I'd have to add to my PHP install, and I didn't want to mess with it. Works great - here's my updated code/notes. Thanks for your help Jerry/Todd!

 

-Krista

 

 

In /catalog/includes/functions/general.php...

REPLACE line 315

global $customer_zone_id, $customer_country_id, $billto, $sendto, $cart, $customer_id;

WITH:

global $customer_zone_id, $customer_country_id, $billto, $sendto, $cart, $customer_id;

 

JUST AFTER line 326, INSERT:

	//DBK: WA State Sales Tax Modification
//Lookup WA State Sales tax from WA Department of Revenue website

if (tep_get_zone_code($customer_country_id, $customer_zone_id, "") == "WA") {
	//this customer is from Washington State,
	//so attempt to get their tax rate based on order destination

	//check to see if customer's address is available
	$tax_address_query = tep_db_query("select ab.entry_street_address, ab.entry_city, ab.entry_postcode from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)(($cart->content_type == 'virtual' ) ? $billto : $sendto) . "'"); 

	if (tep_db_num_rows($tax_address_query)) {
		//we have some address information for this customer, so find their tax rate
		$tax_address = tep_db_fetch_array($tax_address_query);
		$url = "http://dor.wa.gov/AddressRates.aspx?output=text";
		$url .= "&addr=".urlencode($tax_address['entry_street_address']);
		$url .= "&city=".urlencode($tax_address['entry_city']);
		$url .= "&zip=".urlencode($tax_address['entry_postcode']);

		$resultString = '';
		// Start a cURL session and send the data
		if($handle = curl_init($url)){
			// echo 'curl init successful';
			curl_setopt($handle,CURLOPT_RETURNTRANSFER,1);
			curl_setopt($handle, CURLOPT_HEADER, 0);
			curl_setopt($handle, CURLOPT_FORBID_REUSE, 1);
			curl_setopt($handle, CURLOPT_FRESH_CONNECT, 1);
			if($resultString = curl_exec($handle)) curl_close($handle);
		}

		if (!empty($resultString)) {
			$results = explode(' ', $resultString);
			foreach ($results as $key=>$value) {
				$breakPosition = strpos($value,"=");
				$newKey = substr($value,0,$breakPosition);
				$newValue = substr($value,$breakPosition+1);
				$results[$newKey] = $newValue;
			}
			if ((int)$results['ResultCode'] < 3) return $results['Rate']*100;
		}
	}
}
//end Washington State Tax Lookup Modification

Share this post


Link to post
Share on other sites

kehlers,

 

I would hazard a guess. Your unread bytes are 0 because there are none to read. It looks like those lines are reading the body of the page, which was my problem yesterday, there is no page to get the url.xml just generates a response, not an xml page like I thought. Maybe that would be why your response times are huge because it is reading alot of nothing? so commenting those lines out must be preventing the shipping mods from reading whatever they read. Maybe something like:

 

if (characters 0-17 of $url !='http://dor.wa.gov/AddressRates.aspx?output=text' )

then skip those fread lines.

 

lildog

Share this post


Link to post
Share on other sites
I would hazard a guess. Your unread bytes are 0 because there are none to read. It looks like those lines are reading the body of the page, which was my problem yesterday, there is no page to get the url.xml just generates a response, not an xml page like I thought. Maybe that would be why your response times are huge because it is reading alot of nothing? so commenting those lines out must be preventing the shipping mods from reading whatever they read. Maybe something like:

 

Yes, that is what was going on - I printed out the value of it. I think that somehow it's reading beyond EOF or something. However, there is no elegant way that I could think of to manage it. I can't do 1-17 chars, since it's using bytes. Interesting that php manual says (of unread_bytes) "warning: do not use this in scripts". LOL.

 

Anyhow, I figured that the CURL thing is quick/easy - not requiring any horrible hacks, doesn't break my other mods... You can see where I'm going. Great job.

 

Krista

Share this post


Link to post
Share on other sites
I'll bet this is going to wreak havoc with my CreditClassandGiftVouchers install......you think this is a pain, it took me about a year to make it work and EVERYTHING messes it up, but it is so embedded in the code it is easier to fix it than get rid of it. Sorry...little rant there.

 

HA - funny! I have also wrestled the CCGV beast to the ground... took forever. If you put the code in tep_get_tax_rate, I don't imagine it will mess with CCGV. It hasn't with my setup. BUT... maybe that's too much of a hack? I don't know. I thought it was a pretty neat way to do it.

Share this post


Link to post
Share on other sites

That's where I am going to put it, then it shuld only affect the one function. We'll see. Now the question is......do we create a new session so everytime the tax needs to be calculated it doesn't have to communicate with dor, just once?

 

lildog

Share this post


Link to post
Share on other sites

SO...if curl doesn't get the data and the result is empty, what to do? My first thought is return the stores tax rate and email the owner so the tax can be adjusted later. I don't know if this is right, but I do know I would rather eat the tax difference than put the order on hold or have the customer have to wait while we fin the rate manually. Let me know.

 

lildog

Share this post


Link to post
Share on other sites
That's where I am going to put it, then it should only affect the one function. We'll see. Now the question is......do we create a new session so every time the tax needs to be calculated it doesn't have to communicate with dor, just once?

 

IMHO, I think session vars are a little tricky because you have to either refresh the page or go to a different page to make sure the session var has the right value - in fact, this was a HUGE part of my CCGV issues. So, since the DOR access is sub-second timing, I'm just planning to have it re-visit every time tax needs calculating. Thoughts?

 

SO...if curl doesn't get the data and the result is empty, what to do? My first thought is return the stores tax rate and email the owner so the tax can be adjusted later. I don't know if this is right, but I do know I would rather eat the tax difference than put the order on hold or have the customer have to wait while we fin the rate manually. Let me know.

 

Well, my code is structured so that if everything goes fine, it returns the tax rate from DOR. IF, however, any one of several issues happens (the person is not from WA, I can't find the person's tax address info, I can't connect to DOR, there is no reply from DOR, or DOR returns an error code, NOTHING happens, nothing gets returned. Then, the program control resumes with the rest of the original tep_get_tax_rate function, which will return the store's tax rate.

 

Risks of this approach are:

1) the store's tax rate is lower than the delivery address tax rate, in which case the store eats the difference

2) the store's tax rate is higher than the delivery address tax rate, in which case the customer can ask for a refund of sales tax charge

 

I figure both cases are annoying, but not too big of a deal. I mean, the other alternative is to put an error to the customer, but what can they really do? If there was a comm error with DOR, the customer can't fix that. If the customer's address can't be found, we could pop them back to checkout_shipping, but what a pain! My thought was that if the customer gets an error, they are MOST LIKELY to give up and shop somewhere else, and nobody wants that...

 

Another note: I think the code also needs to be added to /catalog/admin/includes/functions/general.php. Haven't tested it there, though - just ran out of time.

Share this post


Link to post
Share on other sites

I have put this together as a contrib. I used kehlers code but put it into a function in general.php to hopefully make future edits easier, and keep edits to core functions to a minimum which sometimes helps when integrating other mods and oscommerce updates. I believe this is complete enough for production servers now, no guarantees though. PLEASE let me, us know of bugs and improvements.

 

THANK YOU GOES TO:

keith01 for getting the ball rolling

jerry for the correct way to retrieve the data

kehlers for most of the code and comments.

 

I still need too incorporate this into the admin side....

 

 

AS soon as I can connect to the add on site I will upload Version 2.0.

 

lildog

Share this post


Link to post
Share on other sites
THANK YOU GOES TO:

keith01 for getting the ball rolling

jerry for the correct way to retrieve the data

kehlers for most of the code and comments.

 

Great job! And you're very welcome for my small part. I have done my own testing on this, and it seems to work fine, and one of my clients is also testing with good results. Will let you know if I get the admin stuff done soon, but honestly, it's not a *huge* priority for me, as I must get back to what I was supposed to be doing this week ... heh heh.

k

Share this post


Link to post
Share on other sites

I'm taking a look at the function file alteration, where is wa_dest_tax.php?

It's not included in the zip?

Share this post


Link to post
Share on other sites
Ah, yes - works now. I'm embarrassed to say that I thought curl was something I'd have to add to my PHP install, and I didn't want to mess with it. Works great - here's my updated code/notes. Thanks for your help Jerry/Todd!

 

-Krista

 

 

In /catalog/includes/functions/general.php...

REPLACE line 315

global $customer_zone_id, $customer_country_id, $billto, $sendto, $cart, $customer_id;

WITH:

global $customer_zone_id, $customer_country_id, $billto, $sendto, $cart, $customer_id;

 

JUST AFTER line 326, INSERT:

	//DBK: WA State Sales Tax Modification
//Lookup WA State Sales tax from WA Department of Revenue website

if (tep_get_zone_code($customer_country_id, $customer_zone_id, "") == "WA") {
	//this customer is from Washington State,
	//so attempt to get their tax rate based on order destination

	//check to see if customer's address is available
	$tax_address_query = tep_db_query("select ab.entry_street_address, ab.entry_city, ab.entry_postcode from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)(($cart->content_type == 'virtual' ) ? $billto : $sendto) . "'"); 

	if (tep_db_num_rows($tax_address_query)) {
		//we have some address information for this customer, so find their tax rate
		$tax_address = tep_db_fetch_array($tax_address_query);
		$url = "http://dor.wa.gov/AddressRates.aspx?output=text";
		$url .= "&addr=".urlencode($tax_address['entry_street_address']);
		$url .= "&city=".urlencode($tax_address['entry_city']);
		$url .= "&zip=".urlencode($tax_address['entry_postcode']);

		$resultString = '';
		// Start a cURL session and send the data
		if($handle = curl_init($url)){
			// echo 'curl init successful';
			curl_setopt($handle,CURLOPT_RETURNTRANSFER,1);
			curl_setopt($handle, CURLOPT_HEADER, 0);
			curl_setopt($handle, CURLOPT_FORBID_REUSE, 1);
			curl_setopt($handle, CURLOPT_FRESH_CONNECT, 1);
			if($resultString = curl_exec($handle)) curl_close($handle);
		}

		if (!empty($resultString)) {
			$results = explode(' ', $resultString);
			foreach ($results as $key=>$value) {
				$breakPosition = strpos($value,"=");
				$newKey = substr($value,0,$breakPosition);
				$newValue = substr($value,$breakPosition+1);
				$results[$newKey] = $newValue;
			}
			if ((int)$results['ResultCode'] < 3) return $results['Rate']*100;
		}
	}
}
//end Washington State Tax Lookup Modification

 

 

This may be a stupid question, but where exactly in general.php is this supposed to go? I see the line numbers you've mentioned, however my general.php has several mods installed. Is this in the tep_get_tax_rate() function? If so, does it replace everything?

 

Thanks,

 

- Charles

Share this post


Link to post
Share on other sites

apologies,wa_dest_tax.php is no longer part of this contribution...delete the lines at the beginning of general.php that reference it. Will update the contrib now.

 

lildog

Share this post


Link to post
Share on other sites

charles, look at the contrib, basically the same code and will show you where the code goes.

 

lildog

Share this post


Link to post
Share on other sites
charles, look at the contrib, basically the same code and will show you where the code goes.

 

lildog

 

Thank you, that worked except for one thing. You never called the parse_DOR() function in the contrib.

 

//BOF WA State Tax Modification
		if (tep_get_zone_code($customer_country_id, $customer_zone_id, "") == "WA") { //make sure this universal
		  //this customer is from Washington State,
		  //so attempt to get their tax rate based on order destination
		  if ($tax_rate!='' && $tax_rate!='0') return $tax_rate;
}
//EOF WA State Tax Modification

Should be:

//BOF WA State Tax Modification
		if (tep_get_zone_code($customer_country_id, $customer_zone_id, "") == "WA") { //make sure this universal
		  //this customer is from Washington State,
		  //so attempt to get their tax rate based on order destination
		  $tax_rate = parse_DOR();
		  if ($tax_rate!='' && $tax_rate!='0') return $tax_rate;
}
//EOF WA State Tax Modification

 

At least, that's what it took for me to get it working correctly. Thanks again to all who made this possible. This came along at the right time as I was having difficulties getting v1.5 to work.

 

USA! USA! USA!

Share this post


Link to post
Share on other sites

Charles you are correct. So many edits so many files I lose track......thank you. You are now officially one of those who made this possible. V1.5 was a work in progress and we didn't think they had an API up....

 

lildog

Share this post


Link to post
Share on other sites
I have put this together as a contrib. I used kehlers code but put it into a function in general.php to hopefully make future edits easier, and keep edits to core functions to a minimum which sometimes helps when integrating other mods and oscommerce updates. I believe this is complete enough for production servers now, no guarantees though. PLEASE let me, us know of bugs and improvements.

 

THANK YOU GOES TO:

keith01 for getting the ball rolling

jerry for the correct way to retrieve the data

kehlers for most of the code and comments.

 

I still need too incorporate this into the admin side....

 

 

AS soon as I can connect to the add on site I will upload Version 2.0.

 

lildog

 

This is great - thanks for taking the time to put it together - very simple and elegant.

 

However, my site is hanging every time that I upload this general.php. I have to upload the old version and restart the server to remedy the issue. Any clues?

Share this post


Link to post
Share on other sites

I tried to place orders with different zip codes in WA that would generate different tax rates, but the confirmation page always displays my default store's tax (8.9%).

Any suggestion? How can I test that I successfully connect to the DOR database?

 

thanks!

Share this post


Link to post
Share on other sites

pixclinic,

Are you using the newest version? 2.1.1? The previous version was missing a bit of code. First be sure curl is installed on your server. in the parse_DOR function you could put an echo statement to see if you are connecting.

 

FIND:

if($handle = curl_init($url)){

curl_setopt($handle,CURLOPT_RETURNTRANSFER,1);

curl_setopt($handle, CURLOPT_HEADER, 0);

curl_setopt($handle, CURLOPT_FORBID_REUSE, 1);

curl_setopt($handle, CURLOPT_FRESH_CONNECT, 1);

if($resultString = curl_exec($handle))curl_close($handle);

}

 

ADD AFTER:

if (extension_loaded('curl')== 1){

echo 'cURL extension is installed.';

}

echo 'DOR rate: '.$resultString;

 

When you try this it should show up on any page that has the shopping cart box, among other things.

Share this post


Link to post
Share on other sites

watermelon,

what exactly do you mean by hanging? Do your server script logs show anything? I would also start by seeing if cURL is installed, see my previous post.

 

lildog

Share this post


Link to post
Share on other sites
pixclinic,

Are you using the newest version? 2.1.1? The previous version was missing a bit of code. First be sure curl is installed on your server. in the parse_DOR function you could put an echo statement to see if you are connecting.

 

FIND:

if($handle = curl_init($url)){

curl_setopt($handle,CURLOPT_RETURNTRANSFER,1);

curl_setopt($handle, CURLOPT_HEADER, 0);

curl_setopt($handle, CURLOPT_FORBID_REUSE, 1);

curl_setopt($handle, CURLOPT_FRESH_CONNECT, 1);

if($resultString = curl_exec($handle))curl_close($handle);

}

 

ADD AFTER:

if (extension_loaded('curl')== 1){

echo 'cURL extension is installed.';

}

echo 'DOR rate: '.$resultString;

 

When you try this it should show up on any page that has the shopping cart box, among other things.

 

I do have the version installed, with the line addition: $tax_rate= parse_DOR();

but when I added, like you suggested

if (extension_loaded('curl')== 1){
 echo 'cURL extension is installed.';
}
echo 'DOR rate: '.$resultString;

 

nothing is echoed "on any page that has the shopping cart box" like you mentioned. In fact nothing can be echoed from that code location (after the bracket following the series of curl calls). If I insert an echo 'tata', I cannot read it anywhere...

 

However, I do have cURL installed.

To double check, I did a test by inserting a test if extension_loaded on my home page, I got a true.

 

Thank you for your suggestions!

Share this post


Link to post
Share on other sites

I just found out something: we need to make this "checkout without account compatible" (because customers with no account have a blank address book, and the address used for DOR comes from there.)

Share this post


Link to post
Share on other sites

One more thing: it doesn't calculate the shipping tax amount correctly when "use the following tax class" is selected in the shipping modules:

 

It seems to calculate the proper tax amount on products, but applies the default store tax rate on the shipping fees.

(example: $100 on products plus $10 shipping shipped to an address with a 7.6% tax from my store with a 8.9% tax rate will return

subtotal: $100.00

shipping: $10.00

tax = ($7.6 + $0.89 = $8.49)

 

could you confirm that this happens in your stores as well?

Share this post


Link to post
Share on other sites

If the address is blank it uses the OSCommerce way of calculating tax. If the address is empty, where are you going to ship it to. Unless you have your prices display with taxes? is this the case?

 

lildog

 

I just found out something: we need to make this "checkout without account compatible" (because customers with no account have a blank address book, and the address used for DOR comes from there.)

Share this post


Link to post
Share on other sites

Did you try checking out? I am not positive where it will show up. I have so many mods my shop may be different.

 

I do have the version installed, with the line addition: $tax_rate= parse_DOR();

but when I added, like you suggested

if (extension_loaded('curl')== 1){
 echo 'cURL extension is installed.';
}
echo 'DOR rate: '.$resultString;

 

nothing is echoed "on any page that has the shopping cart box" like you mentioned. In fact nothing can be echoed from that code location (after the bracket following the series of curl calls). If I insert an echo 'tata', I cannot read it anywhere...

 

However, I do have cURL installed.

To double check, I did a test by inserting a test if extension_loaded on my home page, I got a true.

 

Thank you for your suggestions!

Share this post


Link to post
Share on other sites

×