update batch payment for multiple payment methods, etc., #17878 and #23741
authorMark Wells <mark@freeside.biz>
Mon, 25 Jan 2016 23:03:02 +0000 (15:03 -0800)
committerMark Wells <mark@freeside.biz>
Mon, 25 Jan 2016 23:03:02 +0000 (15:03 -0800)
FS/FS/Schema.pm
FS/FS/cust_main.pm
FS/FS/cust_main/Billing_Batch.pm
FS/FS/cust_main/Billing_Realtime.pm
FS/FS/cust_pay_batch.pm
FS/FS/pay_batch/nacha.pm
FS/FS/pay_batch/paymentech.pm
httemplate/misc/process/payment.cgi

index 1e975dc..3849443 100644 (file)
@@ -2683,6 +2683,7 @@ sub tables_hashref {
         #'exp',          @date_type,                  '', '',
         'exp',           'varchar', 'NULL',      11, '', '', 
         'payname',       'varchar', 'NULL', $char_d, '', '', 
+        'paytype',       'varchar', 'NULL', $char_d, '', '', 
         'amount',      @money_type,                  '', '', 
         'currency',         'char', 'NULL',       3, '', '',
         'status',        'varchar', 'NULL', $char_d, '', '', 
index ee70dea..a202e3d 100644 (file)
@@ -5482,6 +5482,20 @@ sub _upgrade_data { #class method
 
       }
 
+      # at the time we do this, also migrate paytype into cust_pay_batch
+      # so that batches that are open before the migration can still be 
+      # processed
+      my @cust_pay_batch = qsearch('cust_pay_batch', {
+          'custnum' => $cust_main->custnum,
+          'payby'   => 'CHEK',
+          'paytype' => '',
+      });
+      foreach my $cust_pay_batch (@cust_pay_batch) {
+        $cust_pay_batch->set('paytype', $cust_main->get('paytype'));
+        my $error = $cust_pay_batch->replace;
+        die "$error (setting cust_pay_batch.paytype)" if $error;
+      }
+
       $cust_main->complimentary('Y') if $cust_main->payby eq 'COMP';
 
       $cust_main->invoice_attn( $cust_main->payname )
index 7612df3..d8e6f8a 100644 (file)
@@ -140,6 +140,7 @@ sub batch_card {
     'payinfo'  => $options{payinfo}  || $cust_payby->payinfo,
     'exp'      => $options{paydate}  || $cust_payby->paydate,
     'payname'  => $options{payname}  || $cust_payby->payname,
+    'paytype'  => $options{paytype}  || $cust_payby->paytype,
     'amount'   => $amount,                         # consolidating
   } );
   
index 20d0145..3396ec4 100644 (file)
@@ -185,6 +185,15 @@ A third-party transaction will return a hashref containing:
 =cut
 
 # some helper routines
+#
+# _bop_recurring_billing: Checks whether this payment should have the 
+# recurring_billing flag used by some B:OP interfaces (IPPay, PlugnPay,
+# vSecure, etc.). This works in two different modes:
+# - actual_oncard (default): treat the payment as recurring if the customer
+#   has made a payment using this card before.
+# - transaction_is_recur: treat the payment as recurring if the invoice
+#   being paid has any recurring package charges.
+
 sub _bop_recurring_billing {
   my( $self, %opt ) = @_;
 
index 8dd6446..8127c6a 100644 (file)
@@ -63,6 +63,8 @@ following fields are currently supported:
 
 =item payname - name on card 
 
+=item paytype - account type ((personal|business) (checking|savings))
+
 =item first - name 
 
 =item last - name 
@@ -156,6 +158,18 @@ sub check {
   $error = $self->payinfo_check();
   return $error if $error;
 
+  if ( $self->payby eq 'CHEK' ) {
+    # because '' is on the list of paytypes:
+    my $paytype = $self->paytype or return "Bank account type required";
+    if (grep { $_ eq $paytype} FS::cust_payby->paytypes) {
+      #ok
+    } else {
+      return "Bank account type '$paytype' is not allowed"
+    }
+  } else {
+    $self->set('paytype', '');
+  }
+
   if ( $self->exp eq '' ) {
     return "Expiration date required"
       unless $self->payby =~ /^(CHEK|DCHK|WEST)$/;
@@ -408,12 +422,23 @@ sub request_item {
     $self->payinfo =~ /(\d+)@(\d+)/; # or else what?
     $payment{account_number} = $1;
     $payment{routing_code} = $2;
-    $payment{account_type} = $cust_main->paytype;
+    $payment{account_type} = $self->paytype;
     # XXX what if this isn't their regular payment method?
   } else {
     die "unsupported BatchPayment method: ".$pay_batch->payby;
   }
 
+  my $recurring;
+  if ( $cust_main->status =~ /^active|suspended|ordered$/ ) {
+    if ( $self->payinfo_used ) {
+      $recurring = 'S'; # subsequent
+    } else {
+      $recurring = 'F'; # first use
+    }
+  } else {
+    $recurring = 'N'; # non-recurring
+  }
+
   Business::BatchPayment->create(Item =>
     # required
     action      => 'payment',
@@ -429,6 +454,7 @@ sub request_item {
     ( map { $_ => $location->$_ } qw(address2 city state country zip) ),
     
     invoice_number  => $self->invnum,
+    recurring_billing => $recurring,
     %payment,
   );
 }
index befba09..23dda4c 100644 (file)
@@ -136,8 +136,9 @@ $DEBUG = 0;
 
     #XXX paytype should actually be in the batch, but this will do for now
     #27 checking debit, 37 savings debit
-    my $transaction_code = ( $cust_main->paytype =~ /savings/i ? '37' : '27' );
+    my $transaction_code = ( $cust_pay_batch->paytype =~ /savings/i ? '37' : '27' );
 
+    # not $self->payname?
     my $cust_name = substr($cust_main->name. (' 'x22), 0, 22);
     $i++;
     my $tracenum = $dest. substr(('0'x7). $i, -6);
index 91abbf2..1282507 100644 (file)
@@ -128,7 +128,7 @@ my %paymentech_countries = map { $_ => 1 } qw( US CA GB UK );
         ) : (
           ecpCheckRT      => ($_->payinfo =~ /@(\d+)/),
           ecpCheckDDA     => ($_->payinfo =~ /(\d+)@/),
-          ecpBankAcctType => $paytype{lc($_->cust_main->paytype)},
+          ecpBankAcctType => $paytype{lc($_->paytype)},
           ecpDelvMethod   => 'A',
         ),
         avsZip          => bytes_substr($_->zip,      0, 10),
index 5cd5d31..0b0dffd 100644 (file)
@@ -190,6 +190,7 @@ if ( $cgi->param('save') ) {
     'payinfo'       => $payinfo,
     'paymask'       => $paymask,
     'payname'       => $payname,
+    'paytype        => $paytype,
     %saveopt
   );