summaryrefslogtreecommitdiff
path: root/LedgerSMB/Tax.pm
blob: 7c0d9681e3878bedcb4729d97835f575aff8ca43 (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. my $transdate = $form->{transdate} || 'now()';
  36. if ( defined $taxaccounts2 ) {
  37. my @tmpaccounts = @accounts;
  38. $#accounts = -1;
  39. for my $acct ( split / /, $taxaccounts2 ) {
  40. if ( $taxaccounts =~ /\b$acct\b/ ) {
  41. push @accounts, $acct;
  42. }
  43. }
  44. }
  45. my $query = qq|SELECT t.taxnumber, c.description,
  46. t.rate, t.chart_id, t.pass, m.taxmodulename
  47. FROM tax t INNER JOIN chart c ON (t.chart_id = c.id)
  48. INNER JOIN taxmodule m ON (t.taxmodule_id = m.taxmodule_id)
  49. WHERE c.accno = ? AND
  50. coalesce(validto::timestamp, 'infinity'::timestamp) >= ?
  51. ORDER BY
  52. coalesce(validto::timestamp, 'infinity'::timestamp) ASC|;
  53. my $sth = $dbh->prepare($query);
  54. foreach $taxaccount (@accounts) {
  55. next if ( !defined $taxaccount );
  56. if ( defined $taxaccounts2 ) {
  57. next if $taxaccounts2 !~ /\b$taxaccount\b/;
  58. }
  59. $sth->execute($taxaccount, $transdate)
  60. || $form->dberror($query);
  61. my $ref = $sth->fetchrow_hashref;
  62. my $module = $ref->{'taxmodulename'};
  63. require "LedgerSMB/Taxes/${module}.pm";
  64. $module =~ s/\//::/g;
  65. my $tax = ( eval 'Taxes::' . $module )->new();
  66. $tax->pass( $ref->{'pass'} );
  67. $tax->account($taxaccount);
  68. $tax->rate( Math::BigFloat->new( $ref->{'rate'} ) );
  69. $tax->taxnumber( $ref->{'taxnumber'} );
  70. $tax->chart( $ref->{'chart'} );
  71. $tax->description( $ref->{'description'} );
  72. $tax->value( Math::BigFloat->bzero() );
  73. push @taxes, $tax;
  74. $sth->finish;
  75. }
  76. return @taxes;
  77. }
  78. sub calculate_taxes {
  79. my ( $taxes, $form, $subtotal, $extract ) = @_;
  80. my $total = Math::BigFloat->bzero();
  81. my %passes;
  82. foreach my $tax (@taxes) {
  83. push @{ $passes{ $tax->pass } }, $tax;
  84. }
  85. my @passkeys = sort keys %passes;
  86. @passkeys = reverse @passkeys if $extract;
  87. foreach my $pass (@passkeys) {
  88. my $passrate = Math::BigFloat->bzero();
  89. my $passtotal = Math::BigFloat->bzero();
  90. foreach my $tax ( @{ $passes{$pass} } ) {
  91. $passrate += $tax->rate;
  92. }
  93. foreach my $tax ( @{ $passes{$pass} } ) {
  94. $passtotal += $tax->apply_tax( $form, $subtotal + $total )
  95. if not $extract;
  96. $passtotal +=
  97. $tax->extract_tax( $form, $subtotal - $total, $passrate )
  98. if $extract;
  99. }
  100. $total += $passtotal;
  101. }
  102. return $total;
  103. }
  104. sub apply_taxes {
  105. my ( $taxes, $form, $subtotal ) = @_;
  106. return $subtotal + calculate_taxes( $taxes, $form, $subtotal, 0 );
  107. }
  108. sub extract_taxes {
  109. my ( $taxes, $form, $subtotal ) = @_;
  110. return $subtotal - calculate_taxes( $taxes, $form, $subtotal, 1 );
  111. }
  112. 1;