#===================================================================== # # Tax support module for LedgerSMB # LedgerSMB::Tax # Default simple tax application # # LedgerSMB # Small Medium Business Accounting software # http://www.ledgersmb.org/ # # # Copyright (C) 2006 # This work contains copyrighted information from a number of sources all used # with permission. It is released under the GNU General Public License # Version 2 or, at your option, any later version. See COPYRIGHT file for # details. # # #====================================================================== # This package contains tax related functions: # # apply_taxes - applies taxes to the given subtotal # extract_taxes - extracts taxes from the given total # initialize_taxes - loads taxes from the database # calculate_taxes - calculates taxes # #==================================================================== package Tax; use Math::BigFloat; sub init_taxes { my ($form, $taxaccounts) = @_; my $dbh = $form->{dbh}; @taxes = (); my @accounts = split / /, $taxaccounts; my $query = qq|SELECT t.taxnumber, c.description, t.rate, t.chart_id, t.pass, m.taxmodulename FROM tax t INNER JOIN chart c ON (t.chart_id = c.id) INNER JOIN taxmodule m ON (t.taxmodule_id = m.taxmodule_id) WHERE c.accno = ?|; my $sth = $dbh->prepare($query); foreach $taxaccount (@accounts) { $sth->execute(int($taxaccount)) || $form->dberror($query); my $ref = $sth->fetchrow_hashref; my $module = $ref->{'taxmodulename'}; require "LedgerSMB/Taxes/${module}.pm"; $module =~ s/\//::/g; my $tax = (eval 'Taxes::'.$module)->new(); $tax->pass($ref->{'pass'}); $tax->account($taxaccount); $tax->rate(Math::BigFloat->new($ref->{'rate'})); $tax->taxnumber($ref->{'taxnumber'}); $tax->chart($ref->{'chart'}); $tax->description($ref->{'description'}); $tax->value(Math::BigFloat->bzero()); push @taxes, $tax; $sth->finish; } return @taxes; } sub calculate_taxes { my ($taxes, $form, $subtotal, $extract) = @_; my $total = Math::BigFloat->bzero(); my %passes; foreach my $tax (@taxes) { push @{$passes{$tax->pass}}, $tax; } my @passkeys = sort keys %passes; @passkeys = reverse @passkeys if $extract; foreach my $pass (@passkeys) { my $passrate = Math::BigFloat->bzero(); my $passtotal = Math::BigFloat->bzero(); foreach my $tax (@{$passes{$pass}}) { $passrate += $tax->rate; } foreach my $tax (@{$passes{$pass}}) { $passtotal += $tax->apply_tax($form, $subtotal + $total) if not $extract; $passtotal += $tax->extract_tax($form, $subtotal - $total, $passrate) if $extract; } $total += $passtotal; } return $total; } sub apply_taxes { my ($taxes, $form, $subtotal) = @_; return $subtotal + calculate_taxes($taxes, $form, $subtotal, 0); } sub extract_taxes { my ($taxes, $form, $subtotal) = @_; return $subtotal - calculate_taxes($taxes, $form, $subtotal, 1); } 1;