X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fpay_batch%2FRBC.pm;h=f3f81707a55c0442849a922ec4e08939ee6ecf7c;hb=fe708edd0ced9686d96b3ceb3de1300f5984a92e;hp=dc6095cccdcbccae53381f53ee00420a72c2820a;hpb=63a268637b2d51a8766412617724b9436439deb6;p=freeside.git diff --git a/FS/FS/pay_batch/RBC.pm b/FS/FS/pay_batch/RBC.pm index dc6095ccc..f3f81707a 100644 --- a/FS/FS/pay_batch/RBC.pm +++ b/FS/FS/pay_batch/RBC.pm @@ -11,13 +11,26 @@ my ($client_num, $shortname, $longname, $trans_code, $i); $name = 'RBC'; # Royal Bank of Canada ACH Direct Payments Service +# Meaning of initial characters in records: +# 0 - header row, skipped by begin_condition +# 1 - Debit Detail Record (only when subtype is 0) +# 2 - Credit Detail Record, we die with a parse error (shouldn't appear in freeside-generated batches) +# 3 - Account Trailer Record (appears after Returned items, we skip) +# 4 - Client Trailer Record, indicates end of batch in end_condition +# +# Subtypes (27th char) indicate different kinds of Debit/Credit records +# 0 - Credit/Debit Detail Record +# 3 - Error Message Record +# 4 - Foreign Currency Information Records +# We skip all subtypes except 0 %import_info = ( 'filetype' => 'fixed', 'formatre' => - '^(.).{18}(.{4}).{15}(.{19}).{6}(.{30}).{17}(.{9})(.{18}).{6}(.{14}).{23}(.).{9}$', + '^([0134]).{18}(.{4}).{3}(.).{11}(.{19}).{6}(.{30}).{17}(.{9})(.{18}).{6}(.{14}).{23}(.).{9}\r?$', 'fields' => [ qw( recordtype batchnum + subtype paybatchnum custname bank @@ -27,8 +40,9 @@ $name = 'RBC'; ) ], 'hook' => sub { my $hash = shift; - $hash->{'paid'} = sprintf("%.df", $hash->{'paid'} / 100 ); + $hash->{'paid'} = sprintf("%.2f", $hash->{'paid'} / 100 ); $hash->{'_date'} = time; + $hash->{'payinfo'} =~ s/^(\S+).*/$1/; # these often have trailing spaces $hash->{'payinfo'} = $hash->{'payinfo'} . '@' . $hash->{'bank'}; }, 'approved' => sub { @@ -39,17 +53,28 @@ $name = 'RBC'; my $hash = shift; grep { $hash->{'status'} eq $_ } ('E', 'R', 'U', 'T'); }, + 'begin_condition' => sub { + my $hash = shift; + $hash->{recordtype} eq '1'; # Detail Record + }, 'end_hook' => sub { my( $hash, $total, $line ) = @_; $total = sprintf("%.2f", $total); - my $batch_total = sprintf("%.2f", substr($line, 140, 18) / 100); + # 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; ''; }, 'end_condition' => sub { my $hash = shift; - $hash->{recordtype} == '3'; # Account Trailer Record + $hash->{recordtype} eq '4'; # Client Trailer Record + }, + 'skip_condition' => sub { + my $hash = shift; + $hash->{'recordtype'} eq '3' || + $hash->{'subtype'} ne '0'; }, ); @@ -65,6 +90,7 @@ $name = 'RBC'; }, header => sub { my $pay_batch = shift; + '$$AAPASTD0152[PROD[NL$$'."\n". '000001'. 'A'. 'HDR'. @@ -80,6 +106,15 @@ $name = 'RBC'; row => sub { my ($cust_pay_batch, $pay_batch) = @_; my ($account, $aba) = split('@', $cust_pay_batch->payinfo); + my($bankno, $branch); + if ( $aba =~ /^0(\d{3})(\d{5})$/ ) { # standard format for Canadian bank ID + ($bankno, $branch) = ( $1, $2 ); + } elsif ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #how we store branches + ($branch, $bankno) = ( $1, $2 ); + } else { + die "invalid branch/routing number '$aba'\n"; + } + $i++; sprintf("%06u", $i). 'D'. @@ -88,10 +123,11 @@ $name = 'RBC'; ' '. sprintf("%-19s", $cust_pay_batch->paybatchnum). '00'. - sprintf("%09u", $aba). + sprintf("%04s", $bankno). + sprintf("%05s", $branch). sprintf("%-18s", $account). ' '. - sprintf("%010u",$cust_pay_batch->amount*100). + sprintf("%010.0f",$cust_pay_batch->amount*100). ' '. time2str("%Y%j", $pay_batch->download). sprintf("%-30s", $cust_pay_batch->cust_main->first . ' ' . @@ -116,9 +152,9 @@ $name = 'RBC'; 'Z'. 'TRL'. sprintf("%10s", $client_num). - ' ' x 20 . + '0' x 20 . sprintf("%06u", $batchcount). - sprintf("%014u", $batchtotal*100). + sprintf("%014.0f", $batchtotal*100). '00' . '000000' . # total number of customer information records ' ' x 84