[freeside-commits] freeside/FS/FS Schema.pm, 1.120, 1.121 cust_bill_pkg.pm, 1.30, 1.31 cust_bill_pkg_tax_location.pm, NONE, 1.1 cust_main.pm, 1.400, 1.401 tax_rate.pm, 1.14, 1.15 cust_main_county.pm, 1.22, 1.23

Ivan,,, ivan at wavetail.420.am
Sun Jan 18 15:43:41 PST 2009


Update of /home/cvs/cvsroot/freeside/FS/FS
In directory wavetail.420.am:/tmp/cvs-serv10673/FS/FS

Modified Files:
	Schema.pm cust_bill_pkg.pm cust_main.pm tax_rate.pm 
	cust_main_county.pm 
Added Files:
	cust_bill_pkg_tax_location.pm 
Log Message:
finish package location tax reporing, RT#4499

Index: cust_main.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_main.pm,v
retrieving revision 1.400
retrieving revision 1.401
diff -u -d -r1.400 -r1.401
--- cust_main.pm	12 Jan 2009 21:16:39 -0000	1.400
+++ cust_main.pm	18 Jan 2009 23:43:39 -0000	1.401
@@ -28,6 +28,7 @@
 use FS::cust_bill;
 use FS::cust_bill_pkg;
 use FS::cust_bill_pkg_display;
+use FS::cust_bill_pkg_tax_location;
 use FS::cust_pay;
 use FS::cust_pay_pending;
 use FS::cust_pay_void;
@@ -2302,9 +2303,7 @@
   ###
 
   my( $total_setup, $total_recur, $postal_charge ) = ( 0, 0, 0 );
-  my %tax;
   my %taxlisthash;
-  my %taxname;
   my @precommit_hooks = ();
 
   my @cust_pkgs = qsearch('cust_pkg', { 'custnum' => $self->custnum } );
@@ -2386,30 +2385,54 @@
   }
 
   warn "having a look at the taxes we found...\n" if $DEBUG > 2;
+
+  # keys are tax names (as printed on invoices / itemdesc )
+  # values are listrefs of taxlisthash keys (internal identifiers)
+  my %taxname = ();
+
+  # keys are taxlisthash keys (internal identifiers)
+  # values are (cumulative) amounts
+  my %tax = ();
+
+  # keys are taxlisthash keys (internal identifiers)
+  # values are listrefs of cust_bill_pkg_tax_location hashrefs
+  my %tax_location = ();
+
   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 =
+    my $hashref_or_error =
       $tax_object->taxline( $taxlisthash{$tax},
                             'custnum'      => $self->custnum,
                             'invoice_time' => $invoice_time
                           );
-    unless (ref($listref_or_error)) {
+    unless ( ref($hashref_or_error) ) {
       $dbh->rollback if $oldAutoCommit;
-      return $listref_or_error;
+      return $hashref_or_error;
     }
     unshift @{ $taxlisthash{$tax} }, $tax_object;
 
-    warn "adding ". $listref_or_error->[1].
-         " as ". $listref_or_error->[0]. "\n"
-      if $DEBUG > 2;
-    $tax{ $tax } += $listref_or_error->[1];
-    if ( $taxname{ $listref_or_error->[0] } ) {
-      push @{ $taxname{ $listref_or_error->[0] } }, $tax;
-    }else{
-      $taxname{ $listref_or_error->[0] } = [ $tax ];
+    my $name   = $hashref_or_error->{'name'};
+    my $amount = $hashref_or_error->{'amount'};
+
+    #warn "adding $amount as $name\n";
+    $taxname{ $name } ||= [];
+    push @{ $taxname{ $name } }, $tax;
+
+    $tax{ $tax } += $amount;
+
+    $tax_location{ $tax } ||= [];
+    if ( $tax_object->get('pkgnum') || $tax_object->get('locationnum') ) {
+      push @{ $tax_location{ $tax }  },
+        {
+          'taxnum'      => $tax_object->taxnum, 
+          'taxtype'     => ref($tax_object),
+          'pkgnum'      => $tax_object->get('pkgnum'),
+          'locationnum' => $tax_object->get('locationnum'),
+          'amount'      => sprintf('%.2f', $amount ),
+        };
     }
-  
+
   }
 
   #move the cust_tax_exempt_pkg records to the cust_bill_pkgs we will commit
@@ -2475,11 +2498,15 @@
   foreach my $taxname ( keys %taxname ) {
     my $tax = 0;
     my %seen = ();
+    my @cust_bill_pkg_tax_location = ();
     warn "adding $taxname\n" if $DEBUG > 1;
     foreach my $taxitem ( @{ $taxname{$taxname} } ) {
-      $tax += $tax{$taxitem} unless $seen{$taxitem};
-      $seen{$taxitem} = 1;
+      next if $seen{$taxitem}++;
       warn "adding $tax{$taxitem}\n" if $DEBUG > 1;
+      $tax += $tax{$taxitem};
+      push @cust_bill_pkg_tax_location,
+        map { new FS::cust_bill_pkg_tax_location $_ }
+            @{ $tax_location{ $taxitem } };
     }
     next unless $tax;
 
@@ -2493,6 +2520,7 @@
       'sdate'    => '',
       'edate'    => '',
       'itemdesc' => $taxname,
+      'cust_bill_pkg_tax_location' => \@cust_bill_pkg_tax_location,
     };
 
   }
