[freeside-commits] freeside/FS/FS cust_bill_pkg_tax_rate_location.pm, NONE, 1.1 tax_rate_location.pm, NONE, 1.1 Schema.pm, 1.138, 1.139 cust_bill_pkg.pm, 1.32, 1.33 cust_main.pm, 1.424, 1.425 tax_rate.pm, 1.24, 1.25

Jeff Finucane,420,, jeff at wavetail.420.am
Wed May 13 15:27:44 PDT 2009


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

Modified Files:
	Schema.pm cust_bill_pkg.pm cust_main.pm tax_rate.pm 
Added Files:
	cust_bill_pkg_tax_rate_location.pm tax_rate_location.pm 
Log Message:
improved taxproduct tax report RT#4783

--- NEW FILE: cust_bill_pkg_tax_rate_location.pm ---
package FS::cust_bill_pkg_tax_rate_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_rate_location - Object methods for cust_bill_pkg_tax_rate_location records

=head1 SYNOPSIS

  use FS::cust_bill_pkg_tax_rate_location;

  $record = new FS::cust_bill_pkg_tax_rate_location \%hash;
  $record = new FS::cust_bill_pkg_tax_rate_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_rate_location object represents an record of taxation
based on package location.  FS::cust_bill_pkg_tax_rate_location inherits from
FS::Record.  The following fields are currently supported:

=over 4

=item billpkgtaxratelocationnum

billpkgtaxratelocationnum

=item billpkgnum

billpkgnum

=item taxnum

taxnum

=item taxtype

taxtype

=item locationtaxid

locationtaxid

=item taxratelocationnum

taxratelocationnum

=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_rate_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('billpkgtaxratelocationnum')
    || $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_textn('locationtaxid')
    || $self->ut_foreign_key('taxratelocationnum', 'tax_rate_location', 'taxratelocationnum' )
    || $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;


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

use strict;
use base qw( FS::Record );
use FS::Record qw( qsearch qsearchs dbh );

=head1 NAME

FS::tax_rate_location - Object methods for tax_rate_location records

=head1 SYNOPSIS

  use FS::tax_rate_location;

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

  $error = $record->insert;

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

  $error = $record->delete;

  $error = $record->check;

=head1 DESCRIPTION

An FS::tax_rate_location object represents an example.  FS::tax_rate_location inherits from
FS::Record.  The following fields are currently supported:

=over 4

=item taxratelocationnum

Primary key (assigned automatically for new tax_rate_locations)

=item data_vendor

The tax data vendor

=item geocode

A unique geographic location code provided by the data vendor

=item city

City

=item county

County

=item state

State

=item disabled

If 'Y' this record is no longer active.


=back

=head1 METHODS

=over 4

=item new HASHREF

Creates a new tax rate location.  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 { 'tax_rate_location'; }

=item insert

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

=cut

=item delete

Delete this record from the database.

=cut

sub delete {
  return "Can't delete tax rate locations.  Set disable to 'Y' instead.";
  # check that it is unused in any cust_bill_pkg_tax_location records instead?
}

=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.

=cut

=item check

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

=cut

sub check {
  my $self = shift;

  my $error = 
    $self->ut_numbern('taxratelocationnum')
    || $self->ut_textn('data_vendor')
    || $self->ut_alpha('geocode')
    || $self->ut_textn('city')
    || $self->ut_textn('county')
    || $self->ut_textn('state')
    || $self->ut_enum('disabled', [ '', 'Y' ])
  ;
  return $error if $error;

  my $t = qsearchs( 'tax_rate_location',
                    { map { $_ => $self->$_ } qw( data_vendor geocode ) },
                  );

  return "geocode already in use for this vendor"
    if ( $t && $t->taxratelocationnum != $self->taxratelocationnum );

  return "may only be disabled"
    if ( $t && scalar( grep { $t->$_ ne $self->$_ } 
                       grep { $_ ne 'disabled' }
                       $self->fields
                     )
       );

  $self->SUPER::check;
}

=back

=head1 SUBROUTINES

=over 4

=item batch_import

=cut

