[freeside-commits] branch FREESIDE_3_BRANCH updated. 972904e944a37256e67cda6335049079e6fe5f8b
Jonathan Prykop
jonathan at 420.am
Fri Mar 13 12:58:03 PDT 2015
The branch, FREESIDE_3_BRANCH has been updated
via 972904e944a37256e67cda6335049079e6fe5f8b (commit)
from 95ec0ba6b56057953de04c6758cfce6d0a8d5fde (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 972904e944a37256e67cda6335049079e6fe5f8b
Author: Jonathan Prykop <jonathan at freeside.biz>
Date: Thu Mar 12 19:30:08 2015 -0500
RT#33582: RBC return batch processing failure [handling for non-chronological file
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index 3b9a291..6a66163 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -3927,7 +3927,7 @@ and customer address. Include units.',
{
'key' => 'batchconfig-RBC',
'section' => 'billing',
- 'description' => 'Configuration for Royal Bank of Canada PDS batching, four lines: 1. Client number, 2. Short name, 3. Long name, 4. Transaction code.',
+ 'description' => 'Configuration for Royal Bank of Canada PDS batching, five lines: 1. Client number, 2. Short name, 3. Long name, 4. Transaction code 5. (optional) set to TEST to turn on test mode.',
'type' => 'textarea',
},
diff --git a/FS/FS/cust_pay_batch.pm b/FS/FS/cust_pay_batch.pm
index 9acb541..2ab76d5 100644
--- a/FS/FS/cust_pay_batch.pm
+++ b/FS/FS/cust_pay_batch.pm
@@ -386,14 +386,8 @@ sub decline {
}
$cust_pay->void($reason);
}
- elsif ( lc($old->status) eq 'declined' ) {
- # batch files from RBC can have multiple lines for one decline
- # if this causes problems elsewhere, try hacking pay_batch/RBC.pm instead
- return '';
- }
else {
# normal case: refuse to do anything
- # should never happen...only statuses are approved or declined
return "cannot decline paybatchnum $paybatchnum, already resolved ('".$old->status."')";
}
} # !$old->status
diff --git a/FS/FS/pay_batch.pm b/FS/FS/pay_batch.pm
index 55e4d3f..3ce71b0 100644
--- a/FS/FS/pay_batch.pm
+++ b/FS/FS/pay_batch.pm
@@ -234,6 +234,36 @@ I<format> - an L<FS::pay_batch> module
I<gateway> - an L<FS::payment_gateway> object for a batch gateway. This
takes precedence over I<format>.
+Supported format keys (defined in the specified FS::pay_batch module) are:
+
+I<filetype> - required, can be CSV, fixed, variable, XML
+
+I<fields> - required list of field names for each row/line
+
+I<formatre> - regular expression for fixed filetype
+
+I<parse> - required for variable filetype
+
+I<xmlkeys> - required for XML filetype
+
+I<xmlrow> - required for XML filetype
+
+I<begin_condition> - sub, ignore all lines before this returns true
+
+I<end_condition> - sub, stop processing lines when this returns true
+
+I<end_hook> - sub, runs immediately after end_condition returns true
+
+I<skip_condition> - sub, skip lines when this returns true
+
+I<hook> - required, sub, runs before approved/declined conditions are checked
+
+I<approved> - required, sub, returns true when approved
+
+I<declined> - required, sub, returns true when declined
+
+I<close_condition> - sub, decide whether or not to close the batch
+
=cut
sub import_results {
diff --git a/FS/FS/pay_batch/RBC.pm b/FS/FS/pay_batch/RBC.pm
index a99d057..45e888d 100644
--- a/FS/FS/pay_batch/RBC.pm
+++ b/FS/FS/pay_batch/RBC.pm
@@ -6,7 +6,7 @@ use Date::Format 'time2str';
use FS::Conf;
my $conf;
-my ($client_num, $shortname, $longname, $trans_code, $i);
+my ($client_num, $shortname, $longname, $trans_code, $testmode, $i, $declined, $totaloffset);
$name = 'RBC';
# Royal Bank of Canada ACH Direct Payments Service
@@ -24,11 +24,12 @@ $name = 'RBC';
# 4 - Foreign Currency Information Records
# We skip all subtypes except 0
#
-# additional info available at https://www.rbcroyalbank.com/ach/file-451806.pdf
+# additional info available at https://www.rbcroyalbank.com/ach/cid-213166.html
%import_info = (
'filetype' => 'fixed',
+ #this only really applies to Debit Detail, but we otherwise only need first char
'formatre' =>
- '^([0134]).{18}(.{4}).{3}(.).{11}(.{19}).{6}(.{30}).{17}(.{9})(.{18}).{6}(.{14}).{23}(.).{9}\r?$',
+ '^(.).{18}(.{4}).{3}(.).{11}(.{19}).{6}(.{30}).{17}(.{9})(.{18}).{6}(.{14}).{23}(.).{9}\r?$',
'fields' => [ qw(
recordtype
batchnum
@@ -53,30 +54,67 @@ $name = 'RBC';
},
'declined' => sub {
my $hash = shift;
- grep { $hash->{'status'} eq $_ } ('E', 'R', 'U', 'T');
+ my $status = $hash->{'status'};
+ my $message = '';
+ if ($status eq 'E') {
+ $message = 'Reversed payment';
+ } elsif ($status eq 'R') {
+ $message = 'Rejected payment';
+ } elsif ($status eq 'U') {
+ $message = 'Returned payment';
+ } elsif ($status eq 'T') {
+ $message = 'Error';
+ } else {
+ return 0;
+ }
+ $hash->{'error_message'} = $message;
+ $declined->{$hash->{'paybatchnum'}} = 1;
+ return 1;
},
'begin_condition' => sub {
my $hash = shift;
- $hash->{recordtype} eq '1'; # Detail Record
+ # Debit Detail Record
+ if ($hash->{recordtype} eq '1') {
+ $declined = {};
+ $totaloffset = 0;
+ return 1;
+ # Credit Detail Record, will immediately trigger end condition & error
+ } elsif ($hash->{recordtype} eq '2') {
+ return 1;
+ } else {
+ return 0;
+ }
},
'end_hook' => sub {
my( $hash, $total, $line ) = @_;
+ return "Can't process Credit Detail Record, aborting import"
+ if ($hash->{'recordtype'} eq '2');
+ $totaloffset = sprintf("%.2f", $totaloffset / 100 );
+ $total += $totaloffset;
$total = sprintf("%.2f", $total);
- # We assume here that this is an 'All Records' or 'Input Records'
- # report.
+ # We assume here that this is an 'All Records' or 'Input Records' report.
my $batch_total = sprintf("%.2f", substr($line, 59, 18) / 100);
return "Our total $total does not match bank total $batch_total!"
if $total != $batch_total;
- '';
+ return '';
},
'end_condition' => sub {
my $hash = shift;
- $hash->{recordtype} eq '4'; # Client Trailer Record
+ return ($hash->{recordtype} eq '4') # Client Trailer Record
+ || ($hash->{recordtype} eq '2'); # Credit Detail Record, will throw error in end_hook
},
'skip_condition' => sub {
my $hash = shift;
- $hash->{'recordtype'} eq '3' ||
- $hash->{'subtype'} ne '0';
+ #we already declined it this run, no takebacks
+ if ($declined->{$hash->{'paybatchnum'}}) {
+ #file counts this as part of total, but we skip
+ $totaloffset += $hash->{'paid'}
+ if $hash->{'status'} eq ' '; #false laziness with 'approved' above
+ return 1;
+ }
+ return
+ ($hash->{'recordtype'} eq '3') || #Account Trailer Record, concludes returned items
+ ($hash->{'subtype'} ne '0'); #error messages, etc, too late to apply to previous entry
},
);
@@ -87,18 +125,22 @@ $name = 'RBC';
$shortname,
$longname,
$trans_code,
+ $testmode
) = $conf->config("batchconfig-RBC");
+ $testmode = '' unless $testmode eq 'TEST';
$i = 1;
},
header => sub {
my $pay_batch = shift;
- '$$AAPASTD0152[PROD[NL$$'."\n".
+ my $mode = $testmode ? 'TEST' : 'PROD';
+ my $filenum = $testmode ? 'TEST' : sprintf("%04u", $pay_batch->batchnum);
+ '$$AAPASTD0152['.$mode.'[NL$$'."\n".
'000001'.
'A'.
'HDR'.
sprintf("%10s", $client_num).
sprintf("%-30s", $longname).
- sprintf("%04u", $pay_batch->batchnum).
+ $filenum.
time2str("%Y%j", $pay_batch->download).
'CAD'.
'1'.
-----------------------------------------------------------------------
Summary of changes:
FS/FS/Conf.pm | 2 +-
FS/FS/cust_pay_batch.pm | 6 -----
FS/FS/pay_batch.pm | 30 +++++++++++++++++++++
FS/FS/pay_batch/RBC.pm | 68 ++++++++++++++++++++++++++++++++++++++---------
4 files changed, 86 insertions(+), 20 deletions(-)
More information about the freeside-commits
mailing list