41 require_once(
"../../banking/library/hcuACH.i" );
42 require_once(
"$sharedLibrary/sFeatureMnu.i");
43 require_once(
"../library/aGroupSupport.i" );
47 require_once( dirname(__FILE__) .
"/../library/aAdminSettings.i" );
49 const DFI_ACCOUNT_MAX_SIZE = 17;
52 $advPerm = checkPerm($Cn,
"aACHAdv", $Cu)[1] == 1;
54 $self =
"$menu_link?ft=$ft";
58 "operation" => array(
"filter" => FILTER_SANITIZE_STRING),
59 "page" => array(
"filter" => FILTER_SANITIZE_STRING),
60 "trans_id" => array(
"filter" => FILTER_SANITIZE_NUMBER_INT)
62 HCU_ImportVars( $admVars,
"", $admOk );
64 $operation = trim( isset( $admVars[
"operation"]) ? $admVars[
"operation"] :
"" );
66 $page = trim( isset( $admVars[
"page"]) ? $admVars[
"page"] :
"" );
70 $ADM_ENV[
"SYSENV"] = $SYSENV;
73 $ADM_ENV[
"dbh"] = $dbh;
74 $ADM_ENV[
"self"] = $self;
75 $ADM_ENV[
"menu_link"] = $menu_link;
76 $ADM_ENV[
"advPerm"] = $advPerm;
85 $ADM_ENV[
"removeFromBatchTime"] = 14;
88 if ($operation !=
"") {
90 if (!in_array($ft, array(100,99))) {
91 throw new exception(
"Data call isn't using expected ft!", 12);
100 case "achGetBatches":
101 $return = GetCompletedBatches( $ADM_ENV );
103 if ($return[
'code'] !=
'000') {
104 throw new Exception ( HCU_JsonEncode($return[
"errors"]) );
108 $aryResult[$operation] = $return[
"data"];
113 throw new exception ( HCU_JsonEncode(array(
"Need advanced permissions to make a batch.")) );
116 "trans_list" => array(
"filter" => FILTER_SANITIZE_STRING)
118 HCU_ImportVars( $admVars,
"", $admOk );
119 $returnMake = MakeACHBatch( $ADM_ENV, $admVars );
121 if ($returnMake[
'code'] !=
'000') {
122 throw new Exception ( HCU_JsonEncode($returnMake[
"errors"]) );
124 $aryInfo[] =
"Create ACH upload file. Processed time: " . $returnMake[
"data"][
"batch_time"];
129 $aryResult[$operation] = $returnMake[
"data"];
132 $admVars[
"batch_id"] = $returnMake[
"data"][
"batch_id"];
133 $returnCreate = CreateAchFiles( $ADM_ENV, $admVars );
135 if ($returnCreate[
'code'] !=
'000') {
137 $returnErrors = explode(
'^', $returnCreate[
'errors']);
138 $aryInfo = array_merge($aryInfo, $returnErrors);
139 $aryInfo[] =
"Use the <a href=\"main.prg?ft=100\">History</a> screen to attempt re-building the ACH upload file.";
146 $returnNotify = SendACHNotifications( $ADM_ENV, $admVars[
'trans_list'] );
147 if ($returnNotify[
'code'] !==
'000') {
150 $aryInfo[] = $returnNotify[
'errors'];
151 if ($returnNotify[
'code'] == 103) {
152 $aryInfo[] =
"This feature requires an \"ACH Notifications\" email on the <a href=\"main.prg?ft=46\">CU Email Notifications</a> screen.";
153 }
else if ($returnNotify[
'code'] == 104) {
154 $aryInfo[] =
"This feature requires an \"ACH Notifications\" email template on the <a href=\"main.prg?ft=54\">Settings</a> screen.";
160 case "achGetBatchDetail":
162 "batch_id" => array(
"filter" => FILTER_SANITIZE_STRING)
164 HCU_ImportVars( $admVars,
"", $admOk );
166 $return = GetBatchDetail( $ADM_ENV, $admVars );
168 if ($return[
'code'] !=
'000') {
169 throw new Exception ( HCU_JsonEncode($return[
"errors"]) );
173 $aryResult[$operation] = $return[
"data"];
176 $return = GetApprovedACHTrans( $ADM_ENV );
178 if ($return[
'code'] !=
'000') {
179 throw new Exception ( HCU_JsonEncode($return[
"errors"]) );
183 $aryResult[$operation] = $return[
"data"];
186 $transId = isset( $admVars[
"trans_id"]) ? $admVars[
"trans_id"] : 0;
187 $return = GetACHTransDetail( $ADM_ENV, $transId );
189 if ($return[
'code'] !=
'000') {
190 throw new Exception ( HCU_JsonEncode($return[
"errors"]) );
194 $aryResult[$operation] = $return[
"data"];
198 "trans_list" => array(
"filter" => FILTER_SANITIZE_STRING)
200 HCU_ImportVars( $admVars,
"", $admOk );
204 throw new exception ( HCU_JsonEncode(array(
"Need advanced permissions to cancel a batch.")) );
207 $return = CancelACHTrans( $ADM_ENV, $admVars[
"trans_list"] );
209 if ($return[
'code'] !=
'000') {
210 throw new Exception ( HCU_JsonEncode($return[
"errors"]) );
214 $aryResult[$operation] = $return[
"data"];
216 case "ach_download_file":
220 "batch_id" => array(
"filter" => FILTER_SANITIZE_STRING),
221 "download_type" => array(
"filter" => FILTER_SANITIZE_STRING)
223 HCU_ImportVars( $admVars,
"", $admOk );
227 ShowErrorPage(array(
"Need advanced permissions to download ACH file."));
231 $return = DownloadAchFile( $ADM_ENV, $admVars );
233 if ($return[
'code'] !=
'000') {
235 ShowErrorPage( $return[
"errors"] );
240 $filename = $return[
"data"][
"filename"];
241 $outString = $return[
"data"][
"output"];
242 header(
"Content-length: " . strlen($outString));
243 header(
"Content-type: application/octetstream");
244 header(
"Content-disposition: attachment; filename=\"$filename\"");
245 print ( $outString );
250 case "achCreateFile":
254 "batch_id" => array(
"filter" => FILTER_SANITIZE_STRING)
256 HCU_ImportVars( $admVars,
"", $admOk );
260 throw new exception ( HCU_JsonEncode(array(
"Need advanced permissions to create file.")) );
263 $return = ACH_CreateFile($ADM_ENV, $admVars);
264 if ($return[
'code'] !==
'000') {
269 $errors = explode(
"^", $return[
'errors']);
270 throw new Exception( HCU_JsonEncode($errors) );
274 $aryInfo = $return[
'data'][
'message'];
275 $aryResult[$operation] = $return[
'data'];
277 case "achSendNotifications":
279 "batch_id" => array(
"filter" => FILTER_SANITIZE_STRING)
281 HCU_ImportVars( $admVars,
"", $admOk );
285 throw new exception ( HCU_JsonEncode(array(
"Need advanced permissions to send notifications.")) );
289 $transHdrIds = GetProcessedHeaders( $ADM_ENV, $admVars[
'batch_id'] );
290 $return = SendACHNotifications( $ADM_ENV, $transHdrIds);
291 if ($return[
'code'] !==
'000') {
295 $returnErrors = array();
296 $returnErrors[] = $return[
'errors'];
297 if ($return[
'code'] == 103) {
298 $returnErrors[] =
"This feature requires an \"ACH Notifications\" email on the <a href=\"main.prg?ft=46\">CU Email Notifications</a> screen.";
299 }
else if ($return[
'code'] == 104) {
300 $returnErrors[] =
"This feature requires an \"ACH Notifications\" email template on the <a href=\"main.prg?ft=54\">Settings</a> screen.";
303 throw new Exception( HCU_JsonEncode($returnErrors) );
307 $aryResult[$operation] = array(
"batch_id"=>$admVars[
'batch_id']);
308 $aryInfo[] =
"Email notifications have been sent";
310 case "achRemoveBatchTransactions":
314 "batch_id" => array(
"filter" => FILTER_SANITIZE_STRING),
315 "trans_list" => array(
"filter" => FILTER_SANITIZE_STRING)
317 HCU_ImportVars( $admVars,
"", $admOk );
321 throw new exception ( HCU_JsonEncode(array(
"Need advanced permissions to remove transactions.")) );
324 $return = ACH_RemoveBatchTransactions($ADM_ENV, $admVars);
325 if ($return[
'code'] !==
'000') {
326 throw new Exception( HCU_JsonEncode($return[
'errors']) );
330 $aryInfo[] = $return[
'data'][
'message'];
331 $aryResult[$operation] = $return[
'data'];
334 throw new Exception (
"Operation not recognized: $operation.");
337 }
catch (Exception $ex) {
338 $aryReply[
"errors"] = HCU_JsonDecode( $ex->getMessage() );
341 $aryResult = array();
347 if ( count( $aryInfo ) ) {
348 $aryReply[
"info"] = $aryInfo;
351 if ( count( $aryResult ) ) {
352 $aryReply[
"data"] = $aryResult;
355 header(
'Content-type: application/json');
357 print HCU_JsonEncode( array(
"results" => $aryReply ) );
368 $ADM_ENV[
'commercialAccess'] =
false;
369 $featureList = FetchMenuFeatureList( array(
"dbh" => $dbh), array(
"Cu"=>$Cu) );
370 if (in_array(
"ACHPMT", $featureList[
'data']) || in_array(
"ACHCOL", $featureList[
'data'])) {
371 $ADM_ENV[
'commercialAccess'] =
true;
377 throw new exception(
"Invalid access.", 14);
379 PrintActionPage( $ADM_ENV, $admVars );
381 case "ach_show_report":
383 ShowErrorPage(
"Invalid access");
386 "batch_id" => array(
"filter" => FILTER_SANITIZE_STRING),
387 "download" => array(
"filter" => FILTER_SANITIZE_STRING)
389 HCU_ImportVars( $admVars,
"", $admOk );
392 $ADM_ENV[
"cloudfrontDomainName"] = $cloudfrontDomainName;
393 $ADM_ENV[
"homecuKendoVersion"] = $homecuKendoVersion;
394 $ADM_ENV[
"bootstrapVersion"] = $bootstrapVersion;
395 $ADM_ENV[
"fontawesomeVersion"] = $fontawesomeVersion;
396 $ADM_ENV[
"loadStyleSheet"] = $loadStyleSheet;
397 $ADM_ENV[
"chome"] = $ADM_ENV[
"Cu"];
399 PrintAchReport( $ADM_ENV, $admVars );
403 throw new exception(
"Invalid access.", 14);
406 "file" => array(
"filter" => FILTER_SANITIZE_STRING),
407 "show_raw" => array(
"filter" => FILTER_VALIDATE_BOOLEAN)
409 HCU_ImportVars( $admVars,
"", $admOk );
411 PrintValidate( $ADM_ENV, $admVars );
415 throw new exception(
"Invalid access.", 14);
417 MakeBatch($self, $dbh, $Cu, $authval);
421 throw new exception(
"Invalid access: $page", 13);
423 PrintMainPage( $ADM_ENV, $admVars );
427 catch (exception $ex)
430 $message = $ex->getMessage();
431 $code = $ex->getCode();
433 print
"<p>An unexpected error occured. If this error keeps happening please contact Support.</p>";
435 if ( strlen( $message ) ) {
436 print
"<p>Message: $message</p>";
439 if ( strlen( $code ) ) {
440 print
"<p>Code: $code</p>";
443 print
"<p>Creating a new ACH upload file will open a report in a new window. <br />Make sure pop-ups are allowed for this website.</p>";
454 function ShowErrorPage( $pErrors ) {
458 if ( is_array( $pErrors ) ) {
459 for ( $i = 0; $i < count( $pErrors ); $i++ ) {
460 $errorString .= $pErrors[$i] .
"<br>";
463 $errorString = $pErrors;
473 <div
class=
"error-block">
474 <div
class=
"error-header">The following error(s) occured</div>
475 <p
id=
"error">$errorString</p>
476 <p>Please
try your operation again. If
this error persists please contact Support.</p>
480 border-radius: 4px 4px 0 0;
481 border-bottom-style: solid;
482 border-bottom-width: 1px;
483 border-color: #dfd0d0;
486 margin: -2px 0 10px -2px;
494 border-color: #dfd0d0;
498 background-color: #fff0f0;
525 function ACH_CreateFile($pAdmEnv, $pAdmVars) {
526 $returnInfo = array(
"code" =>
"000",
"errors" =>
"",
"data" => array());
530 $batch = HCU_PayloadDecode($pAdmEnv[
'Cu'], $pAdmVars[
'batch_id']);
531 $pAdmVars[
'batch_date'] = $batch[
'batch_date'];
534 $return = CreateAchFiles( $pAdmEnv, $pAdmVars );
535 if ($return[
'code'] !=
'000') {
536 throw new Exception ( $return[
'errors'], $return[
'code'] );
539 $returnInfo[
'data'][
'message'] = array();
540 $returnInfo[
'data'][
'message'][] =
"ACH Files created successfully";
544 $transHdrIds = GetProcessedHeaders( $pAdmEnv, $pAdmVars[
'batch_id'] );
545 $return = SendACHNotifications( $pAdmEnv, $transHdrIds);
546 if ($return[
'code'] !==
'000') {
549 $returnInfo[
'data'][
'message'][] = $return[
'errors'];
550 if ($return[
'code'] == 103) {
551 $returnInfo[
'data'][
'message'][] =
"This feature requires an \"ACH Notifications\" email on the <a href=\"main.prg?ft=46\">CU Email Notifications</a> screen.";
552 }
else if ($return[
'code'] == 104) {
553 $returnInfo[
'data'][
'message'][] =
"This feature requires an \"ACH Notifications\" email template on the <a href=\"main.prg?ft=54\">Settings</a> screen.";
558 $return = GetCompletedBatchRecord($pAdmEnv, $pAdmVars);
559 if ($return[
'code'] !==
'000') {
560 throw new Exception( $return[
'errors'], $return[
'code'] );
563 $returnInfo[
'data'][
'batch_record'] = $return[
'data'][
'batch_record'];
564 $returnInfo[
'data'][
'batch_id'] = $pAdmVars[
'batch_id'];
565 }
catch (Exception $ex) {
566 $returnInfo[
"errors"] = $ex->getMessage();
567 $returnInfo[
"code"] = $ex->getCode();
584 function ACH_RemoveBatchTransactions($pAdmEnv, $pAdmVars) {
585 $returnInfo = array(
"code" =>
"000",
"errors" =>
"",
"data" => array());
589 $batch = HCU_PayloadDecode($pAdmEnv[
'Cu'], $pAdmVars[
'batch_id']);
590 $pAdmVars[
'batch_date'] = $batch[
'batch_date'];
594 $removeTransactionsTime = time() - $pAdmEnv[
'removeFromBatchTime'] * 24 * 60 * 60;
595 $removeBatchTime = strtotime($batch[
'batch_date']);
596 if ($removeBatchTime < $removeTransactionsTime) {
598 $error =
"Transactions cannot be removed from an ACH upload file that is more than 14 days old.";
600 throw new Exception($error);
604 $return = RemoveBatchTransactions($pAdmEnv, $pAdmVars);
605 if ($return[
'code'] !==
'000') {
606 throw new Exception($return[
'errors']);
610 $return = RemoveBatchFiles($pAdmEnv, $pAdmVars);
611 if ($return[
'code'] !==
'000') {
612 throw new Exception($return[
'errors']);
625 $return = CreateAchFiles($pAdmEnv, $pAdmVars);
626 if ($return[
'code'] !==
'000' && $return[
'code'] !== 300) {
627 throw new Exception($return[
'errors']);
631 $return = GetCompletedBatchRecord($pAdmEnv, $pAdmVars);
632 if ($return[
'code'] !==
'000') {
633 throw new Exception($return[
'errors']);
636 $returnInfo[
'data'][
'batch_record'] = $return[
'data'][
'batch_record'];
637 $returnInfo[
'data'][
'batch_id'] = $pAdmVars[
'batch_id'];
638 $returnInfo[
"data"][
"message"] =
"Remove transactions. ACH upload file creation date: " . $return[
'data'][
'batch_date'];
639 }
catch (Exception $ex) {
640 $returnInfo[
"errors"] = $ex->getMessage();
641 $returnInfo[
"code"] = $ex->getCode();
660 function GetCompletedBatchRecord($pAdmEnv, $pAdmVars) {
661 $returnInfo = array(
"code" =>
"000",
"errors" =>
"",
"data" => array());
664 $cu = strtolower( $pAdmEnv[
"Cu"] );
666 $batchPreName =
"Batch";
667 $batchPath =
"/home/{$cu}/admin/ach/";
670 $tz = GetCreditUnionTimezone( $pAdmEnv[
"dbh"], $pAdmEnv[
"Cu"] );
671 $dateTime =
new DateTime( $pAdmVars[
'batch_date'] );
672 $dateTime->setTimezone(
new DateTimeZone($tz));
673 $batchDay = $dateTime->format(
"ymd");
674 $batchHour = $dateTime->format(
"His");
675 $batchDate = $dateTime->format(
"m/d/y H:i:s T");
677 $baseFileName =
"{$batchPreName}_{$batchDay}_{$batchHour}";
678 $batchAch = file_exists(
"{$batchPath}{$baseFileName}.ach" );
679 $batchReport = file_exists(
"{$batchPath}{$baseFileName}.txt" );
683 th.processed_date, th.processed_by, 684 COUNT(DISTINCT th.id) AS count, 685 SUM(CASE WHEN (th.feature_code = 'ACHPMT' OR th.feature_code = 'ACHCOL') AND td.email_notify = 1 THEN 1 ELSE 0 END) AS notify 686 FROM {$pAdmEnv['Cu']}transhdr AS th 687 JOIN {$pAdmEnv['Cu']}transdtl AS td ON th.id = td.transhdr_id 688 WHERE th.processed_date = '{$pAdmVars['batch_date']}' 689 GROUP BY processed_date, processed_by 690 ORDER BY processed_date DESC";
691 $sqlRs = db_query( $sql, $pAdmEnv[
"dbh"] );
693 throw new Exception(
"ACH Query Error - getting approved ach txns" );
696 $sqlRecord = db_fetch_assoc($sqlRs, 0);
700 $returnInfo[
'data'][
'batch_date'] = $batchDate;
701 $returnInfo[
'data'][
'batch_record'] = array();
703 $returnInfo[
'data'][
'batch_record'][
'batch_id'] = $pAdmVars[
'batch_id'];
704 $returnInfo[
'data'][
'batch_record'][
'processed_by'] = $sqlRecord[
'processed_by'];
705 $returnInfo[
'data'][
'batch_record'][
'count'] = intval($sqlRecord[
'count']);
706 $returnInfo[
'data'][
'batch_record'][
'notify'] = intval($sqlRecord[
'notify']);
707 $returnInfo[
'data'][
'batch_record'][
'display'] = $batchDate;
708 $returnInfo[
'data'][
'batch_record'][
'has_ach_file'] = file_exists(
"{$batchPath}{$baseFileName}.ach" );
709 $returnInfo[
'data'][
'batch_record'][
'has_ach_report'] = file_exists(
"{$batchPath}{$baseFileName}.txt" );
711 }
catch (Exception $ex) {
712 $returnInfo[
"errors"] = $ex->getMessage();
713 $returnInfo[
"code"] = $ex->getCode();
729 function RemoveBatchFiles($pAdmEnv, $pAdmVars) {
730 $returnInfo = array(
"code" =>
"000",
"errors" =>
"",
"data" => array());
733 $cu = strtolower( $pAdmEnv[
"Cu"] );
735 $batchDate = $pAdmVars[
'batch_date'];
736 $batchPreName =
"Batch";
737 $batchPath =
"/home/{$cu}/admin/ach/";
740 $tz = GetCreditUnionTimezone( $pAdmEnv[
"dbh"], $pAdmEnv[
"Cu"] );
743 $dateTime =
new DateTime( $batchDate );
744 $dateTime->setTimezone(
new DateTimeZone($tz));
745 $batchDay = $dateTime->format(
"ymd");
746 $batchHour = $dateTime->format(
"His");
749 if ( !file_exists( $batchPath ) ) {
750 throw new Exception(
"Remove ACH Files Error - Directory does not exist - please contact Support", 201 );
753 $achBaseName =
"{$batchPreName}_{$batchDay}_{$batchHour}";
755 $achFileName =
"{$achBaseName}.ach";
756 $achFilePath =
"{$batchPath}{$achFileName}";
758 $achReportName =
"{$achBaseName}.txt";
759 $achReportPath =
"{$batchPath}{$achReportName}";
761 if ( file_exists($achFilePath) ) {
762 if ( !unlink($achFilePath) ) {
763 throw new Exception(
"Error Removing ACH Upload File - Failed to remove ACH upload file.", 202);
767 if ( file_exists($achReportPath) ) {
768 if ( !unlink($achReportPath) ) {
769 throw new Exception(
"Error Removing ACH Upload Report File - Failed to remove ACH upload report file.", 203);
774 $returnInfo[
'data'][
'batch_time'] = $dateTime->format(
"m/d/y H:i:s T");
775 }
catch (Exception $ex) {
776 $returnInfo[
"errors"] = $ex->getMessage();
777 $returnInfo[
"code"] = $ex->getCode();
793 function RemoveBatchTransactions($pAdmEnv, $pAdmVars) {
794 $returnInfo = array(
"code" =>
"000",
"errors" =>
"",
"data" => array());
797 $batchDate = $pAdmVars[
'batch_date'];
798 $batchRemove = trim($pAdmVars[
'trans_list']);
801 UPDATE {$pAdmEnv['Cu']}transhdr SET 802 processed_status = NULL, 803 processed_date = NULL, 805 WHERE processed_date = '{$batchDate}' 806 AND id IN ({$batchRemove})";
807 $sqlRs = db_query($sql, $pAdmEnv[
'dbh']);
809 throw new Exception(
"Failed to remove transactions", 200);
811 }
catch (Exception $ex) {
812 $returnInfo[
"errors"] = $ex->getMessage();
813 $returnInfo[
"code"] = $ex->getCode();
829 function SendACHNotifications( $pAdmEnv, $pTransHdrIds ) {
830 $returnInfo = array(
"code" =>
"000",
"errors" =>
"",
"data" => array());
835 $achNotifyEmail =
"";
836 $achNotifyTemplate =
"";
840 $sql =
"SELECT email FROM cuadmnotify WHERE cu='{$pAdmEnv['Cu']}' AND role = 'achnotify'";
841 $sqlRs = db_query( $sql, $pAdmEnv[
'dbh'] );
843 throw new Exception(
"ACH Query Error - unable to get ACH notifications email: 100", 100 );
845 $sqlData = db_fetch_assoc($sqlRs, 0);
846 if (is_array($sqlData)) {
848 $achNotifyEmail = $sqlData[
'email'];
854 $sql =
"SELECT settings::json->>'achnotify' AS template FROM cuadmin WHERE cu='{$pAdmEnv['Cu']}'";
855 $sqlRs = db_query( $sql, $pAdmEnv[
'dbh'] );
857 throw new Exception(
"ACH Query Error - unable to get ACH notifications email template: 101", 101 );
859 $sqlData = db_fetch_assoc($sqlRs, 0);
860 if (HCU_array_key_value(
"template", $sqlData)) {
862 $achNotifyTemplate = $sqlData[
'template'];
867 $inputList = explode(
",", $pTransHdrIds );
868 for ( $i = 0; $i < count( $inputList ); $i++ ) {
869 if ( ctype_digit( $inputList[$i] ) ) {
870 $idList[] = $inputList[$i];
874 $idString = implode(
",", $idList );
877 if ( strlen( $idString ) > 0 ) {
880 SELECT dtl.id, dtl.amount, dtl.transdata, hdr.processed_date, hdr.feature_code, grp.group_name 881 FROM {$pAdmEnv['Cu']}transdtl dtl 882 LEFT JOIN {$pAdmEnv['Cu']}transhdr hdr ON hdr.id = dtl.transhdr_id 883 LEFT JOIN {$pAdmEnv['Cu']}user usr ON usr.user_id = hdr.posted_by 884 LEFT JOIN {$pAdmEnv['Cu']}group grp ON grp.group_id = usr.group_id 885 WHERE dtl.transhdr_id IN ($idString) 886 AND dtl.email_notify = 1";
887 $sqlRs = db_query( $sql, $pAdmEnv[
'dbh'] );
890 while ($row = db_fetch_array($sqlRs, $dataRow++)) {
891 $row[
'transdata'] = HCU_JsonDecode($row[
'transdata']);
895 if ($row[
'feature_code'] ==
"ACHPMT" || $row[
'feature_code'] ==
"ACHCOL") {
896 if ($achNotifyEmail ==
"") {
897 throw new Exception(
"ACH Notifications Error - ACH notifications email was not found: 103", 103 );
900 if ($achNotifyTemplate ==
"") {
901 throw new Exception(
"ACH Notifications Error - ACH notifications template was not found: 104", 104 );
906 $achNotifyMessage = BuildACHNotification( $pAdmEnv, $row, $achNotifyTemplate );
907 if ($achNotifyMessage[
'code'] !==
'000') {
908 throw new Exception(
"ACH Notifications Error - Unable to build ACH notifications email: 105", 105 );
913 $notify->header =
"Content-Type: text/html";
914 $notify->mailto = $achNotifyMessage[
'data'][
'email'];
915 $notify->mailfrom = $achNotifyEmail;
916 $notify->subject =
"Funds Transfer Notice";
917 $notify->msgbody = $achNotifyMessage[
'data'][
'message'];
918 $notify->callingfunction = __FUNCTION__;
919 $notify->file = __FILE__;
920 $notify->cu = $pAdmEnv[
'Cu'];
928 $sqlUpd =
"UPDATE {$pAdmEnv['Cu']}transdtl SET email_notify=2 WHERE id={$row['id']}";
929 $sqlUpdRs = db_query( $sqlUpd, $pAdmEnv[
'dbh'] );
931 throw new Exception(
"ACH Query Error - unable to update ACH upload file details: 106", 106 );
944 $sql =
"UPDATE {$pAdmEnv['Cu']}transhdr SET processed_status=30 WHERE id IN ($idString)";
945 $sqlRs = db_query( $sql, $pAdmEnv[
'dbh'] );
947 throw new Exception(
"ACH Query Error - unable to update ACH upload file processed: 107", 107 );
950 throw new Exception(
"ACH Query Error - unable to get partner emails: 108", 108 );
953 }
catch (Exception $ex) {
954 $returnInfo[
"errors"] = $ex->getMessage();
955 $returnInfo[
"code"] = $ex->getCode();
971 function GetProcessedHeaders( $pAdmEnv, $pProcessedDate ) {
972 $batch = HCU_PayloadDecode($pAdmEnv[
'Cu'], $pProcessedDate);
973 $batchDate = $batch[
'batch_date'];
975 $sql =
"SELECT id FROM {$pAdmEnv['Cu']}transhdr WHERE processed_date = '$batchDate'";
976 $sqlRs = db_query( $sql, $pAdmEnv[
'dbh'] );
978 throw new Exception(
"ACH Query Error - unable to get ACH upload file information", 102 );
982 $inputList = array();
983 while ($row = db_fetch_assoc( $sqlRs, $rowIndex++ )) {
984 $inputList[] = $row[
'id'];
987 $idString = implode(
",", $inputList);
1002 function BuildACHNotification( $pAdmEnv, $pTransData, $pTemplate ) {
1003 $returnInfo = array(
"code" =>
"000",
"errors" =>
"",
"data" => array());
1006 $stringData = array();
1009 $stringReplacements = array(
1011 "{{company}}",
"{{transactiontype}}",
"{{amount}}",
"{{date}}",
1013 "{{accountname}}",
"{{routing}}",
"{{accountnumber}}",
"{{accounttype}}" 1018 $stringData[] = $pTransData[
'group_name'];
1019 $stringData[] = is_array($pTransData[
'transdata'][
'acct_source']) ?
"withdrawal" :
"deposit";
1020 $stringData[] = $pTransData[
'amount'];
1022 $date =
new DateTime( $pTransData[
'processed_date'] );
1023 $stringData[] = date_format($date,
"m/d/Y");
1025 $acctInfo = is_array($pTransData[
'transdata'][
'acct_source']) ?
1026 $pTransData[
'transdata'][
'acct_source'] :
1027 $pTransData[
'transdata'][
'acct_dest'];
1029 $stringData[] = $acctInfo[
'remote_entity'][
'name'];
1030 $stringData[] = $acctInfo[
'rdfi'][
'rdfi_routing'];
1032 $stringData[] = strlen($acctInfo[
'rdfi'][
'rdfi_account']) > 2 ?
1033 "ending in " . substr($acctInfo[
'rdfi'][
'rdfi_account'], -2) :
1034 "ending in " . $acctInfo[
'rdfi'][
'rdfi_account'];
1035 $stringData[] = $acctInfo[
'rdfi'][
'rdfi_account_type'] == 10 ?
"Checking" :
"Savings";
1038 $emailBody = $pTemplate;
1039 for ($i = 0; $i < count($stringReplacements); $i++) {
1041 $emailBody = str_replace($stringReplacements[$i], $stringData[$i], $emailBody);
1045 $returnInfo[
'data'][
'email'] = $acctInfo[
'remote_entity'][
'email'];
1046 $returnInfo[
'data'][
'message'] = $emailBody;
1048 }
catch (Exception $ex) {
1049 $returnInfo[
"errors"] = $ex->getMessage();
1050 $returnInfo[
"code"] =
"999";
1065 function CancelACHTrans( $pAdmEnv, $pTransList ) {
1066 $returnInfo = array(
"code" =>
"000",
"errors" =>
"",
"data" => array());
1071 $inputList = explode(
",", $pTransList );
1072 for ( $i = 0; $i < count( $inputList ); $i++ ) {
1073 if ( ctype_digit( $inputList[$i] ) ) {
1074 $idList[] = $inputList[$i];
1078 $idString = implode(
",", $idList );
1080 if ( strlen( $idString ) > 0 ) {
1082 $sql =
"SELECT now() AT TIME ZONE 'UTC'";
1083 $rs = db_query( $sql, $pAdmEnv[
"dbh"] );
1085 list( $processedStamp ) = db_fetch_array( $rs, 0 );
1087 throw new Exception(
"ACH Query Error - unable to get timestamp" );
1090 $sql =
"UPDATE {$pAdmEnv["Cu
"]}transhdr SET processed_status = 99, 1091 processed_date = '$processedStamp', 1092 processed_by = '{$pAdmEnv["Cn
"]}' 1093 WHERE id in ($idString) ";
1094 $rs = db_query( $sql, $pAdmEnv[
"dbh"] );
1096 throw new Exception(
"ACH Query Error - cancel" );
1100 $returnInfo[
"data"] = $idString;
1102 throw new Exception(
"ACH Cancel Error - invalid list" );
1104 }
catch (Exception $ex) {
1105 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
1107 $returnInfo[
"errors"] = $ex->getMessage();
1108 $returnInfo[
"code"] =
"999";
1124 function MakeACHBatch( $pAdmEnv, $pAdmVars ) {
1125 $returnInfo = array(
"code" =>
"000",
"errors" => array(),
"data" => array());
1130 $adminAchSettings = AdminReadSettings($pAdmEnv, $pAdmEnv[
"dbh"], $pAdmEnv[
"Cu"]);
1132 $cuRouting = trim( $adminAchSettings[
"settings"][
"routing"] );
1133 if ( strlen( $cuRouting ) != 9 ) {
1134 throw new Exception(
"ACH Settings - invalid CU routing number", 300 );
1138 $transIdList = $pAdmVars[
"trans_list"];
1140 $inputList = explode(
",", $transIdList );
1141 for ( $i = 0; $i < count( $inputList ); $i++ ) {
1142 if ( ctype_digit( $inputList[$i] ) ) {
1143 $idList[] = $inputList[$i];
1147 $idString = implode(
",", $idList );
1149 if ( strlen( $idString ) > 0 ) {
1150 $tz = GetCreditUnionTimezone( $pAdmEnv[
"dbh"], $pAdmEnv[
"Cu"] );
1153 $sql =
"SELECT now() AT TIME ZONE 'UTC'";
1154 $rs = db_query( $sql, $pAdmEnv[
"dbh"] );
1156 list( $processedStamp ) = db_fetch_array( $rs, 0 );
1158 throw new Exception(
"ACH Query Error - unable to get timestamp" );
1161 $sql =
"UPDATE {$pAdmEnv["Cu
"]}transhdr SET processed_by = '{$pAdmEnv["Cn
"]}', 1162 processed_date = '$processedStamp', 1163 processed_status = 10 1164 WHERE id in ($idString) ";
1165 $rs = db_query( $sql, $pAdmEnv[
"dbh"] );
1167 throw new Exception(
"ACH Query Error - recording ACH upload file" );
1171 $payload = array(
"batch_date" => $processedStamp );
1172 $encodedBatchId = HCU_PayloadEncode( $pAdmEnv[
"Cu"], $payload );
1173 $returnInfo[
"data"][
"batch_id"] = $encodedBatchId;
1176 $myDateTime =
new DateTime($processedStamp);
1177 $myDateTime->setTimezone(
new DateTimeZone($tz));
1178 $formatted = $myDateTime->format(
"m/d/y H:i:s T");
1180 $returnInfo[
"data"][
"batch_time"] = $formatted;
1183 throw new Exception(
"Error Building ACH Upload File - invalid transaction list" );
1185 }
catch (Exception $ex) {
1186 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
1188 $returnInfo[
"errors"][] = $ex->getMessage();
1190 if ($ex->getCode() == 300) {
1191 $returnInfo[
"errors"][] =
"This feature requires a valid routing number on the <a href=\"main.prg?ft=54\">Settings</a> screen.";
1193 $returnInfo[
"code"] =
"999";
1207 function GetCompletedBatches( $pAdmEnv ) {
1208 $returnInfo = array(
"code" =>
"000",
"errors" => array(),
"data" => array());
1211 $cu = strtolower( $pAdmEnv[
"Cu"] );
1213 $batchPreName =
"Batch";
1214 $batchPath =
"/home/{$cu}/admin/ach/";
1217 if ( !file_exists( $batchPath ) ) {
1218 throw new Exception(
"Get Completed ACH Files Error - Directory does not exist - please contact Support" );
1222 $tz = GetCreditUnionTimezone( $pAdmEnv[
"dbh"], $pAdmEnv[
"Cu"] );
1227 th.processed_date, th.processed_by, 1228 COUNT(DISTINCT th.id) AS count, 1229 SUM(CASE WHEN (th.feature_code = 'ACHPMT' OR th.feature_code = 'ACHCOL') AND td.email_notify = 1 THEN 1 ELSE 0 END) AS notify 1230 FROM {$cu}transhdr AS th 1231 JOIN {$cu}transdtl AS td ON th.id = td.transhdr_id 1232 WHERE th.processed_date IS NOT NULL 1233 AND th.processed_status >= 10 1234 AND th.processed_status <= 30 1235 AND th.feature_code IN ('TRNEXT', 'ACHCOL', 'ACHPMT') 1236 GROUP BY processed_date, processed_by 1237 ORDER BY processed_date DESC";
1238 $rs = db_query( $sql, $pAdmEnv[
"dbh"] );
1240 throw new Exception(
"ACH Query Error - getting approved ach txns" );
1245 $returnData = array();
1246 while ( $txRow = db_fetch_assoc( $rs, $row++ ) ) {
1248 $myDateTime =
new DateTime( $txRow[
"processed_date"] );
1251 $myDateTime->setTimezone(
new DateTimeZone($tz));
1252 $batchDay = $myDateTime->format(
"ymd");
1253 $batchHour = $myDateTime->format(
"His");
1255 $baseFileName =
"{$batchPreName}_{$batchDay}_{$batchHour}";
1258 $formatted = $myDateTime->format(
"m/d/y H:i:s T ");
1260 $payload = array(
"batch_date" => $txRow[
"processed_date"] );
1261 $encodedBatchId = HCU_PayloadEncode( $pAdmEnv[
"Cu"], $payload );
1263 $returnData[] = array(
"batch_id" => $encodedBatchId,
1264 "processed_by" => $txRow[
"processed_by"],
1265 "count" => $txRow[
"count"],
1266 "notify" => $txRow[
"notify"],
1267 "display" => $formatted,
1268 "has_ach_file" => file_exists(
"{$batchPath}{$baseFileName}.ach" ),
1269 "has_ach_report" => file_exists(
"{$batchPath}{$baseFileName}.txt" )
1273 $returnInfo[
"data"] = $returnData;
1274 }
catch (Exception $ex) {
1275 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
1277 $returnInfo[
"errors"] = $ex->getMessage();
1278 $returnInfo[
"code"] =
"999";
1293 function GetBatchDetail( $pAdmEnv, $pAdmVars ) {
1294 $returnInfo = array(
"code" =>
"000",
"errors" => array(),
"data" => array());
1297 $payloadInfo = HCU_PayloadDecode( $pAdmEnv[
"Cu"], $pAdmVars[
"batch_id"] );
1298 $batchTimestamp = $payloadInfo[
"batch_date"];
1303 $removeTransactionsTime = time() - $pAdmEnv[
'removeFromBatchTime'] * 24 * 60 * 60;
1304 $removeBatchTime = strtotime($payloadInfo[
"batch_date"]);
1307 $sql =
"SELECT id, feature_code, effective_date, u1.user_name AS poster, posted_date, 1308 u2.user_name AS approver, approved_date, accountnumber, 1309 transactioncode, memo, group_name, (select sum(amount) from {$pAdmEnv["Cu
"]}transdtl d where d.transhdr_id = th.id) as amount 1310 FROM {$pAdmEnv["Cu
"]}transhdr th 1311 LEFT JOIN {$pAdmEnv["Cu
"]}user u1 ON u1.user_id = th.posted_by 1312 LEFT JOIN {$pAdmEnv["Cu
"]}user u2 ON u2.user_id = th.approved_by 1313 INNER JOIN {$pAdmEnv["Cu
"]}group g ON g.group_id = u1.group_id 1314 WHERE processed_date = '$batchTimestamp' 1315 AND processed_status >= 10 1316 ORDER BY group_name, feature_code, id";
1317 $rs = db_query( $sql, $pAdmEnv[
"dbh"] );
1319 throw new Exception(
"ACH Query Error - getting approved ach txns" );
1324 $returnData = array();
1325 while ( $txRow = db_fetch_assoc( $rs, $row++ ) ) {
1327 $timestamp = strtotime( $txRow[
"effective_date"] );
1328 $account = trim( $txRow[
"accountnumber"] );
1329 $returnData[] = array(
"id" => $txRow[
"id"],
1330 "feature" => trim( $txRow[
"feature_code"] ),
1331 "eff_date" => date(
"m/d/Y", $timestamp ),
1332 "group" => $txRow[
"group_name"],
1333 "account" => $account,
1334 "amount" => $txRow[
"amount"],
1335 "memo" => $txRow[
"memo"]
1339 $returnInfo[
"data"][
"records"] = $returnData;
1340 $returnInfo[
"data"][
"removeFromBatchAllowed"] = !($removeBatchTime < $removeTransactionsTime);
1341 }
catch (Exception $ex) {
1342 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
1344 $returnInfo[
"errors"] = $ex->getMessage();
1345 $returnInfo[
"code"] =
"999";
1360 function DownloadAchFile( $pAdmEnv, $pAdmVars ) {
1361 $returnInfo = array(
"code" =>
"000",
"errors" => array(),
"data" => array());
1364 $cu = strtolower( $pAdmEnv[
"Cu"] );
1366 $payloadInfo = HCU_PayloadDecode( $pAdmEnv[
"Cu"], $pAdmVars[
"batch_id"] );
1367 $batchTimeString = $payloadInfo[
"batch_date"];
1370 $tz = GetCreditUnionTimezone( $pAdmEnv[
"dbh"], $pAdmEnv[
"Cu"] );
1373 $myDateTime =
new DateTime( $batchTimeString );
1374 $myDateTime->setTimezone(
new DateTimeZone($tz));
1375 $batchDay = $myDateTime->format(
"ymd");
1376 $batchHour = $myDateTime->format(
"His");
1379 $batchPreName =
"Batch";
1380 $batchPath =
"/home/{$cu}/admin/ach/";
1382 $fileType = ( $pAdmVars[
"download_type"] ===
"ach" ) ?
"ach" :
"txt";
1383 $achFileName =
"{$batchPreName}_{$batchDay}_{$batchHour}.{$fileType}";
1386 $fileString = file_get_contents(
"{$batchPath}{$achFileName}" );
1387 if ( $fileString ===
false ) {
1388 throw new Exception(
"Error Building ACH Upload File - ACH upload file not found" );
1391 $returnInfo[
"data"][
"filename"] = $achFileName;
1392 $returnInfo[
"data"][
"output"] = $fileString;
1393 }
catch (Exception $ex) {
1394 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
1396 $returnInfo[
"errors"] = $ex->getMessage();
1397 $returnInfo[
"code"] =
"999";
1404 function GetACHTransactionHeaders( $pAdmEnv, $pBatchTimeString ) {
1409 $sql =
"SELECT 0 as processed, group_name, tax_id, th.* 1410 FROM {$pAdmEnv["Cu
"]}transhdr th 1411 LEFT JOIN {$pAdmEnv["Cu
"]}user u1 ON u1.user_id = th.posted_by 1412 INNER JOIN {$pAdmEnv["Cu
"]}group g ON g.group_id = u1.group_id 1413 WHERE processed_date = '$pBatchTimeString' 1414 AND processed_status >= 10 1415 AND processed_status <= 30 1416 ORDER BY group_name";
1417 $hdrRS = db_query( $sql, $pAdmEnv[
"dbh"] );
1420 while ( $rowHdr = db_fetch_assoc( $hdrRS, $hdrRow++ ) ) {
1421 $retInfo[] = $rowHdr;
1443 function AddMicroDeposits( $pAdmEnv, &$pTransactionHeaders, $pInputParams, &$pAchValues, &$pOutputData, &$pReportLines ) {
1450 $returnInfo = array(
"code" =>
"000",
"error" =>
"" );
1454 $microDepositList = array();
1455 for ( $i = 0; $i < count( $pTransactionHeaders ); $i++ ) {
1456 if ( $pTransactionHeaders[$i][
"feature_code"] ==
"TRNEXT" &&
1457 $pTransactionHeaders[$i][
"transactioncode"] ==
"1P" ) {
1458 $microDepositList[] = $pTransactionHeaders[$i];
1462 $microList = array();
1463 for ( $i = 0; $i < count( $microDepositList ); $i++ ) {
1465 $sql =
"SELECT * FROM {$pAdmEnv["Cu
"]}transdtl WHERE transhdr_id = {$microDepositList[$i]["id"]}";
1466 $dtlRS = db_query( $sql, $pAdmEnv[
"dbh"] );
1468 throw new Exception(
"ACH Query Error - getting microdeposit ach txns" );
1472 while ( $microDtl = db_fetch_assoc( $dtlRS, $microRow++ ) ) {
1473 $microList[] = $microDtl;
1477 $companyEntryAddendaCount = 0;
1478 if ( count( $microList ) > 0 ) {
1480 $pAchValues[
"batchNumber"]++;
1482 $entriesList = array();
1484 $companyID = $pInputParams[
'CompanyIDType'] . $pInputParams[
"OriginatingRouting"];
1487 $companyHeader = array(
"RecordTypeCode" =>
"5",
1488 "ServiceClassCode" =>
"220",
1489 "CompanyName" => MakeValidAchString( $pInputParams[
"CompanyName"], 16 ),
1490 "CompanyData" => str_repeat(
" ", 20 ),
1491 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
1492 "StandardEntryClassCode" =>
"WEB",
1493 "CompanyEntryDescription" => MakeValidAchString( $pInputParams[
"CompanyEntryDescription"], 10 ),
1494 "CompanyDescriptiveDate" => str_repeat(
" ", 6 ),
1495 "EffectiveEntryDate" => MakeValidAchString( $pInputParams[
"EffectiveEntryDate"], 6 ),
1496 "SettlementDate" => str_repeat(
" ", 3 ),
1497 "OriginatorStatusCode" =>
"1",
1498 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
1499 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
1500 $entriesList[] = $companyHeader;
1502 $totalMicroAmount = 0;
1503 $companyControlHash = 0;
1504 for ( $i = 0; $i < count( $microList ); $i++ ) {
1508 $transData = HCU_JsonDecode( $microList[$i][
"transdata"],
true );
1511 if ( strlen( $transData[
"acct_dest"][
"rdfi"][
"rdfi_routing"] ) != 9 ) {
1512 throw new Exception(
"ACH File Creation - invalid routing number (location 111)" );
1515 $receivingDFIRouting = substr( $transData[
"acct_dest"][
"rdfi"][
"rdfi_routing"], 0, 8 );
1516 $receivingCheckDigit = substr( $transData[
"acct_dest"][
"rdfi"][
"rdfi_routing"], -1 );
1517 $account = str_replace(
" ",
"", $transData[
"acct_dest"][
"rdfi"][
"rdfi_account"] );
1518 $receivingDFIAccount = MakeValidAchString( $account, 17 );
1519 $receivingAccountType = $transData[
"acct_dest"][
"rdfi"][
"rdfi_account_type"];
1520 $receivingTxnType = $transData[
"acct_dest"][
"rdfi"][
"rdfi_txn_type"];
1522 $actualAmount = trim( $microList[$i][
"amount"] );
1523 $totalMicroAmount += $actualAmount;
1525 $roundAmount = round( $actualAmount * 100 );
1526 $amount = str_pad( $roundAmount, 10,
"0", STR_PAD_LEFT );
1529 $individualID = MakeValidAchString( $pInputParams[
"OriginatingRouting"], 15 );
1531 $individualName = MakeValidAchString( $transData[
"acct_dest"][
"remote_entity"][
"name"], 22 );
1534 $transactionCode = $receivingAccountType == 10 ?
"22" : ( $receivingAccountType == 20 ?
"32" :
"00" );
1536 if ( $transactionCode ==
"00" ) {
1537 throw new Exception(
"Error Building ACH Upload File (micro deposit) - could not determine transaction code" );
1540 $discretionaryData = str_pad(
"S", 2,
" ", STR_PAD_RIGHT);
1543 $pAchValues[
"traceNumber"]++;
1544 $pAchValues[
"fileEntryAddendaCount"]++;
1545 $companyEntryAddendaCount++;
1546 $entryDetail = array (
"RecordTypeCode" =>
"6",
1547 "TransactionCode" => $transactionCode,
1548 "ReceivingDFI" => $receivingDFIRouting,
1549 "CheckDigit" => $receivingCheckDigit,
1550 "DFIAccountNumber" => $receivingDFIAccount,
1551 "Amount" => $amount,
1552 "IndividualIdentificationNumber" => $individualID,
1553 "IndividualName" => strtoupper( $individualName ),
1554 "DiscretionaryData" => $discretionaryData,
1555 "AddendaRecordIndicator" =>
"0",
1556 "TraceNumber" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ) . substr(
"000000" . $pAchValues[
"traceNumber"], -7 ) );
1558 $entriesList[] = $entryDetail;
1561 $companyControlHash += $receivingDFIRouting;
1562 $pAchValues[
"fileControlHash"] += $receivingDFIRouting;
1564 $formattedAmount = number_format( $actualAmount, 2,
".",
"," );
1565 $pReportLines[] =
" Micro deposit credit of $formattedAmount to " . str_replace(
' ',
'',
"$receivingDFIRouting$receivingCheckDigit") .
" / " . trim( $receivingDFIAccount );
1570 $entryHash = substr( str_repeat(
"0", 10 ) . $companyControlHash, -10 );
1573 $finalMicroAmount = round( $totalMicroAmount * 100 );
1576 $companyControl = array (
"RecordTypeCode" =>
"8",
1577 "ServiceClassCode" =>
"220",
1578 "EntryAddendaCount" => str_pad( $companyEntryAddendaCount, 6,
"0", STR_PAD_LEFT ),
1579 "EntryHash" => $entryHash,
1580 "TotalDebitEntryDollarAmount" => str_pad( 0, 12,
"0", STR_PAD_LEFT ),
1581 "TotalCreditEntryDollarAmount" => str_pad( $finalMicroAmount, 12,
"0", STR_PAD_LEFT ),
1582 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
1583 "MessageAuthenticationCode" => str_repeat(
" ", 19 ),
1584 "Reserved" => str_repeat(
" ", 6 ),
1585 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
1586 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
1588 $entriesList[] = $companyControl;
1589 $pAchValues[
"fileBatchCount"]++;
1592 $pAchValues[
"batchNumber"]++;
1593 $companyHeader = array(
"RecordTypeCode" =>
"5",
1594 "ServiceClassCode" =>
"225",
1595 "CompanyName" => MakeValidAchString( $pInputParams[
"CompanyName"], 16 ),
1596 "CompanyData" => str_repeat(
" ", 20 ),
1597 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
1598 "StandardEntryClassCode" =>
"CCD",
1599 "CompanyEntryDescription" => MakeValidAchString( $pInputParams[
"CompanyEntryDescription"], 10 ),
1600 "CompanyDescriptiveDate" => str_repeat(
" ", 6 ),
1601 "EffectiveEntryDate" => MakeValidAchString( $pInputParams[
"EffectiveEntryDate"], 6 ),
1602 "SettlementDate" => str_repeat(
" ", 3 ),
1603 "OriginatorStatusCode" =>
"1",
1604 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
1605 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
1606 $entriesList[] = $companyHeader;
1608 $companyControlHash = 0;
1611 $receivingDFIRouting = substr( $pInputParams[
"OriginatingRouting"], 0, 8 );
1612 $receivingCheckDigit = substr( $pInputParams[
"OriginatingRouting"], -1 );
1614 $individualID = MakeValidAchString( $pInputParams[
"OriginatingRouting"], 15 );
1615 $individualName = MakeValidAchString( $pInputParams[
"CompanyName"], 22 );
1617 $pAchValues[
"traceNumber"]++;
1618 $pAchValues[
"fileEntryAddendaCount"]++;
1619 $entryDetail = array (
"RecordTypeCode" =>
"6",
1620 "TransactionCode" =>
"47",
1621 "ReceivingDFI" => $receivingDFIRouting,
1622 "CheckDigit" => $receivingCheckDigit,
1623 "DFIAccountNumber" => MakeValidAchString( $pInputParams[
"accountMicroDeposit"], 17 ),
1624 "Amount" => str_pad( $finalMicroAmount, 10,
"0", STR_PAD_LEFT ),
1625 "IndividualIdentificationNumber" => $individualID,
1626 "IndividualName" => strtoupper( $individualName ),
1627 "DiscretionaryData" =>
" ",
1628 "AddendaRecordIndicator" =>
"0",
1629 "TraceNumber" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ) . substr(
"000000" . $pAchValues[
"traceNumber"], -7 ) );
1630 $entriesList[] = $entryDetail;
1632 $formattedAmount = number_format( $totalMicroAmount, 2,
".",
"," );
1633 $pReportLines[] =
" Total from CU account: $formattedAmount from " . trim( $pInputParams[
"OriginatingRouting"] ) .
" / " . trim( $pInputParams[
"accountMicroDeposit"] );
1636 $companyControlHash += $receivingDFIRouting;
1637 $pAchValues[
"fileControlHash"] += $receivingDFIRouting;
1640 $entryHash = substr( str_repeat(
"0", 10 ) . $companyControlHash, -10 );
1643 $companyEntryAddendaCount = 1;
1644 $companyControl = array (
"RecordTypeCode" =>
"8",
1645 "ServiceClassCode" =>
"225",
1646 "EntryAddendaCount" => str_pad( $companyEntryAddendaCount, 6,
"0", STR_PAD_LEFT ),
1647 "EntryHash" => $entryHash,
1648 "TotalDebitEntryDollarAmount" => str_pad( $finalMicroAmount, 12,
"0", STR_PAD_LEFT ),
1649 "TotalCreditEntryDollarAmount" => str_pad( 0, 12,
"0", STR_PAD_LEFT ),
1650 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
1651 "MessageAuthenticationCode" => str_repeat(
" ", 19 ),
1652 "Reserved" => str_repeat(
" ", 6 ),
1653 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
1654 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
1656 $entriesList[] = $companyControl;
1657 $pAchValues[
"fileBatchCount"]++;
1660 $pAchValues[
"totalFileCredit"] += $finalMicroAmount;
1661 $pAchValues[
"totalFileDebit"] += $finalMicroAmount;
1664 for ( $i = 0; $i < count( $entriesList ); $i++ ) {
1665 $item = array_values( $entriesList[$i] );
1667 $outputLine = implode(
"", $item );
1668 if ( strlen( $outputLine ) != 94 ) {
1669 throw new Exception(
"ACH Output Error - micro deposit block size" );
1672 $pOutputData[] = $outputLine;
1676 for ( $i = 0; $i < count( $pTransactionHeaders ); $i++ ) {
1677 if ( $pTransactionHeaders[$i][
"feature_code"] ==
"TRNEXT" &&
1678 $pTransactionHeaders[$i][
"transactioncode"] ==
"1P" ) {
1679 $pTransactionHeaders[$i][
"processed"] =
true;
1684 $pReportLines[] =
" None";
1687 }
catch (Exception $ex) {
1688 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
1690 $returnInfo[
"error"] = $ex->getMessage();
1691 $returnInfo[
"code"] =
"999";
1713 function AddMicroDepositOffsets( $pAdmEnv, &$pTransactionHeaders, $pInputParams, &$pAchValues, &$pOutputData, &$pReportLines ) {
1720 $returnInfo = array(
"code" =>
"000",
"error" =>
"" );
1724 $microDepositList = array();
1725 for ( $i = 0; $i < count( $pTransactionHeaders ); $i++ ) {
1726 if ( $pTransactionHeaders[$i][
"feature_code"] ==
"TRNEXT" &&
1727 $pTransactionHeaders[$i][
"transactioncode"] ==
"2P" ) {
1728 $microDepositList[] = $pTransactionHeaders[$i];
1732 $microList = array();
1733 for ( $i = 0; $i < count( $microDepositList ); $i++ ) {
1735 $sql =
"SELECT * FROM {$pAdmEnv["Cu
"]}transdtl WHERE transhdr_id = {$microDepositList[$i]["id"]}";
1736 $dtlRS = db_query( $sql, $pAdmEnv[
"dbh"] );
1738 throw new Exception(
"ACH Query Error - getting microdeposit offset ach txns" );
1742 $microDtl = db_fetch_assoc( $dtlRS, 0 );
1743 $microList[] = $microDtl;
1746 $companyEntryAddendaCount = 0;
1747 if ( count( $microList ) > 0 ) {
1749 $pAchValues[
"batchNumber"]++;
1751 $entriesList = array();
1753 $companyID = $pInputParams[
'CompanyIDType'] . $pInputParams[
"OriginatingRouting"];
1756 $companyHeader = array(
"RecordTypeCode" =>
"5",
1757 "ServiceClassCode" =>
"225",
1758 "CompanyName" => MakeValidAchString( $pInputParams[
"CompanyName"], 16 ),
1759 "CompanyData" => str_repeat(
" ", 20 ),
1760 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
1761 "StandardEntryClassCode" =>
"WEB",
1762 "CompanyEntryDescription" => MakeValidAchString( $pInputParams[
"CompanyEntryDescription"], 10 ),
1763 "CompanyDescriptiveDate" => str_repeat(
" ", 6 ),
1764 "EffectiveEntryDate" => MakeValidAchString( $pInputParams[
"EffectiveEntryDate"], 6 ),
1765 "SettlementDate" => str_repeat(
" ", 3 ),
1766 "OriginatorStatusCode" =>
"1",
1767 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
1768 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
1769 $entriesList[] = $companyHeader;
1771 $totalMicroAmount = 0;
1772 $companyControlHash = 0;
1773 for ( $i = 0; $i < count( $microList ); $i++ ) {
1777 $transData = HCU_JsonDecode( $microList[$i][
"transdata"],
true );
1780 if ( strlen( $transData[
"acct_source"][
"rdfi"][
"rdfi_routing"] ) != 9 ) {
1781 throw new Exception(
"ACH File Creation - invalid routing number (location 112)" );
1784 $receivingDFIRouting = substr( $transData[
"acct_source"][
"rdfi"][
"rdfi_routing"], 0, 8 );
1785 $receivingCheckDigit = substr( $transData[
"acct_source"][
"rdfi"][
"rdfi_routing"], -1 );
1786 $account = str_replace(
" ",
"", $transData[
"acct_source"][
"rdfi"][
"rdfi_account"] );
1787 $receivingDFIAccount = MakeValidAchString( $account, 17 );
1788 $receivingAccountType = $transData[
"acct_source"][
"rdfi"][
"rdfi_account_type"];
1789 $receivingTxnType = $transData[
"acct_source"][
"rdfi"][
"rdfi_txn_type"];
1791 $actualAmount = trim( $microList[$i][
"amount"] );
1792 $totalMicroAmount += $actualAmount;
1794 $roundAmount = round( $actualAmount * 100 );
1795 $amount = str_pad( $roundAmount, 10,
"0", STR_PAD_LEFT );
1798 $individualID = MakeValidAchString( $pInputParams[
"OriginatingRouting"], 15 );
1800 $individualName = MakeValidAchString( $transData[
"acct_source"][
"remote_entity"][
"name"], 22 );
1803 $transactionCode = $receivingAccountType == 10 ?
"27" : ( $receivingAccountType == 20 ?
"37" :
"00" );
1805 if ( $transactionCode ==
"00" ) {
1806 throw new Exception(
"ACH Batch Build (micro deposit offset) - could not determine transaction code" );
1809 $discretionaryData = str_pad(
"S", 2,
" ", STR_PAD_RIGHT);
1812 $pAchValues[
"traceNumber"]++;
1813 $pAchValues[
"fileEntryAddendaCount"]++;
1814 $companyEntryAddendaCount++;
1815 $entryDetail = array (
"RecordTypeCode" =>
"6",
1816 "TransactionCode" => $transactionCode,
1817 "ReceivingDFI" => $receivingDFIRouting,
1818 "CheckDigit" => $receivingCheckDigit,
1819 "DFIAccountNumber" => $receivingDFIAccount,
1820 "Amount" => $amount,
1821 "IndividualIdentificationNumber" => $individualID,
1822 "IndividualName" => strtoupper( $individualName ),
1823 "DiscretionaryData" => $discretionaryData,
1824 "AddendaRecordIndicator" =>
"0",
1825 "TraceNumber" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ) . substr(
"000000" . $pAchValues[
"traceNumber"], -7 ) );
1826 $entriesList[] = $entryDetail;
1829 $companyControlHash += $receivingDFIRouting;
1830 $pAchValues[
"fileControlHash"] += $receivingDFIRouting;
1832 $formattedAmount = number_format( $actualAmount, 2,
".",
"," );
1833 $pReportLines[] =
" Micro deposit debit of $formattedAmount to " . str_replace(
' ',
'',
"$receivingDFIRouting$receivingCheckDigit") .
" / " . trim( $receivingDFIAccount );
1838 $entryHash = substr( str_repeat(
"0", 10 ) . $companyControlHash, -10 );
1841 $finalMicroAmount = round( $totalMicroAmount * 100 );
1844 $companyControl = array (
"RecordTypeCode" =>
"8",
1845 "ServiceClassCode" =>
"225",
1846 "EntryAddendaCount" => str_pad( $companyEntryAddendaCount, 6,
"0", STR_PAD_LEFT ),
1847 "EntryHash" => $entryHash,
1848 "TotalDebitEntryDollarAmount" => str_pad( $finalMicroAmount, 12,
"0", STR_PAD_LEFT ),
1849 "TotalCreditEntryDollarAmount" => str_pad( 0, 12,
"0", STR_PAD_LEFT ),
1850 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
1851 "MessageAuthenticationCode" => str_repeat(
" ", 19 ),
1852 "Reserved" => str_repeat(
" ", 6 ),
1853 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
1854 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
1856 $entriesList[] = $companyControl;
1857 $pAchValues[
"fileBatchCount"]++;
1860 $pAchValues[
"batchNumber"]++;
1861 $companyHeader = array(
"RecordTypeCode" =>
"5",
1862 "ServiceClassCode" =>
"220",
1863 "CompanyName" => MakeValidAchString( $pInputParams[
"CompanyName"], 16 ),
1864 "CompanyData" => str_repeat(
" ", 20 ),
1865 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
1866 "StandardEntryClassCode" =>
"CCD",
1867 "CompanyEntryDescription" => MakeValidAchString( $pInputParams[
"CompanyEntryDescription"], 10 ),
1868 "CompanyDescriptiveDate" => str_repeat(
" ", 6 ),
1869 "EffectiveEntryDate" => MakeValidAchString( $pInputParams[
"EffectiveEntryDate"], 6 ),
1870 "SettlementDate" => str_repeat(
" ", 3 ),
1871 "OriginatorStatusCode" =>
"1",
1872 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
1873 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
1874 $entriesList[] = $companyHeader;
1876 $companyControlHash = 0;
1879 $receivingDFIRouting = substr( $pInputParams[
"OriginatingRouting"], 0, 8 );
1880 $receivingCheckDigit = substr( $pInputParams[
"OriginatingRouting"], -1 );
1882 $individualID = MakeValidAchString( $pInputParams[
"OriginatingRouting"], 15 );
1883 $individualName = MakeValidAchString( $pInputParams[
"CompanyName"], 22 );
1885 $finalMicroAmount = round( $totalMicroAmount * 100 );
1887 $pAchValues[
"traceNumber"]++;
1888 $pAchValues[
"fileEntryAddendaCount"]++;
1889 $entryDetail = array (
"RecordTypeCode" =>
"6",
1890 "TransactionCode" =>
"42",
1891 "ReceivingDFI" => $receivingDFIRouting,
1892 "CheckDigit" => $receivingCheckDigit,
1893 "DFIAccountNumber" => MakeValidAchString( $pInputParams[
"accountMicroDeposit"], 17 ),
1894 "Amount" => str_pad( $finalMicroAmount, 10,
"0", STR_PAD_LEFT ),
1895 "IndividualIdentificationNumber" => $individualID,
1896 "IndividualName" => strtoupper( $individualName ),
1897 "DiscretionaryData" =>
" ",
1898 "AddendaRecordIndicator" =>
"0",
1899 "TraceNumber" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ) . substr(
"000000" . $pAchValues[
"traceNumber"], -7 ) );
1900 $entriesList[] = $entryDetail;
1902 $formattedAmount = number_format( $totalMicroAmount, 2,
".",
"," );
1903 $pReportLines[] =
" Total into CU account: $formattedAmount to " . trim( $pInputParams[
"OriginatingRouting"] ) .
" / " . trim( $pInputParams[
"accountMicroDeposit"] );
1906 $companyControlHash += $receivingDFIRouting;
1907 $pAchValues[
"fileControlHash"] += $receivingDFIRouting;
1910 $entryHash = substr( str_repeat(
"0", 10 ) . $companyControlHash, -10 );
1912 $companyEntryAddendaCount = 1;
1914 $companyControl = array (
"RecordTypeCode" =>
"8",
1915 "ServiceClassCode" =>
"220",
1916 "EntryAddendaCount" => str_pad( $companyEntryAddendaCount, 6,
"0", STR_PAD_LEFT ),
1917 "EntryHash" => $entryHash,
1918 "TotalDebitEntryDollarAmount" => str_pad( 0, 12,
"0", STR_PAD_LEFT ),
1919 "TotalCreditEntryDollarAmount" => str_pad( $finalMicroAmount, 12,
"0", STR_PAD_LEFT ),
1920 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
1921 "MessageAuthenticationCode" => str_repeat(
" ", 19 ),
1922 "Reserved" => str_repeat(
" ", 6 ),
1923 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
1924 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
1926 $entriesList[] = $companyControl;
1929 $pAchValues[
"fileBatchCount"]++;
1932 $pAchValues[
"totalFileCredit"] += $finalMicroAmount;
1933 $pAchValues[
"totalFileDebit"] += $finalMicroAmount;
1936 for ( $i = 0; $i < count( $entriesList ); $i++ ) {
1937 $item = array_values( $entriesList[$i] );
1939 $outputLine = implode(
"", $item );
1940 if ( strlen( $outputLine ) != 94 ) {
1941 throw new Exception(
"ACH Output Error - micro deposit block size" );
1944 $pOutputData[] = $outputLine;
1948 for ( $i = 0; $i < count( $pTransactionHeaders ); $i++ ) {
1949 if ( $pTransactionHeaders[$i][
"feature_code"] ==
"TRNEXT" &&
1950 $pTransactionHeaders[$i][
"transactioncode"] ==
"2P" ) {
1951 $pTransactionHeaders[$i][
"processed"] =
true;
1956 $pReportLines[] =
" None";
1959 }
catch (Exception $ex) {
1960 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
1962 $returnInfo[
"error"] = $ex->getMessage();
1963 $returnInfo[
"code"] =
"999";
1985 function BuildACHTransfer( $pAdmEnv, $pTxnHeader, $pInputParams, &$pAchValues, &$pOutputData, &$pReportLines ) {
1986 $returnInfo = array(
"code" =>
"000",
"error" =>
"" );
1990 $effDate = ACH_EnsureBusinessDay( $pAdmEnv, $pTxnHeader[
"effective_date"] );
1993 $effectiveDate = date(
"ymd", strtotime( $effDate .
" 3:00" ) );
1995 $adminAchSettings = AdminReadSettings($pAdmEnv, $pAdmEnv[
"dbh"], $pAdmEnv[
"Cu"]);
1997 $transferDirection = substr( $pTxnHeader[
"transactioncode"], 0, 1 );
2001 $sql =
"SELECT * FROM {$pAdmEnv["Cu
"]}transdtl WHERE transhdr_id = {$pTxnHeader["id"]}";
2002 $dtlRS = db_query( $sql, $pAdmEnv[
"dbh"] );
2004 throw new Exception(
"ACH Query Error - getting batch ach txns" );
2007 $detailRows = array();
2009 while ( $rowDtl = db_fetch_assoc( $dtlRS, $dtlRow++ ) ) {
2011 $transData = HCU_JsonDecode( $rowDtl[
"transdata"],
true );
2013 if ( empty( $transData ) ) {
2014 throw new Exception(
"ACH Error - transaction data is missing or corrupt" );
2017 $rowDtl[
"acct_source"] = $transData[
"acct_source"];
2018 $rowDtl[
"acct_dest"] = $transData[
"acct_dest"];
2020 $detailRows[] = $rowDtl;
2023 if ( count( $detailRows ) != 1 ) {
2024 throw new Exception(
"ACH Error - incorrect detail for ACH transfer. Need one detail row, found: " . count( $detailRows ) );
2028 $transferRow = $detailRows[0];
2031 $entryName = trim( $pTxnHeader[
"memo"] );
2032 if ( strlen( $entryName ) == 0 ) {
2033 $entryName =
"Online Funds Transfer";
2036 $companyID = $pInputParams[
'CompanyIDType'] . $pInputParams[
"OriginatingRouting"];
2039 $paymentSource = $transferRow[
"acct_source"];
2040 $paymentDestination = $transferRow[
"acct_dest"];
2047 $serviceClassCode =
"225";
2048 $pAchValues[
"batchNumber"]++;
2050 $companyHeader = array(
"RecordTypeCode" =>
"5",
2051 "ServiceClassCode" => $serviceClassCode,
2052 "CompanyName" => MakeValidAchString( $pInputParams[
"CompanyName"], 16 ),
2053 "CompanyData" => str_repeat(
" ", 20 ),
2054 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
2055 "StandardEntryClassCode" =>
"WEB",
2056 "CompanyEntryDescription" => MakeValidAchString( $entryName, 10 ),
2057 "CompanyDescriptiveDate" => str_repeat(
" ", 6 ),
2058 "EffectiveEntryDate" => $effectiveDate,
2059 "SettlementDate" => str_repeat(
" ", 3 ),
2060 "OriginatorStatusCode" =>
"1",
2061 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
2062 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
2065 $header = array_values( $companyHeader );
2067 $outputLine = implode(
"", $header );
2068 if ( strlen( $outputLine ) != 94 ) {
2069 throw new Exception(
"ACH Output Error - company header block size (location 101)" );
2071 $pOutputData[] = $outputLine;
2073 if ( strlen( $transData[
"acct_source"][
"rdfi"][
"rdfi_routing"] ) != 9 ) {
2074 throw new Exception(
"ACH File Creation - invalid routing number (location 112)" );
2077 $receivingDFIRouting = substr( $paymentSource[
"rdfi"][
"rdfi_routing"], 0, 8 );
2078 $receivingCheckDigit = substr( $paymentSource[
"rdfi"][
"rdfi_routing"], -1 );
2079 $account = str_replace(
" ",
"", $paymentSource[
"rdfi"][
"rdfi_account"] );
2080 $receivingDFIAccount = MakeValidAchString( $account, 17 );
2082 $printableSourceAccount =
"{$paymentSource["rdfi
"]["rdfi_routing
"]} / $account";
2084 $roundAmount = round( $transferRow[
"amount"] * 100 );
2085 $amount = str_pad( $roundAmount, 10,
"0", STR_PAD_LEFT );
2088 $fullName = $paymentSource[
"remote_entity"][
"name"];
2089 $individualID = MakeValidAchString( substr( $fullName, -15 ), 15 );
2091 $individualName = MakeValidAchString( $entryName, 22 );
2094 $pAchValues[
"totalFileDebit"] += $roundAmount;
2097 $pAchValues[
"traceNumber"]++;
2098 $pAchValues[
"fileEntryAddendaCount"]++;
2100 $entryDetail = array (
"RecordTypeCode" =>
"6",
2101 "TransactionCode" =>
"27",
2102 "ReceivingDFI" => $receivingDFIRouting,
2103 "CheckDigit" => $receivingCheckDigit,
2104 "DFIAccountNumber" => $receivingDFIAccount,
2105 "Amount" => $amount,
2106 "IndividualIdentificationNumber" => $individualID,
2107 "IndividualName" => $individualName,
2108 "DiscretionaryData" =>
" ",
2109 "AddendaRecordIndicator" =>
"0",
2110 "TraceNumber" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ) . substr(
"000000" . $pAchValues[
"traceNumber"], -7 ) );
2112 $pAchValues[
"fileControlHash"] += $receivingDFIRouting;
2115 $entry = array_values( $entryDetail );
2117 $outputLine = implode(
"", $entry );
2118 if ( strlen( $outputLine ) != 94 ) {
2119 throw new Exception(
"ACH Output Error - company header block size (location 104)" );
2121 $pOutputData[] = $outputLine;
2124 $entryHash = substr( str_repeat(
"0", 10 ) . $receivingDFIRouting, -10 );
2127 $companyControl = array (
"RecordTypeCode" =>
"8",
2128 "ServiceClassCode" => $serviceClassCode,
2129 "EntryAddendaCount" => str_pad(
"1", 6,
"0", STR_PAD_LEFT ),
2130 "EntryHash" => $entryHash,
2131 "TotalDebitEntryDollarAmount" => str_pad( $amount, 12,
"0", STR_PAD_LEFT ),
2132 "TotalCreditEntryDollarAmount" => str_pad(
"0", 12,
"0", STR_PAD_LEFT ),
2133 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
2134 "MessageAuthenticationCode" => str_repeat(
" ", 19 ),
2135 "Reserved" => str_repeat(
" ", 6 ),
2136 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
2137 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
2140 $control = array_values( $companyControl );
2142 $outputLine = implode(
"", $control );
2143 if ( strlen( $outputLine ) != 94 ) {
2144 throw new Exception(
"ACH Output Error - company control block size (location 108)" );
2146 $pOutputData[] = $outputLine;
2151 $serviceClassCode =
"220";
2152 $pAchValues[
"batchNumber"]++;
2154 $companyHeader = array(
"RecordTypeCode" =>
"5",
2155 "ServiceClassCode" => $serviceClassCode,
2156 "CompanyName" => MakeValidAchString( $pInputParams[
"CompanyName"], 16 ),
2157 "CompanyData" => str_repeat(
" ", 20 ),
2158 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
2159 "StandardEntryClassCode" =>
"PPD",
2160 "CompanyEntryDescription" => MakeValidAchString( $entryName, 10 ),
2161 "CompanyDescriptiveDate" => str_repeat(
" ", 6 ),
2162 "EffectiveEntryDate" => $effectiveDate,
2163 "SettlementDate" => str_repeat(
" ", 3 ),
2164 "OriginatorStatusCode" =>
"1",
2165 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
2166 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
2169 $header = array_values( $companyHeader );
2171 $outputLine = implode(
"", $header );
2172 if ( strlen( $outputLine ) != 94 ) {
2173 throw new Exception(
"ACH Output Error - company header block size (location 102)" );
2175 $pOutputData[] = $outputLine;
2177 if ( strlen( $pInputParams[
"OriginatingRouting"] ) != 9 ) {
2178 throw new Exception(
"ACH File Creation - invalid routing number (location 113)" );
2181 $receivingDFIRouting = substr( $pInputParams[
"OriginatingRouting"], 0, 8 );
2182 $receivingCheckDigit = substr( $pInputParams[
"OriginatingRouting"], -1 );
2183 $destParts = explode(
"|", $paymentDestination );
2184 $account = str_replace(
" ",
"", $destParts[1] );
2185 $subAccount = str_replace(
" ",
"", $destParts[2] );
2186 $receivingDFIAccount = MakeValidAchString( $account . $subAccount, 17 );
2188 $printableDestAccount =
"$account-$subAccount";
2190 $actualAmount = trim( $transferRow[
"amount"] );
2191 $roundAmount = round( $actualAmount * 100 );
2192 $amount = str_pad( $roundAmount, 10,
"0", STR_PAD_LEFT );
2197 $pAchValues[
"totalFileCredit"] += $roundAmount;
2200 $pAchValues[
"traceNumber"]++;
2201 $pAchValues[
"fileEntryAddendaCount"]++;
2203 $entryDetail = array (
"RecordTypeCode" =>
"6",
2204 "TransactionCode" =>
"52",
2205 "ReceivingDFI" => $receivingDFIRouting,
2206 "CheckDigit" => $receivingCheckDigit,
2207 "DFIAccountNumber" => $receivingDFIAccount,
2208 "Amount" => $amount,
2209 "IndividualIdentificationNumber" => $individualID,
2210 "IndividualName" => $individualName,
2211 "DiscretionaryData" =>
" ",
2212 "AddendaRecordIndicator" =>
"0",
2213 "TraceNumber" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ) . substr(
"000000" . $pAchValues[
"traceNumber"], -7 ) );
2215 $pAchValues[
"fileControlHash"] += $receivingDFIRouting;
2218 $entry = array_values( $entryDetail );
2220 $outputLine = implode(
"", $entry );
2221 if ( strlen( $outputLine ) != 94 ) {
2222 throw new Exception(
"ACH Output Error - entry detail block size (location 105)" );
2224 $pOutputData[] = $outputLine;
2227 $entryHash = substr( str_repeat(
"0", 10 ) . $receivingDFIRouting, -10 );
2230 $companyControl = array (
"RecordTypeCode" =>
"8",
2231 "ServiceClassCode" => $serviceClassCode,
2232 "EntryAddendaCount" => str_pad(
"1", 6,
"0", STR_PAD_LEFT ),
2233 "EntryHash" => $entryHash,
2234 "TotalDebitEntryDollarAmount" => str_pad(
"0", 12,
"0", STR_PAD_LEFT ),
2235 "TotalCreditEntryDollarAmount" => str_pad( $amount, 12,
"0", STR_PAD_LEFT ),
2236 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
2237 "MessageAuthenticationCode" => str_repeat(
" ", 19 ),
2238 "Reserved" => str_repeat(
" ", 6 ),
2239 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
2240 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
2243 $control = array_values( $companyControl );
2245 $outputLine = implode(
"", $control );
2246 if ( strlen( $outputLine ) != 94 ) {
2247 throw new Exception(
"ACH Output Error - company control block size (location 109)" );
2249 $pOutputData[] = $outputLine;
2252 $pAchValues[
"fileBatchCount"] += 2;
2255 $formattedAmount = number_format( $actualAmount, 2,
".",
"," );
2256 $pReportLines[] =
" Transfer: $fullName Automated loan payment $formattedAmount from $printableSourceAccount to $printableDestAccount effective $effectiveDate";
2259 $serviceClassCode =
"200";
2262 $pAchValues[
"batchNumber"]++;
2263 $companyControlHash = 0;
2265 $companyHeader = array(
"RecordTypeCode" =>
"5",
2266 "ServiceClassCode" => $serviceClassCode,
2267 "CompanyName" => MakeValidAchString( $pInputParams[
"CompanyName"], 16 ),
2268 "CompanyData" => str_repeat(
" ", 20 ),
2269 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
2270 "StandardEntryClassCode" =>
"WEB",
2271 "CompanyEntryDescription" => MakeValidAchString( $entryName, 10 ),
2272 "CompanyDescriptiveDate" => str_repeat(
" ", 6 ),
2273 "EffectiveEntryDate" => $effectiveDate,
2274 "SettlementDate" => str_repeat(
" ", 3 ),
2275 "OriginatorStatusCode" =>
"1",
2276 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
2277 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
2280 $header = array_values( $companyHeader );
2282 $outputLine = implode(
"", $header );
2283 if ( strlen( $outputLine ) != 94 ) {
2284 throw new Exception(
"ACH Output Error - company header block size (location 103)" );
2286 $pOutputData[] = $outputLine;
2289 if ( $transferDirection == 1 ) {
2291 if ( strlen( $pInputParams[
"OriginatingRouting"] ) != 9 ) {
2292 throw new Exception(
"ACH File Creation - invalid routing number (location 114)" );
2295 $sourceDFIRouting = substr( $pInputParams[
"OriginatingRouting"], 0, 8 );
2296 $sourceCheckDigit = substr( $pInputParams[
"OriginatingRouting"], -1 );
2299 $sourceParts = explode(
"|", $paymentSource );
2300 $account = str_replace(
" ",
"", $sourceParts[1] );
2301 $subAccount = str_replace(
" ",
"", $sourceParts[2] );
2302 $sourceDFIAccount = FormatDFIAccount($account, $subAccount, $adminAchSettings[
"settings"][
"sub_account_mask"]);
2304 $printableSourceAccount =
"$account-$subAccount";
2306 if ( strlen( $transData[
"acct_dest"][
"rdfi"][
"rdfi_routing"] ) != 9 ) {
2307 throw new Exception(
"ACH File Creation - invalid routing number (location 115)" );
2310 $destDFIRouting = substr( $paymentDestination[
"rdfi"][
"rdfi_routing"], 0, 8 );
2311 $destCheckDigit = substr( $paymentDestination[
"rdfi"][
"rdfi_routing"], -1 );
2312 $account = str_replace(
" ",
"", $paymentDestination[
"rdfi"][
"rdfi_account"] );
2313 $destDFIAccount = MakeValidAchString( $account, 17 );
2315 $printableDestAccount =
"{$paymentDestination["rdfi
"]["rdfi_routing
"]} / $account";
2318 $fullName = $paymentDestination[
"remote_entity"][
"name"];
2319 $individualID = MakeValidAchString( substr( $fullName, -15 ), 15 );
2323 if ( $sourceParts[0] ==
"L" ) {
2325 throw new Exception(
"ACH File Creation - cannot debit a loan account: $paymentSource" );
2329 $localACHType = $transData[
"source_meta"][
"deposit_ach_type"];
2330 if ( $localACHType > 0 ) {
2331 $isChecking = $localACHType == 10;
2333 $sql =
"SELECT deposittype 2334 FROM {$pAdmEnv["Cu
"]}accountbalance 2335 WHERE accountnumber = '{$sourceParts[1]}' 2336 AND accounttype = '{$sourceParts[2]}' 2337 AND certnumber = {$sourceParts[3]}";
2338 $acctRS = db_query( $sql, $pAdmEnv[
"dbh"] );
2340 throw new Exception(
"ACH Query Error - getting account deposit type" );
2343 $acctRow = db_fetch_assoc( $acctRS, 0 );
2345 $isChecking = $acctRow[
"deposittype"] ==
"Y";
2348 $sourceTransactionCode = $isChecking ?
"27" :
"37";
2349 $destTransactionCode = $paymentDestination[
"rdfi"][
"rdfi_account_type"] == 10 ?
"22" :
"32";
2352 if ( strlen( $transData[
"acct_source"][
"rdfi"][
"rdfi_routing"] ) != 9 ) {
2353 throw new Exception(
"ACH File Creation - invalid routing number (location 116)" );
2356 $sourceDFIRouting = substr( $paymentSource[
"rdfi"][
"rdfi_routing"], 0, 8 );
2357 $sourceCheckDigit = substr( $paymentSource[
"rdfi"][
"rdfi_routing"], -1 );
2358 $account = str_replace(
" ",
"", $paymentSource[
"rdfi"][
"rdfi_account"] );
2359 $sourceDFIAccount = MakeValidAchString( $account, 17 );
2361 $printableSourceAccount =
"{$paymentSource["rdfi
"]["rdfi_routing
"]} / $account";
2363 if ( strlen( $pInputParams[
"OriginatingRouting"] ) != 9 ) {
2364 throw new Exception(
"ACH File Creation - invalid routing number (location 117)" );
2367 $destDFIRouting = substr( $pInputParams[
"OriginatingRouting"], 0, 8 );
2368 $destCheckDigit = substr( $pInputParams[
"OriginatingRouting"], -1 );
2371 $destParts = explode(
"|", $paymentDestination );
2372 $account = str_replace(
" ",
"", $destParts[1] );
2373 $subAccount = str_replace(
" ",
"", $destParts[2] );
2374 $destDFIAccount = FormatDFIAccount($account, $subAccount, $adminAchSettings[
"settings"][
"sub_account_mask"]);
2377 $printableDestAccount =
"$account-$subAccount";
2380 $fullName = $paymentSource[
"remote_entity"][
"name"];
2381 $individualID = MakeValidAchString( substr( $fullName, -15 ), 15 );
2383 $sourceTransactionCode = $paymentSource[
"rdfi"][
"rdfi_account_type"] == 10 ?
"27" :
"37";
2387 $localACHType = $transData[
"dest_meta"][
"deposit_ach_type"];
2388 if ( $localACHType > 0 ) {
2389 $isChecking = $localACHType == 10;
2390 }
else if( $destParts[0] !=
"L" ) {
2392 $sql =
"SELECT deposittype 2393 FROM {$pAdmEnv["Cu
"]}accountbalance 2394 WHERE accountnumber = '{$destParts[1]}' 2395 AND accounttype = '{$destParts[2]}' 2396 AND certnumber = {$destParts[3]}";
2397 $acctRS = db_query( $sql, $pAdmEnv[
"dbh"] );
2399 throw new Exception(
"ACH Query Error - getting batch ach txns" );
2402 $acctRow = db_fetch_assoc( $acctRS, 0 );
2404 $isChecking = $acctRow[
"deposittype"] ==
"Y";
2407 $isChecking =
false;
2411 if( $destParts[0] ==
"L" ) {
2412 $destTransactionCode =
"52";
2414 $destTransactionCode = $isChecking ?
"22" :
"32";
2418 $actualAmount = trim( $transferRow[
"amount"] );
2419 $roundAmount = round( $actualAmount * 100 );
2420 $amount = str_pad( $roundAmount, 10,
"0", STR_PAD_LEFT );
2422 $individualName = MakeValidAchString( $entryName, 22 );
2425 $transMeta = HCU_JsonDecode($pTxnHeader[
'transmeta']);
2426 $transRecurring = (HCU_array_key_value(
"recurr", $transMeta) ==
"yes") ?
"R" :
"S";
2427 $discretionaryData = str_pad($transRecurring, 2,
" ", STR_PAD_RIGHT);
2430 $pAchValues[
"totalFileCredit"] += $roundAmount;
2431 $pAchValues[
"totalFileDebit"] += $roundAmount;
2434 $pAchValues[
"traceNumber"]++;
2435 $pAchValues[
"fileEntryAddendaCount"]++;
2437 $entryDetail = array (
"RecordTypeCode" =>
"6",
2438 "TransactionCode" => $sourceTransactionCode,
2439 "ReceivingDFI" => $sourceDFIRouting,
2440 "CheckDigit" => $sourceCheckDigit,
2441 "DFIAccountNumber" => $sourceDFIAccount,
2442 "Amount" => $amount,
2443 "IndividualIdentificationNumber" => $individualID,
2444 "IndividualName" => $individualName,
2445 "DiscretionaryData" => $discretionaryData,
2446 "AddendaRecordIndicator" =>
"0",
2447 "TraceNumber" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ) . substr(
"000000" . $pAchValues[
"traceNumber"], -7 ) );
2450 $entry = array_values( $entryDetail );
2452 $outputLine = implode(
"", $entry );
2453 if ( strlen( $outputLine ) != 94 ) {
2454 throw new Exception(
"ACH Output Error - entry detail block size (location 106)" );
2456 $pOutputData[] = $outputLine;
2458 $companyControlHash += $sourceDFIRouting;
2459 $pAchValues[
"fileControlHash"] += $sourceDFIRouting;
2462 $pAchValues[
"traceNumber"]++;
2463 $pAchValues[
"fileEntryAddendaCount"]++;
2465 $entryDetail = array (
"RecordTypeCode" =>
"6",
2466 "TransactionCode" => $destTransactionCode,
2467 "ReceivingDFI" => $destDFIRouting,
2468 "CheckDigit" => $destCheckDigit,
2469 "DFIAccountNumber" => $destDFIAccount,
2470 "Amount" => $amount,
2471 "IndividualIdentificationNumber" => $individualID,
2472 "IndividualName" => $individualName,
2473 "DiscretionaryData" => $discretionaryData,
2474 "AddendaRecordIndicator" =>
"0",
2475 "TraceNumber" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ) . substr(
"000000" . $pAchValues[
"traceNumber"], -7 ) );
2478 $entry = array_values( $entryDetail );
2480 $outputLine = implode(
"", $entry );
2481 if ( strlen( $outputLine ) != 94 ) {
2482 throw new Exception(
"ACH Output Error - entry detail block size (location 107)" );
2484 $pOutputData[] = $outputLine;
2486 $companyControlHash += $destDFIRouting;
2487 $pAchValues[
"fileControlHash"] += $destDFIRouting;
2490 $entryHash = substr( str_repeat(
"0", 10 ) . $companyControlHash, -10 );
2493 $companyControl = array (
"RecordTypeCode" =>
"8",
2494 "ServiceClassCode" => $serviceClassCode,
2495 "EntryAddendaCount" => str_pad(
"2", 6,
"0", STR_PAD_LEFT ),
2496 "EntryHash" => $entryHash,
2497 "TotalDebitEntryDollarAmount" => str_pad( $amount, 12,
"0", STR_PAD_LEFT ),
2498 "TotalCreditEntryDollarAmount" => str_pad( $amount, 12,
"0", STR_PAD_LEFT ),
2499 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
2500 "MessageAuthenticationCode" => str_repeat(
" ", 19 ),
2501 "Reserved" => str_repeat(
" ", 6 ),
2502 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
2503 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
2506 $control = array_values( $companyControl );
2508 $outputLine = implode(
"", $control );
2509 if ( strlen( $outputLine ) != 94 ) {
2510 throw new Exception(
"ACH Output Error - company control block size (location 110)" );
2512 $pOutputData[] = $outputLine;
2515 $pAchValues[
"fileBatchCount"]++;
2518 $formattedAmount = number_format( $actualAmount, 2,
".",
"," );
2520 if ( $destTransactionCode ==
"52" ) {
2521 $pReportLines[] =
" Transfer: $fullName Automated loan payment $formattedAmount from $printableSourceAccount to $printableDestAccount effective $effectiveDate";
2523 $pReportLines[] =
" Transfer: $fullName WEB transfer $formattedAmount from $printableSourceAccount to $printableDestAccount effective $effectiveDate";
2527 }
catch (Exception $ex) {
2528 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
2530 $returnInfo[
"error"] = $ex->getMessage();
2531 $returnInfo[
"code"] =
"999";
2550 function BuildACHBusiness( $pAdmEnv, $pTxnHeader, $pInputParams, &$pAchValues, &$pOutputData, &$pReportLines ) {
2551 $returnInfo = array(
"code" =>
"000",
"error" =>
"" );
2554 $pAchValues[
"batchNumber"]++;
2557 $effectiveDate = date(
"ymd", strtotime( $pTxnHeader[
"effective_date"] .
" 3:00" ) );
2558 $adminAchSettings = AdminReadSettings($pAdmEnv, $pAdmEnv[
"dbh"], $pAdmEnv[
"Cu"]);
2588 $serviceClassCode =
"200";
2593 $transferDirection = substr( $pTxnHeader[
"transactioncode"], 0, 1 );
2596 $standardEntryClass = substr( $pTxnHeader[
"transactioncode"], 1, 1 );
2597 if ( $standardEntryClass ==
"C" ) {
2599 }
else if ( $standardEntryClass ==
"P" ) {
2601 }
else if ( $standardEntryClass ==
"W" ) {
2604 throw new Exception(
"Error Building ACH Upload File - Could not determine Standard Entry Class (201)" );
2608 $companyName = $pTxnHeader[
"group_name"];
2611 $companyID = trim($pTxnHeader[
'tax_id']);
2612 if (strlen($companyID) != 10) {
2616 $groupContext = GroupContext($pAdmEnv, $pAdmEnv[
'Cu']);
2617 $groupContext[
'g_name'] = $companyName;
2618 $group = GroupSelect($pAdmEnv, $pAdmEnv[
'dbh'], $groupContext);
2621 for ($i = 0; $i < count($group[
'group'][
'g_primary']); $i++) {
2622 $payload = urldecode($group[
'group'][
'g_primary'][$i][
'p_payload']);
2623 $primary = HCU_PayloadDecode($pAdmEnv[
'Cu'], $payload);
2625 $group[
'group'][
'g_primary'][$i] = $primary;
2626 $group[
'group'][
'g_primary'][$i][
'p_name'] = $primary[
'user_name'];
2628 $groupEncrypt = GroupEncrypt($pAdmEnv, $pAdmEnv[
'Cu'], $group);
2629 $groupEncrypt = urlencode($groupEncrypt);
2634 $companyIDError =
"Error Building ACH Upload File - Missing Company Identification: 109^This feature requires a \"Company Tax ID\" set up on the <a href=\"main.prg?ft=102101&payload={$groupEncrypt}\">{$companyName}</a> Group Hub";
2635 throw new Exception( $companyIDError, 109 );
2638 $companyICD = substr($companyID, 0, -9);
2639 if ($companyICD !=
"1" && $companyICD !=
"9" && $companyICD !=
" ") {
2640 throw new Exception(
"Error Building ACH Upload File - Invalid Identification Code Designator (202)" );
2646 $companyEntryDescription = $transferDirection ==
"1" ?
"ACH Payment" :
"ACH Collection";
2649 $companyHeader = array(
"RecordTypeCode" =>
"5",
2650 "ServiceClassCode" => $serviceClassCode,
2651 "CompanyName" => MakeValidAchString( $companyName, 16 ),
2652 "CompanyData" => str_repeat(
" ", 20 ),
2653 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
2654 "StandardEntryClassCode" => $secCode,
2655 "CompanyEntryDescription" => MakeValidAchString( $companyEntryDescription, 10 ),
2656 "CompanyDescriptiveDate" => str_repeat(
" ", 6 ),
2657 "EffectiveEntryDate" => $effectiveDate,
2658 "SettlementDate" => str_repeat(
" ", 3 ),
2659 "OriginatorStatusCode" =>
"1",
2660 "OriginatingDFI" => MakeValidAchString( substr( $pInputParams[
"OriginatingRouting"], 0, 8 ), 8 ),
2661 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
2663 $header = array_values( $companyHeader );
2665 $outputLine = implode(
"", $header );
2666 if ( strlen( $outputLine ) != 94 ) {
2667 throw new Exception(
"ACH Output Error - company header block size (203)" );
2669 $pOutputData[] = $outputLine;
2672 $pReportLines[] =
" Group/Company: $companyName";
2675 $sql =
"SELECT * FROM {$pAdmEnv["Cu
"]}transdtl WHERE transhdr_id = {$pTxnHeader["id"]}";
2676 $dtlRS = db_query( $sql, $pAdmEnv[
"dbh"] );
2678 throw new Exception(
"ACH Query Error - getting ACH transactions (204)" );
2681 if (db_num_rows($dtlRS) == 0) {
2682 throw new Exception(
"ACH Error - detail not found for ACH transfer (205)" );
2692 $localAccountInfo = array();
2693 $localAccountInfoSet =
false;
2694 $localAccountTotal = 0;
2695 $localAccountTotalFormatted =
"";
2701 $remoteReportLines = array();
2704 $companyTotalCredit = 0;
2705 $companyTotalDebit = 0;
2706 $companyControlHash = 0;
2707 $companyEntryAddendaCount = 0;
2708 while ( $rowDtl = db_fetch_assoc( $dtlRS, $dtlRow++ ) ) {
2710 $remoteAccountInfo = array();
2713 $transData = HCU_JsonDecode( $rowDtl[
"transdata"],
true );
2715 if (empty($transData)) {
2716 throw new Exception(
"ACH Error - transaction data is missing or corrupt (206)" );
2720 if ( strlen( $pInputParams[
"OriginatingRouting"] ) != 9 ) {
2721 throw new Exception(
"Error Building ACH Upload File - invalid routing number (207)" );
2727 if (!$localAccountInfoSet) {
2729 $localParts = array();
2732 if ($transferDirection ==
"1") {
2733 $localParts = $transData[
'source_key'];
2734 $localType = $transData[
'source_meta'][
'deposit_ach_type'];
2735 $localAccountInfo[
'TransactionCode'] = $localType == 10 ?
"27" : ($localType == 20 ?
"37" :
"00");
2739 $localParts = $transData[
'dest_key'];
2740 $localType = $transData[
'dest_meta'][
'deposit_ach_type'];
2741 $localAccountInfo[
'TransactionCode'] = $localType == 10 ?
"22" : ($localType == 20 ?
"32" :
"00");
2745 if ($localAccountInfo[
'TransactionCode'] ==
"00") {
2746 throw new Exception(
"Error Building ACH Upload File - could not determine transaction code (208)");
2749 $localAccount = str_replace(
" ",
"", $localParts[
'accountnumber'] );
2750 $localSub = str_replace(
" ",
"", $localParts[
'accounttype'] );
2751 $localAccountInfo[
'ReceivingDFI'] = substr( $pInputParams[
"OriginatingRouting"], 0, 8 );
2752 $localAccountInfo[
'CheckDigit'] = substr( $pInputParams[
"OriginatingRouting"], -1 );
2753 $localAccountInfo[
'DFIAccountNumber'] = FormatDFIAccount($localAccount, $localSub, $adminAchSettings[
"settings"][
"sub_account_mask"]);
2756 $localName = $localAccount .
"-" . $localSub;
2757 $localName = strtoupper($localName);
2758 $localAccountInfo[
'IndividualName'] = MakeValidAchString($localName, 22);
2762 $localAccountInfo[
'IndividualIdentificationNumber'] = str_repeat(
" ", 15 );
2763 $localAccountInfo[
'DiscretionaryData'] =
" ";
2764 $localAccountInfo[
'AddendaRecordIndicator'] = 0;
2766 $localAccountInfoSet =
true;
2769 $remoteParts = array();
2773 if ($transferDirection ==
"1") {
2774 $remoteParts = $transData[
'acct_dest'];
2775 $remoteType = $remoteParts[
'rdfi'][
'rdfi_account_type'];
2776 $remoteAccountInfo[
'TransactionCode'] = $remoteType == 10 ?
"22" : ($remoteType == 20 ?
"32" :
"00");
2780 $remoteParts = $transData[
'acct_source'];
2781 $remoteType = $remoteParts[
'rdfi'][
'rdfi_account_type'];
2782 $remoteAccountInfo[
'TransactionCode'] = $remoteType == 10 ?
"27" : ($remoteType == 20 ?
"37" :
"00");
2786 if ($remoteAccountInfo[
'TransactionCode'] ==
"00") {
2787 throw new Exception(
"Error Building ACH Upload File - could not determine transaction code (209)");
2791 if ( strlen( $remoteParts[
"rdfi"][
"rdfi_routing"] ) != 9 ) {
2792 throw new Exception(
"Error Building ACH Upload File - invalid routing number (210)" );
2795 $remoteAccountInfo[
'ReceivingDFI'] = substr( $remoteParts[
"rdfi"][
"rdfi_routing"], 0, 8 );
2796 $remoteAccountInfo[
'CheckDigit'] = substr( $remoteParts[
"rdfi"][
"rdfi_routing"], -1 );
2797 $remoteAccount = str_replace(
" ",
"", $remoteParts[
"rdfi"][
"rdfi_account"] );
2798 $remoteAccountInfo[
'DFIAccountNumber'] = MakeValidAchString( $remoteAccount, 17 );
2801 $remoteName = $remoteParts[
'remote_entity'][
'name'];
2802 $remoteName = strtoupper($remoteName);
2803 $remoteAccountInfo[
'IndividualName'] = MakeValidAchString($remoteName, 22);
2807 $remoteAccountInfo[
'IndividualIdentificationNumber'] = str_repeat(
" ", 15 );
2808 $remoteAccountInfo[
'DiscretionaryData'] =
" ";
2811 $remoteAddenda = trim($remoteParts[
'rdfi'][
'addenda']);
2812 if (strlen($remoteAddenda) > 0) {
2813 $remoteAccountInfo[
'Addenda'] = MakeValidAchString($remoteAddenda, 80);
2814 $remoteAccountInfo[
'AddendaRecordIndicator'] = 1;
2816 $remoteAccountInfo[
'AddendaRecordIndicator'] = 0;
2820 $remoteActual = trim($rowDtl[
'amount']);
2821 $remoteActualFormatted = number_format($remoteActual, 2,
".",
",");
2822 $remoteActualFormatted = str_pad($remoteActualFormatted, 10,
" ", STR_PAD_RIGHT);
2824 $remoteAmount = round($remoteActual * 100);
2825 $remoteAccountInfo[
'Amount'] = str_pad( $remoteAmount, 10,
"0", STR_PAD_LEFT );
2828 $localAccountTotal += $remoteActual;
2829 $localAccountTotalFormatted = number_format($localAccountTotal, 2,
".",
",");
2830 $localAccountTotalFormatted = str_pad($localAccountTotalFormatted, 10,
" ", STR_PAD_RIGHT);
2832 $localAccountAmount = round($localAccountTotal * 100);
2833 $localAccountInfo[
'Amount'] = str_pad($localAccountAmount, 10,
"0", STR_PAD_LEFT);
2836 $companyTotalCredit += $remoteAmount;
2837 $pAchValues[
"totalFileCredit"] += $remoteAmount;
2839 $companyTotalDebit += $remoteAmount;
2840 $pAchValues[
"totalFileDebit"] += $remoteAmount;
2843 $companyEntryAddendaCount++;
2844 $pAchValues[
'fileEntryAddendaCount']++;
2845 $pAchValues[
"traceNumber"]++;
2847 $entryDetail = array (
2848 "RecordTypeCode" =>
"6",
2849 "TransactionCode" => $remoteAccountInfo[
'TransactionCode'],
2850 "ReceivingDFI" => $remoteAccountInfo[
'ReceivingDFI'],
2851 "CheckDigit" => $remoteAccountInfo[
'CheckDigit'],
2852 "DFIAccountNumber" => $remoteAccountInfo[
'DFIAccountNumber'],
2853 "Amount" => $remoteAccountInfo[
'Amount'],
2854 "IndividualIdentificationNumber" => $remoteAccountInfo[
'IndividualIdentificationNumber'],
2855 "IndividualName" => $remoteAccountInfo[
'IndividualName'],
2856 "DiscretionaryData" => $remoteAccountInfo[
'DiscretionaryData'],
2857 "AddendaRecordIndicator" => $remoteAccountInfo[
'AddendaRecordIndicator'],
2858 "TraceNumber" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ) . substr(
"000000" . $pAchValues[
"traceNumber"], -7 ) );
2860 $entry = array_values( $entryDetail );
2861 $outputLine = implode(
"", $entry );
2862 if ( strlen( $outputLine ) != 94 ) {
2863 throw new Exception(
"ACH Output Error - entry detail block size (211)" );
2865 $pOutputData[] = $outputLine;
2867 $rName = $remoteAccountInfo[
'IndividualName'];
2869 $remoteAccountInfo[
'ReceivingDFI'] .
2870 $remoteAccountInfo[
'CheckDigit'] .
" / " .
2871 $remoteAccountInfo[
'DFIAccountNumber'];
2872 $rAmount =
"$" . $remoteActualFormatted;
2873 $remoteReportLines[] =
" Partner: {$rName} {$rAmount} {$rAccount}";
2876 if ( HCU_array_key_exists(
"Addenda", $remoteAccountInfo) ) {
2877 $companyEntryAddendaCount++;
2878 $pAchValues[
"fileEntryAddendaCount"]++;
2881 $addendaRecord = array(
2882 "RecordTypeCode" =>
"7",
2883 "AddendaTypeCode" =>
"05",
2884 "PaymentRelatedInformation" => $remoteAccountInfo[
'Addenda'],
2885 "AddendaSequenceNumber" =>
"0001",
2886 "EntryDetailSequenceNumber" => str_pad( $pAchValues[
"traceNumber"], 7,
"0", STR_PAD_LEFT ) );
2888 $addenda = array_values( $addendaRecord );
2889 $outputLine = implode(
"", $addenda );
2890 if ( strlen( $outputLine ) != 94 ) {
2891 throw new Exception(
"ACH Output Error - addenda entry block size (212)" );
2893 $pOutputData[] = $outputLine;
2894 $remoteReportLines[] =
" Addenda: {$remoteAccountInfo['Addenda']}";
2898 $companyControlHash += $remoteAccountInfo[
'ReceivingDFI'];
2899 $pAchValues[
"fileControlHash"] += $remoteAccountInfo[
'ReceivingDFI'];
2902 $companyEntryAddendaCount++;
2903 $pAchValues[
"fileEntryAddendaCount"]++;
2906 $entryDetail = array (
2907 "RecordTypeCode" =>
"6",
2908 "TransactionCode" => $localAccountInfo[
'TransactionCode'],
2909 "ReceivingDFI" => $localAccountInfo[
'ReceivingDFI'],
2910 "CheckDigit" => $localAccountInfo[
'CheckDigit'],
2911 "DFIAccountNumber" => $localAccountInfo[
'DFIAccountNumber'],
2912 "Amount" => $localAccountInfo[
'Amount'],
2913 "IndividualIdentificationNumber" => $localAccountInfo[
'IndividualIdentificationNumber'],
2914 "IndividualName" => $localAccountInfo[
'IndividualName'],
2915 "DiscretionaryData" => $localAccountInfo[
'DiscretionaryData'],
2916 "AddendaRecordIndicator" => $localAccountInfo[
'AddendaRecordIndicator'],
2917 "TraceNumber" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ) . substr(
"000000" . $pAchValues[
"traceNumber"], -7 ) );
2919 $entry = array_values( $entryDetail );
2920 $outputLine = implode(
"", $entry );
2921 if ( strlen( $outputLine ) != 94 ) {
2922 throw new Exception(
"ACH Output Error - entry detail block size (213)" );
2924 $pOutputData[] = $outputLine;
2927 $companyControlHash += $localAccountInfo[
'ReceivingDFI'];
2928 $pAchValues[
"fileControlHash"] += $localAccountInfo[
'ReceivingDFI'];
2933 $lName = trim($localAccountInfo[
'IndividualName']);
2934 $lAmount =
"$" . trim($localAccountTotalFormatted);
2935 if ($transferDirection ==
"1") {
2936 $pReportLines[] =
" Transfer: ACH Payment, {$lAmount} effective {$effectiveDate} from {$lName} to:";
2938 $pReportLines[] =
" Transfer: ACH Collection, {$lAmount} effective {$effectiveDate} to {$lName} from:";
2943 $pReportLines = array_merge($pReportLines, $remoteReportLines);
2946 $pReportLines[] =
"";
2949 $entryHash = substr( str_repeat(
"0", 10 ) . $companyControlHash, -10 );
2952 $companyControl = array (
2953 "RecordTypeCode" =>
"8",
2954 "ServiceClassCode" => $serviceClassCode,
2955 "EntryAddendaCount" => str_pad( $companyEntryAddendaCount, 6,
"0", STR_PAD_LEFT ),
2956 "EntryHash" => $entryHash,
2957 "TotalDebitEntryDollarAmount" => str_pad( $companyTotalDebit, 12,
"0", STR_PAD_LEFT ),
2958 "TotalCreditEntryDollarAmount" => str_pad( $companyTotalCredit, 12,
"0", STR_PAD_LEFT ),
2959 "CompanyIdentification" => MakeValidAchString( $companyID, 10 ),
2960 "MessageAuthenticationCode" => str_repeat(
" ", 19 ),
2961 "Reserved" => str_repeat(
" ", 6 ),
2962 "OriginatingDFI" => substr( $pInputParams[
"OriginatingRouting"], 0, 8 ),
2963 "BatchNumber" => str_pad( $pAchValues[
"batchNumber"], 7,
"0", STR_PAD_LEFT ) );
2965 $control = array_values( $companyControl );
2967 $outputLine = implode(
"", $control );
2968 if ( strlen( $outputLine ) != 94 ) {
2969 throw new Exception(
"ACH Output Error - company control block size (214)" );
2971 $pOutputData[] = $outputLine;
2974 $pAchValues[
"fileBatchCount"]++;
2975 }
catch (Exception $ex) {
2976 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
2978 $returnInfo[
"error"] = $ex->getMessage();
2979 $returnInfo[
"code"] = $ex->getCode() == 0 ?
"999" : $ex->getCode();
2988 function MakeValidAchString( $inputString, $length ) {
2989 return substr( str_pad( preg_replace( ACH_NOT_ALLOWED,
"", $inputString ), $length ), 0, $length );
3002 function FormatDFIAccount($accountNumber, $subAccountNumber, $mask =
'') {
3003 $maskLength = strlen($mask);
3005 if (strlen($subAccountNumber) >= $maskLength) {
3006 return MakeValidAchString(
"$accountNumber$subAccountNumber", 17 );
3009 $accountLengthDelta = strlen(
"$accountNumber$mask") - DFI_ACCOUNT_MAX_SIZE;
3010 if ($accountLengthDelta > 0) {
3011 $mask = substr($mask, $accountLengthDelta);
3014 $maskedNumber = substr(
"$mask$subAccountNumber", -1 * $maskLength);
3015 $maskedNumber = strtr($maskedNumber,
'+',
' ');
3017 return MakeValidAchString(
"$accountNumber$maskedNumber", 17);
3029 function CreateAchFiles( $pAdmEnv, $pAdmVars ) {
3030 $returnInfo = array(
"code" =>
"000",
"errors" => array(),
"data" => array());
3033 $outputData = array();
3036 $reportLines = array();
3040 require_once( dirname(__FILE__) .
"/../library/aACHValidate.i" );
3042 $cu = strtolower( $pAdmEnv[
"Cu"] );
3043 $CU = strtoupper( $pAdmEnv[
"Cu"] );
3045 $batchPreName =
"Batch";
3046 $batchPath =
"/home/{$cu}/admin/ach/";
3047 $blockingFactor = 10;
3050 if ( !file_exists( $batchPath ) ) {
3051 throw new Exception(
"Create ACH Files Error - Directory does not exist - please contact Support" );
3054 $payloadInfo = HCU_PayloadDecode( $pAdmEnv[
"Cu"], $pAdmVars[
"batch_id"] );
3055 $batchTimeString = $payloadInfo[
"batch_date"];
3058 $creditUnionTz = GetCreditUnionTimezone( $pAdmEnv[
"dbh"], $pAdmEnv[
"Cu"] );
3061 $myDateTime =
new DateTime( $batchTimeString );
3062 $myDateTime->setTimezone(
new DateTimeZone($creditUnionTz));
3063 $batchDay = $myDateTime->format(
"ymd");
3064 $batchHour = $myDateTime->format(
"His");
3067 $fileModifier =
"A";
3070 $results = glob(
"{$batchPath}{$batchPreName}_{$batchDay}_*.ach" );
3071 for ( $i = 0; $i < count( $results ); $i++ ) {
3075 $achBaseName =
"{$batchPreName}_{$batchDay}_{$batchHour}";
3076 $achFileName =
"{$achBaseName}.ach";
3077 $achReportName =
"{$achBaseName}.txt";
3079 $reportLines[] =
"Report for $achBaseName";
3086 $adminAchSettings = AdminReadSettings($pAdmEnv, $pAdmEnv[
"dbh"], $CU);
3088 $cuRouting = trim( $adminAchSettings[
"settings"][
"routing"] );
3089 if ( strlen( $cuRouting ) != 9 ) {
3090 throw new Exception(
"ACH Settings - invalid CU routing number" );
3094 $accountMicroDeposit = $adminAchSettings[
"settings"][
"account"];
3097 $originName = MakeValidAchString( $adminAchSettings[
"settings"][
"name"], 23 );
3131 $myRouting = substr( str_pad( trim( $adminAchSettings[
"settings"][
"routing"] ), 10,
" ", STR_PAD_LEFT ), 0, 10 );
3133 $fileCreateDate =
new DateTimeImmutable(
"now",
new DateTimeZone($creditUnionTz));
3135 $fileHeader = array(
"RecordTypeCode" =>
"1",
3136 "PriorityCode" =>
"01",
3137 "ImmediateDestination" => $myRouting,
3138 "ImmediateOrigin" => $myRouting,
3139 "FileCreateDate" => $fileCreateDate->format(
"ymd"),
3140 "FileCreateTime" => $fileCreateDate->format(
"Hi"),
3141 "FileIDModifier" => $fileModifier,
3142 "RecordSize" =>
"094",
3143 "BlockingFactor" => $blockingFactor,
3144 "FormatCode" =>
"1",
3145 "ImmediateDestinationName" => str_pad(
"Federal Reserve Bank", 23 ),
3146 "ImmediateOriginName" => $originName,
3147 "ReferenceCode" => str_repeat(
" ", 8 ) );
3149 $header = array_values( $fileHeader );
3151 $outputLine = implode(
"", $header );
3152 if ( strlen( $outputLine ) != 94 ) {
3153 throw new Exception(
"ACH Output Error - file header block size" );
3155 $outputData[] = $outputLine;
3158 $transactionHeaders = GetACHTransactionHeaders( $pAdmEnv, $batchTimeString );
3159 if ( !count( $transactionHeaders ) ) {
3160 throw new Exception(
"Error Building ACH Upload File - no ACH transactions for upload", 300 );
3167 $values[
"batchNumber"] = 0;
3168 $values[
"totalFileCredit"] = 0;
3169 $values[
"totalFileDebit"] = 0;
3170 $values[
"fileControlHash"] = 0;
3171 $values[
"fileEntryAddendaCount"] = 0;
3172 $values[
"fileBatchCount"] = 0;
3175 $values[
"traceNumber"] = 0;
3178 $passedParams = array(
"CompanyName" => $originName,
3179 "OriginatingRouting" => $cuRouting,
3180 "CompanyEntryDescription" => $originName,
3181 "EffectiveEntryDate" => (
new DateTime(
"now",
new DateTimeZone($creditUnionTz)))->format(
'ymd'),
3182 "accountMicroDeposit" => $accountMicroDeposit,
3183 "CompanyIDType" => $adminAchSettings[
'settings'][
'type']
3186 $reportLines[] =
"";
3187 $reportLines[] =
"Micro Deposits";
3188 $retInfo = AddMicroDeposits( $pAdmEnv, $transactionHeaders, $passedParams, $values, $outputData, $reportLines );
3189 if ( $retInfo[
"code"] !=
"000" ) {
3190 throw new Exception( $retInfo[
"error"] );
3194 $reportLines[] =
"";
3195 $reportLines[] =
"Micro Deposit Offsetting Entries";
3196 $retInfo = AddMicroDepositOffsets( $pAdmEnv, $transactionHeaders, $passedParams, $values, $outputData, $reportLines );
3197 if ( $retInfo[
"code"] !=
"000" ) {
3198 throw new Exception( $retInfo[
"error"] );
3202 unset( $passedParams[
"accountMicroDeposit"] );
3205 $reportLines[] =
"";
3206 $reportLines[] =
"External Transfers";
3209 for ( $hdrRow = 0; $hdrRow < count( $transactionHeaders ); $hdrRow++ ) {
3210 $rowHdr = $transactionHeaders[$hdrRow];
3212 if ( $rowHdr[
"processed"] > 0 )
continue;
3214 if ( $rowHdr[
"feature_code"] ==
"TRNEXT" ) {
3215 $retInfo = BuildACHTransfer( $pAdmEnv, $rowHdr, $passedParams, $values, $outputData, $reportLines );
3216 if ( $retInfo[
"code"] !=
"000" ) {
3217 throw new Exception( $retInfo[
"error"] );
3221 $transactionHeaders[$hdrRow][
"processed"] =
true;
3227 $reportLines[] =
" None";
3231 $reportLines[] =
"";
3232 $reportLines[] =
"ACH Transactions";
3235 for ( $hdrRow = 0; $hdrRow < count( $transactionHeaders ); $hdrRow++ ) {
3236 $rowHdr = $transactionHeaders[$hdrRow];
3238 if ( $rowHdr[
"processed"] > 0 )
continue;
3240 if ( $rowHdr[
"feature_code"] ==
"ACHCOL" ||
3241 $rowHdr[
"feature_code"] ==
"ACHPMT" ) {
3242 $achBusinessReturn = BuildACHBusiness( $pAdmEnv, $rowHdr, $passedParams, $values, $outputData, $reportLines );
3243 if ($achBusinessReturn[
'code'] !==
"000") {
3244 throw new Exception($achBusinessReturn[
'error'], $achBusinessReturn[
'code']);
3247 $transactionHeaders[$hdrRow][
"processed"] =
true;
3253 $reportLines[] =
" None";
3257 for ( $hdrRow = 0; $hdrRow < count( $transactionHeaders ); $hdrRow++ ) {
3258 $rowHdr = $transactionHeaders[$hdrRow];
3260 if ( $rowHdr[
"processed"] > 0 )
continue;
3263 throw new Exception(
"Error Building ACH Upload File - Unprocessed transaction: " . print_r( $rowHdr,
true ) );
3267 $entryHash = substr( str_repeat(
"0", 10 ) . $values[
"fileControlHash"], -10 );
3271 $realRecordCount = count( $outputData ) + 1;
3272 $fillerCount = $blockingFactor - ($realRecordCount % $blockingFactor);
3273 $totalBlockCount = floor( ( $realRecordCount + $fillerCount ) / $blockingFactor );
3277 $fileControl = array (
"RecordTypeCode" =>
"9",
3278 "BatchCount" => str_pad( $values[
"fileBatchCount"], 6,
"0", STR_PAD_LEFT ),
3279 "BlockCount" => str_pad( $totalBlockCount, 6,
"0", STR_PAD_LEFT ),
3280 "EntryAddendaCount" => str_pad( $values[
"fileEntryAddendaCount"], 8,
"0", STR_PAD_LEFT ),
3281 "EntryHash" => $entryHash,
3282 "TotalDebitEntryDollarAmount" => str_pad( $values[
"totalFileDebit"], 12,
"0", STR_PAD_LEFT ),
3283 "TotalCreditEntryDollarAmount" => str_pad( $values[
"totalFileCredit"], 12,
"0", STR_PAD_LEFT ),
3284 "Reserved" => str_repeat(
" ", 39 ) );
3286 $control = array_values( $fileControl );
3288 $outputLine = implode(
"", $control );
3289 if ( strlen( $outputLine ) != 94 ) {
3290 throw new Exception(
"ACH Output Error - file control block size" );
3292 $outputData[] = $outputLine;
3295 for ( $i = 0; $i < $fillerCount; $i++ ) {
3296 $outputData[] = str_repeat(
"9", 94 );
3300 $reportString = implode(
"\n", $reportLines );
3303 $currDir = getcwd();
3305 if ( chdir( $batchPath ) ) {
3307 $fp = fopen( $achFileName,
"w" );
3310 $outputString = implode(
"\n", $outputData );
3312 $bytesWritten = fputs( $fp, $outputString );
3315 if ( $bytesWritten != strlen( $outputString ) ) {
3316 throw new Exception(
"ACH Output Error - could not write to output file" );
3319 throw new Exception(
"ACH Output Error - could not open output file" );
3323 $fp = fopen( $achReportName,
"w" );
3325 $bytesWritten = fputs( $fp, $reportString );
3328 if ( $bytesWritten != strlen( $reportString ) ) {
3329 throw new Exception(
"ACH Output Error - could not write to report file" );
3332 throw new Exception(
"ACH Output Error - could not open report file" );
3335 throw new Exception(
"ACH Output Error - could not reach file directory" );
3343 for ( $hdrRow = 0; $hdrRow < count( $transactionHeaders ); $hdrRow++ ) {
3344 $hdrList[] = $transactionHeaders[$hdrRow][
'id'];
3346 $hdrString = implode(
",", $hdrList);
3349 $sql =
"UPDATE {$pAdmEnv['Cu']}transhdr SET processed_status = 20 WHERE id IN ($hdrString)";
3350 $sqlRs = db_query( $sql, $pAdmEnv[
'dbh'] );
3352 throw new Exception(
"ACH Output Error - unable to update transaction process" );
3355 $returnInfo[
"data"][
"batch_id"] = $pAdmVars[
"batch_id"];
3356 }
catch (Exception $ex) {
3357 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
3359 $returnInfo[
"errors"] = $ex->getMessage();
3360 $returnInfo[
"code"] = $ex->getCode() == 0 ?
"999" : $ex->getCode();
3375 function GetApprovedACHTrans( $pAdmEnv ) {
3376 $returnInfo = array(
"code" =>
"000",
"errors" => array(),
"data" => array());
3379 $achFeatures =
"'ACHCOL', 'ACHPMT', 'ACHPYRL', 'TRNEXT'";
3382 $sql =
"SELECT id, feature_code, effective_date, u1.user_name AS poster, posted_date, 3383 u2.user_name AS approver, approved_date, accountnumber, 3384 transactioncode, memo, group_name, (select sum(amount) from {$pAdmEnv["Cu
"]}transdtl d where d.transhdr_id = th.id) as amount 3385 FROM {$pAdmEnv["Cu
"]}transhdr th 3386 LEFT JOIN {$pAdmEnv["Cu
"]}user u1 ON u1.user_id = th.posted_by 3387 LEFT JOIN {$pAdmEnv["Cu
"]}user u2 ON u2.user_id = th.approved_by 3388 INNER JOIN {$pAdmEnv["Cu
"]}group g ON g.group_id = u1.group_id 3389 WHERE approved_status = 10 3390 AND processed_status IS NULL 3391 AND feature_code in ($achFeatures) 3392 ORDER BY effective_date, group_name, feature_code, id";
3393 $rs = db_query( $sql, $pAdmEnv[
"dbh"] );
3395 throw new Exception(
"ACH Query Error - getting approved ach txns" );
3400 $returnData = array();
3401 while ( $txRow = db_fetch_assoc( $rs, $row++ ) ) {
3403 $timestamp = strtotime( $txRow[
"effective_date"] );
3404 $account = trim( $txRow[
"accountnumber"] );
3405 $returnData[] = array(
"id" => $txRow[
"id"],
3406 "feature" => trim( $txRow[
"feature_code"] ),
3407 "eff_date" => date(
"m/d/Y", $timestamp ),
3408 "group" => $txRow[
"group_name"],
3409 "account" => $account,
3410 "amount" => $txRow[
"amount"],
3411 "memo" => $txRow[
"memo"]
3415 $returnInfo[
"data"] = $returnData;
3416 }
catch (Exception $ex) {
3417 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
3419 $returnInfo[
"errors"] = $ex->getMessage();
3420 $returnInfo[
"code"] =
"999";
3435 function GetACHTransDetail( $pAdmEnv, $pTransId ) {
3436 $returnInfo = array(
"code" =>
"000",
"errors" => array(),
"data" => array());
3440 $sql =
"SELECT th.feature_code, th.effective_date, th.accountnumber, th.transactioncode, 3441 th.memo, g.group_name, 3443 FROM {$pAdmEnv["Cu
"]}user 3444 WHERE group_id = u.group_id 3445 AND is_group_primary = TRUE 3446 LIMIT 1) as group_owner 3447 FROM {$pAdmEnv["Cu
"]}transhdr th 3448 INNER JOIN {$pAdmEnv["Cu
"]}user u ON u.user_id = th.posted_by 3449 INNER JOIN {$pAdmEnv["Cu
"]}group g ON g.group_id = u.group_id 3450 WHERE id = $pTransId";
3451 $rs = db_query( $sql, $pAdmEnv[
"dbh"] );
3453 throw new Exception(
"ACH Query Error - getting ach detail txn header" );
3456 $headerRow = db_fetch_assoc( $rs, 0 );
3458 $featureCode = trim( $headerRow[
"feature_code"] );
3460 $timestamp = strtotime( $headerRow[
"effective_date"] );
3462 $account = trim( $headerRow[
"accountnumber"] );
3464 $headerData = array(
3465 "feature" => $featureCode,
3466 "eff_date" => date(
"m/d/Y", $timestamp ),
3467 "account" => $account,
3468 "group_name" => trim( $headerRow[
"group_name"] ),
3469 "group_owner" => trim( $headerRow[
"group_owner"] ),
3470 "memo" => trim( $headerRow[
"memo"] )
3474 $sql =
"SELECT * FROM {$pAdmEnv["Cu
"]}transdtl 3475 WHERE transhdr_id = $pTransId 3477 $rs = db_query( $sql, $pAdmEnv[
"dbh"] );
3479 throw new Exception(
"ACH Query Error - getting ach txn detail" );
3483 if ( substr( $headerRow[
"transactioncode"], 0, 1 ) == 1 ) {
3484 $whichRemote =
"acct_dest";
3485 $whichLocal =
"acct_source";
3487 $whichRemote =
"acct_source";
3488 $whichLocal =
"acct_dest";
3493 $returnDetail = array();
3495 while ( $detRow = db_fetch_assoc( $rs, $row++ ) ) {
3497 $transData = HCU_JsonDecode( $detRow[
"transdata"],
true );
3499 if ( $localAccount ==
"" ) {
3500 $localAccount = $transData[$whichLocal];
3504 $dfiAccount =
"{$transData[$whichRemote]["rdfi
"]["rdfi_routing
"]} / {$transData[$whichRemote]["rdfi
"]["rdfi_account
"]}";
3506 $remoteAddress1 = trim( HCU_array_key_value(
'address1', $transData[$whichRemote][
"remote_entity"]) );
3507 $remoteAddress2 = trim( HCU_array_key_value(
'address2', $transData[$whichRemote][
"remote_entity"]) );
3508 $remoteAddress =
"Not Listed";
3509 if ( strlen( $remoteAddress1 ) > 0 ) {
3510 if ( strlen( $remoteAddress2 ) > 0 ) {
3511 $remoteAddress =
"$remoteAddress1 / $remoteAddress2";
3513 $remoteAddress = $remoteAddress1;
3515 }
else if ( strlen( $remoteAddress2 ) ) {
3516 $remoteAddress = $remoteAddress2;
3519 $detailData = array(
"amount" => $detRow[
"amount"],
3520 "dfi_account" => $dfiAccount,
3521 "remote_name" => HCU_array_key_value(
'name', $transData[$whichRemote][
"remote_entity"]),
3522 "remote_address" => $remoteAddress,
3523 "addenda" => HCU_array_key_value(
'addenda', $transData[$whichRemote][
"rdfi"])
3525 $returnDetail[] = $detailData;
3529 if ( $localAccount !=
"" && $localAccount !=
"micro" ) {
3530 $parts = explode(
"|", $localAccount );
3531 $type = $parts[0] ==
"D" ?
"(Deposit)" : ($type ==
"L" ?
"(Loan)" :
"(Unknown)");
3532 $account = trim( $parts[1] );
3533 $subAccount = trim( $parts[2] );
3534 $accountString = trim(
"$account - $subAccount $type" );
3535 $headerData[
"account"] = $accountString;
3536 }
else if ( $localAccount ==
"micro" ) {
3537 $headerData[
"account"] =
"Micro Deposit";
3540 $returnInfo[
"data"][
"header"] = $headerData;
3541 $returnInfo[
"data"][
"detail"] = $returnDetail;
3543 }
catch (Exception $ex) {
3544 $logInfo = array(
"error" => $ex->getMessage(),
"code" => $ex->getCode() );
3546 $returnInfo[
"errors"] = $ex->getMessage();
3547 $returnInfo[
"code"] =
"999";
3553 function BuildFeatureNameLookup( $pDbh ) {
3555 require_once(dirname(__FILE__) .
'/../../shared/library/sFeatureMnu.i');
3556 $result = GetFeatureList( $pDbh );
3558 $menuFeatures = $result[
"data"];
3561 $achFeatureList = array(
"ACHCOL" =>
"Missing menu entry",
3562 "ACHPMT" =>
"Missing menu entry",
3563 "ACHPYRL" =>
"Missing menu entry",
3564 "TRNEXT" =>
"Missing menu entry" );
3569 $lookupList = array_keys( $achFeatureList );
3570 for ( $i = 0; $i < count( $lookupList ); $i++ ) {
3571 $lookup = $lookupList[$i];
3572 for ( $m = 0; $m < count( $menuFeatures ); $m++ ) {
3573 if ( $menuFeatures[$m][
"featurecode"] == $lookup ) {
3574 $achFeatureList[$lookup] = $menuFeatures[$m][
"description"];
3580 return $achFeatureList;
3593 function PrintActionPage( $pAdmEnv, $pAdmVars ) {
3595 $dbh = $pAdmEnv[
"dbh"];
3596 $achFeatureList = BuildFeatureNameLookup( $dbh );
3598 $self = $pAdmEnv[
"self"];
3599 $advPerm = $pAdmEnv[
"advPerm"];
3601 <script type=
"text/javascript">
3602 <?php getShowWaitFunctions(); ?>
3604 var activeWindows= [];
3607 var achTransList = [];
3612 var cachedDetailInfo = [];
3614 var window_stack = [];
3615 var featureList = <?php echo HCU_JsonEncode( $achFeatureList ) ?>;
3618 $(document).ready(
function() {
3619 achDetailModel = kendo.observable({
3627 SetDetail:
function( detailInfo ) {
3628 this.
set(
"achFeature", ( detailInfo.header.feature in featureList ) ? featureList[detailInfo.header.feature] :
'Unknown' );
3629 this.
set(
"groupOwner", detailInfo.header.group_owner );
3630 this.
set(
"groupName", detailInfo.header.group_name );
3631 this.
set(
"account", detailInfo.header.account );
3632 this.
set(
"effDate", detailInfo.header.eff_date );
3633 this.
set(
"memo", detailInfo.header.memo );
3634 this.
set(
"detail", JSON.stringify( detailInfo.detail ) );
3638 dsACHHelper =
new kendo.data.DataSource({
3643 url:
"<?php echo $self; ?>",
3645 contentType:
"application/x-www-form-urlencoded",
3651 parse:
function(response) {
3657 requestStart:
function( e ) {
3658 $.homecuValidator.displayMessage(
"", $.homecuValidator.settings.statusError );
3661 requestEnd:
function( e ) {
3666 if (e.hasOwnProperty(
"response")) {
3667 if (e.response.hasOwnProperty(
"results")) {
3668 var results = e.response.results;
3669 if (results.hasOwnProperty(
"errors")) {
3676 if ( results.hasOwnProperty(
"data") ) {
3678 <?php
if ($advPerm) { ?>
3680 if (results.data.hasOwnProperty(
"achMakeBatch")) {
3681 ShowBatchResults( results.data.achMakeBatch.batch_id );
3683 GetAvailableACHTxns();
3688 dsACHHelper.cancelChanges();
3690 throw results.errors;
3692 if ( results.data ) {
3693 if ( results.data.achGetReady ) {
3694 ShowAvailableACH( results.data.achGetReady );
3696 if ( results.data.achGetDetail ) {
3697 ShowAchDetail( results.data.achGetDetail );
3700 <?php
if ($advPerm) { ?>
3701 if ( results.data.achCancel ) {
3702 HandleCancelResult( results.data.achCancel );
3704 if ( results.data.achMakeBatch ) {
3705 ShowBatchResults( results.data.achMakeBatch.batch_id );
3707 GetAvailableACHTxns();
3718 var successMsg = results.info.splice(0, 1);
3719 $.homecuValidator.displayMessage( successMsg, $.homecuValidator.settings.statusInfo);
3722 var warningContent =
"";
3723 for (var i = 0; i < results.info.length; i++) {
3726 warningContent +=
"<p><strong>" + results.info[i] +
"</strong></p>";
3729 warningContent +=
"<p>" + results.info[i] +
"</p>";
3733 if (warningContent !==
"") {
3735 setTimeout(
function() {
3736 infoDialog.content(warningContent);
3737 infoDialog.center();
3744 throw "Unexpected results from server";
3747 throw "Invalid results from server";
3752 theMessage = error.message ? error.message : error;
3754 theMessage =
"Unknown server error occurred during the operation";
3756 $.homecuValidator.displayMessage( theMessage, $.homecuValidator.settings.statusError );
3762 error:
function( e ) {
3766 <?php
if ($advPerm) { ?>
3768 $(
"#actionsDDL").kendoDropDownList({
3770 dataTextField:
"name",
3771 dataValueField:
"value",
3772 dataSource: [{name:
"Create ACH Upload File", value:
"batch"}, {name:
"Cancel Transactions", value:
"cancel"}],
3773 optionLabel: {name:
"Choose Action...", value:
""},
3774 change:
function(e) {
3776 var action = this.value();
3778 if ( action ===
"cancel" ) {
3779 cancelDialog.open().center();
3780 }
else if ( action ===
"batch" ) {
3781 batchDialog.open().center();
3790 achActionGrid = $(
"#achActionGrid").kendoGrid({
3791 dataSource: achTransList,
3795 template:
"<div class='vsgSecondary'>No available ACH transactions were found</div>" 3798 <?php
if ($advPerm) { ?>
3799 {field:
"checked", headerTemplate:
"<input type='checkbox' id='checkAllForBatch'>", width:
"45px",
3801 template:
"<label><input type='checkbox' class='in-batch-checkbox' name='inBatch' value='1'></label>"},
3803 {field:
"eff_date", title:
"Effective Date", width:
"110px", headerAttributes: {
"class":
"textAlignCenter"}, attributes: {
"class":
"textAlignCenter"}},
3804 {field:
"feature", title:
"Feature", width:
"110px",
3805 headerAttributes: {
"class":
"textAlignCenter"}, attributes: {
"class":
"textAlignCenter"},
3806 template:
"#= ( featureList[feature] === undefined ) ? feature : featureList[feature] #"},
3807 {field:
"group", title:
"Group", width:
"100px", headerAttributes: {
"class":
"textAlignCenter"}, attributes: {
"class":
"textAlignCenter"}},
3808 {field:
"account", title:
"Account", width:
"130px", headerAttributes: {
"class":
"textAlignCenter"}, attributes: {
"class":
"textAlignCenter"}},
3809 {field:
"amount", title:
"Amount", width:
"110px",
3810 headerAttributes: {
"class":
"textAlignRight"}, attributes: {
"class":
"textAlignRight"},
3811 template:
'#= kendo.toString(amount, "c") #'},
3812 {field:
"memo", title:
"Memo"}
3814 change:
function( e ) {
3817 var selectedCell = this.select();
3818 var selectedRow = selectedCell.closest(
"tr");
3819 var cellIndex = selectedCell.index();
3821 var dataItem = achActionGrid.dataItem(selectedRow);
3823 if ( cellIndex < 1 ) {
3825 <?php
if ($advPerm) { ?>
3826 var checkbox = selectedRow.find(
"td:first input");
3827 checkbox.prop(
"checked", !checkbox.prop(
"checked"));
3830 SetAchInBatch( dataItem.id, checkbox.prop(
"checked") );
3835 GetAchDetail( dataItem.id );
3838 selectedCell.removeClass(
"k-state-selected" );
3840 <?php
if ($advPerm) { ?>
3841 dataBound:
function( e ) {
3842 $(
"#checkAllForBatch").click(
function() {
3843 var state = $(
"#checkAllForBatch").prop(
"checked" );
3844 $(
".in-batch-checkbox").prop(
"checked", state );
3847 SetAchInBatch( 0, state );
3852 $(
".in-batch-checkbox").click(
function(e) {
3853 var selectedRow = $(e.target).closest(
"tr");
3855 var dataItem = achActionGrid.dataItem(selectedRow);
3858 var checkbox = selectedRow.find(
"td:first input");
3861 SetAchInBatch( dataItem.id, checkbox.prop(
"checked") );
3867 }).data(
"kendoGrid");
3870 var toolTipProps = homecuTooltip.defaults;
3872 toolTipProps.filter =
"td:nth-child(3),td:nth-child(4),td:nth-child(5),td:nth-child(7)";
3873 toolTipProps.position =
"top",
3874 toolTipProps.maxWidth = 400,
3875 toolTipProps.showAfter = 20,
3876 toolTipProps.content =
function(e) {
3877 var element = e.target[0];
3878 if ( element.offsetWidth < element.scrollWidth ) {
3879 return "<span style='display:block; width:100%;'>" + e.target.text() +
"</span>";
3884 toolTipProps.show =
function(e) {
3885 if( this.content.text() !==
"") {
3886 $(
'[role="tooltip"]').css(
"visibility",
"visible");
3889 toolTipProps.hide =
function() {
3890 $(
'[role="tooltip"]').css(
"visibility",
"hidden");
3893 $(
"#achActionGrid").kendoTooltip(toolTipProps).data(
"kendoTooltip");
3895 achDetailGrid = $(
"#achDetailGrid").kendoGrid({
3896 dataSource:
new kendo.data.DataSource({
3898 read:
function( options ) {
3899 var data = JSON.parse( achDetailModel.detail )
3900 options.success(data);
3907 template:
"<div class='vsgSecondary'>No available ACH transactions were found</div>" 3910 {field:
"remote_name", title:
"Name" },
3911 {field:
"remote_address", title:
"Address",
3912 template:
'# if (remote_address == "Not Listed" ) { # <span class="vsgSecondary">#= remote_address #</span> #} else {# #= remote_address # # } #' },
3913 {field:
"amount", title:
"Amount", width:
"100px",
3914 headerAttributes: { style:
"text-align: center"},
3915 template:
'<div style="text-align:right;">#= kendo.toString(amount, "c") #</div>' },
3916 {field:
"dfi_account", title:
"Account" },
3917 {field:
"addenda", title:
"Addenda" }
3919 }).data(
"kendoGrid");
3921 <?php
if ($advPerm) { ?>
3922 infoDialog = $(
"#infoDialog").kendoDialog({
3923 title:
"ACH Batch Warning",
3929 window_stack.push(
function(e) {
3930 infoDialog.close(e);
3937 { text:
"Ok", primary:
true,
3938 action:
function(e) {}
3941 }).data(
"kendoDialog");
3943 cancelDialog = $(
"#cancelDialog").kendoDialog({
3945 title:
"Cancel ACH Transactions",
3946 content:
"<p><strong>Continuing will cancel the selected transactions.</strong></p><p>Are you sure you want to continue?</p>",
3949 window_stack.push(
function(e) {
3950 cancelDialog.close(e);
3953 close:
function(e) {
3957 actions: [{text:
"Cancel"},
3960 action:
function(e){
3962 var list = GetCheckedTxns();
3963 CancelACHTxns( list );
3970 }).data(
"kendoDialog");
3972 batchDialog = $(
"#batchDialog").kendoDialog({
3974 title:
"Create ACH Upload File",
3975 content:
"<p><strong>Continuing will place all the selected transactions into a single ACH upload file.</strong></p><p>Are you sure you want to continue?</p>",
3978 window_stack.push(
function(e) {
3979 batchDialog.close(e);
3982 close:
function(e) {
3986 actions: [{text:
"Cancel"},
3989 action:
function(e){
3991 var list = GetCheckedTxns();
3992 BatchACHTxns( list );
3999 }).data(
"kendoDialog");
4002 detailWindow = $(
"#achDetailWindow").kendoWindow({
4009 title:
"ACH Transaction Details",
4010 activate:
function(e) {
4012 window_stack.push(
function(e) {
4013 detailWindow.close(e);
4016 $(
"#detailClose").click(
function() {
4017 detailWindow.close();
4021 kendo.bind($(
"#achDetailWindow"), achDetailModel);
4025 this.wrapper.css({ top: 100 });
4028 achDetailGrid.dataSource.read();
4030 close:
function(e) {
4034 }).data(
"kendoWindow");
4037 $.homecuValidator.setup({formErrorTitle:
"Error Occured", formStatusField:
"formACHStatus"});
4040 GetAvailableACHTxns();
4043 $(document).on(
"click",
".k-overlay",
function (e) {
4044 if(window_stack.length > 0) {
4046 var fn = window_stack[window_stack.length - 1];
4053 <?php
if ($advPerm) { ?>
4054 function SetAchInBatch(
id, state ) {
4055 for ( var i = 0; i < achTransList.length; i++ ) {
4056 if ( achTransList[i].
id ==
id ||
id == 0 ) {
4057 achTransList[i].inBatch = state;
4066 function GetCheckedTxns() {
4067 var checkedTxns = [];
4068 for ( var i = 0; i < achTransList.length; i++ ) {
4069 if ( achTransList[i].inBatch ) {
4070 checkedTxns.push( achTransList[i].
id * 1 );
4074 return checkedTxns.toString();
4077 function TestActions() {
4079 var checked =
false;
4080 $(
".in-batch-checkbox").each(
function() {
4081 var state = $(
this).prop(
"checked" );
4088 var dropdownlist = $(
"#actionsDDL").data(
"kendoDropDownList");
4089 dropdownlist.enable(checked);
4093 function GetAvailableACHTxns() {
4094 var request = { operation:
"achGetReady" };
4096 dsACHHelper.read( request );
4099 <?php
if ($advPerm) { ?>
4100 function CancelACHTxns( list ) {
4101 if ( list.length > 0 ) {
4102 var request = { operation:
"achCancel", trans_list: list };
4104 dsACHHelper.read( request );
4107 function BatchACHTxns( list ) {
4108 if ( list.length > 0 ) {
4109 var request = { operation:
"achMakeBatch", trans_list: list };
4111 dsACHHelper.read( request );
4116 function GetAchDetail(
id ) {
4118 var foundInCache =
false;
4119 for ( var i = 0; i < cachedDetailInfo.length; i++ ) {
4120 if ( cachedDetailInfo[i].header.id ==
id ) {
4121 lastDetailInfo = cachedDetailInfo[i];
4122 foundInCache =
true;
4123 detailWindow.open().center();
4128 if ( !foundInCache ) {
4130 var request = { operation:
"achGetDetail", trans_id:
id };
4132 dsACHHelper.read( request );
4135 function ShowAchDetail( detailInfo ) {
4137 cachedDetailInfo.push( detailInfo );
4139 achDetailModel.SetDetail( detailInfo );
4144 detailWindow.open().center();
4147 function ShowAvailableACH( achList ) {
4149 for ( var i = 0; i < achList.length; i++ ) {
4150 var newObject = {id: achList[i].id,
4151 account: achList[i].account,
4152 amount: achList[i].amount * 1,
4153 eff_date: achList[i].eff_date,
4154 feature: achList[i].feature,
4155 group: achList[i].group,
4156 memo: achList[i].memo,
4160 achTransList.push( newObject );
4163 achActionGrid.dataSource.data(achTransList);
4168 <?php
if ($advPerm) { ?>
4169 function HandleCancelResult( idString ) {
4170 var idList = idString.split(
"," );
4173 var tempTransList = [];
4174 for ( var i = 0; i < achTransList.length; i++ ) {
4175 var index = idList.indexOf( achTransList[i].
id );
4177 tempTransList.push( achTransList[i] );
4181 achTransList = tempTransList;
4184 var grid = $(
'#achActionGrid').data(
"kendoGrid");
4185 grid.dataSource.data(achTransList);
4188 $(
"#checkAllForBatch").prop(
"checked",
false );
4191 var dropdownlist = $(
"#actionsDDL").data(
"kendoDropDownList");
4192 dropdownlist.enable(
false);
4196 function ShowBatchResults( batchId ) {
4197 if ( batchId.length > 0 ) {
4198 $(
"#achBatchId").val( batchId );
4199 $(
"#achBatchOperation").attr(
"name",
"page" );
4200 $(
"#achBatchOperation").val(
"ach_show_report" );
4201 $(
"#achBatchDownload").val(
"download" );
4202 $(
"#achPostForm").attr(
"action",
"<?php echo $pAdmEnv["menu_link
"] ?>?ft=101" );
4203 $(
"#achPostForm").attr(
"target",
"achreport" );
4204 $(
"#achPostForm").submit();
4210 var dropdownlist = $(
"#actionsDDL").data(
"kendoDropDownList");
4211 dropdownlist.enable(
false);
4215 <?php PrintCommonStyle() ?>
4217 #achBody .k-grid td { 4218 white-space: nowrap;
4219 text-overflow: ellipsis;
4221 #achBody .k-grid .k-grid-content tr:hover { 4224 .hcu-scrolling-dialog {
4228 <div
id=
"achDetailWindow" class=
"container-fluid hcu-scrolling-dialog" style=
"display:none;">
4229 <div
class=
"h4"><div data-bind=
"text: achFeature" ></div></div>
4230 <div
class=
"form-horizontal well well-sm">
4232 <div
class=
"col-xs-3"><label>Group Owner</label></div>
4233 <div
class=
"col-xs-9"><div data-bind=
"text: groupOwner" class=
"vsgSecondary"></div></div>
4236 <div
class=
"col-xs-3"><label>Group Name</label></div>
4237 <div
class=
"col-xs-9"><div data-bind=
"text: groupName" class=
"vsgSecondary"></div></div>
4240 <div
class=
"col-xs-3"><label>Account</label></div>
4241 <div
class=
"col-xs-9"><div data-bind=
"text: account" class=
"vsgSecondary"></div></div>
4244 <div
class=
"col-xs-3"><label>Effective Date</label></div>
4245 <div
class=
"col-xs-9"><div data-bind=
"text: effDate" class=
"vsgSecondary"></div></div>
4248 <div
class=
"col-xs-3"><label>Memo</label></div>
4249 <div
class=
"col-xs-9"><div data-bind=
"text: memo" class=
"vsgSecondary"></div></div>
4251 <div
id=
"achDetailGrid"></div>
4253 <div
class=
"hcu-template">
4254 <div
class=
"hcu-edit-buttons k-state-default">
4255 <span
class=
"hcu-icon-delete">
4257 <a
id=
"detailClose" style=
"cursor: pointer;" >Close</a>
4261 <form
id=
"achPostForm" method=
"post">
4262 <input type=
"hidden" id=
"achBatchId" name=
"batch_id" value=
"">
4263 <input type=
"hidden" id=
"achBatchOperation" name=
"operation" value=
"">
4264 <input type=
"hidden" id=
"achBatchDownload" name=
"download" value=
"">
4267 <div
id=
"cancelDialog"></div>
4268 <div
id=
"batchDialog"></div>
4269 <div
id=
"infoDialog"></div>
4270 <div
id=
"achBody" class=
"container-fluid">
4271 <div
id=
"formACHStatus" class=
"homecu-formStatus k-block k-error-colored" style=
"display:none;"></div>
4273 <div
class=
"form-horizontal well well-sm">
4275 <div
class=
"col-xs-12"><h2>ACH Actions</h2></div>
4277 <?php
if ($advPerm) { ?>
4279 <div
class=
"col-xs-3"> </div>
4280 <div
class=
"col-xs-3"><input
id=
"actionsDDL" class=
"hcu-all-100"></div>
4283 <div
class=
"col-xs-12 "> </div>
4286 <div
class=
"col-xs-12 small vsgSecondary">A
new ACH upload file report will automatically display in a
new window. Make sure pop-ups are allowed
for this website.</div>
4289 <div
class=
"col-xs-12 small vsgSecondary">Please check NACHA guidelines
for specific timing requirements.</div>
4293 <div
class=
"col-xs-12 small vsgSecondary">You have basic permissions. Creating an ACH file or canceling transactions is not available to you.</div>
4297 <div
class=
"col-xs-12"><div
id=
"achActionGrid"></div></div>
4314 function PrintMainPage( $pAdmEnv, $pAdmVars ) {
4316 $achFeatureList = BuildFeatureNameLookup( $pAdmEnv[
"dbh"] );
4318 $self = $pAdmEnv[
"self"];
4319 $advPerm = $pAdmEnv[
"advPerm"];
4321 <script type=
"text/javascript">
4322 <?php getShowWaitFunctions(); ?>
4324 var activeWindows = [];
4326 var achBatchItemGrid;
4328 var achBatchList = [];
4329 var achBatchItems = [];
4330 var achCurrSelectedBatchItem;
4332 var batchDetailWindow;
4333 var cachedDetailInfo = [];
4335 var window_stack = [];
4336 var featureList = <?php echo HCU_JsonEncode( $achFeatureList ) ?>;
4337 var commercialAccess = <?php echo $pAdmEnv[
'commercialAccess'] == 1 ?
"true" :
"false"; ?>;
4338 var removeFromBatchAllowed =
false;
4341 $(document).ready(
function() {
4342 dsACHHelper =
new kendo.data.DataSource({
4347 url:
"<?php echo $self; ?>",
4349 contentType:
"application/x-www-form-urlencoded",
4355 parse:
function(response) {
4361 requestStart:
function( e ) {
4362 $.homecuValidator.displayMessage(
"", $.homecuValidator.settings.statusError );
4365 requestEnd:
function( e ) {
4370 if (e.hasOwnProperty(
"response")) {
4371 if (e.response.hasOwnProperty(
"results")) {
4372 var results = e.response.results;
4373 if (results.hasOwnProperty(
"errors")) {
4375 dsACHHelper.cancelChanges();
4376 throw results.errors;
4378 if ( results.data ) {
4379 if ( results.data.achRemoveBatchTransactions ) {
4380 UpdateACHResults( results.data.achRemoveBatchTransactions,
"achRemove" );
4381 batchDetailWindow.close();
4383 if ( results.data.achSendNotifications ) {
4384 UpdateACHResults( results.data.achSendNotifications,
"achNotify" );
4386 if ( results.data.achGetBatches ) {
4387 ShowACHBatches( results.data.achGetBatches );
4389 if ( results.data.achCreateFile ) {
4390 UpdateACHResults( results.data.achCreateFile,
"achFile" );
4392 if ( results.data.achGetBatchDetail ) {
4393 ShowACHBatchDetail( results.data.achGetBatchDetail );
4403 var successMsg = results.info.splice(0, 1);
4404 $.homecuValidator.displayMessage( successMsg, $.homecuValidator.settings.statusInfo);
4407 var warningContent =
"";
4408 for (var i = 0; i < results.info.length; i++) {
4411 warningContent +=
"<p><strong>" + results.info[i] +
"</strong></p>";
4414 warningContent +=
"<p>" + results.info[i] +
"</p>";
4418 if (warningContent !==
"") {
4420 setTimeout(
function() {
4421 infoDialog.content(warningContent);
4422 infoDialog.center();
4429 throw "Unexpected results from server";
4432 throw "Invalid results from server";
4437 theMessage = error.message ? error.message : error;
4439 theMessage =
"Unknown server error occurred during the operation";
4441 $.homecuValidator.displayMessage( theMessage, $.homecuValidator.settings.statusError );
4447 error:
function( e ) {
4451 achHistoryGrid = $(
"#achHistoryGrid").kendoGrid({
4452 dataSource: achBatchList,
4459 template:
"<div class='vsgSecondary'>No available ACH upload files were found</div>" 4462 {field:
"batch_time", title:
"Processed Date", width:
"120px"},
4463 {field:
"processed_by", title:
"Processed By", width:
"120px"},
4464 {field:
"count", title:
"Item Count", width:
"70px"},
4465 <?php
if ($advPerm) { ?>
4466 {title:
"",
template:
"<div class='fa #= ((hasACHFile) ? 'fa-download' : 'fa-gears')#'></div>", width:
"20px"},
4468 {title:
"",
template:
"<div class='fa fa-file-text-o' #= ((!hasACHReport) ? 'style=\"opacity: 0.38;\"' : '')#></div>", width:
"20px"},
4469 <?php
if ($advPerm) { ?>
4470 {title:
"",
template:
"<div class='fa fa-envelope' #= ((!showSendNotify) ? 'style=\"opacity: 0.38;\"' : 'style=\"color: \\#f0ad4e;\"')#></div>",
4471 width:
"20px", hidden: !commercialAccess}
4474 change:
function( e ) {
4476 var selectedCell = this.select();
4477 var cellIndex = selectedCell[0].cellIndex;
4478 var selectedRow = selectedCell.closest(
"tr");
4481 achCurrSelectedBatchItem = achHistoryGrid.dataItem(selectedRow);
4484 <?php
if ($advPerm) { ?>
4486 if ( achCurrSelectedBatchItem.hasACHFile ) {
4489 $(
"#achBatchId").val( achCurrSelectedBatchItem.batch_id );
4490 $(
"#achBatchOperation").attr(
"name",
"operation" );
4491 $(
"#achPostForm").attr(
"action",
"<?php echo $pAdmEnv["self"] ?>" );
4492 $(
"#achPostForm").attr(
"target",
"" );
4493 $(
"#achBatchOperation").val(
"ach_download_file" );
4494 $(
"#achPostForm").submit();
4497 CreateACHFile( achCurrSelectedBatchItem.batch_id );
4504 if ( achCurrSelectedBatchItem.showSendNotify ) {
4505 SendNotifications( achCurrSelectedBatchItem.batch_id );
4513 if ( achCurrSelectedBatchItem.hasACHReport ) {
4515 $(
"#achBatchId").val( achCurrSelectedBatchItem.batch_id );
4516 $(
"#achBatchOperation").attr(
"name",
"page" );
4517 $(
"#achBatchOperation").val(
"ach_show_report" );
4518 $(
"#achPostForm").attr(
"action",
"<?php echo $pAdmEnv["menu_link
"] ?>?ft=101" );
4519 $(
"#achPostForm").attr(
"target",
"achreport" );
4520 $(
"#achPostForm").submit();
4525 GetBatchDetail( achCurrSelectedBatchItem.batch_id );
4529 selectedCell.removeClass(
"k-state-selected" );
4531 dataBound:
function( e ) {
4534 }).data(
"kendoGrid");
4537 achBatchItemGrid = $(
"#achBatchItemGrid").kendoGrid({
4538 dataSource:
new kendo.data.DataSource({
4540 read:
function( options ) {
4541 var data = achBatchItems;
4542 options.success(data);
4549 template:
"<div class='vsgSecondary'>No available ACH transactions were found</div>" 4552 <?php
if ($advPerm) { ?>
4553 {field:
"remove", title:
"Remove", width:
"30px",
4555 template:
"<input type=\"checkbox\" onclick=\"SelectRemove(this);\">",
4556 headerTemplate:
"<input type=\"checkbox\" onclick=\"SelectRemoveAll(this);\">" 4559 {field:
"group", title:
"Group" },
4560 {field:
"feature", title:
"Type",
4561 template:
"#= ( featureList[feature] === undefined ) ? feature : featureList[feature] #"},
4562 {field:
"amount", title:
"Amount" },
4563 {field:
"account", title:
"Account" },
4564 {field:
"memo", title:
"Memo" }
4566 change:
function(e) {
4569 var selectedRow = this.select();
4574 if (removeFromBatchAllowed) {
4575 var selectedInput = this.select().find(
"td:eq(0) input[type=\"checkbox\"]");
4576 selectedInput.click();
4580 selectedRow.removeClass(
"k-state-selected" );
4582 dataBound:
function( e ) {
4585 this.wrapper.find(
"input[type=\"checkbox\"]").each(
function(e) {
4586 $(
this).prop(
"checked",
false);
4589 }).data(
"kendoGrid");
4591 batchDetailWindow = $(
"#batchItems").kendoWindow({
4598 title:
"ACH Upload File Details.",
4599 activate:
function(e) {
4601 window_stack.push(
function(e) {
4602 batchDetailWindow.close(e);
4606 $.homecuValidator.setup({
4607 formStatusField:
"batchItemForm" 4610 $(
"#lnkRemove").off();
4611 $(
"#lnkRemove").click(
function() {
4614 var transListRemove = GetSelectedTransactions();
4615 <?php
if ($advPerm) { ?>
4616 if (transListRemove !=
"") {
4617 removeConfirm.open();
4622 $(
"#batchItemsClose").off();
4623 $(
"#batchItemsClose").click(
function(e) {
4625 batchDetailWindow.close();
4629 this.title(
"ACH Upload File Details: " + achCurrSelectedBatchItem.batch_time );
4632 this.wrapper.css({ top: 100 });
4635 achBatchItemGrid.dataSource.read();
4637 <?php
if ($advPerm) { ?>
4638 if (removeFromBatchAllowed) {
4639 achBatchItemGrid.showColumn(0);
4640 $(
"#removeTranSecondaryText").show();
4641 $(
"#lnkRemove").show();
4643 achBatchItemGrid.hideColumn(0);
4644 $(
"#removeTranSecondaryText").hide();
4645 $(
"#lnkRemove").hide();
4649 close:
function(e) {
4651 $(
"#lnkRemove").addClass(
"vsgDisabled");
4656 $.homecuValidator.setup({
4657 formStatusField:
"formACHStatus" 4660 }).data(
"kendoWindow");
4662 <?php
if ($advPerm) { ?>
4663 removeConfirm = $(
"#removeConfirmDialog").kendoDialog({
4664 title:
"Remove Transactions",
4665 content: $(
"#removeConfirmDialogTemplate").html(),
4671 window_stack.push(
function(e) {
4672 removeConfirm.close(e);
4675 close:
function(e) {
4680 action:
function(e) { }
4682 { text:
"Yes", primary:
true,
4683 action: RemoveTransactions
4686 }).data(
"kendoDialog");
4689 infoDialog = $(
"#infoDialog").kendoDialog({
4690 title:
"ACH Batch Warning",
4696 window_stack.push(
function(e) {
4697 infoDialog.close(e);
4704 { text:
"Ok", primary:
true,
4705 action:
function(e) {}
4708 }).data(
"kendoDialog");
4714 $(document).on(
"click",
".k-overlay",
function (e) {
4715 if(window_stack.length > 0) {
4717 var fn = window_stack[window_stack.length - 1];
4724 function GetSelectedTransactions() {
4725 var transListRemove =
"";
4727 achBatchItemGrid.wrapper.find(
"tbody tr").each(
function(e, i) {
4728 var isChecked = $(
this).find(
"td:eq(0) input").prop(
"checked");
4729 var dataItem = achBatchItemGrid.dataItem(i);
4731 transListRemove += dataItem.id;
4732 transListRemove +=
",";
4736 transListRemove = transListRemove.replace(/(,$)/g,
'');
4737 transListRemove = transListRemove.trim();
4738 return transListRemove;
4741 function RemoveTransactions() {
4742 var batchId = achCurrSelectedBatchItem.batch_id;
4743 var transListRemove = GetSelectedTransactions();
4746 operation:
"achRemoveBatchTransactions",
4748 trans_list: transListRemove
4751 dsACHHelper.read( request );
4755 function SelectRemoveAll(e) {
4757 var inputChecked = input.prop(
"checked");
4759 achBatchItemGrid.wrapper.find(
"tbody tr").each(
function(e) {
4760 $(
this).find(
"td:eq(0) input[type=\"checkbox\"]").prop(
"checked", inputChecked);
4764 $(
"#lnkRemove").removeClass(
"vsgDisabled");
4766 $(
"#lnkRemove").addClass(
"vsgDisabled");
4770 function SelectRemove(e) {
4772 var headerInput = achBatchItemGrid.wrapper.find(
"thead tr th:eq(0) input[type=\"checkbox\"]");
4773 var headerChecked = headerInput.prop(
"checked");
4776 var numRows = numChecked = 0;
4777 achBatchItemGrid.wrapper.find(
"tbody tr").each(
function(e) {
4778 var isChecked = $(
this).find(
"td:eq(0) input[type=\"checkbox\"]").prop(
"checked");
4787 if (numChecked == numRows) {
4788 headerInput.prop(
"checked",
true);
4790 headerInput.prop(
"checked",
false);
4793 if (numChecked > 0) {
4794 $(
"#lnkRemove").removeClass(
"vsgDisabled");
4796 $(
"#lnkRemove").addClass(
"vsgDisabled");
4800 function GetACHBatches() {
4801 var request = { operation:
"achGetBatches" };
4803 dsACHHelper.read( request );
4806 function ShowACHBatches( achList ) {
4808 for ( var i = 0; i < achList.length; i++ ) {
4814 var setShowSendNotify =
4815 (achList[i].notify > 0) &&
4816 (achList[i].has_ach_file);
4818 var newObject = {batch_id: achList[i].batch_id,
4819 count: achList[i].count,
4820 processed_by: achList[i].processed_by,
4821 batch_time: achList[i].display,
4822 hasACHFile: achList[i].has_ach_file,
4823 hasACHReport: achList[i].has_ach_report,
4824 showSendNotify: setShowSendNotify
4826 achBatchList.push( newObject );
4829 achHistoryGrid.dataSource.data(achBatchList);
4832 function GetBatchDetail(
id ) {
4833 var request = { operation:
"achGetBatchDetail", batch_id:
id };
4835 dsACHHelper.read( request );
4837 function ShowACHBatchDetail( batchData ) {
4838 achBatchItems = batchData.records;
4839 removeFromBatchAllowed = batchData.removeFromBatchAllowed;
4842 batchDetailWindow.open().center();
4846 <?php
if ($advPerm) { ?>
4847 function CreateACHFile(
id ) {
4848 var request = { operation:
"achCreateFile", batch_id:
id };
4850 dsACHHelper.read( request );
4852 function UpdateACHResults( data, updateType ) {
4854 var batchId = data.hasOwnProperty(
"batch_id") ? data.batch_id :
"";
4855 var batchRecord = data.hasOwnProperty(
"batch_record") ? data.batch_record : [];
4857 var removeIndex = -1;
4858 for ( var i = 0; i < achBatchList.length; i++ ) {
4859 if ( achBatchList[i].batch_id == batchId ) {
4863 if ( updateType ==
"achNotify" ) {
4864 achBatchList[i].showSendNotify =
false;
4865 achBatchList[i].notify = 0;
4868 if ( updateType ==
"achRemove" || updateType ==
"achFile" ) {
4871 if (batchRecord.length == 0) {
4872 achBatchList.splice(i, 1);
4877 achBatchList[i].count = batchRecord.count;
4878 achBatchList[i].notify = batchRecord.notify;
4879 achBatchList[i].hasACHFile = batchRecord.has_ach_file;
4880 achBatchList[i].hasACHReport = batchRecord.has_ach_report;
4881 achBatchList[i].showSendNotify = batchRecord.notify > 0;
4886 achHistoryGrid.dataSource.data(achBatchList);
4889 function SendNotifications(
id ) {
4890 var request = { operation:
"achSendNotifications", batch_id:
id };
4892 dsACHHelper.read( request );
4897 <?php PrintCommonStyle() ?>
4899 #achBody .k-grid td { 4900 white-space: nowrap;
4901 text-overflow: ellipsis;
4903 #achBody .k-grid .k-grid-content tr:hover { 4906 .hcu-scrolling-dialog {
4910 <?php
if ($advPerm) { ?>
4911 <script type=
"text/template" id=
"removeConfirmDialogTemplate">
4915 You are about to
remove these transactions from
this ACH upload file.<br><br>
4916 This action cannot be undone. If you have already successfully submitted the ACH upload file you should not be doing this.<br><br>
4917 New ACH upload and report files will be generated automatically.
4920 <p>Do you wish to
continue?</p>
4924 <div
id=
"infoDialog"></div>
4925 <?php
if ($advPerm) { ?>
4926 <div
id=
"removeConfirmDialog"></div>
4928 <div
id=
"batchItems" class=
"container-fluid hcu-scrolling-dialog">
4929 <div
id=
"batchItemForm"></div>
4931 <div
class=
"col-xs-12 hcu-secondary">
4932 <?php
if ($advPerm) { ?>
4933 <div
class=
"small vsgSecondary" id=
"removeTranSecondaryText">
4934 <span>To
remove transactions from
this ACH upload file, use the checkboxes to select the records you wish to
remove and click
"Remove" below.</span>
4939 <div
id=
"achBatchItemGrid"></div>
4940 <div
class=
"hcu-template">
4941 <div
class=
"hcu-edit-buttons k-state-default">
4942 <?php
if ($advPerm) { ?>
4943 <span
class=
"hcu-icon-delete">
4944 <a href=
"#" id=
"lnkRemove" class=
"vsgDisabled">Remove</a>
4947 <button href=
"##" id=
"batchItemsClose" class=
"k-button k-primary">
4953 <form
id=
"achPostForm" action=
"<?php echo $self; ?>" method=
"post">
4954 <input type=
"hidden" id=
"achBatchId" name=
"batch_id" value=
"">
4955 <input type=
"hidden" id=
"achBatchOperation" name=
"operation" value=
"ach_create_file">
4956 <input type=
"hidden" name=
"download_type" value=
"ach">
4958 <div
id=
"achBody" class=
"container-fluid">
4959 <div
id=
"formACHStatus" class=
"homecu-formStatus k-block k-error-colored" style=
"display:none;"></div>
4962 <div
class=
"form-horizontal well well-sm">
4964 <div
class=
"col-xs-12"><h2>ACH History</h2></div>
4967 <div
class=
"col-xs-12 hcu-secondary">
4968 <div
class=
"small vsgSecondary">Click row to see detail.</div>
4969 <!-- only show
this label
if credit
union has access to commercial ach -->
4970 <?php if ($advPerm) { ?>
4971 <?php
if ($pAdmEnv[
'commercialAccess']): ?>
4972 <div
class=
"small vsgSecondary">Click the <span
class=
"fa fa-envelope" style=
"color: #f0ad4e;"></span> to restart the email notification process.</div>
4975 <div
class=
"small vsgSecondary">You have basic permissions. The downloading and resending email actions are not available to you.</div>
4980 <div
class=
"col-xs-12"><div
id=
"achHistoryGrid"></div></div>
4983 if ( getenv(
"DEVMODE" ) == 1 ) {
4987 visibility: visible;
4990 <div
class=
"k-block" style=
"margin: 1em; border: 5px ridge lightblue; border-radius: 10px;">
4991 <div style=
"margin:2px;">ACH File Validator (developer tool)</div>
4992 <form method=
"post" action=
"<?php echo $self; ?>" >
4993 <input type=
"hidden" name=
"page" value=
"validate">
4994 <div
class=
"demo-section k-content">
4995 <input name=
"achFile" id=
"files" type=
"file" />
4996 <label>Show Raw File Output <input type=
"checkbox" name=
"show_raw" id=
"show_raw" /></label>
4997 <p style=
"text-align: right">
4998 <input type=
"submit" value=
"Submit" class=
"k-button k-primary" />
5004 $(document).ready(
function() {
5005 $(
"#files").kendoUpload({
5008 allowedExtensions: [
".ACH",
".ach",
".txt"],
5011 select:
'Select File To Upload',
5036 function PrintAchReport( $pAdmEnv, $pAdmVars ) {
5039 $cu = strtolower( $pAdmEnv[
"Cu"] );
5040 $advPerm = $pAdmEnv[
"advPerm"];
5042 $payloadInfo = HCU_PayloadDecode( $pAdmEnv[
"Cu"], $pAdmVars[
"batch_id"] );
5045 $myDateTime =
new DateTime( $payloadInfo[
"batch_date"] );
5048 $tz = GetCreditUnionTimezone( $pAdmEnv[
"dbh"], $pAdmEnv[
"Cu"] );
5050 $myDateTime->setTimezone(
new DateTimeZone($tz));
5051 $batchDay = $myDateTime->format(
"ymd");
5052 $batchHour = $myDateTime->format(
"His");
5053 $batchPreName =
"Batch";
5054 $batchPath =
"/home/{$cu}/admin/ach/";
5056 $achFileName =
"{$batchPreName}_{$batchDay}_{$batchHour}.txt";
5059 if (!file_exists(
"{$batchPath}{$achFileName}")) {
5060 ShowErrorPage(
"Unable to find ACH report file" );
5065 $fileString = file_get_contents(
"{$batchPath}{$achFileName}" );
5066 if ( $fileString ===
false ) {
5067 ShowErrorPage(
"Unable to find ACH report file" );
5071 }
catch (Exception $ex) {
5072 ShowErrorPage(
"Unexpected error trying to show ACH report: {$ex->getMessage()}" );
5078 <title><?php echo $achFileName ?></title>
5081 setIncludeFiles(
false,
false, GetAdminDefaultKendoStyle(),
false, $pAdmEnv);
5088 background-color: white;
5091 .ach-report-wrapper {
5095 .ach-pre-scrollable pre {
5096 background-color: white;
5098 page-
break-inside:
auto;
5103 background-color: white;
5106 .ach-report-wrapper {
5110 .ach-pre-scrollable {
5112 -ms-word-wrap: normal;
5114 overflow-wrap: normal;
5119 .ach-pre-scrollable pre {
5120 background-color: white;
5125 <body
class=
"ach-report-body">
5126 <script type=
"text/javascript">
5127 $(document).ready(
function() {
5128 $(
"#printReport").click(
function() {
5131 $(
"#closeReport").click(
function() {
5134 <?php
if ($advPerm) { ?>
5135 $(
"#downloadReport").click(
function() {
5136 $(
"#achReportForm").submit();
5140 if ( isset( $pAdmVars[
"download"] ) && $pAdmVars[
"download"] ==
"download" ) {
5142 $(
"#achPostForm").submit();
5148 <?php
if ($advPerm) { ?>
5149 <form
id=
"achReportForm" action=
"<?php echo $pAdmEnv["menu_link
"]; ?>?ft=100" method=
"post">
5150 <input type=
"hidden" id=
"achBatchId" name=
"batch_id" value=
"<?php echo $pAdmVars["batch_id
"]; ?>">
5151 <input type=
"hidden" id=
"achBatchOperation" name=
"operation" value=
"ach_download_file">
5152 <input type=
"hidden" name=
"download_type" value=
"report">
5155 <div
class=
"container-fluid ach-report-wrapper">
5156 <div
class=
"form-horizontal well well-sm hidden-print">
5158 <div
class=
"col-xs-12 h4 text-center">Odyssey ACH Report</div>
5161 <div
class=
"col-xs-12 text-center">
5162 <div
class=
"btn-group" role=
"group" aria-label=
"...">
5163 <?php
if ($advPerm) { ?>
5164 <button
id=
"downloadReport" class=
"btn">Download</button>
5166 <button
id=
"closeReport" class=
"btn">Close</button>
5167 <button
id=
"printReport" class=
"btn">Print</button>
5172 <div
class=
"ach-pre-scrollable">
5174 <?php echo $fileString ?>
5180 if ( isset($pAdmVars[
"download"]) && $pAdmVars[
"download"] ==
"download" ) {
5183 <form
id=
"achPostForm" action=
"<?php echo $pAdmEnv["menu_link
"]; ?>?ft=100" method=
"post">
5184 <input type=
"hidden" id=
"achBatchId" name=
"batch_id" value=
"<?php echo $pAdmVars["batch_id
"]; ?>">
5185 <input type=
"hidden" id=
"achBatchOperation" name=
"operation" value=
"ach_download_file">
5186 <input type=
"hidden" name=
"download_type" value=
"ach">
5203 function PrintValidate( $pAdmEnv, $pAdmVars ) {
5205 <script type=
"text/javascript">
5206 $(document).ready(
function() {
5207 $(
".returnLink").click(
function() {
5208 $(
"#redirectForm").submit();
5214 <div
class=
"container-fluid">
5215 <form
id=
"redirectForm" action=
"<?php echo $pAdmEnv["self"]; ?>" method=
"post">
5216 <input type=
"hidden" name=
"page" value=
"">
5218 <div><a
class=
"returnLink" style=
"cursor:pointer;">Return</a></div>
5220 <div
id=
"formValidateDiv" class=
"k-block k-error-colored" style=
"display:none">
5224 $name =
"Filename Not Found";
5228 if ( $_FILES[
'achFile'][
'error'] == UPLOAD_ERR_OK ) {
5229 $tmp_name = $_FILES[
"achFile"][
"tmp_name"];
5232 $name = basename($_FILES[
"achFile"][
"name"]);
5235 if ( !preg_match(
"`^[-0-9A-Z_\.]+$`i",$name) ) {
5236 $name =
"Your ACH File";
5240 $fileContents = file( $tmp_name, FILE_IGNORE_NEW_LINES );
5243 unlink( $tmp_name );
5248 require_once( dirname(__FILE__) .
"/../library/aACHValidate.i" );
5251 $fileHeaderArray = array();
5252 $companyHeaderArray = array();
5253 $entryDetailArray = array();
5255 $printWarningList = array();
5256 $printErrorList = array();
5258 $printErrorList[] =
"ACH File Validate Error - Error uploading file. Please try again.";
5262 $fileRecordCount = 0;
5263 $validRecordTypes = [
"1",
"5",
"6",
"7",
"8",
"9"];
5264 for ( $i = 0; $i < count( $fileContents ); $i++ ) {
5265 $recordType = substr( $fileContents[$i], 0, 1 );
5267 if ( !in_array( $recordType, $validRecordTypes ) ) {
5268 $printErrorList[] =
"Unexpected ACH Record Type: $recordType";
5273 if ( !preg_match( ALPHAMERIC_STRING, $fileContents[$i] ) ) {
5274 $printErrorList[] =
"Invalid ACH character on line $i";
5275 $printErrorList[] =
"**{$fileContents[$i]}**";
5280 $testString = preg_replace(
"/[\r\n]+/",
"", $fileContents[$i] );
5281 if ( strlen( $testString ) != 94 ) {
5282 $checkString = str_replace(
" ",
"_", $testString );
5283 $printErrorList[] =
"ACH Record length not 94 characters. Record: $i (zero-based)" . strlen( $checkString );
5284 $printErrorList[] =
"ACH Record: " . $checkString;
5292 $fileContentsLine = 0;
5294 if ( !count( $printErrorList ) ) {
5296 $extractionResults = GetFileHeaderRecord( $pAdmEnv, $fileContents[$fileContentsLine++] );
5297 if ( $extractionResults[
"code"] !=
"000" ) {
5298 $printErrorList[] =
"ACH File extraction error";
5299 $printErrorList[] = $extractionResults[
"error"][0];
5300 $printWarningList[] = $extractionResults[
"warning"][0];
5302 $fileHeaderArray = $extractionResults[
"data"];
5304 $results = ValidateFileHeaderRecord( $pAdmEnv, $fileHeaderArray );
5305 if ( count( $results[
"error"] ) ) {
5306 $printErrorList[] =
"Invalid ACH File - File Header Record";
5308 for ( $e = 0; $e < count($results[
"error"]); $e++ ) {
5309 $printErrorList[] = $results[
"error"][$e];
5312 if ( count( $results[
"warning"] ) ) {
5313 $printWarningList[] =
"ACH File Header Record Warnings";
5315 for ( $e = 0; $e < count($results[
"warning"]); $e++ ) {
5316 $printWarningList[] = $results[
"warning"][$e];
5320 if ( count( $fileHeaderArray ) ) {
5321 print
"<div class='k-block' style='background-color: lightcyan;'>";
5322 print
"<div class='h4'>File Header</div>";
5324 $arrayKeys = array_keys( $fileHeaderArray );
5325 for ( $i = 0; $i < count( $arrayKeys ); $i++ ) {
5326 print
"<b>{$arrayKeys[$i]}</b>: <span style='background-color:white'>{$fileHeaderArray[$arrayKeys[$i]]}</span><br>";
5335 $fileBatchCount = 0;
5336 $fileEntryAddendaCount = 0;
5338 $fileTotalDebitEntryDollarAmount = 0;
5339 $fileTotalCreditEntryDollarAmount = 0;
5343 $companyHeaderArray =
null;
5344 if ( !count( $printErrorList ) ) {
5346 $extractionResults = GetCompanyHeaderRecord( $pAdmEnv, $fileContents[$fileContentsLine++] );
5347 if ( $extractionResults[
"code"] !=
"000" ) {
5348 $printErrorList[] =
"ACH File extraction error";
5349 $printErrorList[] = $extractionResults[
"error"];
5351 $companyHeaderArray = $extractionResults[
"data"];
5353 $results = ValidateCompanyHeaderRecord( $pAdmEnv, $companyHeaderArray );
5354 if ( count( $results[
"error"] ) ) {
5355 $printErrorList[] =
"Invalid ACH File - Company Header Record";
5357 for ( $e = 0; $e < count($results[
"error"]); $e++ ) {
5358 $printErrorList[] = $results[
"error"][$e];
5361 if ( count( $results[
"warning"] ) ) {
5362 $printWarningList[] =
"ACH Company Header Record Warnings";
5364 for ( $e = 0; $e < count($results[
"warning"]); $e++ ) {
5365 $printWarningList[] = $results[
"warning"][$e];
5369 if ( count( $companyHeaderArray ) ) {
5370 print
"<div class='k-block k-info-colored'>";
5371 print
"<div class='h4'>Company Header</div>";
5372 $arrayKeys = array_keys( $companyHeaderArray );
5373 for ( $i = 0; $i < count( $arrayKeys ); $i++ ) {
5374 print
"<b>{$arrayKeys[$i]}</b>: <span style='background-color:white'>{$companyHeaderArray[$arrayKeys[$i]]}</span><br>";
5383 print
"<div style='margin-left: 2em'>";
5386 $companyEntryAddendaCount = 0;
5387 $companyEntryHash = 0;
5388 $companyTotalDebitEntryDollarAmount = 0;
5389 $companyTotalCreditEntryDollarAmount = 0;
5391 if ( !count( $printErrorList ) ) {
5393 $extractionResults = GetEntryDetailRecord( $pAdmEnv, $fileContents[$fileContentsLine++] );
5394 if ( $extractionResults[
"code"] !=
"000" ) {
5395 $printErrorList[] =
"ACH File extraction error";
5396 $printErrorList[] = $extractionResults[
"error"];
5398 $entryDetailArray = $extractionResults[
"data"];
5400 $results = ValidateEntryDetailRecord( $pAdmEnv, $entryDetailArray, $companyHeaderArray );
5401 if ( count( $results[
"error"] ) ) {
5402 $printErrorList[] =
"Invalid ACH File - Entry Detail Record";
5404 for ( $e = 0; $e < count($results[
"error"]); $e++ ) {
5405 $printErrorList[] = $results[
"error"][$e];
5408 if ( count( $results[
"warning"] ) ) {
5409 $printWarningList[] =
"ACH Entry Detail Record Warnings";
5411 for ( $e = 0; $e < count($results[
"warning"]); $e++ ) {
5412 $printWarningList[] = $results[
"warning"][$e];
5415 if ( count( $entryDetailArray ) ) {
5416 print
"<div class='k-block'>";
5417 print
"<div class='h4'>Entry Detail</div>";
5418 $arrayKeys = array_keys( $entryDetailArray );
5419 for ( $i = 0; $i < count( $arrayKeys ); $i++ ) {
5420 print
"<b>{$arrayKeys[$i]}</b>: <span style='background-color:white'>{$entryDetailArray[$arrayKeys[$i]]}</span><br>";
5429 if ( !count( $printErrorList ) ) {
5430 $companyEntryAddendaCount++;
5432 $companyEntryHash += $entryDetailArray[
"ReceivingDFI"];
5433 if ( $entryDetailArray[
"TransactionCode"] ==
"22" ||
5434 $entryDetailArray[
"TransactionCode"] ==
"32" ||
5435 $entryDetailArray[
"TransactionCode"] ==
"42" ||
5436 $entryDetailArray[
"TransactionCode"] ==
"52" ) {
5437 $companyTotalCreditEntryDollarAmount += $entryDetailArray[
"Amount"];
5439 $companyTotalDebitEntryDollarAmount += $entryDetailArray[
"Amount"];
5443 $addendaDetailArray = array();
5444 if ( !count( $printErrorList ) &&
5445 $entryDetailArray[
"AddendaRecordIndicator"] ==
"1" ) {
5446 $extractionResults = GetAddendaRecord( $pAdmEnv, $fileContents[$fileContentsLine++] );
5447 if ( $extractionResults[
"code"] !=
"000" ) {
5448 $printErrorList[] =
"ACH File extraction error";
5449 $printErrorList[] = $extractionResults[
"error"];
5451 $addendaDetailArray = $extractionResults[
"data"];
5453 $entryDetailSequenceNumber = substr( $entryDetailArray[
"TraceNumber"], -7 );
5454 $results = ValidateAddendaRecord( $pAdmEnv, $addendaDetailArray, $entryDetailSequenceNumber );
5455 if ( count( $results[
"error"] ) ) {
5456 $printErrorList[] =
"Invalid ACH File - Addenda Record";
5458 for ( $e = 0; $e < count($results[
"error"]); $e++ ) {
5459 $printErrorList[] = $results[
"error"][$e];
5462 if ( count( $results[
"warning"] ) ) {
5463 $printWarningList[] =
"ACH Entry Detail Record Warnings";
5465 for ( $e = 0; $e < count($results[
"warning"]); $e++ ) {
5466 $printWarningList[] = $results[
"warning"][$e];
5469 if ( count( $addendaDetailArray ) ) {
5470 print
"<div class='k-block' style='background-color:BlanchedAlmond;'>";
5471 print
"<div class='h4'>Addenda Detail</div>";
5472 $arrayKeys = array_keys( $addendaDetailArray );
5473 for ( $i = 0; $i < count( $arrayKeys ); $i++ ) {
5474 print
"<b>{$arrayKeys[$i]}</b>: <span style='background-color:white'>{$addendaDetailArray[$arrayKeys[$i]]}</span><br>";
5483 if ( !count( $printErrorList ) &&
5484 isset( $addendaDetailArray[
"RecordTypeCode"] ) &&
5485 $addendaDetailArray[
"RecordTypeCode"] ==
"7") {
5486 $companyEntryAddendaCount++;
5490 $nextTypeCode = substr( $fileContents[$fileContentsLine], 0 , 1 );
5491 }
while ( !count( $printErrorList ) && $nextTypeCode != 8 );
5494 if ( !count( $printErrorList ) ) {
5496 $extractionResults = GetCompanyControlRecord( $pAdmEnv, $fileContents[$fileContentsLine++] );
5497 if ( $extractionResults[
"code"] !=
"000" ) {
5498 $printErrorList[] =
"ACH File extraction error";
5499 $printErrorList[] = $extractionResults[
"error"];
5501 $companyControlArray = $extractionResults[
"data"];
5503 $results = ValidateCompanyControlRecord( $pAdmEnv, $companyControlArray );
5504 if ( count( $results[
"error"] ) ) {
5505 $printErrorList[] =
"Invalid ACH File - Company Control Record";
5507 for ( $e = 0; $e < count($results[
"error"]); $e++ ) {
5508 $printErrorList[] = $results[
"error"][$e];
5511 if ( count( $results[
"warning"] ) ) {
5512 $printWarningList[] =
"ACH Company Control Record Warnings";
5514 for ( $e = 0; $e < count($results[
"warning"]); $e++ ) {
5515 $printWarningList[] = $results[
"warning"][$e];
5519 if ( count( $companyControlArray ) ) {
5520 print
"<div class='k-block k-success-colored'>";
5521 print
"<div class='h4'>Company Control Record</div>";
5522 $arrayKeys = array_keys( $companyControlArray );
5523 for ( $i = 0; $i < count( $arrayKeys ); $i++ ) {
5524 print
"<b>{$arrayKeys[$i]}</b>: <span style='background-color:white'>{$companyControlArray[$arrayKeys[$i]]}</span><br>";
5532 if ( !count( $printErrorList ) ) {
5533 if ( intval( $companyEntryAddendaCount ) != intval( $companyControlArray[
"EntryAddendaCount"] ) ) {
5534 $printErrorList[] =
"Company control record Entry Addenda Count does not match: $companyEntryAddendaCount vs {$companyControlArray["EntryAddendaCount
"]}";
5537 $hashTest = str_pad( $companyEntryHash, 10,
"0", STR_PAD_LEFT );
5539 if ( $hashTest !== $companyControlArray[
"EntryHash"] ) {
5540 $printErrorList[] =
"Company control record Entry Hash does not match";
5543 if ( $companyTotalDebitEntryDollarAmount != $companyControlArray[
"TotalDebitEntryDollarAmount"] ) {
5544 print
"Test: Debit: $companyTotalDebitEntryDollarAmount, Credit: $companyTotalCreditEntryDollarAmount<br>";
5545 print_r( $companyControlArray );
5546 $printErrorList[] =
"Company control record Total Debit Entry Dollar Amount does not match {$companyTotalDebitEntryDollarAmount} vs {$companyControlArray["TotalDebitEntry
"]}";
5549 if ( $companyTotalCreditEntryDollarAmount != $companyControlArray[
"TotalCreditEntryDollarAmount"] ) {
5550 print
"Test: Debit: $companyTotalDebitEntryDollarAmount, Credit: $companyTotalCreditEntryDollarAmount<br>";
5551 print_r( $companyControlArray );
5552 $printErrorList[] =
"Company control record Total Credit Entry Dollar Amount does not match {$companyTotalCreditEntryDollarAmount} vs {$companyControlArray["TotalCreditEntry
"]}";
5555 if ( $companyHeaderArray[
"CompanyID"] != $companyControlArray[
"CompanyID"] ) {
5556 $printErrorList[] =
"Company control record Company Identifier does not match";
5559 if ( $companyHeaderArray[
"BatchNumber"] != $companyControlArray[
"BatchNumber"] ) {
5560 $printErrorList[] =
"Company control record Batch Number does not match";
5564 if ( !count( $printErrorList ) ) {
5567 $fileEntryAddendaCount += $companyEntryAddendaCount;
5568 $fileEntryHash += $companyEntryHash;
5569 $fileTotalDebitEntryDollarAmount += $companyTotalDebitEntryDollarAmount;
5570 $fileTotalCreditEntryDollarAmount += $companyTotalCreditEntryDollarAmount;
5576 $nextTypeCode = substr( $fileContents[$fileContentsLine], 0 , 1 );
5577 }
while (!count( $printErrorList ) && $nextTypeCode != 9 );
5580 if ( !count( $printErrorList ) ) {
5582 $extractionResults = GetFileControlRecord( $pAdmEnv, $fileContents[$fileContentsLine++] );
5583 if ( $extractionResults[
"code"] !=
"000" ) {
5584 $printErrorList[] =
"ACH File extraction error";
5585 $printErrorList[] = $extractionResults[
"error"];
5587 $fileControlArray = $extractionResults[
"data"];
5589 $results = ValidateFileControlRecord( $pAdmEnv, $fileControlArray );
5590 if ( count( $results[
"error"] ) ) {
5591 $printErrorList[] =
"Invalid ACH File - File Control Record";
5593 for ( $e = 0; $e < count($results[
"error"]); $e++ ) {
5594 $printErrorList[] = $results[
"error"][$e];
5597 if ( count( $results[
"warning"] ) ) {
5598 $printWarningList[] =
"ACH File Control Record Warnings";
5600 for ( $e = 0; $e < count($results[
"warning"]); $e++ ) {
5601 $printWarningList[] = $results[
"warning"][$e];
5605 if ( count( $fileControlArray ) ) {
5606 print
"<div class='k-block' style='background-color: lightcyan;'>";
5607 print
"<div class='h4'>File Control Record</div>";
5608 $arrayKeys = array_keys( $fileControlArray );
5609 for ( $i = 0; $i < count( $arrayKeys ); $i++ ) {
5610 print
"<b>{$arrayKeys[$i]}</b>: <span style='background-color:white'>{$fileControlArray[$arrayKeys[$i]]}</span><br>";
5618 if ( !count( $printErrorList ) ) {
5619 if ( $fileBatchCount != $fileControlArray[
"BatchCount"] ) {
5620 $printErrorList[] =
"File Control record Batch Count does not match";
5621 $printErrorList[] =
"Counted: $fileBatchCount, Control record: {$fileControlArray["BatchCount
"]}";
5625 $fileBlockCount = round( $fileRecordCount / 10 );
5626 if ( $fileBlockCount != (
int) $fileControlArray[
"BlockCount"] ) {
5627 $printErrorList[] =
"File Control record Block Count does not match: counted $fileBlockCount; file {$fileControlArray["BlockCount
"]}";
5630 if ( $fileEntryAddendaCount != $fileControlArray[
"EntryAddendaCount"] ) {
5631 $printErrorList[] =
"File Control record Entry Addenda Count does not match";
5634 if ( strlen( $hashTest ) > 10 ) {
5635 $hashTest = substr( $fileEntryHash, -10 );
5637 $hashTest = str_pad( $fileEntryHash, 10,
"0", STR_PAD_LEFT );
5641 if ( $hashTest !== $fileControlArray[
"EntryHash"] ) {
5642 $printErrorList[] =
"File Control record Entry Hash does not match";
5645 if ( $fileTotalDebitEntryDollarAmount != $fileControlArray[
"TotalDebitEntryDollarAmount"] ) {
5646 $printErrorList[] =
"File Control record Total Debit Entry does not match";
5649 if ( $fileTotalCreditEntryDollarAmount != $fileControlArray[
"TotalCreditEntryDollarAmount"] ) {
5650 $printErrorList[] =
"File Control record Total Credit Entry does not match";
5655 }
catch (Exception $ex ) {
5656 $printErrorList[] = $ex->getMessage();
5660 if ( count( $printErrorList ) ) {
5661 $errorString .=
"The following <b>errors</b> occurred: ";
5662 $errorString .=
"<ul>";
5663 for ( $i = 0; $i < count( $printErrorList ); $i++ ) {
5664 $errorString .=
"<li>{$printErrorList[$i]}</li>";
5666 $errorString .=
"Validation stops if error found, so check the last record validated.";
5667 $errorString .=
"</ul>";
5669 if ( count( $printWarningList ) ) {
5670 $errorString .=
"The following <b>warnings</b> occurred: ";
5671 $errorString .=
"<ul>";
5672 for ( $i = 0; $i < count( $printWarningList ); $i++ ) {
5673 $errorString .=
"<li>{$printWarningList[$i]}</li>";
5675 $errorString .=
"</ul>";
5678 if ( isset( $pAdmVars[
"show_raw"] ) && $pAdmVars[
"show_raw"] ) {
5680 <div><a
class=
"returnLink" style=
"cursor:pointer;">Return</a></div>
5681 <div> Raw Data</div>
5682 <div> File <?php echo $name ?></div>
5684 for ( $i = 0; $i < count( $fileContents ); $i++ ) {
5685 print
"{$fileContents[$i]}<br>";
5691 <div><a
class=
"returnLink" style=
"cursor:pointer;">Return</a></div>
5693 $(document).ready(
function() {
5695 if ( strlen( $errorString ) ) {
5697 $(
"#formValidateDiv").html(
"<?php echo $errorString ?>" ).show();
5710 function PrintCommonStyle()
5718 input[type=
"email"], input[type=
"password"] {
5719 border-style: solid;
5721 font-family: inherit;
5734 .homecu-formStatus {
5735 margin-bottom: 10px;