sub batch_import {
  my ($param, $job) = @_;

  my $fh = $param->{filehandle};
  my $format = $param->{'format'};

  my %insert = ();
  my %delete = ();

  my @fields;
  my $hook;

  my @column_lengths = ();
  my @column_callbacks = ();
  if ( $format eq 'cch-fixed' || $format eq 'cch-fixed-update' ) {
    $format =~ s/-fixed//;
    my $trim = sub { my $r = shift; $r =~ s/^\s*//; $r =~ s/\s*$//; $r };
    push @column_lengths, qw( 28 25 2 10 );
    push @column_lengths, 1 if $format eq 'cch-update';
    push @column_callbacks, $trim foreach (@column_lengths);
  }

  my $line;
  my ( $count, $last, $min_sec ) = (0, time, 5); #progressbar
  if ( $job || scalar(@column_callbacks) ) {
    my $error =
      csv_from_fixed(\$fh, \$count, \@column_lengths, \@column_callbacks);
    return $error if $error;
  }

  if ( $format eq 'cch' || $format eq 'cch-update' ) {
    @fields = qw( city county state geocode );
    push @fields, 'actionflag' if $format eq 'cch-update';

    $hook = sub {
      my $hash = shift;

      $hash->{'data_vendor'} ='cch';

      if (exists($hash->{'actionflag'}) && $hash->{'actionflag'} eq 'D') {
        delete($hash->{actionflag});

        $hash->{deleted} = '';
        my $tax_rate_location = qsearchs('tax_rate_location', $hash);
        return "Can't find tax_rate_location to delete: ".
               join(" ", map { "$_ => ". $hash->{$_} } @fields)
          unless $tax_rate_location;

        $tax_rate_location->disabled('Y');
        my $error = $tax_rate_location->replace;
        return $error if $error;

        delete($hash->{$_}) foreach (keys %$hash);
      }

      delete($hash->{'actionflag'});

      '';

    };

  } elsif ( $format eq 'extended' ) {
    die "unimplemented\n";
    @fields = qw( );
    $hook = sub {};
  } else {
    die "unknown format $format";
  }

  eval "use Text::CSV_XS;";
  die $@ if $@;

  my $csv = new Text::CSV_XS;

  my $imported = 0;

  local $SIG{HUP} = 'IGNORE';
  local $SIG{INT} = 'IGNORE';
  local $SIG{QUIT} = 'IGNORE';
  local $SIG{TERM} = 'IGNORE';
  local $SIG{TSTP} = 'IGNORE';
  local $SIG{PIPE} = 'IGNORE';

  my $oldAutoCommit = $FS::UID::AutoCommit;
  local $FS::UID::AutoCommit = 0;
  my $dbh = dbh;

  while ( defined($line=<$fh>) ) {
    $csv->parse($line) or do {
      $dbh->rollback if $oldAutoCommit;
      return "can't parse: ". $csv->error_input();
    };

    if ( $job ) {  # progress bar
      if ( time - $min_sec > $last ) {
        my $error = $job->update_statustext(
          int( 100 * $imported / $count )
        );
        die $error if $error;
        $last = time;
      }
    }

    my @columns = $csv->fields();

    my %tax_rate_location = ();
    foreach my $field ( @fields ) {
      $tax_rate_location{$field} = shift @columns;
    }
    if ( scalar( @columns ) ) {
      $dbh->rollback if $oldAutoCommit;
      return "Unexpected trailing columns in line (wrong format?): $line";
    }

    my $error = &{$hook}(\%tax_rate_location);
    if ( $error ) {
      $dbh->rollback if $oldAutoCommit;
      return $error;
    }

    if (scalar(keys %tax_rate_location)) { #inserts only

      my $tax_rate_location = new FS::tax_rate_location( \%tax_rate_location );
      $error = $tax_rate_location->insert;

      if ( $error ) {
        $dbh->rollback if $oldAutoCommit;
        return "can't insert tax_rate for $line: $error";
      }

    }

    $imported++;

  }

  $dbh->commit or die $dbh->errstr if $oldAutoCommit;

  return "Empty file!" unless ($imported || $format eq 'cch-update');

  ''; #no error

}

=head1 BUGS

Currently somewhat specific to CCH supplied data.

=head1 SEE ALSO

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

=cut

1;


Index: cust_main.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_main.pm,v
retrieving revision 1.424
retrieving revision 1.425
diff -u -d -r1.424 -r1.425
--- cust_main.pm	1 May 2009 20:21:42 -0000	1.424
+++ cust_main.pm	13 May 2009 22:27:41 -0000	1.425
@@ -30,6 +30,7 @@
 use FS::cust_bill_pkg;
 use FS::cust_bill_pkg_display;
 use FS::cust_bill_pkg_tax_location;
+use FS::cust_bill_pkg_tax_rate_location;
 use FS::cust_pay;
 use FS::cust_pay_pending;
 use FS::cust_pay_void;
@@ -40,6 +41,7 @@
 use FS::cust_main_county;
 use FS::cust_location;
 use FS::tax_rate;
+use FS::tax_rate_location;
 use FS::cust_tax_location;
 use FS::part_pkg_taxrate;
 use FS::agent;
@@ -2461,6 +2463,10 @@
   # values are listrefs of cust_bill_pkg_tax_location hashrefs
   my %tax_location = ();
 
+  # keys are taxlisthash keys (internal identifiers)
+  # values are listrefs of cust_bill_pkg_tax_rate_location hashrefs
+  my %tax_rate_location = ();
+
   foreach my $tax ( keys %taxlisthash ) {
     my $tax_object = shift @{ $taxlisthash{$tax} };
     warn "found ". $tax_object->taxname. " as $tax\n" if $DEBUG > 2;
@@ -2497,6 +2503,20 @@
         };
     }
 
