change texas-style tax exemptions to be against a specific line item rather than...
authorivan <ivan>
Wed, 25 Jan 2006 12:34:29 +0000 (12:34 +0000)
committerivan <ivan>
Wed, 25 Jan 2006 12:34:29 +0000 (12:34 +0000)
13 files changed:
FS/FS/Record.pm
FS/FS/Schema.pm
FS/FS/cust_bill.pm
FS/FS/cust_main.pm
FS/FS/cust_tax_exempt.pm
FS/FS/cust_tax_exempt_pkg.pm [new file with mode: 0644]
FS/FS/h_cust_bill.pm [new file with mode: 0644]
FS/FS/h_cust_tax_exempt.pm [new file with mode: 0644]
FS/MANIFEST
FS/t/cust_tax_exempt_pkg.t [new file with mode: 0644]
FS/t/h_cust_bill.t [new file with mode: 0644]
FS/t/h_cust_tax_exempt.t [new file with mode: 0644]
README.2.0.0 [new file with mode: 0644]

index 887c8dc..19da3d1 100644 (file)
@@ -977,6 +977,11 @@ sub replace {
 
   warn "[debug]$me $new ->replace $old\n" if $DEBUG;
 
+  if ( $new->can('replace_check') ) {
+    my $error = $new->replace_check($old);
+    return $error if $error;
+  }
+
   return "Records not in same table!" unless $new->table eq $old->table;
 
   my $primary_key = $old->dbdef_table->primary_key;
index 451ef2d..d502a12 100644 (file)
@@ -976,6 +976,24 @@ sub tables_hashref {
       'index'       => [],
     },
 
+    'cust_tax_exempt_pkg' => {
+      'columns' => [
+        'exemptpkgnum',  'serial', '', '',
+        #'custnum',      'int', '', '',
+        'billpkgnum',   'int', '', '',
+        'taxnum',       'int', '', '',
+        'year',         'int', '', '',
+        'month',        'int', '', '',
+        'amount',       @money_type,
+      ],
+      'primary_key' => 'exemptpkgnum',
+      'unique' => [],
+      'index'  => [ [ 'taxnum', 'year', 'month' ],
+                    [ 'billpkgnum' ],
+                    [ 'taxnum' ]
+                  ],
+    },
+
     'router' => {
       'columns' => [
         'routernum', 'serial', '', '',
index 6e3b2b2..159c9e4 100644 (file)
@@ -121,8 +121,14 @@ returns the error, otherwise returns false.
 
 =item delete
 
-Currently unimplemented.  I don't remove invoices because there would then be
-no record you ever posted this invoice (which is bad, no?)
+This method now works but you probably shouldn't use it.  Instead, apply a
+credit against the invoice.
+
+Using this method to delete invoices outright is really, really bad.  There
+would be no record you ever posted this invoice, and there are no check to
+make sure charged = 0 or that there are no associated cust_bill_pkg records.
+
+Really, don't use it.
 
 =cut
 
@@ -142,14 +148,20 @@ collect method of a customer object (see L<FS::cust_main>).
 
 =cut
 
-sub replace {
+#replace can be inherited from Record.pm
+
+# replace_check is now the preferred way to #implement replace data checks
+# (so $object->replace() works without an argument)
+
+sub replace_check {
   my( $new, $old ) = ( shift, shift );
   return "Can't change custnum!" unless $old->custnum == $new->custnum;
   #return "Can't change _date!" unless $old->_date eq $new->_date;
   return "Can't change _date!" unless $old->_date == $new->_date;
-  return "Can't change charged!" unless $old->charged == $new->charged;
+  return "Can't change charged!" unless $old->charged == $new->charged
+                                     || $old->charged == 0;
 
-  $new->SUPER::replace($old);
+  '';
 }
 
 =item check
index a265e41..b5ccf5a 100644 (file)
@@ -43,6 +43,7 @@ use FS::part_pkg;
 use FS::part_bill_event;
 use FS::cust_bill_event;
 use FS::cust_tax_exempt;
+use FS::cust_tax_exempt_pkg;
 use FS::type_pkgs;
 use FS::payment_gateway;
 use FS::agent_payment_gateway;
@@ -1617,16 +1618,28 @@ sub bill {
 
   $self->select_for_update; #mutex
 
+  #create a new invoice
+  #(we'll remove it later if it doesn't actually need to be generated [contains
+  # no line items] and we're inside a transaciton so nothing else will see it)
+  my $cust_bill = new FS::cust_bill ( {
+    'custnum' => $self->custnum,
+    '_date'   => $time,
+    #'charged' => $charged,
+    'charged' => 0,
+  } );
+  $error = $cust_bill->insert;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return "can't create invoice for customer #". $self->custnum. ": $error";
+  }
+  my $invnum = $cust_bill->invnum;
+
+  ###
   # find the packages which are due for billing, find out how much they are
   # & generate invoice database.
-  my( $total_setup, $total_recur ) = ( 0, 0 );
-  #my( $taxable_setup, $taxable_recur ) = ( 0, 0 );
-  my @cust_bill_pkg = ();
-  #my $tax = 0;##
-  #my $taxable_charged = 0;##
-  #my $charged = 0;##
+  ###
 
+  my( $total_setup, $total_recur ) = ( 0, 0 );
   my %tax;
 
   foreach my $cust_pkg (
@@ -1649,7 +1662,10 @@ sub bill {
 
     my @details = ();
 
+    ###
     # bill setup
+    ###
+
     my $setup = 0;
     if ( !$cust_pkg->setup || $options{'resetup'} ) {
     
@@ -1664,7 +1680,10 @@ sub bill {
       $cust_pkg->setfield('setup', $time) unless $cust_pkg->setup;
     }
 
-    #bill recurring fee
+    ###
+    # bill recurring fee
+    ### 
+
     my $recur = 0;
     my $sdate;
     if ( $part_pkg->getfield('freq') ne '0' &&
@@ -1719,6 +1738,10 @@ sub bill {
     warn "\$recur is undefined" unless defined($recur);
     warn "\$cust_pkg->bill is undefined" unless defined($cust_pkg->bill);
 
+    ###
+    # If $cust_pkg has been modified, update it and create cust_bill_pkg records
+    ###
+
     if ( $cust_pkg->modified ) {
 
       warn "  package ". $cust_pkg->pkgnum. " modified; updating\n"
@@ -1740,10 +1763,13 @@ sub bill {
         $dbh->rollback if $oldAutoCommit;
         return "negative recur $recur for pkgnum ". $cust_pkg->pkgnum;
       }
+
       if ( $setup != 0 || $recur != 0 ) {
-        warn "    charges (setup=$setup, recur=$recur); queueing line items\n"
+
+        warn "    charges (setup=$setup, recur=$recur); adding line items\n"
           if $DEBUG > 1;
         my $cust_bill_pkg = new FS::cust_bill_pkg ({
+          'invnum'  => $invnum,
           'pkgnum'  => $cust_pkg->pkgnum,
           'setup'   => $setup,
           'recur'   => $recur,
@@ -1751,10 +1777,18 @@ sub bill {
           'edate'   => $cust_pkg->bill,
           'details' => \@details,
         });
-        push @cust_bill_pkg, $cust_bill_pkg;
+        $error = $cust_bill_pkg->insert;
+        if ( $error ) {
+          $dbh->rollback if $oldAutoCommit;
+          return "can't create invoice line item for invoice #$invnum: $error";
+        }
         $total_setup += $setup;
         $total_recur += $recur;
 
+        ###
+        # handle taxes
+        ###
+
         unless ( $self->tax =~ /Y/i || $self->payby eq 'COMP' ) {
 
           my @taxes = qsearch( 'cust_main_county', {
@@ -1803,7 +1837,8 @@ sub bill {
             next unless $taxable_charged;
 
             if ( $tax->exempt_amount && $tax->exempt_amount > 0 ) {
-              my ($mon,$year) = (localtime($sdate) )[4,5];
+              #my ($mon,$year) = (localtime($sdate) )[4,5];
+              my ($mon,$year) = (localtime( $sdate || $cust_bill->_date ) )[4,5];
               $mon++;
               my $freq = $part_pkg->freq || 1;
               if ( $freq !~ /(\d+)$/ ) {
@@ -1811,40 +1846,74 @@ sub bill {
                 return "daily/weekly package definitions not (yet?)".
                        " compatible with monthly tax exemptions";
               }
-              my $taxable_per_month = sprintf("%.2f", $taxable_charged / $freq );
+              my $taxable_per_month =
+                sprintf("%.2f", $taxable_charged / $freq );
+
+              #call the whole thing off if this customer has any old
+              #exemption records...
+              my @cust_tax_exempt =
+                qsearch( 'cust_tax_exempt' => { custnum=> $self->custnum } );
+              if ( @cust_tax_exempt ) {
+                $dbh->rollback if $oldAutoCommit;
+                return
+                  'this customer still has old-style tax exemption records; '.
+                  'run bin/fs-migrate-cust_tax_exempt?';
+              }
+
               foreach my $which_month ( 1 .. $freq ) {
-                my %hash = (
-                  'custnum' => $self->custnum,
-                  'taxnum'  => $tax->taxnum,
-                  'year'    => 1900+$year,
-                  'month'   => $mon++,
-                );
-                #until ( $mon < 12 ) { $mon -= 12; $year++; }
-                until ( $mon < 13 ) { $mon -= 12; $year++; }
-                my $cust_tax_exempt =
-                  qsearchs('cust_tax_exempt', \%hash)
-                  || new FS::cust_tax_exempt( { %hash, 'amount' => 0 } );
-                my $remaining_exemption = sprintf("%.2f",
-                  $tax->exempt_amount - $cust_tax_exempt->amount );
+
+                #maintain the new exemption table now
+                my $sql = "
+                  SELECT SUM(amount)
+                    FROM cust_tax_exempt_pkg
+                      LEFT JOIN cust_bill_pkg USING ( billpkgnum )
+                      LEFT JOIN cust_bill     USING ( invnum     )
+                    WHERE custnum = ?
+                      AND taxnum  = ?
+                      AND year    = ?
+                      AND month   = ?
+                ";
+                my $sth = dbh->prepare($sql) or do {
+                  $dbh->rollback if $oldAutoCommit;
+                  return "fatal: can't lookup exising exemption: ". dbh->errstr;
+                };
+                $sth->execute(
+                  $self->custnum,
+                  $tax->taxnum,
+                  1900+$year,
+                  $mon,
+                ) or do {
+                  $dbh->rollback if $oldAutoCommit;
+                  return "fatal: can't lookup exising exemption: ". dbh->errstr;
+                };
+                my $existing_exemption = $sth->fetchrow_arrayref->[0];
+                
+                my $remaining_exemption =
+                  $tax->exempt_amount - $existing_exemption;
                 if ( $remaining_exemption > 0 ) {
                   my $addl = $remaining_exemption > $taxable_per_month
                     ? $taxable_per_month
                     : $remaining_exemption;
                   $taxable_charged -= $addl;
-                  my $new_cust_tax_exempt = new FS::cust_tax_exempt ( {
-                    $cust_tax_exempt->hash,
-                    'amount' =>
-                      sprintf("%.2f", $cust_tax_exempt->amount + $addl),
+
+                  my $cust_tax_exempt_pkg = new FS::cust_tax_exempt_pkg ( {
+                    'billpkgnum' => $cust_bill_pkg->billpkgnum,
+                    'taxnum'     => $tax->taxnum,
+                    'year'       => 1900+$year,
+                    'month'      => $mon,
+                    'amount'     => sprintf("%.2f", $addl ),
                   } );
-                  $error = $new_cust_tax_exempt->exemptnum
-                    ? $new_cust_tax_exempt->replace($cust_tax_exempt)
-                    : $new_cust_tax_exempt->insert;
+                  $error = $cust_tax_exempt_pkg->insert;
                   if ( $error ) {
                     $dbh->rollback if $oldAutoCommit;
-                    return "fatal: can't update cust_tax_exempt: $error";
+                    return "fatal: can't insert cust_tax_exempt_pkg: $error";
                   }
-  
                 } # if $remaining_exemption > 0
+
+                #++
+                $mon++;
+                #until ( $mon < 12 ) { $mon -= 12; $year++; }
+                until ( $mon < 13 ) { $mon -= 12; $year++; }
   
               } #foreach $which_month
   
@@ -1866,86 +1935,41 @@ sub bill {
 
   } #foreach my $cust_pkg
 
-  my $charged = sprintf( "%.2f", $total_setup + $total_recur );
-#  my $taxable_charged = sprintf( "%.2f", $taxable_setup + $taxable_recur );
-
-  unless ( @cust_bill_pkg ) { #don't create invoices with no line items
+  unless ( $cust_bill->cust_bill_pkg ) {
+    $cust_bill->delete; #don't create an invoice w/o line items
     $dbh->commit or die $dbh->errstr if $oldAutoCommit;
     return '';
-  } 
-
-#  unless ( $self->tax =~ /Y/i
-#           || $self->payby eq 'COMP'
-#           || $taxable_charged == 0 ) {
-#    my $cust_main_county = qsearchs('cust_main_county',{
-#        'state'   => $self->state,
-#        'county'  => $self->county,
-#        'country' => $self->country,
-#    } ) or die "fatal: can't find tax rate for state/county/country ".
-#               $self->state. "/". $self->county. "/". $self->country. "\n";
-#    my $tax = sprintf( "%.2f",
-#      $taxable_charged * ( $cust_main_county->getfield('tax') / 100 )
-#    );
-
-  if ( dbdef->table('cust_bill_pkg')->column('itemdesc') ) { #1.5 schema
-
-    foreach my $taxname ( grep { $tax{$_} > 0 } keys %tax ) {
-      my $tax = sprintf("%.2f", $tax{$taxname} );
-      $charged = sprintf( "%.2f", $charged+$tax );
-  
-      my $cust_bill_pkg = new FS::cust_bill_pkg ({
-        'pkgnum'   => 0,
-        'setup'    => $tax,
-        'recur'    => 0,
-        'sdate'    => '',
-        'edate'    => '',
-        'itemdesc' => $taxname,
-      });
-      push @cust_bill_pkg, $cust_bill_pkg;
-    }
-  
-  } else { #1.4 schema
-
-    my $tax = 0;
-    foreach ( values %tax ) { $tax += $_ };
-    $tax = sprintf("%.2f", $tax);
-    if ( $tax > 0 ) {
-      $charged = sprintf( "%.2f", $charged+$tax );
-
-      my $cust_bill_pkg = new FS::cust_bill_pkg ({
-        'pkgnum' => 0,
-        'setup'  => $tax,
-        'recur'  => 0,
-        'sdate'  => '',
-        'edate'  => '',
-      });
-      push @cust_bill_pkg, $cust_bill_pkg;
-    }
-
   }
 
-  my $cust_bill = new FS::cust_bill ( {
-    'custnum' => $self->custnum,
-    '_date'   => $time,
-    'charged' => $charged,
-  } );
-  $error = $cust_bill->insert;
-  if ( $error ) {
-    $dbh->rollback if $oldAutoCommit;
-    return "can't create invoice for customer #". $self->custnum. ": $error";
-  }
+  my $charged = sprintf( "%.2f", $total_setup + $total_recur );
 
-  my $invnum = $cust_bill->invnum;
-  my $cust_bill_pkg;
-  foreach $cust_bill_pkg ( @cust_bill_pkg ) {
-    #warn $invnum;
-    $cust_bill_pkg->invnum($invnum);
+  foreach my $taxname ( grep { $tax{$_} > 0 } keys %tax ) {
+    my $tax = sprintf("%.2f", $tax{$taxname} );
+    $charged = sprintf( "%.2f", $charged+$tax );
+  
+    my $cust_bill_pkg = new FS::cust_bill_pkg ({
+      'invnum'   => $invnum,
+      'pkgnum'   => 0,
+      'setup'    => $tax,
+      'recur'    => 0,
+      'sdate'    => '',
+      'edate'    => '',
+      'itemdesc' => $taxname,
+    });
     $error = $cust_bill_pkg->insert;
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
-      return "can't create invoice line item for customer #". $self->custnum.
-             ": $error";
+      return "can't create invoice line item for invoice #$invnum: $error";
     }
+    $total_setup += $tax;
+
+  }
+
+  $cust_bill->charged( sprintf( "%.2f", $total_setup + $total_recur ) );
+  $error = $cust_bill->replace;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return "can't update charged for invoice #$invnum: $error";
   }
   
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
index da0de00..3e39887 100644 (file)
@@ -3,6 +3,8 @@ package FS::cust_tax_exempt;
 use strict;
 use vars qw( @ISA );
 use FS::Record qw( qsearch qsearchs );
+use FS::cust_main;
+use FS::cust_main_county;
 
 @ISA = qw(FS::Record);
 
@@ -27,7 +29,7 @@ FS::cust_tax_exempt - Object methods for cust_tax_exempt records
 
 =head1 DESCRIPTION
 
-An FS::cust_tax_exempt object represents a historical record of a customer tax
+An FS::cust_tax_exempt object represents a record of an old-style customer tax
 exemption.  Currently this is only used for "texas tax".  FS::cust_tax_exempt
 inherits from FS::Record.  The following fields are currently supported:
 
@@ -47,6 +49,12 @@ inherits from FS::Record.  The following fields are currently supported:
 
 =back
 
+=head1 NOTE
+
+Old-style customer tax exemptions are only useful for legacy migrations - if
+you are looking for current customer tax exemption data see
+L<FS::cust_tax_exempt_pkg>.
+
 =head1 METHODS
 
 =over 4
@@ -115,6 +123,17 @@ sub check {
   ;
 }
 
+=item cust_main_county
+
+Returns the FS::cust_main_county object associated with this tax exemption.
+
+=cut
+
+sub cust_main_county {
+  my $self = shift;
+  qsearchs( 'cust_main_county', { 'taxnum' => $self->taxnum } );
+}
+
 =back
 
 =head1 BUGS
diff --git a/FS/FS/cust_tax_exempt_pkg.pm b/FS/FS/cust_tax_exempt_pkg.pm
new file mode 100644 (file)
index 0000000..7193ace
--- /dev/null
@@ -0,0 +1,135 @@
+package FS::cust_tax_exempt_pkg;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+use FS::cust_bill_pkg;
+use FS::cust_main_county;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::cust_tax_exempt_pkg - Object methods for cust_tax_exempt_pkg records
+
+=head1 SYNOPSIS
+
+  use FS::cust_tax_exempt_pkg;
+
+  $record = new FS::cust_tax_exempt_pkg \%hash;
+  $record = new FS::cust_tax_exempt_pkg { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_tax_exempt_pkg object represents a record of a customer tax
+exemption.  Currently this is only used for "texas tax".  FS::cust_tax_exempt
+inherits from FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item exemptpkgnum - primary key
+
+=item billpkgnum - invoice line item (see L<FS::cust_bill_pkg>)
+
+=item taxnum - tax rate (see L<FS::cust_main_county>)
+
+=item year
+
+=item month
+
+=item amount
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new exemption record.  To add the example 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
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'cust_tax_exempt_pkg'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=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
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid example.  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;
+
+  $self->ut_numbern('exemptnum')
+#    || $self->ut_foreign_key('custnum', 'cust_main', 'custnum')
+    || $self->ut_foreign_key('billpkgnum', 'cust_bill_pkg', 'billpkgnum')
+    || $self->ut_foreign_key('taxnum', 'cust_main_county', 'taxnum')
+    || $self->ut_number('year') #check better
+    || $self->ut_number('month') #check better
+    || $self->ut_money('amount')
+    || $self->SUPER::check
+  ;
+}
+
+=back
+
+=head1 BUGS
+
+Texas tax is still a royal pain in the ass.
+
+=head1 SEE ALSO
+
+L<FS::cust_main_county>, L<FS::cust_bill_pkg>, L<FS::Record>, schema.html from
+the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/h_cust_bill.pm b/FS/FS/h_cust_bill.pm
new file mode 100644 (file)
index 0000000..7a3d811
--- /dev/null
@@ -0,0 +1,33 @@
+package FS::h_cust_bill;
+
+use strict;
+use vars qw( @ISA );
+use FS::h_Common;
+use FS::cust_bill;
+
+@ISA = qw( FS::h_Common FS::cust_bill );
+
+sub table { 'h_cust_bill' };
+
+=head1 NAME
+
+FS::h_cust_bill - Historical record of customer tax changes (old-style)
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+An FS::h_cust_bill object represents historical changes to invoices.
+FS::h_cust_bill inherits from FS::h_Common and FS::cust_bill.
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::cust_bill>,  L<FS::h_Common>, L<FS::Record>, schema.html from the base
+documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/h_cust_tax_exempt.pm b/FS/FS/h_cust_tax_exempt.pm
new file mode 100644 (file)
index 0000000..9d2318b
--- /dev/null
@@ -0,0 +1,40 @@
+package FS::h_cust_tax_exempt;
+
+use strict;
+use vars qw( @ISA );
+use FS::h_Common;
+use FS::cust_tax_exempt;
+
+@ISA = qw( FS::h_Common FS::cust_tax_exempt );
+
+sub table { 'h_cust_tax_exempt' };
+
+=head1 NAME
+
+FS::h_cust_tax_exempt - Historical record of customer tax changes (old-style)
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+An FS::h_cust_tax_exempt object represents historical changes to old-style
+customer tax exemptions.  FS::h_cust_tax_exempt inherits from FS::h_Common and
+FS::cust_tax_exempt.
+
+=head1 NOTE
+
+Old-style customer tax exemptions are only useful for legacy migrations - if
+you are looking for current customer tax exemption data see
+L<FS::cust_tax_exempt_pkg>.
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::cust_tax_exempt>, L<FS::cust_tax_exempt_pkg>, L<FS::h_Common>,
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
index e7d9dea..54ea525 100644 (file)
@@ -65,7 +65,9 @@ FS/cust_refund.pm
 FS/cust_credit_refund.pm
 FS/cust_svc.pm
 FS/h_Common.pm
+FS/h_cust_bill.pm
 FS/h_cust_svc.pm
+FS/h_cust_tax_exempt.pm
 FS/h_domain_record.pm
 FS/h_svc_acct.pm
 FS/h_svc_broadband.pm
@@ -152,6 +154,7 @@ FS/queue_arg.pm
 FS/queue_depend.pm
 FS/msgcat.pm
 FS/cust_tax_exempt.pm
+FS/cust_tax_exempt_pkg.pm
 FS/clientapi_session.pm
 FS/clientapi_session_field.pm
 t/agent.t
@@ -189,7 +192,9 @@ t/cust_pay_refund.t
 t/cust_pkg.t
 t/cust_refund.t
 t/cust_svc.t
+t/h_cust_bill.t
 t/h_cust_svc.t
+t/h_cust_tax_exempt.t
 t/h_Common.t
 t/h_cust_svc.t
 t/h_domain_record.t
@@ -200,6 +205,7 @@ t/h_svc_external.t
 t/h_svc_forward.t
 t/h_svc_www.t
 t/cust_tax_exempt.t
+t/cust_tax_exempt_pkg.t
 t/domain_record.t
 t/nas.t
 t/part_bill_event.t
diff --git a/FS/t/cust_tax_exempt_pkg.t b/FS/t/cust_tax_exempt_pkg.t
new file mode 100644 (file)
index 0000000..099a0ce
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_tax_exempt_pkg;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/h_cust_bill.t b/FS/t/h_cust_bill.t
new file mode 100644 (file)
index 0000000..ceccb2a
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::h_cust_bill;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/h_cust_tax_exempt.t b/FS/t/h_cust_tax_exempt.t
new file mode 100644 (file)
index 0000000..432238a
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::h_cust_tax_exempt;
+$loaded=1;
+print "ok 1\n";
diff --git a/README.2.0.0 b/README.2.0.0
new file mode 100644 (file)
index 0000000..3f5f115
--- /dev/null
@@ -0,0 +1,17 @@
+
+make install-perl-modules
+run "freeside-upgrade username" to uprade your database schema
+
+(if freeside-upgrade hangs, try stopping Apache, all Freeside processes, and
+ anything else connected to your database, especially on older Pg versions)
+
+If you have any records in the cust_tax_exempt table, you *MUST* migrate them
+to the new cust_tax_exempt_pkg table.  An example script to get you started is
+in bin/fs-migrate-cust_tax_exempt - it may need to be customized for your
+specific data.
+
+------
+
+make install-docs
+ (or "make deploy" if you've got everything setup in the Makefile)
+