first part of ACL and re-skinning work and some other small stuff
[freeside.git] / FS / FS / cust_bill.pm
index 4424797..bcae4d6 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
@@ -236,6 +248,25 @@ sub cust_main {
   qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
 }
 
+=item cust_suspend_if_balance_over AMOUNT
+
+Suspends the customer associated with this invoice if the total amount owed on
+this invoice and all older invoices is greater than the specified amount.
+
+Returns a list: an empty list on success or a list of errors.
+
+=cut
+
+sub cust_suspend_if_balance_over {
+  my( $self, $amount ) = ( shift, shift );
+  my $cust_main = $self->cust_main;
+  if ( $cust_main->total_owed_date($self->_date) < $amount ) {
+    return ();
+  } else {
+    $cust_main->suspend;
+  }
+}
+
 =item cust_credit
 
 Depreciated.  See the cust_credited method.
@@ -739,16 +770,9 @@ server
 username
 password
 dir
-format - 'default' or 'billco'
-
-#???
-If I<format> is not specified or "default", the file will be named
-"N-YYYYMMDDHHMMSS.csv" where N is the invoice number and YYMMDDHHMMSS is a
-timestamp.
 
-#???
-If I<format> is "billco", two files will be created and uploaded.  They will be named "N-YYYYMMDDHHMMSS-header.csv" and "N-YYYYMMDDHHMMSS-detail.csv" where N
-is the invoice number and YYMMDDHHMMSS is a timestamp(???).
+The file will be named "N-YYYYMMDDHHMMSS.csv" where N is the invoice number
+and YYMMDDHHMMSS is a timestamp.
 
 See L</print_csv> for a description of the output format.
 
@@ -763,27 +787,13 @@ sub send_csv {
   mkdir $spooldir, 0700 unless -d $spooldir;
 
   my $tracctnum = $self->invnum. time2str('-%Y%m%d%H%M%S', time);
-  my $file = "$spooldir/$tracctnum";
-  if ( lc($opt{'format'}) eq 'billco' ) {
-    $file .= '-header.csv';
-  } else {
-    #$file = $spooldir. '/'. $self->invnum. time2str('-%Y%m%d%H%M%S.csv', time);
-    $file .= '.csv';
-  }
+  my $file = "$spooldir/$tracctnum.csv";
   
   my ( $header, $detail ) = $self->print_csv(%opt, 'tracctnum' => $tracctnum );
 
   open(CSV, ">$file") or die "can't open $file: $!";
   print CSV $header;
 
-  my $oldfile = '';
-  if ( lc($opt{'format'}) eq 'billco' ) {
-    close CSV;
-    $oldfile = $file;
-    $file = "$spooldir/$tracctnum-detail.csv";
-    open(CSV,">$file") or die "can't open $file: $!";
-  }
-
   print CSV $detail;
 
   close CSV;
@@ -804,14 +814,10 @@ sub send_csv {
 
   $net->cwd($opt{dir}) or die "can't cwd to $opt{dir}";
 
-  if ( $oldfile) {
-    $net->put($oldfile) or die "can't put $oldfile: $!";
-  }
   $net->put($file) or die "can't put $file: $!";
 
   $net->quit;
 
-  unlink $oldfile if $oldfile;
   unlink $file;
 
 }
@@ -828,6 +834,10 @@ Options are:
 
 =item dest - if set (to POST, EMAIL or FAX), only sends spools invoices if the customer has the corresponding invoice destinations set (see L<FS::cust_main_invoice>).
 
+=item agent_spools - if set to a true value, will spool to per-agent files rather than a single global file
+
+=item balanceover - if set, only spools the invoice if the total amount owed on this invoice and all older invoices is greater than the specified amount.
+
 =back
 
 =cut
@@ -835,25 +845,30 @@ Options are:
 sub spool_csv {
   my($self, %opt) = @_;
 
+  my $cust_main = $self->cust_main;
+
   if ( $opt{'dest'} ) {
     my %invoicing_list = map { /^(POST|FAX)$/ or 'EMAIL' =~ /^(.*)$/; $1 => 1 }
-                             $self->cust_main->invoicing_list;
-    return unless $invoicing_list{$opt{'dest'}};
+                             $cust_main->invoicing_list;
+    return 'N/A' unless $invoicing_list{$opt{'dest'}}
+                     || ! keys %invoicing_list;
   }
 
-  #create file(s)
+  if ( $opt{'balanceover'} ) {
+    return 'N/A'
+      if $cust_main->total_owed_date($self->_date) < $opt{'balanceover'};
+  }
 
   my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/cust_bill";
   mkdir $spooldir, 0700 unless -d $spooldir;
 
   my $tracctnum = $self->invnum. time2str('-%Y%m%d%H%M%S', time);
-  my $file = "$spooldir/spool";
-  if ( lc($opt{'format'}) eq 'billco' ) {
-    $file .= '-header.csv';
-  } else {
-    #$file = $spooldir. '/'. $self->invnum. time2str('-%Y%m%d%H%M%S.csv', time);
-    $file .= '.csv';
-  }
+
+  my $file =
+    "$spooldir/".
+    ( $opt{'agent_spools'} ? 'agentnum'.$cust_main->agentnum : 'spool' ).
+    ( lc($opt{'format'}) eq 'billco' ? '-header' : '' ) .
+    '.csv';
   
   my ( $header, $detail ) = $self->print_csv(%opt, 'tracctnum' => $tracctnum );
 
@@ -863,14 +878,15 @@ sub spool_csv {
 
   print CSV $header;
 
-  my $oldfile = '';
   if ( lc($opt{'format'}) eq 'billco' ) {
 
     flock(CSV, LOCK_UN);
     close CSV;
 
-    $oldfile = $file;
-    $file = "$spooldir/spool-detail.csv";
+    $file =
+      "$spooldir/".
+      ( $opt{'agent_spools'} ? 'agentnum'.$cust_main->agentnum : 'spool' ).
+      '-detail.csv';
 
     open(CSV,">>$file") or die "can't open $file: $!";
     flock(CSV, LOCK_EX);
@@ -882,6 +898,8 @@ sub spool_csv {
   flock(CSV, LOCK_UN);
   close CSV;
 
+  return '';
+
 }
 
 =item print_csv OPTION => VALUE, ...
@@ -2409,6 +2427,7 @@ sub _items_payments {
 
 }
 
+
 =back
 
 =head1 SUBROUTINES
@@ -2444,6 +2463,7 @@ use Data::Dumper;
 use MIME::Base64;
 sub process_re_X {
   my( $method, $job ) = ( shift, shift );
+  warn "process_re_X $method for job $job\n" if $DEBUG;
 
   my $param = thaw(decode_base64(shift));
   warn Dumper($param) if $DEBUG;
@@ -2459,6 +2479,10 @@ sub process_re_X {
 sub re_X {
   my($method, $job, %param ) = @_;
 #              [ 'begin', 'end', 'agentnum', 'open', 'days', 'newest_percust' ],
+  if ( $DEBUG ) {
+    warn "re_X $method for job $job with param:\n".
+         join( '', map { "  $_ => ". $param{$_}. "\n" } keys %param );
+  }
 
   #some false laziness w/search/cust_bill.html
   my $distinct = '';