+    $tax_rate_location{ $tax } ||= [];
+    if ( ref($tax_object) eq 'FS::tax_rate' ) {
+      my $taxratelocationnum =
+        $tax_object->tax_rate_location->taxratelocationnum;
+      push @{ $tax_rate_location{ $tax }  },
+        {
+          'taxnum'             => $tax_object->taxnum, 
+          'taxtype'            => ref($tax_object),
+          'amount'             => sprintf('%.2f', $amount ),
+          'locationtaxid'      => $tax_object->location,
+          'taxratelocationnum' => $taxratelocationnum,
+        };
+    }
+
   }
 
   #move the cust_tax_exempt_pkg records to the cust_bill_pkgs we will commit
@@ -2516,6 +2536,7 @@
     my $tax = 0;
     my %seen = ();
     my @cust_bill_pkg_tax_location = ();
+    my @cust_bill_pkg_tax_rate_location = ();
     warn "adding $taxname\n" if $DEBUG > 1;
     foreach my $taxitem ( @{ $taxname{$taxname} } ) {
       next if $seen{$taxitem}++;
@@ -2524,6 +2545,9 @@
       push @cust_bill_pkg_tax_location,
         map { new FS::cust_bill_pkg_tax_location $_ }
             @{ $tax_location{ $taxitem } };
+      push @cust_bill_pkg_tax_rate_location,
+        map { new FS::cust_bill_pkg_tax_rate_location $_ }
+            @{ $tax_rate_location{ $taxitem } };
     }
     next unless $tax;
 
@@ -2538,6 +2562,7 @@
       'edate'    => '',
       'itemdesc' => $taxname,
       'cust_bill_pkg_tax_location' => \@cust_bill_pkg_tax_location,
+      'cust_bill_pkg_tax_rate_location' => \@cust_bill_pkg_tax_rate_location,
     };
 
   }

Index: Schema.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Schema.pm,v
retrieving revision 1.138
retrieving revision 1.139
diff -u -d -r1.138 -r1.139
--- Schema.pm	9 May 2009 00:39:13 -0000	1.138
+++ Schema.pm	13 May 2009 22:27:41 -0000	1.139
@@ -560,7 +560,7 @@
         'billpkgtaxlocationnum', 'serial',      '', '', '', '',
         'billpkgnum',               'int',      '', '', '', '',
         'taxnum',                   'int',      '', '', '', '',
-        'taxtype',              'varchar', $char_d, '', '', '',
+        'taxtype',              'varchar',      '', $char_d, '', '',
         'pkgnum',                   'int',      '', '', '', '',
         'locationnum',              'int',      '', '', '', '', #redundant?
         'amount',                   @money_type,        '', '',
@@ -570,6 +570,21 @@
       'index'  => [ [ 'billpkgnum' ], [ 'taxnum' ], [ 'pkgnum' ], [ 'locationnum' ] ],
     },
 
