diff options
| author | jeff <jeff> | 2008-06-04 13:28:18 +0000 | 
|---|---|---|
| committer | jeff <jeff> | 2008-06-04 13:28:18 +0000 | 
| commit | 3b35ccbf226efe00c94f3a72dd1c7ed64d926a7c (patch) | |
| tree | 7718ce922148d2c4892895e43707555c7634405a | |
| parent | 9c236c52118ead925e960571f0532fa064fd81bf (diff) | |
tax on tax
| -rw-r--r-- | FS/FS/Record.pm | 2 | ||||
| -rw-r--r-- | FS/FS/cust_main.pm | 74 | ||||
| -rw-r--r-- | FS/FS/tax_rate.pm | 63 | 
3 files changed, 129 insertions, 10 deletions
| diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index 5a446d886..e2d0a0fc5 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -1923,7 +1923,7 @@ sub ut_agentnum_acl {    if ( $self->$field() ) { -    return "Access deined" +    return "Access denied"        unless $curuser->agentnum($self->$field());    } else { diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index c28991fff..d49091671 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -2071,6 +2071,7 @@ sub bill {    my( $total_setup, $total_recur ) = ( 0, 0 );    my %tax;    my %taxlisthash; +  my %taxname;    my @precommit_hooks = ();    foreach my $cust_pkg ( @@ -2292,7 +2293,7 @@ sub bill {                                })                  if scalar(@taxclassnums); -   +              }else{                my %taxhash = map { $_ => $self->get("$prefix$_") } @@ -2364,20 +2365,85 @@ sub bill {      return '';    } +  warn "having a look at the taxes we found...\n" if $DEBUG > 2;    foreach my $tax ( keys %taxlisthash ) {      my $tax_object = shift @{ $taxlisthash{$tax} }; +    warn "found ". $tax_object->taxname. " as $tax\n" if $DEBUG > 2;      my $listref_or_error = $tax_object->taxline( @{ $taxlisthash{$tax} } );      unless (ref($listref_or_error)) {        $dbh->rollback if $oldAutoCommit;        return $listref_or_error;      } +    unshift @{ $taxlisthash{$tax} }, $tax_object; -    $tax{ $listref_or_error->[0] } += $listref_or_error->[1]; +    warn "adding ". $listref_or_error->[1]. +         " as ". $listref_or_error->[0]. "\n" +      if $DEBUG > 2; +    $tax{ $tax_object->taxname } += $listref_or_error->[1]; +    if ( $taxname{ $listref_or_error->[0] } ) { +      push @{ $taxname{ $listref_or_error->[0] } }, $tax_object->taxname; +    }else{ +      $taxname{ $listref_or_error->[0] } = [ $tax_object->taxname ]; +    }    } -  foreach my $taxname ( grep { $tax{$_} > 0 } keys %tax ) { -    my $tax = sprintf('%.2f', $tax{$taxname} ); +  #some taxes are taxed +  my %totlisthash; +   +  warn "finding taxed taxes...\n" if $DEBUG > 2; +  foreach my $tax ( keys %taxlisthash ) { +    my $tax_object = shift @{ $taxlisthash{$tax} }; +    warn "found possible taxed tax ". $tax_object->taxname. " we call $tax\n" +      if $DEBUG > 2; +    next unless $tax_object->can('tax_on_tax'); + +    foreach my $tot ( $tax_object->tax_on_tax( $self ) ) { +      my $totname = ref( $tot ). ' '. $tot->taxnum; + +      warn "checking $totname which we call ". $tot->taxname. " as applicable\n" +        if $DEBUG > 2; +      next unless exists( $taxlisthash{ $totname } ); # only increase +                                                      # existing taxes +      warn "adding $totname to taxed taxes\n" if $DEBUG > 2; +      if ( exists( $totlisthash{ $totname } ) ) { +        push @{ $totlisthash{ $totname  } }, $tax{ $tax_object->taxname }; +      }else{ +        $totlisthash{ $totname } = [ $tot, $tax{ $tax_object->taxname } ]; +      } +    } +  } + +  warn "having a look at taxed taxes...\n" if $DEBUG > 2; +  foreach my $tax ( keys %totlisthash ) { +    my $tax_object = shift @{ $totlisthash{$tax} }; +    warn "found previously found taxed tax ". $tax_object->taxname. "\n" +      if $DEBUG > 2; +    my $listref_or_error = $tax_object->taxline( @{ $totlisthash{$tax} } ); +    unless (ref($listref_or_error)) { +      $dbh->rollback if $oldAutoCommit; +      return $listref_or_error; +    } + +    warn "adding taxed tax amount ". $listref_or_error->[1]. +         " as ". $tax_object->taxname. "\n" +      if $DEBUG; +    $tax{ $tax_object->taxname } += $listref_or_error->[1]; +  } +   +  #consolidate and create tax line items +  warn "consolidating and generating...\n" if $DEBUG > 2; +  foreach my $taxname ( keys %taxname ) { +    my $tax = 0; +    my %seen = (); +    warn "adding $taxname\n" if $DEBUG > 1; +    foreach my $taxitem ( @{ $taxname{$taxname} } ) { +      $tax += $tax{$taxitem} unless $seen{$taxitem}; +      warn "adding $tax{$taxitem}\n" if $DEBUG > 1; +    } +    next unless $tax; + +    $tax = sprintf('%.2f', $tax );      $total_setup = sprintf('%.2f', $total_setup+$tax );      push @cust_bill_pkg, new FS::cust_bill_pkg { diff --git a/FS/FS/tax_rate.pm b/FS/FS/tax_rate.pm index 18f2e110e..81b63abd7 100644 --- a/FS/FS/tax_rate.pm +++ b/FS/FS/tax_rate.pm @@ -7,11 +7,12 @@ use vars qw( @ISA $DEBUG $me  use Date::Parse;  use Storable qw( thaw );  use MIME::Base64; -use FS::Record qw( qsearchs dbh ); +use FS::Record qw( qsearch qsearchs dbh );  use FS::tax_class;  use FS::cust_bill_pkg;  use FS::cust_tax_location;  use FS::part_pkg_taxrate; +use FS::cust_main;  @ISA = qw( FS::Record ); @@ -338,16 +339,18 @@ sub passtype_name {    $tax_passtypes{$self->passtype};  } -=item taxline CUST_BILL_PKG, ... +=item taxline CUST_BILL_PKG|AMOUNT, ...  Returns a listref of a name and an amount of tax calculated for the list -of packages.  If an error occurs, a message is returned as a scalar. +of packages/amounts.  If an error occurs, a message is returned as a scalar.  =cut  sub taxline {    my $self = shift; -  my @cust_bill_pkg = @_; + +  my $taxable_charged = 0; +  my @cust_bill_pkg = grep { $taxable_charged += $_ unless ref; ref; } @_;    warn "calculating taxes for ". $self->taxnum. " on ".      join (",", map { $_->pkgnum } @cust_bill_pkg) @@ -380,7 +383,6 @@ sub taxline {      if ($self->passtype == 2);    my $amount = 0; -  my $taxable_charged = 0;    unless ($self->setuptax =~ /^Y$/i) {      $taxable_charged += $_->setup foreach @cust_bill_pkg;    } @@ -419,6 +421,57 @@ sub taxline {  } +=item tax_on_tax CUST_MAIN + +Returns a list of taxes which are candidates for taxing taxes for the +given customer (see L<FS::cust_main>) + +=cut + +sub tax_on_tax { +  my $self = shift; +  my $cust_main = shift; + +  warn "looking up taxes on tax ". $self->taxnum. " for customer ". +    $cust_main->custnum +    if $DEBUG; + +  my $geocode = $cust_main->geocode($self->data_vendor); + +  # CCH oddness in m2m +  my $dbh = dbh; +  my $extra_sql = ' AND ('. +    join(' OR ', map{ 'geocode = '. $dbh->quote(substr($geocode, 0, $_)) } +                 qw(10 5 2) +        ). +    ')'; + +  my $order_by = 'ORDER BY taxclassnum, length(geocode) desc'; +  my $select   = 'DISTINCT ON(taxclassnum) *'; + +  # should qsearch preface columns with the table to facilitate joins? +  my @taxclassnums = map { $_->taxclassnum } +    qsearch( { 'table'     => 'part_pkg_taxrate', +               'select'    => $select, +               'hashref'   => { 'data_vendor'      => $self->data_vendor, +                                'taxclassnumtaxed' => $self->taxclassnum, +                              }, +               'extra_sql' => $extra_sql, +               'order_by'  => $order_by, +           } ); + +  return () unless @taxclassnums; + +  $extra_sql = +    "AND (".  join(' OR ', map { "taxclassnum = $_" } @taxclassnums ). ")"; + +  qsearch({ 'table'     => 'tax_rate', +            'hashref'   => { 'geocode' => $geocode, }, +            'extra_sql' => $extra_sql, +         }) + +} +  =back  =head1 SUBROUTINES | 
