Forum

Thread tagged as: Shop

Incorrect tax location after customer changes/updates their billing address

EDIT: So after going back to the drawing board this question as well as a clean way of handling US States/counties based sales tax has been completely solved by simply adding the following code to all relevant pages which in my case was my cart, confirmation, and payment pages.

if (perch_member_logged_in()) {
    $state = perch_shop_order_addresses(array('template'=>'shop/addresses/stateonly.html'), true);
    $tax_exempt = 3;
    $tx_tax = 1;

    if ($state == 'TX') {
        perch_shop_set_tax_location($tx_tax);
    } else {
        perch_shop_set_tax_location($tax_exempt);
    };
}

I was able to come up with dual solution by referencing this thread: A Tax Solution for Multi-Region Countries.

Old post: Before diving in to my problem I should clarify how I have my tax system set up. The store is US based and will only be selling within US; additionally sales tax will only need to be collected if the buyer(billing address) is also located in Texas which has a state wide sales tax rate (fairly simple stuff). Given that tax locations in the current version of perch shop are country based I simply used the US Virgin Islands as my "Texas" tax location and the United States for everything else. When customers are signing up I use javascript to watch the state select box and set the hidden country field to US Virgin Islands if they select Texas. Obviously this is not ideal but for now it serves it's purpose. I am also not sure if this is causing the problem either.

The Problem: When a new customer signs up everything works fine and the proper tax is applied based on whether they are inside or outside of Texas. The problem seems to be that regardless of whether they were inside or outside of Texas, if the customer updates their address info (while having items currently in the cart) to a state with a different tax situation the changes do not reflect on the sales tax that is being applied. I also tested this by logging in without having anything in the cart and updated the address and occasionally it would reflect the correct sales tax but not always.

For example: A customer adds an item to cart, registers with a Texas address (which would trigger sales tax), and then gets to the confirmation page before payment and will see that sales tax is applied. But if they then changed their billing address to say New York and then returned to the confirmation page, they would still see that Texas sales tax is being applied.

I am thinking that it might have something to do with cart caching and when the customer updates their tax location it is not being updated in the cached data. I checked the database and the country id is being correctly updated by the address edit form, it just seems that the cart is not recognizing this.

Debug Message from confirmation/payment page:

Debug Message
[1] SELECT * FROM perch2_members_sessions WHERE sessionID='bc0a4e9035e14f78e8517f0d196065fe61ffdedf' AND sessionHttpFootprint='38f8f923b72f7008863fa247a328aa92dcb16837' AND sessionExpires>'2017-04-18 17:33:10' LIMIT 1
User is logged in
[1] SELECT * FROM perch2_pages WHERE pagePath='/store/cart/checkout/payment.php' LIMIT 1
[1] SELECT * FROM perch2_shop_cart WHERE cartID=2573
[1] SELECT * FROM perch2_shop_cart WHERE cartID=2573
Using cart from cache.
[1] SELECT * FROM perch2_shop_products WHERE productID=19 AND productDeleted IS NULL LIMIT 1
[10] SELECT productID, productVariantDesc, stock_level FROM perch2_shop_products WHERE parentID=19 AND productDeleted IS NULL ORDER BY productOrder ASC
[2] SELECT o.* FROM perch2_shop_options o, perch2_shop_product_options po WHERE o.optionID=po.optionID AND po.productID=19 AND o.optionDeleted IS NULL ORDER BY optionPrecendence ASC
[5] SELECT valueID AS id, valueTitle AS title, valueSKUCode AS skucode FROM perch2_shop_option_values WHERE optionID=1 AND valueDeleted IS NULL ORDER BY valueOrder ASC
[5] SELECT pov.prodoptID, pov.optionID, pov.valueID, o.optionTitle, ov.* FROM perch2_shop_product_option_values pov, perch2_shop_options o, perch2_shop_option_values ov WHERE pov.productID='19' AND pov.optionID=o.optionID AND pov.valueID=ov.valueID AND o.optionDeleted IS NULL AND ov.valueDeleted IS NULL AND o.optionID='1' ORDER BY o.optionPrecendence ASC, ov.valueOrder ASC
[5] SELECT valueID AS id, valueTitle AS title, valueSKUCode AS skucode FROM perch2_shop_option_values WHERE optionID=12 AND valueDeleted IS NULL ORDER BY valueOrder ASC
[2] SELECT pov.prodoptID, pov.optionID, pov.valueID, o.optionTitle, ov.* FROM perch2_shop_product_option_values pov, perch2_shop_options o, perch2_shop_option_values ov WHERE pov.productID='19' AND pov.optionID=o.optionID AND pov.valueID=ov.valueID AND o.optionDeleted IS NULL AND ov.valueDeleted IS NULL AND o.optionID='12' ORDER BY o.optionPrecendence ASC, ov.valueOrder ASC
[33] SELECT DISTINCT settingID, settingValue FROM perch2_settings WHERE userID=0
[1] Using template: /templates/shop/cart/cart_static.html
[1] SELECT * FROM perch2_shop_customers WHERE memberID=7
[2] SELECT main.* FROM perch2_shop_addresses main WHERE 1=1 AND (customerID=7) AND addressDeleted IS NULL AND orderID IS NULL ORDER BY addressTitle ASC
[2] Using template: /templates/shop/addresses/list.html
[1] SELECT * FROM perch2_shop_countries WHERE countryID='238' LIMIT 1
[1] SELECT * FROM perch2_shop_countries WHERE countryID='238' LIMIT 1
Using template: /templates/shop/gateways/braintree_payment_form.html

