RT# 82988 - Fixed so only formats that can handle electronic refunds can download...
[freeside.git] / FS / FS / cust_main / Billing_Batch.pm
index 7612df3..c1bb35f 100644 (file)
@@ -55,7 +55,8 @@ sub batch_card {
     return;
   }
   
-  my $invnum = delete $options{invnum};
+  #my $invnum = delete $options{invnum};
+  my $invnum = $options{invnum};
 
   #pay fields should all come from either cust_payby or options, not both
   #  in theory, could just pass payby, and use it to select cust_payby,
@@ -82,6 +83,10 @@ sub batch_card {
                               );
   }
 
+  my $paycode= $options{paycode} || '';
+  my $batch_type = "DEBIT";
+  $batch_type = "CREDIT" if $paycode eq 'C';
+
   my $oldAutoCommit = $FS::UID::AutoCommit;
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
@@ -89,11 +94,12 @@ sub batch_card {
   #this needs to handle mysql as well as Pg, like svc_acct.pm
   #(make it into a common function if folks need to do batching with mysql)
   $dbh->do("LOCK TABLE pay_batch IN SHARE ROW EXCLUSIVE MODE")
-    or return "Cannot lock pay_batch: " . $dbh->errstr;
+    or die "Cannot lock pay_batch: " . $dbh->errstr;
 
   my %pay_batch = (
     'status' => 'O',
     'payby'  => FS::payby->payby2payment($payby),
+    'type'   => $batch_type,
   );
   $pay_batch{agentnum} = $self->agentnum if $conf->exists('batch-spoolagent');
 
@@ -114,7 +120,7 @@ sub batch_card {
   } );
 
   foreach (qw( address1 address2 city state zip country latitude longitude
-               payby payinfo paydate payname ))
+               payby payinfo paydate payname paycode paytype ))
   {
     $options{$_} = '' unless exists($options{$_});
   }
@@ -138,9 +144,16 @@ sub batch_card {
     'country'  => $options{country}  || $loc->country,
     'payby'    => $options{payby}    || $cust_payby->payby,
     'payinfo'  => $options{payinfo}  || $cust_payby->payinfo,
+    'paymask'  => ( $options{payinfo}
+                      ? FS::payinfo_Mixin->mask_payinfo( $options{payby},
+                                                         $options{payinfo} )
+                      : $cust_payby->paymask
+                  ),
     'exp'      => $options{paydate}  || $cust_payby->paydate,
     'payname'  => $options{payname}  || $cust_payby->payname,
+    'paytype'  => $options{paytype}  || $cust_payby->paytype,
     'amount'   => $amount,                         # consolidating
+    'paycode'  => $options{paycode}  || '',
   } );
   
   $cust_pay_batch->paybatchnum($old_cust_pay_batch->paybatchnum)
@@ -155,7 +168,64 @@ sub batch_card {
 
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
-    die $error;
+    #die $error;
+    return $error; # e.g. "Illegal zip" ala RT#75998
+  }
+
+  if ($options{'processing-fee'} > 0) {
+    my $pf_cust_pkg;
+    my $processing_fee_text = 'Payment Processing Fee';
+
+    unless ( $invnum ) { # probably from a payment screen
+      # do we have any open invoices? pick earliest
+      # uses the fact that cust_main->cust_bill sorts by date ascending
+      my @open = $self->open_cust_bill;
+      $invnum = $open[0]->invnum if scalar(@open);
+    }
+
+    unless ( $invnum ) {  # still nothing? pick last closed invoice
+      # again uses fact that cust_main->cust_bill sorts by date ascending
+      my @closed = $self->cust_bill;
+      $invnum = $closed[$#closed]->invnum if scalar(@closed);
+    }
+
+    unless ( $invnum ) {
+      # XXX: unlikely case - pre-paying before any invoices generated
+      # what it should do is create a new invoice and pick it
+      warn '\PROCESS FEE AND NO INVOICES PICKED TO APPLY IT!';
+      return '';
+    }
+
+    my $pf_change_error = $self->charge({
+            'amount'  => $options{'processing-fee'},
+            'pkg'   => $processing_fee_text,
+            'setuptax'  => 'Y',
+            'cust_pkg_ref' => \$pf_cust_pkg,
+    });
+
+    if($pf_change_error) {
+      warn 'Unable to add payment processing fee';
+      return '';
+    }
+
+    $pf_cust_pkg->setup(time);
+    my $pf_error = $pf_cust_pkg->replace;
+    if($pf_error) {
+      warn 'Unable to set setup time on cust_pkg for processing fee';
+      # but keep going...
+    }
+
+    my $cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum });
+    unless ( $cust_bill ) {
+      warn "race condition + invoice deletion just happened";
+      return '';
+    }
+
+    my $grand_pf_error =
+      $cust_bill->add_cc_surcharge($pf_cust_pkg->pkgnum,$options{'processing-fee'});
+
+    warn "cannot add Processing fee to invoice #$invnum: $grand_pf_error"
+      if $grand_pf_error;
   }
 
   my $unapplied =   $self->total_unapplied_credits