[freeside-commits] branch master updated. 386c1c45a7cb9e8ad93862d9aa2d59cdb4ed0d3a

Christopher Burger burgerc at 420.am
Thu May 18 08:59:56 PDT 2017


The branch, master has been updated
       via  386c1c45a7cb9e8ad93862d9aa2d59cdb4ed0d3a (commit)
      from  a8d055471f77f59883f921d9eeda056a2e7ad279 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 386c1c45a7cb9e8ad93862d9aa2d59cdb4ed0d3a
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Thu May 18 11:58:26 2017 -0400

    RT# 74435 - Adding option to allow refunds using electronic check batch with RBC format.

diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index f3e7c4e..086fcff 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -2705,6 +2705,7 @@ sub tables_hashref {
         'status',        'varchar', 'NULL', $char_d, '', '', 
         'failure_status','varchar', 'NULL',      16, '', '',
         'error_message', 'varchar', 'NULL', $char_d, '', '',
+        'paycode',       'varchar', 'NULL', $char_d, '', '',
       ],
       'primary_key'  => 'paybatchnum',
       'unique'       => [],
diff --git a/FS/FS/cust_main/Billing_Batch.pm b/FS/FS/cust_main/Billing_Batch.pm
index d8e6f8a..d8ae3b4 100644
--- a/FS/FS/cust_main/Billing_Batch.pm
+++ b/FS/FS/cust_main/Billing_Batch.pm
@@ -114,7 +114,7 @@ sub batch_card {
   } );
 
   foreach (qw( address1 address2 city state zip country latitude longitude
-               payby payinfo paydate payname ))
+               payby payinfo paydate payname paycode ))
   {
     $options{$_} = '' unless exists($options{$_});
   }
@@ -142,6 +142,7 @@ sub batch_card {
     'payname'  => $options{payname}  || $cust_payby->payname,
     'paytype'  => $options{paytype}  || $cust_payby->paytype,
     'amount'   => $amount,                         # consolidating
+    'paycode'  => $options{paycode}  || $cust_payby->paycode,
   } );
   
   $cust_pay_batch->paybatchnum($old_cust_pay_batch->paybatchnum)
diff --git a/FS/FS/pay_batch/RBC.pm b/FS/FS/pay_batch/RBC.pm
index b013678..21dae42 100644
--- a/FS/FS/pay_batch/RBC.pm
+++ b/FS/FS/pay_batch/RBC.pm
@@ -175,8 +175,13 @@ $name = 'RBC';
     }
 
     $i++;
+
+    ## set to D for debit by default, then override to what cust_pay_batch has as payments may not have paycode.
+    my $debitorcredit = 'D';
+    $debitorcredit = $cust_pay_batch->paycode unless !$cust_pay_batch->paycode;
+
     sprintf("%06u", $i).
-    'D'.
+    $debitorcredit.
     sprintf("%3s",$trans_code).
     sprintf("%10s",$client_num).
     ' '.
diff --git a/httemplate/edit/cust_refund.cgi b/httemplate/edit/cust_refund.cgi
index 32da454..e1975ed 100755
--- a/httemplate/edit/cust_refund.cgi
+++ b/httemplate/edit/cust_refund.cgi
@@ -102,7 +102,28 @@
       <TD ALIGN="right">Check #</TD>
       <TD COLSPAN=2><INPUT TYPE="text" NAME="payinfo" VALUE="<% $payinfo %>" SIZE=10></TD>
     </TR>
+% }
+%  elsif ($payby eq 'CHEK') {
+%
+% my @cust_payby = ();
+% if ( $payby eq 'CARD' ) {
+%   @cust_payby = $cust_main->cust_payby('CARD','DCRD');
+% } elsif ( $payby eq 'CHEK' ) {
+%   @cust_payby = $cust_main->cust_payby('CHEK','DCHK');
 % } else {
+%   die "unknown payby $payby";
+% }
+%
+% my $custpaybynum = length(scalar($cgi->param('custpaybynum')))
+%                      ? scalar($cgi->param('custpaybynum'))
+%                      : scalar(@cust_payby) && $cust_payby[0]->custpaybynum;
+<& /elements/tr-select-cust_payby.html,
+     'cust_payby' => \@cust_payby,
+     'curr_value' => $custpaybynum,
+     'onchange'   => 'cust_payby_changed(this)',
+&>
+    <INPUT TYPE="hidden" NAME="batch" VALUE="1">
+%  } else {
     <INPUT TYPE="hidden" NAME="payinfo" VALUE="">
 % }
 
@@ -157,6 +178,9 @@ if ( $cgi->param('paynum') =~ /^(\d+)$/ ) {
 }
 die "no custnum or paynum specified!" unless $custnum;
 
+my $cust_main = qsearchs( 'cust_main', { 'custnum'=>$custnum } );
+die "unknown custnum $custnum" unless $cust_main;
+
 my $_date = time;
 
 my $p1 = popurl(1);
