- #=====================================================================
- #
- # 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, $taxaccounts2 ) = @_;
- my $dbh = $form->{dbh};
- @taxes = ();
- my @accounts = split / /, $taxaccounts;
- if ( defined $taxaccounts2 ) {
- my @tmpaccounts = @accounts;
- $#accounts = -1;
- for my $acct ( split / /, $taxaccounts2 ) {
- if ( $taxaccounts =~ /\b$acct\b/ ) {
- push @accounts, $acct;
- }
- }
- }
- 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 = ?
- AND coalesce(validto::timestamp, 'infinity')
- >= coalesce(?::timestamp, now())
- ORDER BY validto ASC
- LIMIT 1
- |;
- my $sth = $dbh->prepare($query);
- foreach $taxaccount (@accounts) {
- next if ( !defined $taxaccount );
- if ( defined $taxaccounts2 ) {
- next if $taxaccounts2 !~ /\b$taxaccount\b/;
- }
- $sth->execute($taxaccount, $form->{transdate}) || $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;
|