diff options
author | tetragon <tetragon@4979c152-3d1c-0410-bac9-87ea11338e46> | 2006-10-08 20:47:38 +0000 |
---|---|---|
committer | tetragon <tetragon@4979c152-3d1c-0410-bac9-87ea11338e46> | 2006-10-08 20:47:38 +0000 |
commit | 68399771603d9a2d084a9eaca480f17016801fe6 (patch) | |
tree | 02859ae3e2743f8b141a9837f703c21d77651759 | |
parent | 7376ef357ac4dce6bf30548c773774dddd2ea033 (diff) |
First round of tax code replacement, adds cumulative tax support
git-svn-id: https://ledger-smb.svn.sourceforge.net/svnroot/ledger-smb/trunk@195 4979c152-3d1c-0410-bac9-87ea11338e46
-rwxr-xr-x | LedgerSMB/AM.pm | 34 | ||||
-rwxr-xr-x | LedgerSMB/Form.pm | 2 | ||||
-rwxr-xr-x | LedgerSMB/IR.pm | 42 | ||||
-rwxr-xr-x | LedgerSMB/IS.pm | 80 | ||||
-rwxr-xr-x | LedgerSMB/OE.pm | 159 | ||||
-rwxr-xr-x | LedgerSMB/Tax.pm | 100 | ||||
-rwxr-xr-x | LedgerSMB/Taxes/Simple.pm | 64 | ||||
-rwxr-xr-x | bin/mozilla/aa.pl | 120 | ||||
-rwxr-xr-x | bin/mozilla/am.pl | 20 | ||||
-rwxr-xr-x | bin/mozilla/ic.pl | 4 | ||||
-rwxr-xr-x | bin/mozilla/io.pl | 9 | ||||
-rwxr-xr-x | bin/mozilla/ir.pl | 20 | ||||
-rwxr-xr-x | bin/mozilla/is.pl | 30 | ||||
-rwxr-xr-x | bin/mozilla/oe.pl | 22 | ||||
-rwxr-xr-x | bin/mozilla/pos.pl | 30 | ||||
-rwxr-xr-x | sql/Canada-French_General-chart.sql | 2 | ||||
-rwxr-xr-x | sql/Pg-tables.sql | 12 | ||||
-rw-r--r-- | sql/Pg-upgrade-2.6.18-2.6.19.sql | 20 |
18 files changed, 447 insertions, 323 deletions
diff --git a/LedgerSMB/AM.pm b/LedgerSMB/AM.pm index c1576aed..82b58534 100755 --- a/LedgerSMB/AM.pm +++ b/LedgerSMB/AM.pm @@ -35,7 +35,7 @@ #====================================================================== package AM; - +use LedgerSMB::Tax; sub get_account { @@ -1479,15 +1479,18 @@ sub defaultaccounts { sub taxes { my ($self, $myconfig, $form) = @_; + my $taxaccounts = ''; # connect to database my $dbh = $form->{dbh}; my $query = qq| - SELECT c.id, c.accno, c.description, - t.rate * 100 AS rate, t.taxnumber, t.validto + SELECT c.id, c.accno, c.description, + t.rate * 100 AS rate, t.taxnumber, t.validto, + t.pass, m.taxmodulename FROM chart c JOIN tax t ON (c.id = t.chart_id) + JOIN taxmodule m ON (t.taxmodule_id = m.taxmodule_id) ORDER BY 3, 6|; my $sth = $dbh->prepare($query); @@ -1495,6 +1498,21 @@ sub taxes { while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { push @{ $form->{taxrates} }, $ref; + $taxaccounts .= " " . $ref{accno}; + } + + $sth->finish; + + $query = qq| + SELECT taxmodule_id, taxmodulename FROM taxmodule + ORDER BY 2|; + + $sth = $dbh->prepare($query); + $sth->execute || $form->dberror($query); + + while (my $ref = $sth->fetchrow_hashref(NAME_lc)) { + $form->{"taxmodule_".$ref->{taxmodule_id}} = + $ref->{taxmodulename}; } $sth->finish; @@ -1516,16 +1534,20 @@ sub save_taxes { $query = qq| - INSERT INTO tax (chart_id, rate, taxnumber, validto) - VALUES (?, ?, ?, ?)|; + INSERT INTO tax (chart_id, rate, taxnumber, validto, + pass, taxmodule_id) + VALUES (?, ?, ?, ?, ?, ?)|; my $sth = $dbh->prepare($query); foreach my $item (split / /, $form->{taxaccounts}) { my ($chart_id, $i) = split /_/, $item; my $rate = $form->parse_amount( $myconfig, $form->{"taxrate_$i"}) / 100; + my $validto = $form->{"validto_$i"}; + $validto = undef if not $validto; my @queryargs = ($chart_id, $rate, $form->{"taxnumber_$i"}, - $form->{"validto_$i"}); + $validto, $form->{"pass_$i"}, + $form->{"taxmodule_id_$i"}); $sth->execute(@queryargs) || $form->dberror($query); } diff --git a/LedgerSMB/Form.pm b/LedgerSMB/Form.pm index cd30803b..e5fa4f61 100755 --- a/LedgerSMB/Form.pm +++ b/LedgerSMB/Form.pm @@ -1579,7 +1579,7 @@ sub check_exchangerate { my $sth = $self->{dbh}->prepare($query); $sth->execute($currenct, $transdate); - my ($exchangerate) = $sth->fetchrow_array($query); + my ($exchangerate) = $sth->fetchrow_array; $sth->finish; $self->{dbh}->commit; diff --git a/LedgerSMB/IR.pm b/LedgerSMB/IR.pm index 92e2c964..9f2da830 100755 --- a/LedgerSMB/IR.pm +++ b/LedgerSMB/IR.pm @@ -32,6 +32,7 @@ #====================================================================== package IR; +use LedgerSMB::Tax; use LedgerSMB::PriceMatrix; sub post_invoice { @@ -172,33 +173,24 @@ sub post_invoice { my $linetotal = $form->round_amount($amount, 2); $fxdiff += $amount - $linetotal; - @taxaccounts = split / /, $form->{"taxaccounts_$i"}; + @taxaccounts = Tax::init_taxes($form, $form->{"taxaccounts_$i"}); - $ml = 1; - $tax = 0; - $fxtax = 0; + $tax = Math::BigFloat->bzero(); + $fxtax = Math::BigFloat->bzero(); - for (0 .. 1) { - $taxrate = 0; - - # add tax rates - for (@taxaccounts) { - $taxrate += $form->{"${_}_rate"} if ($form->{"${_}_rate"} * $ml) > 0; - } - - if ($form->{taxincluded}) { - $tax += $amount = $linetotal * ($taxrate / (1 + ($taxrate * $ml))); - $form->{"sellprice_$i"} -= $amount / $form->{"qty_$i"}; - } else { - $tax += $amount = $linetotal * $taxrate; - $fxtax += $fxlinetotal * $taxrate; - } - - for (@taxaccounts) { - $form->{acc_trans}{$form->{id}}{$_}{amount} += $amount * $form->{"${_}_rate"} / $taxrate if ($form->{"${_}_rate"} * $ml) > 0; - } - - $ml = -1; + if ($form->{taxincluded}) { + $tax += $amount = Tax::calculate_taxes(\@taxaccounts, $form, + $linetotal, 1); + $form->{"sellprice_$i"} -= $amount / $form{"qty_$i"}; + } else { + $tax += $amount = Tax::calculate_taxes(\@taxaccounts, $form, + $linetotal, 0); + $fxtax += Tax::calculate_taxes(\@taxaccounts, $form, + $fxlinetotal, 0); + } + + for (@taxaccounts) { + $form->{acc_trans}{$form->{id}}{$_->account}{amount} += $_->value; } $grossamount = $form->round_amount($linetotal, 2); diff --git a/LedgerSMB/IS.pm b/LedgerSMB/IS.pm index eda3a984..0b38b3a8 100755 --- a/LedgerSMB/IS.pm +++ b/LedgerSMB/IS.pm @@ -32,6 +32,7 @@ #====================================================================== package IS; +use LedgerSMB::Tax; use LedgerSMB::PriceMatrix; sub invoice_details { @@ -263,44 +264,30 @@ sub invoice_details { $form->{"linetotal_$i"} = $form->format_amount($myconfig, $linetotal, 2); push(@{ $form->{linetotal} }, $form->{"linetotal_$i"}); - @taxaccounts = split / /, $form->{"taxaccounts_$i"}; + @taxaccounts = Tax::init_taxes($form, $form->{"taxaccounts_$i"}); my $ml = 1; my @taxrates = (); $tax = 0; - for (0 .. 1) { - $taxrate = 0; - - for (@taxaccounts) { $taxrate += $form->{"${_}_rate"} if ($form->{"${_}_rate"} * $ml) > 0 } - - $taxrate *= $ml; - $taxamount = $linetotal * $taxrate / (1 + $taxrate); - $taxbase = ($linetotal - $taxamount); - - foreach $item (@taxaccounts) { - if (($form->{"${item}_rate"} * $ml) > 0) { - - push @taxrates, $form->{"${item}_rate"} * 100; - - if ($form->{taxincluded}) { - $taxaccounts{$item} += $linetotal * $form->{"${item}_rate"} / (1 + $taxrate); - $taxbase{$item} += $taxbase; - } else { - $taxbase{$item} += $linetotal; - $taxaccounts{$item} += $linetotal * $form->{"${item}_rate"}; - } - } - } + if ($form->{taxincluded}) { + $taxamount = Tax::calculate_taxes(\@taxaccounts, $form, $linetotal, 1); + $taxbase = ($linetotal - $taxamount); + $tax += Tax::extract_taxes(\@taxaccounts, $form, $linetotal); + } else { + $taxamount = Tax::calculate_taxes(\@taxaccounts, $form, $linetotal, 0); + $tax += Tax::apply_taxes(\@taxaccounts, $form, $linetotal); + } + foreach $item (@taxaccounts) { + push @taxrates, 100 * $item->rate; + $taxaccounts{$item->account} += $item->value; if ($form->{taxincluded}) { - $tax += $linetotal * ($taxrate / (1 + ($taxrate * $ml))); + $taxbase{$item->account} += $taxbase; } else { - $tax += $linetotal * $taxrate; + $taxbase{$item->account} += $linetotal; } - - $ml *= -1; } push(@{ $form->{lineitems} }, { amount => $linetotal, tax => $form->round_amount($tax, 2) }); @@ -699,31 +686,20 @@ sub post_invoice { my $linetotal = $form->round_amount($amount, 2); $fxdiff += $amount - $linetotal; - @taxaccounts = split / /, $form->{"taxaccounts_$i"}; + @taxaccounts = Tax::init_taxes($form, $form->{"taxaccounts_$i"}); $ml = 1; $tax = 0; $fxtax = 0; - for (0 .. 1) { - $taxrate = 0; - - # add tax rates - for (@taxaccounts) { $taxrate += $form->{"${_}_rate"} if ($form->{"${_}_rate"} * $ml) > 0 } - - if ($form->{taxincluded}) { - $tax += $amount = $linetotal * ($taxrate / (1 + ($taxrate * $ml))); - $form->{"sellprice_$i"} -= $amount / $form->{"qty_$i"}; - $fxtax += $fxlinetotal * ($taxrate / (1 + ($taxrate * $ml))); - } else { - $tax += $amount = $linetotal * $taxrate; - $fxtax += $fxlinetotal * $taxrate; - } - - for (@taxaccounts) { - $form->{acc_trans}{$form->{id}}{$_}{amount} += $amount * $form->{"${_}_rate"} / $taxrate if ($form->{"${_}_rate"} * $ml) > 0; - } - - $ml = -1; + if ($form->{taxincluded}) { + $tax += $amount = Tax::calculate_taxes(\@taxaccounts, $form, + $linetotal, 1); + $form->{"sellprice_$i"} -= $amount / $form->{"qty_$i"}; + $fxtax += Tax::calculate_taxes(\@taxaccounts, $form, $linetotal, 1); + } else { + $tax += $amount = Tax::calculate_taxes(\@taxaccounts, $form, + $linetotal, 0); + $fxtax += Tax::calculate_taxes(\@taxaccounts, $form, $linetotal, 0); } $grossamount = $form->round_amount($linetotal, 2); @@ -832,7 +808,11 @@ sub post_invoice { $invnetamount = $amount; $amount = 0; - for (split / /, $form->{taxaccounts}) { $amount += $form->{acc_trans}{$form->{id}}{$_}{amount} = $form->round_amount($form->{acc_trans}{$form->{id}}{$_}{amount}, 2) } + for (split / /, $form->{taxaccounts}) { + $amount += + $form->{acc_trans}{$form->{id}}{$_}{amount} = + $form->round_amount($form->{acc_trans}{$form->{id}}{$_}{amount}, 2); + } $invamount = $invnetamount + $amount; $diff = 0; diff --git a/LedgerSMB/OE.pm b/LedgerSMB/OE.pm index 9ebbad19..0d9ab99d 100755 --- a/LedgerSMB/OE.pm +++ b/LedgerSMB/OE.pm @@ -33,7 +33,7 @@ #====================================================================== package OE; - +use LedgerSMB::Tax; sub transactions { my ($self, $myconfig, $form) = @_; @@ -419,67 +419,52 @@ sub save { $form->{"sellprice_$i"} * $form->{"qty_$i"}, 2 ); - @taxaccounts = split / /, $form->{"taxaccounts_$i"}; - $taxrate = 0; - $taxdiff = 0; - - for (@taxaccounts) { $taxrate += $form->{"${_}_rate"} } - + @taxaccounts = Tax::init_taxes($form, + $form->{"taxaccounts_$i"}); if ($form->{taxincluded}) { - $taxamount = $linetotal * $taxrate - / (1 + $taxrate); - $taxbase = $linetotal - $taxamount; - # we are not keeping a natural price, - # do not round - $form->{"sellprice_$i"} = - $form->{"sellprice_$i"} - * (1 / (1 + $taxrate)); + $taxamount = Tax::calculate_taxes(\@taxaccounts, + $form, $linetotal, 1); + $form->{"sellprice_$i"} = Tax::extract_taxes(\@taxaccounts, + $form, $form->{"sellprice_$i"}); + $taxbase = Tax::extract_taxes(\@taxaccounts, + $form, $linetotal); } else { - $taxamount = $linetotal * $taxrate; + $taxamount = Tax::apply_taxes(\@taxaccounts, + $form, $linetotal); $taxbase = $linetotal; } - - if (@taxaccounts && $form->round_amount($taxamount, 2) - == 0) { - if ($form->{taxincluded}) { + + if (@taxaccounts && $form->round_amount($taxamount, 2) + == 0) { + if ($form->{taxincluded}) { foreach $item (@taxaccounts) { $taxamount = $form->round_amount( - - $linetotal - * $form->{"${item}_rate"} - / (1 + abs( - $form->{"${item}_rate"} - )), 2 - ); - - $taxaccounts{$item} += + $item->value, 2); + $taxaccounts{$item->account} += $taxamount; - $taxdiff += $taxamount; - - $taxbase{$item} += $taxbase; + $taxdiff += $taxamount; + $taxbase{$item->account} += + $taxbase; } - $taxaccounts{$taxaccounts[0]} + $taxaccounts{$taxaccounts[0]->account} += $taxdiff; - } else { + } else { foreach $item (@taxaccounts) { - $taxaccounts{$item} += - $linetotal * - $form->{"${item}_rate"}; - $taxbase{$item} += $taxbase; + $taxaccounts{$item->account} += + $item->value; + $taxbase{$item->account} += + $taxbase; } } } else { foreach $item (@taxaccounts) { - $taxaccounts{$item} += - $taxamount * - $form->{"${item}_rate"} / - $taxrate; - $taxbase{$item} += $taxbase; + $taxaccounts{$item->account} += + $item->value; + $taxbase{$item->account} += $taxbase; } } - $netamount += $form->{"sellprice_$i"} * $form->{"qty_$i"}; @@ -939,7 +924,7 @@ sub retrieve { $sth->finish; # get recurring transaction - $form->get_recurring($dbh); + $form->get_recurring; @queries = $form->run_custom_queries('oe', 'SELECT'); $form->{dbh}->commit; @@ -1328,66 +1313,39 @@ sub order_details { $myconfig, $linetotal, 2); push(@{ $form->{linetotal} }, $form->{"linetotal_$i"}); - @taxaccounts = split / /, $form->{"taxaccounts_$i"}; + @taxaccounts = Tax::init_taxes($form, + $form->{"taxaccounts_$i"}); my $ml = 1; my @taxrates = (); $tax = 0; - for (0 .. 1) { - $taxrate = 0; - - for (@taxaccounts) { - $taxrate += $form->{"${_}_rate"} - if ($form->{"${_}_rate"} * $ml) - > 0; - } - - $taxrate *= $ml; - $taxamount = $linetotal * $taxrate - / (1 + $taxrate); - $taxbase = ($linetotal - $taxamount); - - foreach $item (@taxaccounts) { - if (($form->{"${item}_rate"} * $ml) - > 0) { - - push @taxrates, - $form->{"${item}_rate"} - * 100; - - if ($form->{taxincluded}) { - - $taxaccounts{$item} - += $linetotal - * $form->{"${item}_rate"} - / - (1 + $taxrate); - - $taxbase{$item} - += $taxbase; - } else { - $taxbase{$item} - += $linetotal; - - $taxaccounts{$item} - += $linetotal - * $form->{"${item}_rate"}; - - } - } - } - + $taxamount = Tax::calculate_taxes(\@taxaccounts, + $form, $linetotal, 1); + $taxbase = Tax::extract_taxes(\@taxaccounts, + $form, $linetotal); + foreach $item (@taxaccounts) { + push @taxrates, Math::BigFloat->new(100) * + $item->rate; if ($form->{taxincluded}) { - $tax += $linetotal - * ($taxrate - / (1 + ($taxrate * $ml))); + $taxaccounts{$item->account} += + $item->value; + $taxbase{$item->account} += $taxbase; } else { - $tax += $linetotal * $taxrate; + Tax::apply_taxes(\@taxaccounts, $form, + $linetotal); + $taxbase{$item->account} += $linetotal; + $taxaccounts{$item->account} += + $item->value; } - - $ml *= -1; + } + if ($form->{taxincluded}) { + $tax += Tax::calculate_taxes(\@taxaccounts, + $form, $linetotal, 1); + } else { + $tax += Tax::calculate_taxes(\@taxaccounts, + $form, $linetotal, 0); } push(@{ $form->{lineitems} }, @@ -2422,19 +2380,24 @@ sub generate_orders { $sth->execute($parts_id) || $form->dberror($query); my $rate = 0; + my $taxes = ''; while ($ref = $sth->fetchrow_hashref(NAME_lc)) { $description = $ref->{description}; $unit = $ref->{unit}; $rate += $tax{$ref->{accno}}; + $taxes .= "$ref->{accno} "; } - $sth->finish; + $sth->finish; + chop $taxes; + my @taxaccounts = Tax::init_taxes($form, $taxes); $netamount += $linetotal; if ($taxincluded) { $amount += $linetotal; } else { $amount += $form->round_amount( - $linetotal * (1 + $rate), 2); + Tax::apply_taxes(\@taxaccounts, $form, + $linetotal), 2); } diff --git a/LedgerSMB/Tax.pm b/LedgerSMB/Tax.pm new file mode 100755 index 00000000..4c7bd121 --- /dev/null +++ b/LedgerSMB/Tax.pm @@ -0,0 +1,100 @@ +#===================================================================== +# +# 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; diff --git a/LedgerSMB/Taxes/Simple.pm b/LedgerSMB/Taxes/Simple.pm new file mode 100755 index 00000000..57777be4 --- /dev/null +++ b/LedgerSMB/Taxes/Simple.pm @@ -0,0 +1,64 @@ +#===================================================================== +# +# Simple Tax support module for LedgerSMB +# Taxes::Simple +# 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: +# +# calculate_tax - calculates tax on subtotal +# apply_tax - sets $value to the tax value for the subtotal +# extract_tax - sets $value to the tax value on a tax-included subtotal +# +#==================================================================== +package Taxes::Simple; + +use Class::Struct; +use Math::BigFloat; + +struct Taxes::Simple => { + taxnumber => '$', + description => '$', + rate => 'Math::BigFloat', + chart => '$', + account => '$', + value => 'Math::BigFloat', + pass => '$' +}; + +sub calculate_tax { + my ($self, $form, $subtotal, $extract, $passrate) = @_; + my $rate = $self->rate; + my $tax = $subtotal * $rate / (Math::BigFloat->bone() + $passrate); + $tax = $subtotal * $rate if not $extract; + return $tax; +} + +sub apply_tax { + my ($self, $form, $subtotal) = @_; + my $tax = $self->calculate_tax($form, $subtotal, 0); + $self->value($tax); + return $tax; +} + +sub extract_tax { + my ($self, $form, $subtotal, $passrate) = @_; + my $tax = $self->calculate_tax($form, $subtotal, 1, $passrate); + $self->value($tax); + return $tax; +} + +1; diff --git a/bin/mozilla/aa.pl b/bin/mozilla/aa.pl index 4f6665dc..6e0b09ac 100755 --- a/bin/mozilla/aa.pl +++ b/bin/mozilla/aa.pl @@ -44,6 +44,8 @@ # #====================================================================== +use LedgerSMB::Tax; + # any custom scripts for this one if (-f "$form->{path}/custom_aa.pl") { eval { require "$form->{path}/custom_aa.pl"; }; @@ -257,7 +259,8 @@ sub create_links { if ($form->{taxincluded}) { $diff = 0; - # add tax to individual amounts + # add tax to individual amounts + # XXX needs alteration for conditional taxes for $i (1 .. $form->{rowcount}) { if ($netamount) { $amount = $form->{"amount_$i"} * (1 + $tax / $netamount); @@ -272,53 +275,26 @@ sub create_links { # taxincluded is terrible to calculate # this works only if all taxes are checked - @taxaccounts = split / /, $form->{taxaccounts}; + @taxaccounts = Tax::init_taxes($form, $form->{taxaccounts}); if ($form->{id}) { if ($form->{taxincluded}) { - $ml = 1; + $amount = Tax::calculate_taxes(\@taxaccounts, $form, + $form->{invtotal}, 1); + $tax = $form->round_amount($amount, 2); - for (0 .. 1) { - $taxrate = 0; - $diff = 0; - - for (@taxaccounts) { $taxrate += $form->{"${_}_rate"} if ($form->{"${_}_rate"} * $ml) > 0 } - $taxrate *= $ml; - - foreach $item (@taxaccounts) { - - if (($form->{"${item}_rate"} * $ml) > 0) { - if ($taxrate) { - $amount = $form->{invtotal} * $form->{"${item}_rate"} / (1 + $taxrate); - $tax = $form->round_amount($amount, 2); - $tax{$item} = $form->round_amount($amount - $diff, 2); - $diff = $tax{$item} - ($amount - $diff); - - if ($tax) { - if ($form->{"tax_$item"} == $tax{$item}) { - $form->{"calctax_$item"} = 1; - } - } - } - } - } - $ml *= -1; + } else { + $tax = $form->round_amount(Tax::calculate_taxes(\@taxaccounts, + $form, $netamount, 0)); } - - } else { - for (@taxaccounts) { - $tax = $form->round_amount($netamount * $form->{"${_}_rate"}, 2); - if ($tax) { - if ($form->{"tax_$_"} == $tax) { - $form->{"calctax_$_"} = 1; - } + foreach $item (@taxaccounts) { + $tax{$item->account} = $form->round_amount($item->value, 2); + $form->{"calctax_".$item->account} = 1 if $item->value and ( + $tax{$item->account} == $form->{"tax_".$item->account}); } - } - } - } else { - for (@taxaccounts) { $form->{"calctax_$_"} = 1 } + for (@taxaccounts) { $form->{"calctax_".$_->account} = 1 } } @@ -830,61 +806,21 @@ sub update { for (@taxaccounts) { $form->{"tax_$_"} = $form->parse_amount(\%myconfig, $form->{"tax_$_"}) } + @taxaccounts = Tax::init_taxes($form, $form->{taxaccounts}); if ($form->{taxincluded}) { - - $ml = 1; - - for (0 .. 1) { - $taxrate = 0; - $diff = 0; - - for (@taxaccounts) { - if (($form->{"${_}_rate"} * $ml) > 0) { - if ($form->{"calctax_$_"}) { - $taxrate += $form->{"${_}_rate"}; - } else { - if ($form->{checktax}) { - if ($form->{"tax_$_"}) { - $taxrate += $form->{"${_}_rate"}; - } - } - } - } - } - - $taxrate *= $ml; - - foreach $item (@taxaccounts) { - if (($form->{"${item}_rate"} * $ml) > 0) { - - if ($taxrate) { - $a = $form->{invtotal} * $form->{"${item}_rate"} / (1 + $taxrate); - $b = $form->round_amount($a, 2); - $tax = $form->round_amount($a - $diff, 2); - $diff = $b - ($a - $diff); - } - $form->{"tax_$item"} = $tax if $form->{"calctax_$item"}; - - $form->{"select$form->{ARAP}_tax_$item"} = qq|<option>$item--$form->{"${item}_description"}|; - $totaltax += $form->{"tax_$item"}; - } - } - $ml *= -1; - } - $totaltax += $form->round_amount($diff, 2); - - $form->{checktax} = 1; - + $totaltax = Tax::calculate_taxes(\@taxaccounts, $form, + $form->{invtotal}, 1); } else { - foreach $item (@taxaccounts) { - $form->{"calctax_$item"} = 1 if $form->{calctax}; - - if ($form->{"calctax_$item"}) { - $form->{"tax_$item"} = $form->round_amount($form->{invtotal} * $form->{"${item}_rate"}, 2); - } - $form->{"select$form->{ARAP}_tax_$item"} = qq|<option>$item--$form->{"${item}_description"}|; - $totaltax += $form->{"tax_$item"}; + $totaltax = Tax::calculate_taxes(\@taxaccounts, $form, + $form->{invtotal}, 0); + } + foreach $item (@taxaccounts) { + $taccno = $item->account; + if ($form->{calctax}) { + $form->{"calctax_$taccno"} = 1; + $form->{"tax_$taccno"} = $form->round_amount($item->value, 2); } + $form->{"select$form->{ARAP}_tax_$taccno"} = qq|<option>$taccno--$form->{"${taccno}_description"}|; } $form->{invtotal} = ($form->{taxincluded}) ? $form->{invtotal} : $form->{invtotal} + $totaltax; diff --git a/bin/mozilla/am.pl b/bin/mozilla/am.pl index 9be1c020..666b5522 100755 --- a/bin/mozilla/am.pl +++ b/bin/mozilla/am.pl @@ -1868,7 +1868,9 @@ sub taxes { $form->{"taxrate_$i"} = $form->format_amount(\%myconfig, $ref->{rate}); $form->{"taxdescription_$i"} = $ref->{description}; - for (qw(taxnumber validto)) { $form->{"${_}_$i"} = $ref->{$_} } + for (qw(taxnumber validto pass taxmodulename)) { + $form->{"${_}_$i"} = $ref->{$_}; + } $form->{taxaccounts} .= "$ref->{id}_$i "; } chop $form->{taxaccounts}; @@ -1901,6 +1903,8 @@ sub display_taxes { <th>|.$locale->text('Rate').qq| (%)</th> <th>|.$locale->text('Number').qq|</th> <th>|.$locale->text('Valid To').qq|</th> + <th>|.$locale->text('Order').qq|</th> + <th>|.$locale->text('Tax Rules').qq|</th> </tr> |; @@ -1926,8 +1930,18 @@ sub display_taxes { <td><input name="taxrate_$i" size=6 value=$form->{"taxrate_$i"}></td> <td><input name="taxnumber_$i" value="$form->{"taxnumber_$i"}"></td> <td><input name="validto_$i" size=11 value="$form->{"validto_$i"}" title="$myconfig{dateformat}"></td> - </tr> -|; + <td><input name="pass_$i" size=6 value="$form->{"pass_$i"}"></td> + <td><select name="taxmodule_id_$i" size=1>|; + foreach my $taxmodule (sort keys %$form) { + next if ($taxmodule !~ /^taxmodule_/); + my $modulenum = $taxmodule; + $modulenum =~ s/^taxmodule_//; + print '<option label="'.$form->{$taxmodule}.'" value="'.$modulenum . '"'; + print " SELECTED " if $form->{$taxmodule} eq $form->{"taxmodulename_$i"}; + print " />\n"; + } + print qq|</select></td> + </tr> |; $sametax = $form->{"taxdescription_$i"}; } diff --git a/bin/mozilla/ic.pl b/bin/mozilla/ic.pl index 99eb7f5c..16e67d24 100755 --- a/bin/mozilla/ic.pl +++ b/bin/mozilla/ic.pl @@ -42,6 +42,7 @@ use LedgerSMB::IC; +use LedgerSMB::Tax; require "$form->{path}/io.pl"; @@ -2981,7 +2982,8 @@ sub save { $amount = $form->{"sellprice_$i"} * (1 - $form->{"discount_$i"} / 100) * $form->{"qty_$i"}; for (split / /, $form->{"taxaccounts_$i"}) { $form->{"${_}_base"} += $amount } if (!$form->{taxincluded}) { - for (split / /, $form->{"taxaccounts_$i"}) { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } + my @taxlist= Tax::init_taxes($form, $form->{"taxaccounts_$i"}); + $amount += Tax::calculate_taxes(\@taxlist, $form, $amount, 0); } $ml = 1; diff --git a/bin/mozilla/io.pl b/bin/mozilla/io.pl index d81fa34c..b2ea21b2 100755 --- a/bin/mozilla/io.pl +++ b/bin/mozilla/io.pl @@ -38,6 +38,8 @@ # ####################################################################### +use LedgerSMB::Tax; + # any custom scripts for this one if (-f "$form->{path}/custom_io.pl") { eval { require "$form->{path}/custom_io.pl"; }; @@ -504,7 +506,8 @@ sub item_selected { $amount = $form->{"sellprice_$i"} * (1 - $form->{"discount_$i"} / 100) * $form->{"qty_$i"}; for (split / /, $form->{"taxaccounts_$i"}) { $form->{"${_}_base"} += $amount } if (!$form->{taxincluded}) { - for (split / /, $form->{"taxaccounts_$i"}) { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } + my @taxlist= Tax::init_taxes($form, $form->{"taxaccounts_$i"}); + $amount += Tax::calculate_taxes(\@taxlist, $form, $amount, 0); } $form->{creditremaining} -= $amount; @@ -840,7 +843,9 @@ sub invoicetotal { } if (!$form->{taxincluded}) { - for (split / /, $form->{taxaccounts}) { $form->{oldinvtotal} += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } + my @taxlist= Tax::init_taxes($form, $form->{taxaccounts}); + $form->{oldinvtotal} += Tax::calculate_taxes(\@taxlist, $form, + $amount, 0); } $form->{oldtotalpaid} = 0; diff --git a/bin/mozilla/ir.pl b/bin/mozilla/ir.pl index 35f9975b..be87e9eb 100755 --- a/bin/mozilla/ir.pl +++ b/bin/mozilla/ir.pl @@ -41,6 +41,7 @@ use LedgerSMB::IR; use LedgerSMB::PE; +use LedgerSMB::Tax; require "$form->{path}/io.pl"; require "$form->{path}/arap.pl"; @@ -422,11 +423,14 @@ sub form_footer { } if (!$form->{taxincluded}) { - - foreach $item (split / /, $form->{taxaccounts}) { + my @taxset = Tax::init_taxes($form, $form->{taxaccounts}); + $form->{invtotal} += $form->round_amount( + Tax::calculate_taxes(\@taxset, $form, $form->{invsubtotal}, 0), 2); + foreach $taxobj (@taxset) { + $item = $taxobj->account; if ($form->{"${item}_base"}) { - $form->{invtotal} += $form->{"${item}_total"} = $form->round_amount($form->{"${item}_base"} * $form->{"${item}_rate"}, 2); - $form->{"${item}_total"} = $form->format_amount(\%myconfig, $form->{"${item}_total"}, 2); + $form->{"${item}_total"} = $form->format_amount(\%myconfig, + $form->round_amount($taxobj->value, 2), 2); $tax .= qq| <tr> @@ -673,7 +677,10 @@ sub import_text { $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * (1 - $form->{"discount_$i"} / 100); map { $form->{"${_}_base"} = 0 } (split / /, $form->{taxaccounts}); map { $form->{"${_}_base"} += $amount } (split / /, $form->{"taxaccounts_$i"}); - map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded}; + if (!$form->{taxincluded}) { + my @taxes = Tax::init_taxes($form, $form->{taxaccounts}); + $amount += (Tax::calculate_taxes(\@taxes, $form, $amount, 0)); + } $form->{creditremaining} -= $amount; @@ -794,7 +801,8 @@ sub update { for (split / /, $form->{taxaccounts}) { $form->{"${_}_base"} = 0 } for (split / /, $form->{"taxaccounts_$i"}) { $form->{"${_}_base"} += $amount } if (!$form->{taxincluded}) { - for (split / /, $form->{"taxaccounts_$i"}) { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } + my @taxes = Tax::init_taxes($form, $form->{"taxaccounts_$i"}); + $amount += (Tax::calculate_taxes(\@taxes, $form, $amount, 0)); } $form->{creditremaining} -= $amount; diff --git a/bin/mozilla/is.pl b/bin/mozilla/is.pl index 5696dd11..c93c2337 100755 --- a/bin/mozilla/is.pl +++ b/bin/mozilla/is.pl @@ -46,6 +46,7 @@ use LedgerSMB::IS; use LedgerSMB::PE; +use LedgerSMB::Tax; require "$form->{path}/arap.pl"; require "$form->{path}/io.pl"; @@ -470,19 +471,19 @@ sub form_footer { if (!$form->{taxincluded}) { - for (split / /, $form->{taxaccounts}) { - if ($form->{"${_}_base"}) { - $form->{"${_}_total"} = $form->round_amount($form->{"${_}_base"} * $form->{"${_}_rate"}, 2); - $form->{invtotal} += $form->{"${_}_total"}; - $form->{"${_}_total"} = $form->format_amount(\%myconfig, $form->{"${_}_total"}, 2); - - $tax .= qq| - <tr> - <th align=right>$form->{"${_}_description"}</th> - <td align=right>$form->{"${_}_total"}</td> - </tr> -|; - } + my @taxes = Tax::init_taxes($form, $form->{taxaccounts}); + $form->{invtotal} += Tax::calculate_taxes(\@taxes, $form, + $form->{invsubtotal}, 0); + foreach $item (@taxes) { + my $taccno = $item->account; + $form->{"${taccno}_total"} = $form->format_amount(\%myconfig, + $item->value, 2); + $tax .= qq| + <tr> + <th align=right>$form->{"${taccno}_description"}</th> + <td align=right>$form->{"${taccno}_total"}</td> + </tr> + | if $item->value; } $form->{invsubtotal} = $form->format_amount(\%myconfig, $form->{invsubtotal}, 2, 0); @@ -813,7 +814,8 @@ sub update { for (split / /, $form->{taxaccounts}) { $form->{"${_}_base"} = 0 } for (split / /, $form->{"taxaccounts_$i"}) { $form->{"${_}_base"} += $amount } if (!$form->{taxincluded}) { - for (split / /, $form->{"taxaccounts_$i"}) { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } + my @taxes = Tax::init_taxes($form, $form->{"taxaccounts_$i"}); + $amount += Tax::calculate_taxes(\@taxes, $form, $amount, 0); } $form->{creditremaining} -= $amount; diff --git a/bin/mozilla/oe.pl b/bin/mozilla/oe.pl index b0910db5..d4b4bba3 100755 --- a/bin/mozilla/oe.pl +++ b/bin/mozilla/oe.pl @@ -44,6 +44,7 @@ use LedgerSMB::OE; use LedgerSMB::IR; use LedgerSMB::IS; use LedgerSMB::PE; +use LedgerSMB::Tax; require "$form->{path}/arap.pl"; require "$form->{path}/io.pl"; @@ -600,19 +601,21 @@ sub form_footer { if (!$form->{taxincluded}) { - for (split / /, $form->{taxaccounts}) { - if ($form->{"${_}_base"}) { - $form->{invtotal} += $form->{"${_}_total"} = $form->round_amount($form->{"${_}_base"} * $form->{"${_}_rate"}, 2); - $form->{"${_}_total"} = $form->format_amount(\%myconfig, $form->{"${_}_total"}, 2); + my @taxes = Tax::init_taxes($form, $form->{taxaccounts}); + $form->{invtotal} += Tax::calculate_taxes(\@taxes, + $form, $form->{invsubtotal}, 0); + foreach my $item (@taxes) { + my $taccno = $item->account; + $form->{"${taccno}_total"} = $form->format_amount(\%myconfig, + $item->value, 2); $tax .= qq| <tr> - <th align=right>$form->{"${_}_description"}</th> - <td align=right>$form->{"${_}_total"}</td> + <th align=right>$form->{"${taccno}_description"}</th> + <td align=right>$form->{"${taccno}_total"}</td> </tr> -|; + | if $item->value; } - } $form->{invsubtotal} = $form->format_amount(\%myconfig, $form->{invsubtotal}, 2, 0); @@ -917,7 +920,8 @@ sub update { for (split / /, $form->{taxaccounts}) { $form->{"${_}_base"} = 0 } for (split / /, $form->{"taxaccounts_$i"}) { $form->{"${_}_base"} += $amount } if (!$form->{taxincluded}) { - for (split / /, $form->{taxaccounts}) { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } + my @taxes = Tax::init_taxes($form, $form->{taxaccounts}); + $amount += Tax::calculate_taxes(\@taxes, $form, $amount, 0); } $form->{creditremaining} -= $amount; diff --git a/bin/mozilla/pos.pl b/bin/mozilla/pos.pl index f7f817ea..ef2fbd92 100755 --- a/bin/mozilla/pos.pl +++ b/bin/mozilla/pos.pl @@ -40,6 +40,7 @@ # #===================================================================== +use LedgerSMB::Tax; 1; # end @@ -376,19 +377,22 @@ sub form_footer { if (!$form->{taxincluded}) { - for (split / /, $form->{taxaccounts}) { - if ($form->{"${_}_base"}) { - $form->{"${_}_total"} = $form->round_amount($form->{"${_}_base"} * $form->{"${_}_rate"}, 2); - $form->{invtotal} += $form->{"${_}_total"}; - $form->{"${_}_total"} = $form->format_amount(\%myconfig, $form->{"${_}_total"}, 2, 0); - - $tax .= qq| - <tr> - <th align=right>$form->{"${_}_description"}</th> - <td align=right>$form->{"${_}_total"}</td> - </tr> -|; - } + my @taxes = Tax::init_taxes($form, $form->{taxaccounts}); + $form->{invtotal} += Tax::calculate_taxes(\@taxes, $form, + $form->{invsubtotal}, 0); + + foreach my $item (@taxes) { + my $taccno = $item->account; + + $form->{"${taccno}_total"} = $form->format_amount(\%myconfig, + $item->value, 2, 0); + + $tax .= qq| + <tr> + <th align=right>$form->{"${taccno}_description"}</th> + <td align=right>$form->{"${taccno}_total"}</td> + </tr> + | if $item->value; } $form->{invsubtotal} = $form->format_amount(\%myconfig, $form->{invsubtotal}, 2, 0); diff --git a/sql/Canada-French_General-chart.sql b/sql/Canada-French_General-chart.sql index 647dd121..add09a73 100755 --- a/sql/Canada-French_General-chart.sql +++ b/sql/Canada-French_General-chart.sql @@ -73,6 +73,6 @@ INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('5800', 'Taxes d''affaires, droits d''adhésion et permis', 'A', 'E', 'AP_amount', '8760'); -- insert into tax (chart_id,rate) values ((select id from chart where accno = '2310'),0.06); -insert into tax (chart_id,rate) values ((select id from chart where accno = '2320'),0.08025); +insert into tax (chart_id,rate,pass) values ((select id from chart where accno = '2320'),0.08,1); -- update defaults set inventory_accno_id = (select id from chart where accno = '1520'), income_accno_id = (select id from chart where accno = '4020'), expense_accno_id = (select id from chart where accno = '5010'), fxgain_accno_id = (select id from chart where accno = '4450'), fxloss_accno_id = (select id from chart where accno = '4450'), curr = 'CAD:USD:EUR', weightunit = 'kg'; diff --git a/sql/Pg-tables.sql b/sql/Pg-tables.sql index 42471a15..40a81af8 100755 --- a/sql/Pg-tables.sql +++ b/sql/Pg-tables.sql @@ -12,7 +12,7 @@ CREATE SEQUENCE jcitemsid; SELECT nextval ('jcitemsid'); -- -create table transactions ( +CREATE TABLE transactions ( id int PRIMARY KEY, table_name text ); @@ -243,12 +243,20 @@ CREATE TABLE partstax ( PRIMARY KEY (parts_id, chart_id) ); -- +CREATE TABLE taxmodule ( + taxmodule_id serial PRIMARY KEY, + taxmodulename text NOT NULL +}; +-- CREATE TABLE tax ( chart_id int PRIMARY KEY, rate numeric, taxnumber text, validto date, - FOREIGN KEY (chart_id) REFERENCES chart (id) + pass integer DEFAULT 0 NOT NULL, + taxmodule_id int, + FOREIGN KEY (chart_id) REFERENCES chart (id), + FOREIGN KEY (taxmodule_id) REFERENCES taxmodule (taxmodule_id) ); -- CREATE TABLE customertax ( diff --git a/sql/Pg-upgrade-2.6.18-2.6.19.sql b/sql/Pg-upgrade-2.6.18-2.6.19.sql index 07541bde..d8e304f3 100644 --- a/sql/Pg-upgrade-2.6.18-2.6.19.sql +++ b/sql/Pg-upgrade-2.6.18-2.6.19.sql @@ -120,3 +120,23 @@ SET DEFAULT nextval('shipto_entry_id_seq'); UPDATE shipto SET entry_id = nextval('shipto_entry_id_seq'); ALTER TABLE shipto ADD PRIMARY KEY (entry_id); + +CREATE TABLE taxmodule ( + taxmodule_id serial PRIMARY KEY, + taxmodulename text NOT NULL +); + +INSERT INTO taxmodule ( + taxmodule_id, taxmodulename + ) VALUES ( + 1, 'Simple' +); + +LOCK tax IN EXCLUSIVE MODE; +ALTER TABLE tax ADD COLUMN pass int DEFAULT 0; +UPDATE tax SET pass = 0; +ALTER TABLE tax ALTER COLUMN pass SET NOT NULL; + +ALTER TABLE tax ADD COLUMN taxmodule_id int REFERENCES taxmodule DEFAULT 1; +UPDATE tax SET taxmodule_id = 1; +ALTER TABLE tax ALTER COLUMN taxmodule_id SET NOT NULL; |