1 package FS::pay_batch::nacha;
4 use vars qw( %import_info %export_info $name $conf $entry_hash $DEBUG );
6 #use Time::Local 'timelocal';
21 'approved' => sub { 1 },
22 'declined' => sub { 0 },
36 my( $pay_batch, $cust_pay_batch_arrayref ) = @_;
38 $conf->config('batchconfig-nacha-destination') =~ /^\s*(\d{9})\s*$/
39 or die 'illegal NACHA Destination';
42 my $dest_name = $conf->config('batchconfig-nacha-destination_name');
43 $dest_name = substr( $dest_name. (' 'x23), 0, 23);
45 $conf->config('batchconfig-nacha-origin') =~ /^\s*(\d{10})\s*$/
46 or die 'illegal NACHA Origin';
49 my $company = $conf->config('company_name', $pay_batch->agentnum);
51 my $origin_name = $conf->config('batchconfig-nacha-origin_name')
53 $origin_name = substr(uc($origin_name). (' 'x23), 0, 23);
55 $company = substr(uc($company). (' 'x16), 0, 16);
59 #haha don't want to break after a quarter million years of a batch a day
60 #or 54 years for 5000 agent-virtualized hosted companies batching daily
61 my $refcode = substr( (' 'x8). $pay_batch->batchnum, -8);
63 #or only 25,000 years or 5.4 for 5000 companies :)
64 #though they would probably want them numbered per company
65 my $batchnum = substr( ('0'x7). $pay_batch->batchnum, -7);
69 warn "building File & Batch Header Records\n" if $DEBUG;
75 '1'. #Record Type Code
77 ' '. $dest. #Immediate Destination / 9-digit transit routing #
78 $origin. #Immediate Origin / 10 digit company number
79 time2str('%y%m%d', $now). #File Creation Date
80 time2str('%H%M', $now). #File Creation Time
81 'A'. #XXX file ID modifier, mult. files in transit? [A-Z0-9]
82 '094'. #94 character records
83 '10'. #Blocking Factor
85 $dest_name. #Immediate Destination Name / 23 char bank name
86 $origin_name. #Immediate Origin Name / 23 char company name
87 $refcode. "\n". #Reference Code (internal/optional)
93 '5'. #Record Type Code
94 '225'. #Service Class Code (220 credits only,
95 # 200 mixed debits & credits)
96 $company. #on cust. statements
97 (' 'x20 ). #20 char "company internal use if desired"
98 $origin. #Company Identification (Immediate Origin)
100 #PPD "Prearranged Payments and Deposit entries" for consumer items
101 #CCD (Cash Concentration and Disbursement)
102 #CTX (Corporate Trade Exchange)
103 #TEL (Telephone initiated entires)
104 #WEB (Authorization received via the Internet)
105 'InterntSvc'. #XXX from conf 10 char txn desc, printed on cust. statements
107 #6 char "Descriptive date" printed on customer statements
108 #XXX now? or use a separate post date?
109 time2str('%y%m%d', $now).
111 #6 char date transactions are to be posted
112 #XXX now? or do we need a future banking day date like eft_canada trainwreck
113 time2str('%y%m%d', $now).
115 (' 'x3). #Settlement Date / Reserved
116 '1'. #Originator Status Code
117 substr($dest, 0, 8). #Originating Financial Institution
118 $batchnum. "\n" #Batch Number ("number batches sequentially")
123 my( $cust_pay_batch, $pay_batch, $batchcount, $batchtotal ) = @_;
125 my ($account, $aba) = split('@', $cust_pay_batch->payinfo);
127 $conf->config('batchconfig-nacha-destination') =~ /^\s*(\d{9})\s*$/
128 or die 'illegal NACHA Destination';
131 # "Total of all positions 4-11 on each 6 record"
132 $entry_hash += substr($aba,0,8);
134 my $cust_main = $cust_pay_batch->cust_main;
135 my $cust_identifier = substr($cust_main->display_custnum. (' 'x15), 0, 15);
137 #XXX paytype should actually be in the batch, but this will do for now
138 #27 checking debit, 37 savings debit
139 my $transaction_code = ( $cust_pay_batch->paytype =~ /savings/i ? '37' : '27' );
141 # not $self->payname?
142 my $cust_name = substr($cust_main->name. (' 'x22), 0, 22);
144 my $tracenum = $dest. substr(('0'x7). $i, -6);
145 #non-PPD transactions? future
147 warn "building PPD Record\n" if $DEBUG;
150 # PPD Entry Detail Record
153 '6'. #Record Type Code
154 $transaction_code. #Transaction Code
155 $aba. #Receiving DFI Identification, check digit
156 substr($account.(' 'x17), 0, 17). #DFI Account number (Left justify)
157 sprintf('%010.0f', $cust_pay_batch->amount * 100). #Amount
158 $cust_identifier. #Individual Identification Number, 15 char
159 $cust_name. #Individual name (22-char)
160 ' '. #2 char "company internal use if desired"
161 '0'. #Addenda Record Indicator
162 # (' 'x15). #15 digit "bank will assign trace number"
168 my( $pay_batch, $batchcount, $batchtotal ) = @_;
170 #Only use the final 10 positions in the entry
171 $entry_hash = substr( '00'.$entry_hash, -10);
173 $conf->config('batchconfig-nacha-destination') =~ /^\s*(\d{9})\s*$/
174 or die 'illegal NACHA Destination';
177 $conf->config('batchconfig-nacha-origin') =~ /^\s*(\d{10})\s*$/
178 or die 'illegal NACHA Origin';
181 my $batchnum = substr( ('0'x7). $pay_batch->batchnum, -7);
183 my $lines = $batchcount + 4;
184 my $blocks = int($lines/10);
187 if ( my $remainder = $lines % 10 ) {
189 $fill = ("\n".('9'x94))x( 10 - $remainder );
192 warn "building Batch & File Control Records\n" if $DEBUG;
195 # Batch Control Record
198 '8'. #Record Type Code
199 '225'. #Service Class Code (220 credits only,
200 # 200 mixed debits&credits)
201 sprintf('%06d', $batchcount). #Entry / Addenda Count
203 sprintf('%012.0f', $batchtotal * 100). #Debit total
204 '000000000000'. #Credit total
205 $origin. #Company Identification (Immediate Origin)
206 (' 'x19). #Message Authentication Code (19 char blank)
207 (' 'x6). #Federal Reserve Use (6 char blank)
208 substr($dest, 0, 8). #Originating Financial Institution
209 $batchnum. "\n". #Batch Number ("number batches sequentially")
212 # File Control Record
215 '9'. #Record Type Code
216 '000001'. #Batch Counter (# of batch header recs)
217 sprintf('%06d', $blocks). #num of physical blocks on the file
218 sprintf('%08d', $batchcount). #total # of entry detail and addenda
220 sprintf('%012.0f', $batchtotal * 100). #Debit total
221 '000000000000'. #Credit total
222 ( ' 'x39 ). #Reserved / blank
225 # Pad with 9999 records to blocks of 10