start adding package locations, RT#4499
[freeside.git] / FS / FS / cust_main.pm
index c7bcf67..2b94dca 100644 (file)
@@ -9,7 +9,7 @@ use Safe;
 use Carp;
 use Exporter;
 use Scalar::Util qw( blessed );
-use Time::Local qw(timelocal_nocheck);
+use Time::Local qw(timelocal timelocal_nocheck);
 use Data::Dumper;
 use Tie::IxHash;
 use Digest::MD5 qw(md5_base64);
@@ -135,101 +135,181 @@ FS::Record.  The following fields are currently supported:
 
 =over 4
 
-=item custnum - primary key (assigned automatically for new customers)
+=item custnum
 
-=item agentnum - agent (see L<FS::agent>)
+Primary key (assigned automatically for new customers)
 
-=item refnum - Advertising source (see L<FS::part_referral>)
+=item agentnum
+
+Agent (see L<FS::agent>)
+
+=item refnum
+
+Advertising source (see L<FS::part_referral>)
+
+=item first
+
+First name
+
+=item last
 
-=item first - name
+Last name
 
-=item last - name
+=item ss
 
-=item ss - social security number (optional)
+Cocial security number (optional)
 
-=item company - (optional)
+=item company
+
+(optional)
 
 =item address1
 
-=item address2 - (optional)
+=item address2
+
+(optional)
 
 =item city
 
-=item county - (optional, see L<FS::cust_main_county>)
+=item county
+
+(optional, see L<FS::cust_main_county>)
 
-=item state - (see L<FS::cust_main_county>)
+=item state
+
+(see L<FS::cust_main_county>)
 
 =item zip
 
-=item country - (see L<FS::cust_main_county>)
+=item country
+
+(see L<FS::cust_main_county>)
+
+=item daytime
 
-=item daytime - phone (optional)
+phone (optional)
 
-=item night - phone (optional)
+=item night
 
-=item fax - phone (optional)
+phone (optional)
 
-=item ship_first - name
+=item fax
 
-=item ship_last - name
+phone (optional)
 
-=item ship_company - (optional)
+=item ship_first
+
+Shipping first name
+
+=item ship_last
+
+Shipping last name
+
+=item ship_company
+
+(optional)
 
 =item ship_address1
 
-=item ship_address2 - (optional)
+=item ship_address2
+
+(optional)
 
 =item ship_city
 
-=item ship_county - (optional, see L<FS::cust_main_county>)
+=item ship_county
+
+(optional, see L<FS::cust_main_county>)
 
-=item ship_state - (see L<FS::cust_main_county>)
+=item ship_state
+
+(see L<FS::cust_main_county>)
 
 =item ship_zip
 
-=item ship_country - (see L<FS::cust_main_county>)
+=item ship_country
+
+(see L<FS::cust_main_county>)
+
+=item ship_daytime
+
+phone (optional)
+
+=item ship_night
+
+phone (optional)
 
-=item ship_daytime - phone (optional)
+=item ship_fax
 
-=item ship_night - phone (optional)
+phone (optional)
 
-=item ship_fax - phone (optional)
+=item payby
+
+Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
 
-=item payby - Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
+=item payinfo
 
-=item payinfo - Payment Information (See L<FS::payinfo_Mixin> for data format)
+Payment Information (See L<FS::payinfo_Mixin> for data format)
 
-=item paymask - Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
+=item paymask
+
+Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
 
 =item paycvv
 
 Card Verification Value, "CVV2" (also known as CVC2 or CID), the 3 or 4 digit number on the back (or front, for American Express) of the credit card
 
-=item paydate - expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy
+=item paydate
+
+Expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy
+
+=item paystart_month
+
+Start date month (maestro/solo cards only)
+
+=item paystart_year
+
+Start date year (maestro/solo cards only)
+
+=item payissue
+
+Issue number (maestro/solo cards only)
+
+=item payname
+
+Name on card or billing name
+
+=item payip
 
-=item paystart_month - start date month (maestro/solo cards only)
+IP address from which payment information was received
 
-=item paystart_year - start date year (maestro/solo cards only)
+=item tax
 
-=item payissue - issue number (maestro/solo cards only)
+Tax exempt, empty or `Y'
 
-=item payname - name on card or billing name
+=item otaker
 
-=item payip - IP address from which payment information was received
+Order taker (assigned automatically, see L<FS::UID>)
 
-=item tax - tax exempt, empty or `Y'
+=item comments
 
-=item otaker - order taker (assigned automatically, see L<FS::UID>)
+Comments (optional)
 
-=item comments - comments (optional)
+=item referral_custnum
 
-=item referral_custnum - referring customer number
+Referring customer number
 
-=item spool_cdr - Enable individual CDR spooling, empty or `Y'
+=item spool_cdr
 
-=item dundate - a suggestion to events (see L<FS::part_bill_event">) to delay until this unix timestamp
+Enable individual CDR spooling, empty or `Y'
 
-=item squelch_cdr - Discourage individual CDR printing, empty or `Y'
+=item dundate
+
+A suggestion to events (see L<FS::part_bill_event">) to delay until this unix timestamp
+
+=item squelch_cdr
+
+Discourage individual CDR printing, empty or `Y'
 
 =back
 