Diagnostic:

Perch: 2.8.34, PHP: 5.6.29-0+deb8u1, MySQL: 5.5.53, with PDO
Server OS: Linux, apache2handler
Installed apps: content (2.8.34), assets (2.8.34), categories (2.8.34), perch_blog (5.0), perch_shop_orders (1.0.12), perch_shop_products (1.0.12), perch_shop (1.0.12), perch_members (1.5)
App runtimes: <?php $apps_list = array( 'content', 'categories', 'perch_blog', 'perch_members', 'perch_shop', );
PERCH_LOGINPATH: /admin
PERCH_PATH: /mnt/Target01/341004/653390/perch2.relative-marketing.com/web/content/admin
PERCH_CORE: /mnt/Target01/341004/653390/perch2.relative-marketing.com/web/content/admin/core
PERCH_RESFILEPATH: /mnt/Target01/341004/653390/perch2.relative-marketing.com/web/content/admin/resources
Image manipulation: GD Imagick
PHP limits: Max upload 8M, Max POST 8M, Memory: 128M, Total max file upload: 8M
F1: 6a33f95eca3667f9e0c39bf5ca2980fe
Resource folder writeable: Yes
HTTP_HOST: perch2.relative-marketing.com
DOCUMENT_ROOT: /mnt/Target01/341004/653390/perch2.relative-marketing.com/web/content
REQUEST_URI: /admin/core/settings/diagnostics/
SCRIPT_NAME: /admin/core/settings/diagnostics/index.php

address edit template (/templates/shop/addresses/edit.html):

