Forums / Bug Reports / Coupon (amount + free shipping) tax calculations incorrect

Coupon (amount + free shipping) tax calculations incorrect

Views: 1,126

Results 1 to 5 of 5
15 Apr 2016, 4:29 PM
#1
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,119
Plugin Contributions:
56

Coupon (amount + free shipping) tax calculations incorrect

Fresh copy (2016-03-29) of Zen Cart 1.5.5 with demo products included. Defined a new coupon for $25.00 off plus free shipping on orders $30.00 or more. Flat rate ($5.00) shipping enabled and untaxed.

Go to storefront, add Red Corner Linked (products_id 14) and Matrox G200 MMS (products_id 1) with all default options. Price reflected in the shopping cart is $331.99.

Sign in and make sure that the order is going to Florida (7% sales tax). Click Checkout.

On the checkout_payment page, enter the coupon-code for the newly-created coupon and press enter (after you've chosen a payment method). The checkout_confirmation page registers the fact that the coupon was entered, but the tax calculation isn't correct:

Sub-Total:                    $331.99
Flat Rate (Best Way):         $5.00
Discount Coupon: 40794fad55 : -$30.00
FL TAX 7.0%:                  $21.14
Total:                        $328.13

The tax result should be based on the amount (331.99 - 25.00) = 306.99 * 0.07 = 21.49, but it's being calcualted on (331.99 - 30.00) = 301.99 * 0.07 = 21.14.

17 Apr 2016, 5:45 PM
#2
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,119
Plugin Contributions:
56

Re: Coupon (amount + free shipping) tax calculations incorrect

Here's an update the Zen Cart 1.5.5 /includes/modules/order_total/ot_coupon.php's calculate_deductions function to correct the issue for both the amount-off and percentage-off plus free shipping cases:

  function calculate_deductions() {
    global $db, $order, $messageStack, $currencies;
    $currencyDecimalPlaces = $currencies->get_decimal_places($_SESSION['currency']);
    $od_amount = array('tax'=>0, 'total'=>0);
    if ($_SESSION['cc_id'])
    {
      $coupon = $db->Execute("select * from " . TABLE_COUPONS . " where coupon_id = '" . (int)$_SESSION['cc_id'] . "'");
      $this->coupon_code = $coupon->fields['coupon_code'];
      $orderTotalDetails = $this->get_order_total($_SESSION['cc_id']);
      if ($coupon->RecordCount() > 0 && $orderTotalDetails['orderTotal'] != 0 )
      {
// left for total order amount vs qualified order amount just switch the commented lines
//        if (strval($orderTotalDetails['totalFull']) >= $coupon->fields['coupon_minimum_order'])
        if (strval($orderTotalDetails['orderTotal']) >= $coupon->fields['coupon_minimum_order'])
        {
          [B]$coupon_is_free_shipping = false; //-20160417-lat9-Correct tax on free-shipping+off/%  *** 1 of 4 ***[/B]
          switch($coupon->fields['coupon_type'])
          {
            case 'S': // Free Shipping
              $od_amount['total'] = $orderTotalDetails['shipping'];
              $od_amount['type'] = 'S';
              $od_amount['tax'] = ($this->calculate_tax == 'Standard') ? $orderTotalDetails['shippingTax'] : 0;
              if (isset($_SESSION['shipping_tax_description']) && $_SESSION['shipping_tax_description'] != '') {
                $od_amount['tax_groups'][$_SESSION['shipping_tax_description']] = $od_amount['tax'];
              }
              return $od_amount;
              break;
            case 'P': // percentage
              $od_amount['total'] = zen_round($orderTotalDetails['orderTotal']*($coupon->fields['coupon_amount']/100), $currencyDecimalPlaces);
              $od_amount['type'] = $coupon->fields['coupon_type'];
              $ratio = $od_amount['total']/$orderTotalDetails['orderTotal'];
              break;
            case 'E': // percentage & Free Shipping
              $od_amount['total'] = zen_round($orderTotalDetails['orderTotal']*($coupon->fields['coupon_amount']/100), $currencyDecimalPlaces);
              $od_amount['type'] = $coupon->fields['coupon_type'];
              // add in Free Shipping
[B]//-bof-20160417-lat9-Correct tax on free-shipping+off/%  *** 2 of 4 ***
//              $od_amount['total'] = $od_amount['total'] + $orderTotalDetails['shipping'];
              $coupon_is_free_shipping = true;
//-eof-20160417-lat9-Correct tax on free-shipping+off/%  *** 2 of 4 ***[/B]
              $od_amount['tax'] = ($this->calculate_tax == 'Standard') ? $orderTotalDetails['shippingTax'] : 0;
              $ratio = $od_amount['total']/$orderTotalDetails['orderTotal'];
              if (isset($_SESSION['shipping_tax_description']) && $_SESSION['shipping_tax_description'] != '') {
                $od_amount['tax_groups'][$_SESSION['shipping_tax_description']] = $od_amount['tax'];
              }
              break;
            case 'F': // amount Off
              $od_amount['total'] = zen_round(($coupon->fields['coupon_amount'] > $orderTotalDetails['orderTotal'] ? $orderTotalDetails['orderTotal'] : $coupon->fields['coupon_amount']) * ($orderTotalDetails['orderTotal']>0), $currencyDecimalPlaces);
              $od_amount['type'] = $coupon->fields['coupon_type']; // amount off 'F' or amount off and free shipping 'O'
              $ratio = $od_amount['total']/$orderTotalDetails['orderTotal'];
              break;
            case 'O': // amount off & Free Shipping
              $od_amount['total'] = zen_round(($coupon->fields['coupon_amount'] > $orderTotalDetails['orderTotal'] ? $orderTotalDetails['orderTotal'] : $coupon->fields['coupon_amount']) * ($orderTotalDetails['orderTotal']>0), $currencyDecimalPlaces);
              $od_amount['type'] = $coupon->fields['coupon_type']; // amount off 'F' or amount off and free shipping 'O'
              // add in Free Shipping
[B]//-bof-20160417-lat9-Correct tax on free-shipping+off/%  *** 3 of 4 ***
//              if ($this->include_shipping == 'false') {
//                $od_amount['total'] = $od_amount['total'] + $orderTotalDetails['shipping'];
//              }
              $coupon_is_free_shipping = true;
//-eof-20160417-lat9-Correct tax on free-shipping+off/%  *** 3 of 4 ***[/B]
              $od_amount['tax'] = ($this->calculate_tax == 'Standard') ? $orderTotalDetails['shippingTax'] : 0;
              $ratio = $od_amount['total']/$orderTotalDetails['orderTotal'];
              if (isset($_SESSION['shipping_tax_description']) && $_SESSION['shipping_tax_description'] != '') {
                $od_amount['tax_groups'][$_SESSION['shipping_tax_description']] = $od_amount['tax'];
              }
              break;
          }
          switch ($this->calculate_tax)
          {
            case 'None':
              break;
            case 'Standard':
              if ($od_amount['total'] >= $orderTotalDetails['orderTotal']) $ratio = 1;
              foreach ($orderTotalDetails['orderTaxGroups'] as $key=>$value)
              {
                $od_amount['tax_groups'][$key] = zen_round($orderTotalDetails['orderTaxGroups'][$key] * $ratio, $currencyDecimalPlaces);
                $od_amount['tax'] += $od_amount['tax_groups'][$key];
                if ($od_amount['tax_groups'][$key] == 0) unset($od_amount['tax_groups'][$key]);
              }
              if (DISPLAY_PRICE_WITH_TAX == 'true' && $coupon->fields['coupon_type'] == 'F') $od_amount['total'] = $od_amount['total'] + $od_amount['tax'];
              break;
            case 'Credit Note':
              $tax_rate = zen_get_tax_rate($this->tax_class);
              $od_amount['tax'] = zen_calculate_tax($od_amount['total'], $tax_rate);
              $tax_description = zen_get_tax_description($this->tax_class);
              $od_amount['tax_groups'][$tax_description] = $od_amount['tax'];
          }
[B]//-bof-20160417-lat9-Correct tax on free-shipping+off/%  *** 4 of 4 ***
          if ($coupon_is_free_shipping) {
              $od_amount['total'] += $orderTotalDetails['shipping'];
          }
//-bof-20160417-lat9-Correct tax on free-shipping+off/%  *** 4 of 4 ***[/B]
        }
      }
    }

//    print_r($order->info);
//    print_r($orderTotalDetails);echo "<br><br>";
//    echo 'RATIo = '. $ratio;
//    print_r($od_amount);
      return $od_amount;
  }
17 Apr 2016, 6:20 PM
#3
rixstix avatar

rixstix

Totally Zenned

Join Date:
Aug 2009
Location:
North Idaho, USA
Posts:
2,015
Plugin Contributions:
0

Re: Coupon (amount + free shipping) tax calculations incorrect

Some tax authorities require tax to be calculated upon the undiscounted sub-total.

Would changing the OT sort orders and putting the ot_coupon 'above' the ot_subtotal yield your expected result?

Rick
RixStix (dot) com
aka: ChainWeavers (dot) com

17 Apr 2016, 6:55 PM
#4
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,119
Plugin Contributions:
56

Re: Coupon (amount + free shipping) tax calculations incorrect

Changing the OT sort orders results in the same incorrect tax calculations (using the as-shipped version of the ot_coupon.php code):

Sub-Total:                    $331.99
Discount Coupon: 40794fad55 : -$30.00
Flat Rate (Best Way):         $0.00
FL TAX 7.0%:                  $21.14
Total:                        $328.13

... with the extra-added feature of setting the shipping amount display to be 0. Note that the shipping display of $0.00 will also be shown using my updated version, since the free-shipping handling within the ot_coupon code forces the shipping-amount to 0 prior to the ot_shipping display when the coupon-handling is moved prior to the shipping-handling.

That one's going to be a :censored: to get right, since it requires "cooperation" between the ot_coupon and ot_shipping total's processing.

17 Apr 2016, 8:04 PM
#5
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,119
Plugin Contributions:
56

Re: Coupon (amount + free shipping) tax calculations incorrect

RixStix:

Some tax authorities require tax to be calculated upon the undiscounted sub-total.
That's where the Discount Coupon's Recalculate Tax setting comes into play. If your tax authority requires that calculation, set that field to None.