X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2FTaxEngine%2Finternal.pm;h=91b547ce0875f4c87ce63453ed81b7754cf0b786;hp=99535ad38161bd669bb73eeec24f97a9bd732a58;hb=194c16bf0af62048d118ad28e55f5e1eb5d92ffa;hpb=0fda4498e5b48587090b03d40ea97fec1e024385 diff --git a/FS/FS/TaxEngine/internal.pm b/FS/FS/TaxEngine/internal.pm index 99535ad38..91b547ce0 100644 --- a/FS/FS/TaxEngine/internal.pm +++ b/FS/FS/TaxEngine/internal.pm @@ -3,6 +3,12 @@ package FS::TaxEngine::internal; use strict; use base 'FS::TaxEngine'; use FS::Record qw(dbh qsearch qsearchs); +use FS::Conf; +use vars qw( $conf ); + +FS::UID->install_callback(sub { + $conf = FS::Conf->new; +}); =head1 SUMMARY @@ -60,10 +66,11 @@ sub taxline { my $taxnum = $tax_object->taxnum; my $exemptions = $self->{exemptions}->{$taxnum} ||= []; - my $name = $tax_object->taxname || 'Tax'; my $taxable_cents = 0; my $tax_cents = 0; + my $round_per_line_item = $conf->exists('tax-round_per_line_item'); + my $cust_main = $self->{cust_main}; my $custnum = $cust_main->custnum; my $invoice_time = $self->{invoice_time}; @@ -87,14 +94,7 @@ sub taxline { push @existing_exemptions, @{ $_->cust_tax_exempt_pkg } foreach @$taxables; - my $tax_item = FS::cust_bill_pkg->new({ - 'pkgnum' => 0, - 'recur' => 0, - 'sdate' => '', - 'edate' => '', - 'itemdesc' => $name, - }); - my @tax_location; + my @tax_links; foreach my $cust_bill_pkg (@$taxables) { @@ -243,7 +243,9 @@ sub taxline { exempt_monthly => 'Y', year => $year, month => $mon, + taxnum => $tax_object->taxnum, }); + $taxable_charged -= $addl; } # if they're using multiple months of exemption for a multi-month @@ -257,16 +259,38 @@ sub taxline { } } # if exempt_amount - $_->taxnum($tax_object->taxnum) foreach @new_exemptions; - # attach them to the line item - push @{ $cust_bill_pkg->cust_tax_exempt_pkg }, @new_exemptions; + foreach my $ex (@new_exemptions) { + + if ( $cust_bill_pkg->billpkgnum ) { + # the exempted item is already inserted (it should be, these days) so + # insert the exemption record now: + $ex->set('billpkgnum', $cust_bill_pkg->billpkgnum); + my $error = $ex->insert; + return "inserting tax exemption record: $error" if $error; + + } else { + # defer it until the item is inserted + push @{ $cust_bill_pkg->cust_tax_exempt_pkg }, $ex; + } + } + + # and remember we've used the exemption push @existing_exemptions, @new_exemptions; $taxable_charged = sprintf( "%.2f", $taxable_charged); next if $taxable_charged == 0; - my $this_tax_cents = int($taxable_charged * $tax_object->tax); + my $this_tax_cents = $taxable_charged * $tax_object->tax; + if ( $round_per_line_item ) { + # Round the tax to the nearest cent for each line item, instead of + # across the whole invoice. + $this_tax_cents = sprintf('%.0f', $this_tax_cents); + } else { + # Otherwise truncate it so that rounding error is always positive. + $this_tax_cents = int($this_tax_cents); + } + my $location = FS::cust_bill_pkg_tax_location->new({ 'taxnum' => $tax_object->taxnum, 'taxtype' => ref($tax_object), @@ -274,25 +298,31 @@ sub taxline { 'pkgnum' => $cust_bill_pkg->pkgnum, 'locationnum' => $cust_bill_pkg->cust_pkg->tax_locationnum, 'taxable_cust_bill_pkg' => $cust_bill_pkg, - 'tax_cust_bill_pkg' => $tax_item, }); - push @tax_location, $location; + push @tax_links, $location; $taxable_cents += $taxable_charged; $tax_cents += $this_tax_cents; } #foreach $cust_bill_pkg - # now round and distribute + # calculate tax and rounding error for the whole group my $extra_cents = sprintf('%.2f', $taxable_cents * $tax_object->tax / 100) * 100 - $tax_cents; # make sure we have an integer $extra_cents = sprintf('%.0f', $extra_cents); + + # if we're rounding per item, then ignore that and don't distribute any + # extra cents. + if ( $round_per_line_item ) { + $extra_cents = 0; + } + if ( $extra_cents < 0 ) { die "nonsense extra_cents value $extra_cents"; } $tax_cents += $extra_cents; my $i = 0; - foreach (@tax_location) { # can never require more than a single pass, yes? + foreach (@tax_links) { # can never require more than a single pass, yes? my $cents = $_->get('cents'); if ( $extra_cents > 0 ) { $cents++; @@ -300,10 +330,8 @@ sub taxline { } $_->set('amount', sprintf('%.2f', $cents/100)); } - $tax_item->set('setup' => sprintf('%.2f', $tax_cents / 100)); - $tax_item->set('cust_bill_pkg_tax_location', \@tax_location); - return $tax_item; + return @tax_links; } sub info {