fix sales tax rounding in some edge cases, #42263, from #39487
[freeside.git] / FS / t / suite / 08-sales_tax.t
1 #!/usr/bin/perl
2
3 =head2 DESCRIPTION
4
5 Tests basic sales tax calculations, including consolidation and rounding.
6 The invoice will have two charges that add up to $50 and two taxes:
7 - Tax 1, 8.25%, for $4.125 in tax, which will round up.
8 - Tax 2, 8.245%, for $4.1225 in tax, which will round down.
9
10 Correct: The invoice will have one line item for each of those taxes, with
11 the correct amount.
12
13 =cut
14
15 use strict;
16 use Test::More tests => 2;
17 use FS::Test;
18 use Date::Parse 'str2time';
19 use Date::Format 'time2str';
20 use Test::MockTime qw(set_fixed_time);
21 use FS::cust_main;
22 use FS::cust_pkg;
23 use FS::Conf;
24 my $FS= FS::Test->new;
25
26 # test configuration
27 my @taxes = (
28   [ 'Tax 1', 8.250, 4.13 ],
29   [ 'Tax 2', 8.245, 4.12 ],
30 );
31  
32 # Create the customer and charge them
33 my $cust = $FS->new_customer('Basic taxes');
34 $cust->bill_location->state('AZ'); # move it away from the default of CA
35 my $error;
36 $error = $cust->insert;
37 BAIL_OUT("can't create test customer: $error") if $error;
38 $error = $cust->charge( {
39   amount    => 25.00,
40   pkg       => 'Test charge 1',
41 } ) || 
42 $cust->charge({
43   amount    => 25.00,
44   pkg       => 'Test charge 2',
45 });
46 BAIL_OUT("can't create test charges: $error") if $error;
47
48 # Create tax defs
49 foreach my $tax (@taxes) {
50   my $cust_main_county = FS::cust_main_county->new({
51     'country'       => 'US',
52     'state'         => 'AZ',
53     'exempt_amount' => 0.00,
54     'taxname'       => $tax->[0],
55     'tax'           => $tax->[1],
56   });
57   $error = $cust_main_county->insert;
58   BAIL_OUT("can't create tax definitions: $error") if $error;
59 }
60
61 # Bill the customer
62 set_fixed_time(str2time('2016-03-10 08:00'));
63 my @return;
64 $error = $cust->bill( return_bill => \@return );
65 BAIL_OUT("can't bill charges: $error") if $error;
66 my $cust_bill = $return[0] or BAIL_OUT("no invoice generated");
67 # Check amounts
68 diag("Tax on 25.00 + 25.00");
69 foreach my $cust_bill_pkg ($cust_bill->cust_bill_pkg) {
70   next if $cust_bill_pkg->pkgnum;
71   my ($tax) = grep { $_->[0] eq $cust_bill_pkg->itemdesc } @taxes;
72   if ( $tax ) {
73     ok ( $cust_bill_pkg->setup eq $tax->[2], "Tax at rate $tax->[1]% = $tax->[2]")
74       or diag("is ". $cust_bill_pkg->setup);
75   }
76 }