@@ -2100,6 +2180,7 @@ sub bill {
     if $DEBUG;
 
   my $time = $options{'time'} || time;
+  my $invoice_time = $options{'invoice_time'} || $time;
 
   #put below somehow?
   local $SIG{HUP} = 'IGNORE';
@@ -2210,7 +2291,11 @@ sub bill {
   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} } );
+    my $listref_or_error =
+      $tax_object->taxline( $taxlisthash{$tax},
+                            'custnum'      => $self->custnum,
+                            'invoice_time' => $invoice_time
+                          );
     unless (ref($listref_or_error)) {
       $dbh->rollback if $oldAutoCommit;
       return $listref_or_error;
@@ -2220,15 +2305,26 @@ sub bill {
     warn "adding ". $listref_or_error->[1].
          " as ". $listref_or_error->[0]. "\n"
       if $DEBUG > 2;
-    $tax{ $tax_object->taxname } += $listref_or_error->[1];
+    $tax{ $tax } += $listref_or_error->[1];
     if ( $taxname{ $listref_or_error->[0] } ) {
-      push @{ $taxname{ $listref_or_error->[0] } }, $tax_object->taxname;
+      push @{ $taxname{ $listref_or_error->[0] } }, $tax;
     }else{
-      $taxname{ $listref_or_error->[0] } = [ $tax_object->taxname ];
+      $taxname{ $listref_or_error->[0] } = [ $tax ];
     }
   
   }
 
+  #move the cust_tax_exempt_pkg records to the cust_bill_pkgs we will commit
+  my %packagemap = map { $_->pkgnum => $_ } @cust_bill_pkg;
+  foreach my $tax ( keys %taxlisthash ) {
+    foreach ( @{ $taxlisthash{$tax} }[1 ... scalar(@{ $taxlisthash{$tax} })] ) {
+      next unless ref($_) eq 'FS::cust_bill_pkg'; # shouldn't happen
+
+      push @{ $packagemap{$_->pkgnum}->_cust_tax_exempt_pkg }, 
+        splice( @{ $_->_cust_tax_exempt_pkg } );
+    }
+  }
+
   #some taxes are taxed
   my %totlisthash;
   
@@ -2248,9 +2344,9 @@ sub bill {
                                                       # existing taxes
       warn "adding $totname to taxed taxes\n" if $DEBUG > 2;
       if ( exists( $totlisthash{ $totname } ) ) {
-        push @{ $totlisthash{ $totname  } }, $tax{ $tax_object->taxname };
+        push @{ $totlisthash{ $totname  } }, $tax{ $tax };
       }else{
-        $totlisthash{ $totname } = [ $tot, $tax{ $tax_object->taxname } ];
+        $totlisthash{ $totname } = [ $tot, $tax{ $tax } ];
       }
     }
   }
@@ -2260,7 +2356,11 @@ sub bill {
     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} } );
+    my $listref_or_error =
+      $tax_object->taxline( $totlisthash{$tax},
+                            'custnum'      => $self->custnum,
+                            'invoice_time' => $invoice_time
+                          );
     unless (ref($listref_or_error)) {
       $dbh->rollback if $oldAutoCommit;
       return $listref_or_error;
@@ -2269,7 +2369,7 @@ sub bill {
     warn "adding taxed tax amount ". $listref_or_error->[1].
          " as ". $tax_object->taxname. "\n"
       if $DEBUG;
-    $tax{ $tax_object->taxname } += $listref_or_error->[1];
+    $tax{ $tax } += $listref_or_error->[1];
   }
   
   #consolidate and create tax line items
@@ -2304,7 +2404,7 @@ sub bill {
   #create the new invoice
   my $cust_bill = new FS::cust_bill ( {
     'custnum' => $self->custnum,
-    '_date'   => ( $options{'invoice_time'} || $time ),
+    '_date'   => ( $invoice_time ),
     'charged' => $charged,
   } );
   my $error = $cust_bill->insert;
@@ -2885,6 +2985,11 @@ Only return events for the specified eventtable (by default, events of all event
 
 Explicitly pass the objects to be tested (typically used with eventtable).
 
+=item testonly
+
+Set to true to return the objects, but not actually insert them into the
+database.
+
 =back
 
 =cut
@@ -2915,7 +3020,8 @@ sub due_cust_event {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  $self->select_for_update; #mutex
+  $self->select_for_update #mutex
+    unless $opt{testonly};
 
   ###
   # 1: find possible events (initial search)
@@ -6657,7 +6763,7 @@ sub generate_letter {
 
   $letter_data{company_name} = $conf->config('company_name');
 
-  my $dir = $FS::UID::conf_dir."cache.". $FS::UID::datasrc;
+  my $dir = $FS::UID::conf_dir."/cache.". $FS::UID::datasrc;
   my $fh = new File::Temp( TEMPLATE => 'letter.'. $self->custnum. '.XXXXXXXX',
                            DIR      => $dir,
                            SUFFIX   => '.tex',