diff --git a/httemplate/edit/process/cust_refund.cgi b/httemplate/edit/process/cust_refund.cgi
index 5a4b327..0a3d550 100755
--- a/httemplate/edit/process/cust_refund.cgi
+++ b/httemplate/edit/process/cust_refund.cgi
@@ -21,6 +21,8 @@ die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Refund payment')
       || $FS::CurrentUser::CurrentUser->access_right('Post refund');
 
+my $conf = new FS::Conf;
+
 $cgi->param('custnum') =~ /^(\d*)$/ or die "Illegal custnum!";
 my $custnum = $1;
 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
@@ -42,6 +44,149 @@ if ( $error ) {
 } elsif ( $payby =~ /^(CARD|CHEK)$/ ) { 
   my %options = ();
   my $bop = $FS::payby::payby2bop{$1};
+
+  my %payby2fields = (
+  'CARD' => [ qw( address1 address2 city county state zip country ) ],
+  'CHEK' => [ qw( ss paytype paystate stateid stateid_state ) ],
+  );
+  my %type = ( 'CARD' => 'credit card',
+             'CHEK' => 'electronic check (ACH)',
+             );
+
+my( $cust_payby, $payinfo, $paycvv, $month, $year, $payname );
+my $paymask = '';
+if ( (my $custpaybynum = scalar($cgi->param('custpaybynum'))) > 0 ) {
+
+  ##
+  # use stored cust_payby info
+  ##
+
+  $cust_payby = qsearchs('cust_payby', { custnum      => $custnum,
+                                            custpaybynum => $custpaybynum, } )
+    or die "unknown custpaybynum $custpaybynum";
+
+  # not needed for realtime_bop, but still needed for batch_card
+  $payinfo = $cust_payby->payinfo;
+  $paymask = $cust_payby->paymask;
+  $paycvv = $cust_payby->paycvv; # pass it if we got it, running a transaction will clear it
+  ( $month, $year ) = $cust_payby->paydate_mon_year;
+  $payname = $cust_payby->payname;
+
+} else {
+
+  ##
+  # use new info
+  ##
+
+  $cgi->param('year') =~ /^(\d+)$/
+    or errorpage("illegal year ". $cgi->param('year'));
+  $year = $1;
+
+  $cgi->param('month') =~ /^(\d+)$/
+    or errorpage("illegal month ". $cgi->param('month'));
+  $month = $1;
+
+  $cgi->param('payname') =~ /^([\w \,\.\-\']+)$/
+    or errorpage(gettext('illegal_name'). " payname: ". $cgi->param('payname'));
+  $payname = $1;
+
+  if ( $payby eq 'CHEK' ) {
+
+    $cgi->param('payinfo1') =~ /^(\d+)$/
+      or errorpage("Illegal account number ". $cgi->param('payinfo1'));
+    my $payinfo1 = $1;
+    $cgi->param('payinfo2') =~ /^(\d+)$/
+      or errorpage("Illegal ABA/routing number ". $cgi->param('payinfo2'));
+    my $payinfo2 = $1;
+    if ( $conf->config('echeck-country') eq 'CA' ) {
+      $cgi->param('payinfo3') =~ /^(\d{5})$/
+        or errorpage("Illegal branch number ". $cgi->param('payinfo2'));
+      $payinfo2 = "$1.$payinfo2";
+    }
+    $payinfo = $payinfo1 . '@'. $payinfo2;
+
+  } elsif ( $payby eq 'CARD' ) {
+
+    $payinfo = $cgi->param('payinfo');
+
+    $payinfo =~ s/\D//g;
+    $payinfo =~ /^(\d{13,19}|\d{8,9})$/
+      or errorpage(gettext('invalid_card'));
+    $payinfo = $1;
+    validate($payinfo)
+      or errorpage(gettext('invalid_card'));
+
+    unless ( $cust_main->tokenized($payinfo) ) { #token
+
+      my $cardtype = cardtype($payinfo);
+
+      errorpage(gettext('unknown_card_type'))
+        if $cardtype eq "Unknown";
+
+      my %bop_card_types = map { $_=>1 } values %{ card_types() };
+      errorpage("$cardtype not accepted") unless $bop_card_types{$cardtype};
+
+    }
+
+    if ( length($cgi->param('paycvv') ) ) {
+      if ( cardtype($payinfo) eq 'American Express card' ) {
+        $cgi->param('paycvv') =~ /^(\d{4})$/
+          or errorpage("CVV2 (CID) for American Express cards is four digits.");
+        $paycvv = $1;
+      } else {
+        $cgi->param('paycvv') =~ /^(\d{3})$/
+          or errorpage("CVV2 (CVC2/CID) is three digits.");
+        $paycvv = $1;
+      }
+    } elsif ( $conf->exists('backoffice-require_cvv') ){
+      errorpage("CVV2 is required");
+    }
+
+  } else {
+    die "unknown payby $payby";
+  }
+
+  # save first, for proper tokenization
+  if ( $cgi->param('save') ) {
+
+    my %saveopt;
+    if ( $payby eq 'CARD' ) {
+      my $bill_location = FS::cust_location->new;
+      $bill_location->set( $_ => scalar($cgi->param($_)) )
+        foreach @{$payby2fields{$payby}};
+      $saveopt{'bill_location'} = $bill_location;
+      $saveopt{'paycvv'} = $paycvv; # save_cust_payby contains conf logic for when to use this
+      $saveopt{'paydate'} = "$year-$month-01";
+    } else {
+      # ss/stateid/stateid_state won't be saved, but should be harmless to pass
+      %saveopt = map { $_ => scalar($cgi->param($_)) } @{$payby2fields{$payby}};
+    }
+
+    my $error = $cust_main->save_cust_payby(
+      'saved_cust_payby' => \$cust_payby,
+      'payment_payby' => $payby,
+      'auto'          => scalar($cgi->param('auto')),
+      'weight'        => scalar($cgi->param('weight')),
+      'payinfo'       => $payinfo,
+      'payname'       => $payname,
+      %saveopt
+    );
+
+    errorpage("error saving info, payment not processed: $error")
+      if $error;
+
+  } elsif ( $payby eq 'CARD' ) { # not saving
+
+    $paymask = FS::payinfo_Mixin->mask_payinfo('CARD',$payinfo); # for untokenized but tokenizable payinfo
+
+  }
+
+}
+
+##
+# now run the refund
+##
+
   $cgi->param('refund') =~ /^(\d*)(\.\d{2})?$/
     or die "illegal refund amount ". $cgi->param('refund');
   my $refund = "$1$2";
@@ -49,10 +194,42 @@ if ( $error ) {
   my $paynum = $1;
   my $paydate = $cgi->param('exp_year'). '-'. $cgi->param('exp_month'). '-01';
   $options{'paydate'} = $paydate if $paydate =~ /^\d{2,4}-\d{1,2}-01$/;
-  $error = $cust_main->realtime_refund_bop( $bop, 'amount' => $refund,
+
+  if ( $cgi->param('batch') ) {
+
+    $error ||= $cust_main->batch_card(
+                                     'payby'    => $payby,
+                                     'amount'   => $refund,
+                                     'payinfo'  => $payinfo,
+                                     'paydate'  => "$year-$month-01",
+                                     'payname'  => $payname,
+                                     'paycode'  => 'C',
+                                     map { $_ => scalar($cgi->param($_)) }
+                                       @{$payby2fields{$payby}}
+                                   );
+    errorpage($error) if $error;
+
+#### post refund #####
+    my %hash = map {
+      $_, scalar($cgi->param($_))
+    } fields('cust_refund');
+    $paynum = $cgi->param('paynum');
+    $paynum =~ /^(\d*)$/ or die "Illegal paynum!";
+    if ($paynum) {
+      my $cust_pay = qsearchs('cust_pay',{ 'paynum' => $paynum });
+      die "Could not find paynum $paynum" unless $cust_pay;
+      $error = $cust_pay->refund(\%hash);
+    } else {
+      my $new = new FS::cust_refund ( \%hash );
+      $error = $new->insert;
+    }
+    # if not a batch refund run realtime.
+  } else {
+    $error = $cust_main->realtime_refund_bop( $bop, 'amount' => $refund,
                                                   'paynum' => $paynum,
                                                   'reasonnum' => scalar($cgi->param('reasonnum')),
                                                   %options );
+  }
 } else {
   my %hash = map {
     $_, scalar($cgi->param($_))
diff --git a/httemplate/view/cust_main/menu.html b/httemplate/view/cust_main/menu.html
index dcba1fb..f3aca21 100644
--- a/httemplate/view/cust_main/menu.html
+++ b/httemplate/view/cust_main/menu.html
@@ -459,6 +459,13 @@ my @menu = (
         #  acl         => ['Post refund' ],
         ##  condition   => sub { $payby{MCHK} },
         #},
+        {
+           label       => 'Batch Electronic check refund',
+           popup       => "edit/cust_refund.cgi?popup=1;payby=CHEK;custnum=$custnum",
+           actionlabel => 'Enter electronic check refund',
+           width       => 440,
+           acl         => ['Post refund' ],
+        },
 
       ],
 

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Schema.pm                         |    1 +
 FS/FS/cust_main/Billing_Batch.pm        |    3 +-
 FS/FS/pay_batch/RBC.pm                  |    7 +-
 httemplate/edit/cust_refund.cgi         |   24 +++++
 httemplate/edit/process/cust_refund.cgi |  179 ++++++++++++++++++++++++++++++-
 httemplate/view/cust_main/menu.html     |    7 ++
 6 files changed, 218 insertions(+), 3 deletions(-)




More information about the freeside-commits mailing list