<perch:form id="address" action="/store/customer/addresses/" method="post" app="perch_shop">
<div class="checkoutform">
    <div class="billing-shipping-wrap">
        <div class="billing updateform">
            <h2><perch:if id="addressSlug" value="shipping">Shipping Address<perch:else />Billing Address</perch:if></h2>
            <div class="billing-first">
                <perch:label for="first_name">First name</perch:label> <perch:error for="first_name" type="required"><span class="fielderror">*Required</span></perch:error>
                <perch:input id="first_name" type="text" required="true" label="First Name" />
            </div>

            <div class="billing-last">
                <perch:label for="last_name">Last name</perch:label> <perch:error for="last_name" type="required"><span class="fielderror">*Required</span></perch:error>
                <perch:input id="last_name" type="text" required="true" label="Last Name" />
            </div>

            <div class="billing-address">
                <perch:label for="address_1">Address line 1</perch:label> <perch:error for="address_1" type="required"><span class="fielderror">*Required</span></perch:error>
                <perch:input id="address_1" type="text" required="true" label="Address 1" />

                <perch:label for="address_2">Address line 2</perch:label>
                <perch:input id="address_2" type="text" label="Address 2" />
            </div>

            <div class="billing-city">
                <perch:label for="city">City</perch:label> <perch:error for="city" type="required"><span class="fielderror">*Required</span></perch:error>
                <perch:input type="text" id="city" label="City" required="true" />
            </div>

            <div class="billing-state">
                <!-- ID is set to county do to perch weirdness -->
                <perch:label for="county">State</perch:label>
                <perch:input type="select" id="county" label="State" required="true" options="Alabama|AL,Alaska|AK,Arizona|AZ,Arkansas|AR,California|CA,Colorado|CO,Connecticut|CT,Delaware|DE,Florida|FL,Georgia|GA,Hawaii|HI,Idaho|ID,Illinois|IL,Indiana|IN,Iowa|IA,Kansas|KS,Kentucky|KY,Louisiana|LA,Maine|ME,Maryland|MD,Massachusetts|MA,Michigan|MI,Minnesota|MN,Mississippi|MS,Missouri|MO,Montana|MT,Nebraska|NE,Nevada|NV,New Hampshire|NH,New Jersey|NJ,New Mexico|NM,New York|NY,North Carolina|NC,North Dakota|ND,Ohio|OH,Oklahoma|OK,Oregon|OR,Pennsylvania|PA,Rhode Island|RI,South Carolina|SC,South Dakota|SD,Tennessee|TN,Texas|TX,Utah|UT,Vermont|VT,Virginia|VA,Washington|WA,West Virginia|WV,Wisconsin|WI,Wyoming|WY" />
            </div>

            <div class="billing-zip">
                <perch:label for="postcode">Zipcode</perch:label> <perch:error for="postcode" type="required"><span class="fielderror">*Required</span></perch:error>
                <perch:input id="postcode" type="text" label="Postcode" required="true" />
            </div>

            <perch:input type="hidden" value="237" id="country" label="Country" class="countryboxbilling" />

            <div class="updatebutton">
                <input type="button" value="Update" id="updatebutton" class="updatebutton" onClick="submitUpdateForm()"/>
                <perch:input type="submit" value="Update" class="btn btn-primary" class="hiddensubmit"/>
                <perch:input type="hidden" id="addressID" />
                <perch:input type="hidden" id="r" value="/store/customer" />
            </div>
        </div>
    </div>
</div>  
    <perch:success>
        <p>Thanks!</p>
    </perch:success>

</perch:form>

Javascript for setting country(my dummy tax locations):

function txTaxCheckBilling(){
    var outsideTX = 237;
    var insideTX = 238;
    var countryBoxBilling = $('.countryboxbilling');
    if($('.billing-state select option:selected').val()=="TX"){
        countryBoxBilling.val(insideTX);
    } else {
        countryBoxBilling.val(outsideTX);
    }
}

//Check when select box changes
if($('.billing-state').length){
    $('.billing-state select').change(txTaxCheckBilling);
}

//Check before submitting form--fix for when form gets auto filled
function submitUpdateForm(){
    txTaxCheckBilling();
    $('#form1_address').submit();
}
Cody Sherrod

Cody Sherrod 0 points

  • 4 years ago

Has the customer logged out then back in after the changes?

The session may not be updated while customer is still logged in.

Robert Ketter said:

Has the customer logged out then back in after the changes?

The session may not be updated while customer is still logged in.

Tried updating address and then logging out and then back in and it still does not display the correct tax after an update.

Drew McLellan

Drew McLellan 2638 points
Perch Support

How are you updating the tax location?

Drew McLellan said:

How are you updating the tax location?

Well maybe I fell into the trap of assuming that the system checked for taxes based off of countryID. After your response I found location_form.html in in /templates/shop/tax/. I am guessing that this would need to be updated regardless of what a user changes their billing billing country to? Would it be possible to automatically update this value behind the scenes based off of the billing country id, rather than presenting the customer with an additional form?

Ok so using the tax location form (/templates/shop/tax/location_form.html) correctly updates the customer tax location and recalculates the cart to apply the correct tax based on what I have set up. The issues with doing it this way though is that it is presenting the customer with an additional form to fill out before getting back to the checkout page. Additionally, this leaves correct tax collection up to user error.

Is there a function to call that can set the location and recalculate the cart without presenting the customer with the additional form? IE: When the customer updates their billing state using the address edit template(/templates/shop/addresses/edit.html) automatically set the tax location and recalculate the cart based on what was submitted.

EDIT: I tried using the following as per another thread discussing a similar issues:

$ShopRuntime = PerchShop_Runtime::fetch();
$ShopRuntime->set_location_from_address('default');

and even though the debug message said the following:

UPDATE perch2_shop_cart SET locationID='1' WHERE cartID='4483'

which is the same thing that happens when submitting the form from the location_form.html template the tax is not actually updating. From what I am seeing tax location is only being correctly updated when using location_form.html.