summaryrefslogtreecommitdiff
path: root/LedgerSMB/Tax.pm
blob: 1996f23c4c768be9da1e87778945051e628ea8e5 (plain)
  1. #=====================================================================
  2. #
  3. # Tax support module for LedgerSMB
  4. # LedgerSMB::Tax
  5. # Default simple tax application
  6. #
  7. # LedgerSMB
  8. # Small Medium Business Accounting software
  9. # http://www.ledgersmb.org/
  10. #
  11. #
  12. # Copyright (C) 2006
  13. # This work contains copyrighted information from a number of sources all used
  14. # with permission. It is released under the GNU General Public License
  15. # Version 2 or, at your option, any later version. See COPYRIGHT file for
  16. # details.
  17. #
  18. #
  19. #======================================================================
  20. # This package contains tax related functions:
  21. #
  22. # apply_taxes - applies taxes to the given subtotal
  23. # extract_taxes - extracts taxes from the given total
  24. # initialize_taxes - loads taxes from the database
  25. # calculate_taxes - calculates taxes
  26. #
  27. #====================================================================
  28. package Tax;
  29. use Math::BigFloat;
  30. sub init_taxes {
  31. my ($form, $taxaccounts, $taxaccounts2) = @_;
  32. my $dbh = $form->{dbh};
  33. @taxes = ();
  34. my @accounts = split / /, $taxaccounts;
  35. if (defined $taxaccounts2){
  36. my @tmpaccounts = @accounts;
  37. $#accounts = 0;
  38. for my $acct (split / /, $taxaccounts2){
  39. if ($taxaccounts =~ /\s$acct\s/){
  40. push @accounts, $acct;
  41. }
  42. }
  43. }
  44. my $query = qq|SELECT t.taxnumber, c.description,
  45. t.rate, t.chart_id, t.pass, m.taxmodulename
  46. FROM tax t INNER JOIN chart c ON (t.chart_id = c.id)
  47. INNER JOIN taxmodule m ON (t.taxmodule_id = m.taxmodule_id)
  48. WHERE c.accno = ?|;
  49. my $sth = $dbh->prepare($query);
  50. foreach $taxaccount (@accounts) {
  51. next if (! defined $taxaccount);
  52. if (defined $taxaccounts2){
  53. next if $taxaccount !~ /$taxaccounts2/;
  54. }
  55. $sth->execute($taxaccount) || $form->dberror($query);
  56. my $ref = $sth->fetchrow_hashref;
  57. my $module = $ref->{'taxmodulename'};
  58. require "LedgerSMB/Taxes/${module}.pm";
  59. $module =~ s/\//::/g;
  60. my $tax = (eval 'Taxes::'.$module)->new();
  61. $tax->pass($ref->{'pass'});
  62. $tax->account($taxaccount);
  63. $tax->rate(Math::BigFloat->new($ref->{'rate'}));
  64. $tax->taxnumber($ref->{'taxnumber'});
  65. $tax->chart($ref->{'chart'});
  66. $tax->description($ref->{'description'});
  67. $tax->value(Math::BigFloat->bzero());
  68. push @taxes, $tax;
  69. $sth->finish;
  70. }
  71. return @taxes;
  72. }
  73. sub calculate_taxes {
  74. my ($taxes, $form, $subtotal, $extract) = @_;
  75. my $total = Math::BigFloat->bzero();
  76. my %passes;
  77. foreach my $tax (@taxes) {
  78. push @{$passes{$tax->pass}}, $tax;
  79. }
  80. my @passkeys = sort keys %passes;
  81. @passkeys = reverse @passkeys if $extract;
  82. foreach my $pass (@passkeys) {
  83. my $passrate = Math::BigFloat->bzero();
  84. my $passtotal = Math::BigFloat->bzero();
  85. foreach my $tax (@{$passes{$pass}}) {
  86. $passrate += $tax->rate;
  87. }
  88. foreach my $tax (@{$passes{$pass}}) {
  89. $passtotal += $tax->apply_tax($form, $subtotal + $total) if not $extract;
  90. $passtotal += $tax->extract_tax($form, $subtotal - $total, $passrate) if $extract;
  91. }
  92. $total += $passtotal;
  93. }
  94. return $total;
  95. }
  96. sub apply_taxes {
  97. my ($taxes, $form, $subtotal) = @_;
  98. return $subtotal + calculate_taxes($taxes, $form, $subtotal, 0);
  99. }
  100. sub extract_taxes {
  101. my ($taxes, $form, $subtotal) = @_;
  102. return $subtotal - calculate_taxes($taxes, $form, $subtotal, 1);
  103. }
  104. 1;