@@ -2766,71 +2794,89 @@
   my %cust_bill_pkg = ();
   my %taxes = ();
     
-  my $prefix = 
-    ( $conf->exists('tax-ship_address') && length($self->ship_last) )
-    ? 'ship_'
-    : '';
-
   my @classes;
   #push @classes, $cust_bill_pkg->usage_classes if $cust_bill_pkg->type eq 'U';
   push @classes, $cust_bill_pkg->usage_classes if $cust_bill_pkg->usage;
   push @classes, 'setup' if $cust_bill_pkg->setup;
   push @classes, 'recur' if $cust_bill_pkg->recur;
 
-  if ( $conf->exists('enable_taxproducts')
-       && (scalar($part_pkg->part_pkg_taxoverride) || $part_pkg->has_taxproduct)
-       && ( $self->tax !~ /Y/i && $self->payby ne 'COMP' )
-     )
-  { 
+  if ( $self->tax !~ /Y/i && $self->payby ne 'COMP' ) {
 
-    foreach my $class (@classes) {
-      my $err_or_ref = $self->_gather_taxes( $part_pkg, $class, $prefix );
-      return $err_or_ref unless ref($err_or_ref);
-      $taxes{$class} = $err_or_ref;
-    }
+    if ( $conf->exists('enable_taxproducts')
+         && ( scalar($part_pkg->part_pkg_taxoverride)
+              || $part_pkg->has_taxproduct
+            )
+       )
+    {
 
-    unless (exists $taxes{''}) {
-      my $err_or_ref = $self->_gather_taxes( $part_pkg, '', $prefix );
-      return $err_or_ref unless ref($err_or_ref);
-      $taxes{''} = $err_or_ref;
-    }
+      if ( $conf->exists('tax-pkg_address') && $cust_pkg->locationnum ) {
+        return "fatal: Can't (yet) use tax-pkg_address with taxproducts";
+      }
 
-  } elsif ( $self->tax !~ /Y/i && $self->payby ne 'COMP' ) {
+      foreach my $class (@classes) {
+        my $err_or_ref = $self->_gather_taxes( $part_pkg, $class );
+        return $err_or_ref unless ref($err_or_ref);
+        $taxes{$class} = $err_or_ref;
+      }
 
-    my %taxhash = map { $_ => $self->get("$prefix$_") }
-                      qw( state county country );
+      unless (exists $taxes{''}) {
+        my $err_or_ref = $self->_gather_taxes( $part_pkg, '' );
+        return $err_or_ref unless ref($err_or_ref);
+        $taxes{''} = $err_or_ref;
+      }
 
-    $taxhash{'taxclass'} = $part_pkg->taxclass;
+    } else {
 
-    my @taxes = qsearch( 'cust_main_county', \%taxhash );
+      my @loc_keys = qw( state county country );
+      my %taxhash;
+      if ( $conf->exists('tax-pkg_address') && $cust_pkg->locationnum ) {
+        my $cust_location = $cust_pkg->cust_location;
+        %taxhash = map { $_ => $cust_location->$_()    } @loc_keys;
+      } else {
+        my $prefix = 
+          ( $conf->exists('tax-ship_address') && length($self->ship_last) )
+          ? 'ship_'
+          : '';
+        %taxhash = map { $_ => $self->get("$prefix$_") } @loc_keys;
+      }
 
-    unless ( @taxes ) {
-      $taxhash{'taxclass'} = '';
-      @taxes =  qsearch( 'cust_main_county', \%taxhash );
-    }
+      $taxhash{'taxclass'} = $part_pkg->taxclass;
 
-    #one more try at a whole-country tax rate
-    unless ( @taxes ) {
-      $taxhash{$_} = '' foreach qw( state county );
-      @taxes =  qsearch( 'cust_main_county', \%taxhash );
-    }
+      my @taxes = qsearch( 'cust_main_county', \%taxhash );
 
-    $taxes{''} = [ @taxes ];
-    $taxes{'setup'} = [ @taxes ];
-    $taxes{'recur'} = [ @taxes ];
-    $taxes{$_} = [ @taxes ] foreach (@classes);
+      unless ( @taxes ) {
+        $taxhash{'taxclass'} = '';
+        @taxes =  qsearch( 'cust_main_county', \%taxhash );
+      }
 
-    # maybe eliminate this entirely, along with all the 0% records
-    unless ( @taxes ) {
-      return
-        "fatal: can't find tax rate for state/county/country/taxclass ".
-        join('/', ( map $self->get("$prefix$_"),
-                        qw(state county country)
-                  ),
-                  $part_pkg->taxclass ). "\n";
-    }
+      #one more try at a whole-country tax rate
+      unless ( @taxes ) {
+        $taxhash{$_} = '' foreach qw( state county );
+        @taxes =  qsearch( 'cust_main_county', \%taxhash );
+      }
 
-  } #if $conf->exists('enable_taxproducts') ...
+      if ( $conf->exists('tax-pkg_address') && $cust_pkg->locationnum ) {
+        foreach (@taxes) {
+          $_->set('pkgnum',      $cust_pkg->pkgnum );
+          $_->set('locationnum', $cust_pkg->locationnum );
+        }
+      }
+
+      $taxes{''} = [ @taxes ];
+      $taxes{'setup'} = [ @taxes ];
+      $taxes{'recur'} = [ @taxes ];
+      $taxes{$_} = [ @taxes ] foreach (@classes);
+
+      # maybe eliminate this entirely, along with all the 0% records
+      unless ( @taxes ) {
+        return
+          "fatal: can't find tax rate for state/county/country/taxclass ".
+          join('/', map $taxhash{$_}, qw(state county country taxclass) );
+      }
+
+    } #if $conf->exists('enable_taxproducts') ...
+
+  }
  
   my @display = ();
   if ( $conf->exists('separate_usage') ) {
@@ -2856,7 +2902,12 @@
     my $tax_cust_bill_pkg = $tax_cust_bill_pkg{$key};
 
     foreach my $tax ( @taxes ) {
-      my $taxname = ref( $tax ). ' '. $tax->taxnum;
+
+      my $taxname = ref( $tax ). ' taxnum'. $tax->taxnum;
+#      $taxname .= ' pkgnum'. $cust_pkg->pkgnum.
+#                  ' locationnum'. $cust_pkg->locationnum
+#        if $conf->exists('tax-pkg_address') && $cust_pkg->locationnum;
+
       if ( exists( $taxlisthash->{ $taxname } ) ) {
         push @{ $taxlisthash->{ $taxname  } }, $tax_cust_bill_pkg;
       }else{
@@ -2872,7 +2923,6 @@
   my $self = shift;
   my $part_pkg = shift;
   my $class = shift;
-  my $prefix = shift;
 
   my @taxes = ();
   my $geocode = $self->geocode('cch');
@@ -2900,12 +2950,11 @@
   # maybe eliminate this entirely, along with all the 0% records
   unless ( @taxes ) {
     return 
-      "fatal: can't find tax rate for zip/taxproduct/pkgpart ".
-      join('/', ( map $self->get("$prefix$_"),
-                      qw(zip)
-                ),
+      "fatal: can't find tax rate for geocode/taxproduct/pkgpart ".
+      join('/', $geocode,
                 $part_pkg->taxproduct_description,
-                $part_pkg->pkgpart ). "\n";
+                $part_pkg->pkgpart
+          );
   }
 
   warn "Found taxes ".

Index: cust_main_county.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_main_county.pm,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- cust_main_county.pm	25 Dec 2008 00:45:57 -0000	1.22
+++ cust_main_county.pm	18 Jan 2009 23:43:39 -0000	1.23
@@ -198,29 +198,18 @@
   map $_->[0], @{ $sth->fetchall_arrayref };
 }
 
-=item taxline TAXABLES, [ OPTIONSHASH ]
+=item taxline TAXABLES_ARRAYREF, [ OPTION => VALUE ... ]
 
 Returns a listref of a name and an amount of tax calculated for the list of
-packages or amounts referenced by TAXABLES.  Returns a scalar error message
-on error.  
+packages or amounts referenced by TAXABLES_ARRAYREF.  Returns a scalar error
+message on error.  
 
-OPTIONSHASH includes custnum and invoice_date and are hints to this method
+Options include custnum and invoice_date and are hints to this method
 
 =cut
 
 sub taxline {
-  my $self = shift;
-
-  my $taxables;
-  my %opt = ();
-
-  if (ref($_[0]) eq 'ARRAY') {
-    $taxables = shift;
-    %opt = @_;
-  }else{
-    $taxables = [ @_ ];
-    # exemptions broken in this case
-  }
+  my( $self, $taxables, %opt ) = @_;
 
   my @exemptions = ();
   push @exemptions, @{ $_->_cust_tax_exempt_pkg }
@@ -362,7 +351,12 @@
   }
 
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
-  return [ $name, $amount ]
+
+  return {
+    'name'   => $name,
+    'amount' => $amount,
+  };
+
 }
 
 =back

--- NEW FILE: cust_bill_pkg_tax_location.pm ---
package FS::cust_bill_pkg_tax_location;

use strict;
use base qw( FS::Record );
use FS::Record qw( qsearch qsearchs );
use FS::cust_bill_pkg;
use FS::cust_pkg;
use FS::cust_location;

=head1 NAME

FS::cust_bill_pkg_tax_location - Object methods for cust_bill_pkg_tax_location records

=head1 SYNOPSIS

  use FS::cust_bill_pkg_tax_location;

  $record = new FS::cust_bill_pkg_tax_location \%hash;
  $record = new FS::cust_bill_pkg_tax_location { 'column' => 'value' };

  $error = $record->insert;

  $error = $new_record->replace($old_record);

  $error = $record->delete;

  $error = $record->check;

=head1 DESCRIPTION

An FS::cust_bill_pkg_tax_location object represents an record of taxation
based on package location.  FS::cust_bill_pkg_tax_location inherits from
FS::Record.  The following fields are currently supported:

=over 4

=item billpkgtaxlocationnum

billpkgtaxlocationnum

=item billpkgnum

billpkgnum

=item taxnum

taxnum

=item taxtype

taxtype

=item pkgnum

pkgnum

=item locationnum

locationnum

=item amount

amount


=back

=head1 METHODS

=over 4

=item new HASHREF

Creates a new record.  To add the record to the database, see L<"insert">.

Note that this stores the hash reference, not a distinct copy of the hash it
points to.  You can ask the object for a copy with the I<hash> method.

=cut

sub table { 'cust_bill_pkg_tax_location'; }

=item insert

Adds this record to the database.  If there is an error, returns the error,
otherwise returns false.

=item delete

Delete this record from the database.

=item replace OLD_RECORD

Replaces the OLD_RECORD with this one in the database.  If there is an error,
returns the error, otherwise returns false.

=item check

Checks all fields to make sure this is a valid record.  If there is
an error, returns the error, otherwise returns false.  Called by the insert
and replace methods.

=cut

# the check method should currently be supplied - FS::Record contains some
# data checking routines

sub check {
  my $self = shift;

  my $error = 
    $self->ut_numbern('billpkgtaxlocationnum')
    || $self->ut_foreign_key('billpkgnum', 'cust_bill_pkg', 'billpkgnum' )
    || $self->ut_number('taxnum') #cust_bill_pkg/tax_rate key, based on taxtype
    || $self->ut_enum('taxtype', [ qw( FS::cust_main::county FS::tax_rate ) ] )
    || $self->ut_foreign_key('pkgnum', 'cust_pkg', 'pkgnum' )
    || $self->ut_foreign_key('locationnum', 'cust_location', 'locationnum' )
    || $self->ut_money('amount')
  ;
  return $error if $error;

  $self->SUPER::check;
}

=back

=head1 BUGS

=head1 SEE ALSO

L<FS::Record>, schema.html from the base documentation.

=cut

1;


Index: Schema.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Schema.pm,v
retrieving revision 1.120
retrieving revision 1.121
diff -u -d -r1.120 -r1.121
--- Schema.pm	10 Jan 2009 23:56:56 -0000	1.120
+++ Schema.pm	18 Jan 2009 23:43:39 -0000	1.121
@@ -498,19 +498,19 @@
 
     'cust_bill_pkg' => {
       'columns' => [
-        'billpkgnum', 'serial', '', '', '', '', 
-        'pkgnum',  'int', '', '', '', '', 
-        'pkgpart_override',  'int', 'NULL', '', '', '', 
-        'invnum',  'int', '', '', '', '', 
-        'setup',   @money_type, '', '', 
-        'recur',   @money_type, '', '', 
-        'sdate',   @date_type, '', '', 
-        'edate',   @date_type, '', '', 
-        'itemdesc', 'varchar', 'NULL', $char_d, '', '', 
-        'section',  'varchar', 'NULL', $char_d, '', '', 
-        'quantity',  'int', 'NULL', '', '', '',
-        'unitsetup', @money_typen, '', '', 
-        'unitrecur', @money_typen, '', '', 
+        'billpkgnum',        'serial',     '',      '', '', '', 
+        'invnum',               'int',     '',      '', '', '', 
+        'pkgnum',               'int',     '',      '', '', '', 
+        'pkgpart_override',     'int', 'NULL',      '', '', '', 
+        'setup',               @money_type,             '', '', 
+        'recur',               @money_type,             '', '', 
+        'sdate',               @date_type,              '', '', 
+        'edate',               @date_type,              '', '', 
+        'itemdesc',         'varchar', 'NULL', $char_d, '', '', 
+        'section',          'varchar', 'NULL', $char_d, '', '', 
+        'quantity',             'int', 'NULL',      '', '', '',
+        'unitsetup',           @money_typen,            '', '', 
+        'unitrecur',           @money_typen,            '', '', 
       ],
       'primary_key' => 'billpkgnum',
       'unique' => [],
@@ -549,6 +549,21 @@
       'index' => [ ['billpkgnum'], ],
     },
 
+    'cust_bill_pkg_tax_location' => {
+      'columns' => [
+        'billpkgtaxlocationnum', 'serial',      '', '', '', '',
+        'billpkgnum',               'int',      '', '', '', '',
+        'taxnum',                   'int',      '', '', '', '',
+        'taxtype',              'varchar', $char_d, '', '', '',
+        'pkgnum',                   'int',      '', '', '', '',
+        'locationnum',              'int',      '', '', '', '', #redundant?
+        'amount',                   @money_type,        '', '',
+      ],
+      'primary_key' => 'billpkgtaxlocationnum',
+      'unique' => [],
+      'index'  => [ [ 'billpkgnum' ], [ 'taxnum' ], [ 'pkgnum' ], [ 'locationnum' ] ],
+    },
+
     'cust_credit' => {
       'columns' => [
         'crednum',  'serial', '', '', '', '', 
@@ -742,7 +757,9 @@
       'primary_key' => 'taxnum',
       'unique' => [],
   #    'unique' => [ ['taxnum'], ['state', 'county'] ],
-      'index' => [ [ 'county' ], [ 'state' ], [ 'country' ] ],
+      'index' => [ [ 'county' ], [ 'state' ], [ 'country' ],
+                   [ 'taxclass' ],
+                 ],
     },
 
     'tax_rate'    => {

Index: cust_bill_pkg.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_bill_pkg.pm,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- cust_bill_pkg.pm	25 Dec 2008 00:45:57 -0000	1.30
+++ cust_bill_pkg.pm	18 Jan 2009 23:43:39 -0000	1.31
@@ -152,6 +152,20 @@
     }
   }
 
+  my $tax_location = $self->get('cust_bill_pkg_tax_location');
+  if ( $tax_location ) {
+    foreach my $cust_bill_pkg_tax_location ( @$tax_location ) {
+      $cust_bill_pkg_tax_location->billpkgnum($self->billpkgnum);
+      warn $cust_bill_pkg_tax_location;
+      $error = $cust_bill_pkg_tax_location->insert;
+      warn $error;
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+    }
+  }
+
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   '';
 

Index: tax_rate.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/tax_rate.pm,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- tax_rate.pm	5 Jan 2009 21:12:06 -0000	1.14
+++ tax_rate.pm	18 Jan 2009 23:43:39 -0000	1.15
@@ -443,7 +443,10 @@
   warn "calculated taxes as [ $name, $amount ]\n"
     if $DEBUG;
 
-  return [$name, $amount];
+  return {
+    'name'   => $name,
+    'amount' => $amount,
+  };
 
 }
 



More information about the freeside-commits mailing list