summaryrefslogtreecommitdiff
path: root/LedgerSMB
diff options
context:
space:
mode:
Diffstat (limited to 'LedgerSMB')
-rwxr-xr-xLedgerSMB/AM.pm34
-rwxr-xr-xLedgerSMB/Form.pm2
-rwxr-xr-xLedgerSMB/IR.pm42
-rwxr-xr-xLedgerSMB/IS.pm80
-rwxr-xr-xLedgerSMB/OE.pm159
-rwxr-xr-xLedgerSMB/Tax.pm100
-rwxr-xr-xLedgerSMB/Taxes/Simple.pm64
7 files changed, 301 insertions, 180 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;