[freeside-commits] branch FREESIDE_3_BRANCH updated. 56ff5b54ef32ac5c3c03c6762e48342033ca46d8

Mark Wells mark at 420.am
Thu Jun 16 18:56:37 PDT 2016


The branch, FREESIDE_3_BRANCH has been updated
       via  56ff5b54ef32ac5c3c03c6762e48342033ca46d8 (commit)
      from  9d1315b91e3deaeba52cb883c93ea36f10a10373 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 56ff5b54ef32ac5c3c03c6762e48342033ca46d8
Author: Mark Wells <mark at freeside.biz>
Date:   Thu Jun 16 18:17:20 2016 -0700

    fix sales tax rounding in some edge cases, #42263, from #39487

diff --git a/FS/FS/cust_main_county.pm b/FS/FS/cust_main_county.pm
index 91c61b2..6eadff2 100644
--- a/FS/FS/cust_main_county.pm
+++ b/FS/FS/cust_main_county.pm
@@ -277,7 +277,7 @@ sub taxline {
   my $dbh = dbh;
 
   my $name = $self->taxname || 'Tax';
-  my $taxable_cents = 0;
+  my $taxable_total = 0;
   my $tax_cents = 0;
 
   my $round_per_line_item = $conf->exists('tax-round_per_line_item');
@@ -478,15 +478,18 @@ sub taxline {
     });
     push @tax_location, $location;
 
-    $taxable_cents += $taxable_charged;
+    $taxable_total += $taxable_charged;
     $tax_cents += $this_tax_cents;
   } #foreach $cust_bill_pkg
- 
-  # calculate tax and rounding error for the whole group
-  my $extra_cents = sprintf('%.2f', $taxable_cents * $self->tax / 100) * 100
-                    - $tax_cents;
-  # make sure we have an integer
-  $extra_cents = sprintf('%.0f', $extra_cents);
+
+
+  # calculate tax and rounding error for the whole group: total taxable
+  # amount times tax rate (as cents per dollar), minus the tax already
+  # charged
+  # and force 0.5 to round up
+  my $extra_cents = sprintf('%.0f',
+    ($taxable_total * $self->tax) - $tax_cents + 0.00000001
+  );
 
   # if we're rounding per item, then ignore that and don't distribute any
   # extra cents.
diff --git a/FS/t/suite/08-sales_tax.t b/FS/t/suite/08-sales_tax.t
new file mode 100755
index 0000000..bf1ae48
--- /dev/null
+++ b/FS/t/suite/08-sales_tax.t
@@ -0,0 +1,76 @@
+#!/usr/bin/perl
+
+=head2 DESCRIPTION
+
+Tests basic sales tax calculations, including consolidation and rounding.
+The invoice will have two charges that add up to $50 and two taxes:
+- Tax 1, 8.25%, for $4.125 in tax, which will round up.
+- Tax 2, 8.245%, for $4.1225 in tax, which will round down.
+
+Correct: The invoice will have one line item for each of those taxes, with
+the correct amount.
+
+=cut
+
+use strict;
+use Test::More tests => 2;
+use FS::Test;
+use Date::Parse 'str2time';
+use Date::Format 'time2str';
+use Test::MockTime qw(set_fixed_time);
+use FS::cust_main;
+use FS::cust_pkg;
+use FS::Conf;
+my $FS= FS::Test->new;
+
+# test configuration
+my @taxes = (
+  [ 'Tax 1', 8.250, 4.13 ],
+  [ 'Tax 2', 8.245, 4.12 ],
+);
+ 
+# Create the customer and charge them
+my $cust = $FS->new_customer('Basic taxes');
+$cust->bill_location->state('AZ'); # move it away from the default of CA
+my $error;
+$error = $cust->insert;
+BAIL_OUT("can't create test customer: $error") if $error;
+$error = $cust->charge( {
+  amount    => 25.00,
+  pkg       => 'Test charge 1',
+} ) || 
+$cust->charge({
+  amount    => 25.00,
+  pkg       => 'Test charge 2',
+});
+BAIL_OUT("can't create test charges: $error") if $error;
+
+# Create tax defs
+foreach my $tax (@taxes) {
+  my $cust_main_county = FS::cust_main_county->new({
+    'country'       => 'US',
+    'state'         => 'AZ',
+    'exempt_amount' => 0.00,
+    'taxname'       => $tax->[0],
+    'tax'           => $tax->[1],
+  });
+  $error = $cust_main_county->insert;
+  BAIL_OUT("can't create tax definitions: $error") if $error;
+}
+
+# Bill the customer
+set_fixed_time(str2time('2016-03-10 08:00'));
+my @return;
+$error = $cust->bill( return_bill => \@return );
+BAIL_OUT("can't bill charges: $error") if $error;
+my $cust_bill = $return[0] or BAIL_OUT("no invoice generated");
+# Check amounts
+diag("Tax on 25.00 + 25.00");
+foreach my $cust_bill_pkg ($cust_bill->cust_bill_pkg) {
+  next if $cust_bill_pkg->pkgnum;
+  my ($tax) = grep { $_->[0] eq $cust_bill_pkg->itemdesc } @taxes;
+  if ( $tax ) {
+    ok ( $cust_bill_pkg->setup eq $tax->[2], "Tax at rate $tax->[1]% = $tax->[2]")
+      or diag("is ". $cust_bill_pkg->setup);
+  }
+}

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/cust_main_county.pm |   19 +++++++-----
 FS/t/suite/08-sales_tax.t |   76 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+), 8 deletions(-)
 create mode 100755 FS/t/suite/08-sales_tax.t




More information about the freeside-commits mailing list