+    'cust_bill_pkg_tax_rate_location' => {
+      'columns' => [
+        'billpkgtaxratelocationnum', 'serial',      '', '', '', '',
+        'billpkgnum',                   'int',      '', '', '', '',
+        'taxnum',                       'int',      '', '', '', '',
+        'taxtype',                  'varchar',      '', $char_d, '', '',
+        'locationtaxid',            'varchar',  'NULL', $char_d, '', '',
+        'taxratelocationnum',           'int',      '', '', '', '',
+        'amount',                       @money_type,        '', '',
+      ],
+      'primary_key' => 'billpkgtaxratelocationnum',
+      'unique' => [],
+      'index'  => [ [ 'billpkgnum' ], [ 'taxnum' ], [ 'taxratelocationnum' ] ],
+    },
+
     'cust_credit' => {
       'columns' => [
         'crednum',  'serial', '', '', '', '', 
@@ -805,6 +820,21 @@
       'index' => [ ['taxclassnum'], ['data_vendor', 'geocode'] ],
     },
 
+    'tax_rate_location' => { 
+      'columns' => [
+        'taxratelocationnum', 'serial',  '',     '', '', '', 
+        'data_vendor',        'varchar', 'NULL', $char_d, '', '',
+        'geocode',            'varchar', '',     20,      '', '', 
+        'city',               'varchar', 'NULL', $char_d, '', '',
+        'county',             'varchar', 'NULL', $char_d, '', '',
+        'state',              'char',    '',     2,  '', '', 
+        'disabled',           'char',    'NULL', 1, '', '',
+      ],
+      'primary_key' => 'taxratelocationnum',
+      'unique' => [],
+      'index' => [ [ 'data_vendor', 'geocode', 'disabled' ] ],
+    },
+
     'cust_tax_location' => { 
       'columns' => [
         'custlocationnum', 'serial',  '',     '', '', '', 

Index: cust_bill_pkg.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_bill_pkg.pm,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- cust_bill_pkg.pm	21 Feb 2009 17:56:07 -0000	1.32
+++ cust_bill_pkg.pm	13 May 2009 22:27:41 -0000	1.33
@@ -162,6 +162,19 @@
     }
   }
 
+  my $tax_rate_location = $self->get('cust_bill_pkg_tax_rate_location');
+  if ( $tax_rate_location ) {
+    foreach my $cust_bill_pkg_tax_rate_location ( @$tax_rate_location ) {
+      $cust_bill_pkg_tax_rate_location->billpkgnum($self->billpkgnum);
+      $error = $cust_bill_pkg_tax_rate_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.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- tax_rate.pm	23 Apr 2009 20:31:26 -0000	1.24
+++ tax_rate.pm	13 May 2009 22:27:42 -0000	1.25
@@ -19,6 +19,7 @@
 use FS::tax_class;
 use FS::cust_bill_pkg;
 use FS::cust_tax_location;
+use FS::tax_rate_location;
 use FS::part_pkg_taxrate;
 use FS::cust_main;
 use FS::Misc qw( csv_from_fixed );
@@ -538,6 +539,26 @@
 
 }
 
+=item tax_rate_location
+
+Returns an object representing the location associated with this tax
+(see L<FS::tax_rate_location>)
+
+=cut
+
+sub tax_rate_location {
+  my $self = shift;
+
+  qsearchs({ 'table'     => 'tax_rate_location',
+             'hashref'   => { 'data_vendor' => $self->data_vendor, 
+                              'geocode'     => $self->geocode,
+                              'disabled'    => '',
+                            },
+          }) ||
+  new FS::tax_rate_location;
+
+}
+
 =back
 
 =head1 SUBROUTINES
@@ -845,7 +866,8 @@
     my $error = '';
     my $have_location = 0;
 
-    my @list = ( 'CODE',     'codefile',  \&FS::tax_class::batch_import,
+    my @list = ( 'GEOCODE',  'geofile',   \&FS::tax_rate_location::batch_import,
+                 'CODE',     'codefile',  \&FS::tax_class::batch_import,
                  'PLUS4',    'plus4file', \&FS::cust_tax_location::batch_import,
                  'ZIP',      'zipfile',   \&FS::cust_tax_location::batch_import,
                  'TXMATRIX', 'txmatrix',  \&FS::part_pkg_taxrate::batch_import,
@@ -887,7 +909,8 @@
     my @insert_list = ();
     my @delete_list = ();
 
-    my @list = ( 'CODE',     'codefile',  \&FS::tax_class::batch_import,
+    my @list = ( 'GEOCODE',  'geofile',   \&FS::tax_rate_location::batch_import,
+                 'CODE',     'codefile',  \&FS::tax_class::batch_import,
                  'PLUS4',    'plus4file', \&FS::cust_tax_location::batch_import,
                  'ZIP',      'zipfile',   \&FS::cust_tax_location::batch_import,
                  'TXMATRIX', 'txmatrix',  \&FS::part_pkg_taxrate::batch_import,



More information about the freeside-commits mailing list