agent-virt batches and batchconfig-eftcanada config (argh!), RT#14859
[freeside.git] / FS / FS / pay_batch.pm
index 7db123c..bde8fdb 100644 (file)
@@ -5,8 +5,9 @@ use vars qw( @ISA $DEBUG %import_info %export_info $conf );
 use Time::Local;
 use Text::CSV_XS;
 use FS::Record qw( dbh qsearch qsearchs );
-use FS::cust_pay;
 use FS::Conf;
+use FS::cust_pay;
+use FS::agent;
 use Date::Parse qw(str2time);
 use Business::CreditCard qw(cardtype);
 
@@ -40,6 +41,8 @@ from FS::Record.  The following fields are currently supported:
 
 =item batchnum - primary key
 
+=item agentnum - optional agent number for agent batches
+
 =item payby - CARD or CHEK
 
 =item status - O (Open), I (In-transit), or R (Resolved)
@@ -112,6 +115,7 @@ sub check {
     $self->ut_numbern('batchnum')
     || $self->ut_enum('payby', [ 'CARD', 'CHEK' ])
     || $self->ut_enum('status', [ 'O', 'I', 'R' ])
+    || $self->ut_foreign_keyn('agentnum', 'agent', 'agentnum')
   ;
   return $error if $error;
 
@@ -231,17 +235,12 @@ sub import_results {
 
   my $reself = $self->select_for_update;
 
-  unless ( $reself->status eq 'I' ) {
+  if ( $reself->status ne 'I' 
+      and !$conf->exists('batch-manual_approval') ) {
     $dbh->rollback if $oldAutoCommit;
     return "batchnum ". $self->batchnum. "no longer in transit";
   }
 
-  my $error = $self->set_status('R');
-  if ( $error ) {
-    $dbh->rollback if $oldAutoCommit;
-    return $error;
-  }
-
   my $total = 0;
   my $line;
 
@@ -352,13 +351,16 @@ sub import_results {
     my $custnum = $cust_pay_batch->custnum,
     my $payby = $cust_pay_batch->payby,
 
-    my $new_cust_pay_batch = new FS::cust_pay_batch { $cust_pay_batch->hash };
-
     &{$hook}(\%hash, $cust_pay_batch->hashref);
 
+    my $new_cust_pay_batch = new FS::cust_pay_batch { $cust_pay_batch->hash };
+
     my $error = '';
     if ( &{$approved_condition}(\%hash) ) {
 
+      foreach ('paid', '_date', 'payinfo') {
+        $new_cust_pay_batch->$_($hash{$_}) if $hash{$_};
+      }
       $error = $new_cust_pay_batch->approve($hash{'paybatch'} || $self->batchnum);
       $total += $hash{'paid'};
 
@@ -385,15 +387,22 @@ sub import_results {
 
   } # foreach (@all_values)
 
+  my $close = 1;
   if ( defined($close_condition) ) {
     # Allow the module to decide whether to close the batch.
     # $close_condition can also die() to abort the whole import.
-    my $close = eval { $close_condition->($self) };
+    $close = eval { $close_condition->($self) };
     if ( $@ ) {
       $dbh->rollback;
       die $@;
     }
-    $self->set_status('I') if !$close;
+  }
+  if ( $close ) {
+    my $error = $self->set_status('R');
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
   }
 
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
@@ -472,18 +481,11 @@ sub export_batch {
     }
   }
 
-  my $delim = exists($info->{'delimiter'}) ? $info->{'delimiter'} : "\n";
+  if ($first_download) { #remove or reduce entries if customer's balance changed
 
-  my $h = $info->{'header'};
-  if(ref($h) eq 'CODE') {
-    $batch .= &$h($self, \@cust_pay_batch) . $delim;
-  }
-  else {
-    $batch .= $h . $delim;
-  }
-  foreach my $cust_pay_batch (@cust_pay_batch) {
+    my @new = ();
+    foreach my $cust_pay_batch (@cust_pay_batch) {
 
-    if ($first_download) {
       my $balance = $cust_pay_batch->cust_main->balance;
       if ($balance <= 0) { # then don't charge this customer
         my $error = $cust_pay_batch->delete;
@@ -502,20 +504,35 @@ sub export_batch {
         }
       }
       # else $balance >= $cust_pay_batch->amount
+
+      push @new, $cust_pay_batch;
     }
+    @cust_pay_batch = @new;
+
+  }
+
+  my $delim = exists($info->{'delimiter'}) ? $info->{'delimiter'} : "\n";
+
+  my $h = $info->{'header'};
+  if (ref($h) eq 'CODE') {
+    $batch .= &$h($self, \@cust_pay_batch). $delim;
+  } else {
+    $batch .= $h. $delim;
+  }
 
+  foreach my $cust_pay_batch (@cust_pay_batch) {
     $batchcount++;
     $batchtotal += $cust_pay_batch->amount;
-    $batch .= &{$info->{'row'}}($cust_pay_batch, $self, $batchcount, $batchtotal) . $delim;
-
+    $batch .=
+      &{$info->{'row'}}($cust_pay_batch, $self, $batchcount, $batchtotal).
+      $delim;
   }
 
   my $f = $info->{'footer'};
-  if(ref($f) eq 'CODE') {
-    $batch .= &$f($self, $batchcount, $batchtotal) . $delim;
-  }
-  else {
-    $batch .= $f . $delim;
+  if (ref($f) eq 'CODE') {
+    $batch .= &$f($self, $batchcount, $batchtotal). $delim;
+  } else {
+    $batch .= $f. $delim;
   }
 
   if ($info->{'autopost'}) {
@@ -535,6 +552,7 @@ sub manual_approve {
   my $date = time;
   my %opt = @_;
   my $paybatch = $opt{'paybatch'} || $self->batchnum;
+  my $usernum = $opt{'usernum'} || die "manual approval requires a usernum";
   my $conf = FS::Conf->new;
   return 'manual batch approval disabled' 
     if ( ! $conf->exists('batch-manual_approval') );
@@ -559,8 +577,9 @@ sub manual_approve {
   ) {
     my $new_cust_pay_batch = new FS::cust_pay_batch { 
       $cust_pay_batch->hash,
-      'paid'  => $cust_pay_batch->amount,
-      '_date' => $date,
+      'paid'    => $cust_pay_batch->amount,
+      '_date'   => $date,
+      'usernum' => $usernum,
     };
     my $error = $new_cust_pay_batch->approve($paybatch);
     if ( $error ) {
@@ -569,9 +588,7 @@ sub manual_approve {
     }
     $payments++;
   }
-  return 'no unresolved payments in batch' if $payments == 0;
   $self->set_status('R');
-  
   $dbh->commit;
   return;
 }