4 #use LWP::Simple qw(get $ua); 13 # Fetches packets for live homebanking members with recurring transactions 15 # If provided, -p packetstamp is used as the fetch 'if_mod_since' parameter 16 # Otherwise, if_mod_since is set to current timestamp - 24 hours 17 # Fetcher cutoff is set to 'if_mod_since' - 1 day 19 # Loads alert tables (alertus, alertab, alertah, alertlb, alertlh) with data 20 # alertus contains user info for members with active repeating transactions 21 # alertab, alertah, alertlb, alertlh have homebanking data 23 # Processes recurring transactions and notifies members 26 $serviceMinimal =
true;
27 $serviceShowInfo =
false;
28 $serviceLoadMenu =
false;
29 $serviceShowMenu =
false;
30 $serviceLoadCuInfo =
false;
34 require_once(
'/var/www/html/banking/library/hcuService.i');
36 require_once(
'/var/www/html/shared/library/sAPIAppl.i');
37 require_once(
'/var/www/html/shared/library/sAPIAppl.std.i');
38 require_once(
'/var/www/html/banking/library/hcuTransferScheduled.i');
39 require_once(
'/var/www/html/banking/library/hcuTransfer.i');
42 require_once(
'/var/www/html/shared/library/cu_sms.i');
43 require_once(
"/var/www/html/shared/library/cu_data.i");
46 $logger = $HB_ENV[
"SYSENV"][
"logger"];
48 # # # # # # # # # # # # # # # # 49 # Import Server Variables 50 # # # # # # # # # # # # # # # # 61 $wwwhost =
'www0.homecu.net';
63 $dbhost = getenv(
'DATABASE_HOST');
64 $dbport = getenv(
'DATABASE_PORT');
65 $dbname = getenv(
'DATABASE_NAME');
66 $dbuser = getenv(
'DATABASE_USER');
67 $dbpasswd = getenv(
'DATABASE_PASSWORD');
69 $pReplyEmail =
"nobody@homecu.net";
72 # SET LONG CODE AVAILABLE NUMBERS (for alerts messaging) 73 $gRoundRobinCounter = 0;
74 $LONGCODE_ROUNDROBIN = array(
'+12672458136',
'+12082982149',
'+16017142198',
'+12082547302',
'+16017142199',
'+13306492200');
78 # a = action - either "alerts" or "scheduled" 79 # c = limit fetching and processing to this particular cu code 80 # x = exclude this cu code when fetching and processing 81 # l = limit number of packets retrieved 82 # n = nap interval between requests 83 # m = fetch and process for this member only 84 # p = 'if_mod_since' pktstamp to pass to fetcher 85 # s = skip loading tables 86 # f = fetch only - no messages sent 87 # t = limit fetching and processing to this particular time zone 88 # d = database host to use - fully-qualified host.homecu.net name 89 # r = runslot override - used to override the calculated runslot 97 $allowedOptions =
"c::l::n::m::p::t::x::d::s::f::r::";
98 $longOptions = array(
"help::",
"dryrun::" );
99 $commandOptions = getopt( $allowedOptions, $longOptions );
100 if ( $commandOptions === FALSE || isset( $commandOptions[
"help"] ) ) {
105 $action = trim( $argv[$argc-1] );
108 $opt_c = isset( $commandOptions[
"c"] ) ? $commandOptions[
"c"] :
"";
109 $opt_l = isset( $commandOptions[
"l"] ) ? $commandOptions[
"l"] :
"";
110 $opt_n = isset( $commandOptions[
"n"] ) ? $commandOptions[
"n"] :
"";
111 $opt_m = isset( $commandOptions[
"m"] ) ? $commandOptions[
"m"] :
"";
112 $opt_p = isset( $commandOptions[
"p"] ) ? $commandOptions[
"p"] :
"";
113 $opt_s = isset( $commandOptions[
"s"] ) ? true :
false;
114 $opt_f = isset( $commandOptions[
"f"] ) ? true :
false;
115 $opt_d = isset( $commandOptions[
"d"] ) ? $commandOptions[
"d"] :
"";
116 $opt_x = isset( $commandOptions[
"x"] ) ? $commandOptions[
"x"] :
"";
117 $opt_t = isset( $commandOptions[
"t"] ) ? $commandOptions[
"t"] :
"";
118 $opt_r = isset( $commandOptions[
"r"] ) ? trim( $commandOptions[
"r"] ) :
"";
120 $dryRun = isset( $commandOptions[
"dryrun"] );
122 $dryRunPrefix = $dryRun ?
"Dry run: " :
"";
125 if ( $action ==
"" || !($action ==
"alerts" || $action ==
"scheduled") ) {
126 print
"Missing action. Supported actions: alerts OR scheduled\n";
129 if (
"$opt_d" ==
"" &&
"$dbhost" ==
"" ) {
130 print
"Missing database host.\n";
133 if (
"$opt_r" !=
"" && !$opt_s ) {
134 print
"[-r runslot (DAYHHMM)] should be used with the [-s] (skip load) option.\n";
140 die(
"Usage: {$argv[0]} [-dDbhost] [-cCucode] [-xCucode] [-tTimezone] [-lLimit] [-nNap] [-mMember] [-pPktstamp] [-rRunslot] [-s] [-f] [--dryrun] <action>\n[runslot] is expected to be used with -s option\n<action> can be 'alerts' or 'scheduled'\n" );
143 if (
"$opt_d" !=
"" ) { $dbhost =
"$opt_d"; }
146 $WORKINGDIRECTORY =
"/home/homecu/html";
147 # Change Directory to where this script has permissions 148 chdir( $WORKINGDIRECTORY );
150 date_default_timezone_set (
"America/Denver" );
152 $DMSMAIL =
'support@homecu.net';
153 $ALERTMAIL =
'support@homecu.net';
155 $STARTDATE = date(
"D M d, Y G:i" );
156 $TODAY = date (
"Y-m-d" );
157 $STDOUT = fopen(
'php://stdout',
'w');
158 fwrite( $STDOUT,
"$STARTDATE $TODAY\n" );
163 list( $s, $m, $h, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();
165 # CREATE THE RUNSLOT value -- IT will be the key used in tables 166 $weekdays = array(
"SUN",
"MON",
"TUE",
"WED",
"THR",
"FRI",
"SAT");
167 # Minute segments -- sections of quarter hour 168 $minsegs = array(
"00",
"15",
"30",
"45");
171 # Create a string for the hour/min segment 172 $runslotPrefix = $action ==
"alerts" ?
"A" :
"S";
174 $HB_ENV[
'platform'] = ($action ==
"alerts" ?
"ALERT" :
"SCHED");
176 if ( strlen( $opt_r ) > 0 ) {
177 $runslotseg = substr( $opt_r, -4 );
178 $runslot = $runslotPrefix . $opt_r;
180 $runslotseg = sprintf(
"%02d", $h) . sprintf(
"%02d", $minsegs[intval($m / 15)]);
181 $runslot = $runslotPrefix . $weekdays[$wday] . $runslotseg;
184 $PIDFILE = $action ==
"alerts" ? $WORKINGDIRECTORY .
"/runalerts{$runslot}.pid" : $WORKINGDIRECTORY .
"/runrecur{$runslot}.pid";
185 if ( file_exists(
"$PIDFILE" ) ) {
186 $errorMessage =
"Prior PID file $PIDFILE still exists -- giving up";
188 print
"Dry Run: Would send error email to HomeCU: $errorMessage\n";
190 dmserror( $DMSMAIL,
'WARN',
"$errorMessage\n" );
195 $PID = fopen( $PIDFILE,
"w+" );
196 fwrite( $PID, getmypid() .
"\n" );
199 list ($s, $m, $h, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();
200 $T = sprintf(
"%4d%02d%02d%02d%02d%02d", 1900+$year,$mon+1,$mday,$h,$m,$s );
203 $STAT = fopen(
'php://stdout',
'w');
204 fprintf( $STAT,
"Dry Run: outputting to standard output\n" );
206 if ( $action ==
"alerts") {
207 $filename =
"alerts$T.txt";
208 $STAT = fopen( $filename,
"w+" );
209 }
else if ( $action ==
"scheduled" ) {
210 $filename =
"recurltx$T.txt";
211 $STAT = fopen( $filename,
"w+" );
213 dmserror( $DMSMAIL,
'FATAL',
"Unknown action: $action\n" );
216 fwrite( $STDOUT,
"Results will be in {$WORKINGDIRECTORY}/$filename\n" );
222 foreach( glob(
"recur*") as $filename ) {
224 if ( filemtime( $filename ) < (time() - 90 * 24 * 3600) ) {
226 fprintf( $STAT,
"Dry Run: removing old recurring file $filename\n" );
232 foreach( glob(
"alert*") as $filename ) {
234 if ( filemtime( $filename ) < (time() - 90 * 24 * 3600) ) {
236 fprintf( $STAT,
"Dry Run: removing old alerts file $filename\n" );
243 $cucode = ($opt_c ?
"'" . strtoupper($opt_c) .
"'" :
"");
244 $xcucode = ($opt_x ?
"'" . strtoupper($opt_x) .
"'":
"");
245 $opt_t = str_replace(
" ",
"", $opt_t );
246 $opt_t = ucfirst(strtolower($opt_t));
247 $limit = ($opt_l > 0 ? $opt_l :
"");
248 $nap = ( $opt_n < 0 ? 0 : intval( $opt_n ) );
249 $member = ($opt_m ? $opt_m :
"");
250 $skipload = ($opt_s ? 1 :
"");
251 $fetchonly = ($opt_f ? true :
false);
252 $pktstamp = (intval($opt_p) > 0 ? $opt_p : time() - 86400);
254 $alertdate = date(
"D M d Y H:i:s T");
256 $opt_m = str_replace(
" ",
"", $opt_m );
258 $memberSQL = ($opt_m ?
" and s.accountnumber = '$opt_m' " :
"");
260 if ( $opt_t ==
"Eastern" ) {
261 $timezoneSQL =
" and a.tz in ('Eastern','East-Indiana','Indiana-Starke','Michigan','America/Port_of_Spain','America/St_Thomas','America/Barbados') ";
262 } elseif ( $opt_t ==
"Pacific" ) {
263 $timezoneSQL =
" and a.tz in ('Pacific','Alaska','Arizona') ";
265 $timezoneSQL = ($opt_t ?
" and a.tz = '$opt_t' " :
"");
272 $sql_xcucodes = $xcucode;
273 $xcucode_arr = (! empty($xcucode))? [str_replace(
"'",
'', $xcucode)] : [];
277 if (($opt_t !=
'') && $xcucode ==
'') {
282 $xcu_arr = ReturnBlackList();
283 $sql_xcucodes =
"'" . implode(
"', '", $xcu_arr) .
"'";
284 $returnString =
"\nExcluded Blacklisted: $sql_xcucodes\n\n";
286 }
else if ( ($opt_t ==
"") && $cucode ==
"" ) {
287 # If timezone is BLANK 288 # AND cucode is currently blank -- 289 # THEN build cucode from the ReturnRunSlotList Function 290 # Pass the runslot segment to the function 'HH:MM' 291 $cucode = ReturnRunSlotList( $runslotseg );
294 $ignore_cu_arr = ReturnIgnoreList($dbh);
295 if (count($ignore_cu_arr) > 0) {
297 if ( $cucode ==
"" || ($cucode !=
"" && in_array($cucode, $ignore_cu_arr))) {
299 $sql_xcucodes =
"'" . implode(
"', '", array_unique(array_merge($xcucode_arr, $xcu_arr, $ignore_cu_arr))) .
"'";
300 $returnString =
"\nExcluded Blacklisted: " 301 .
"'" . implode(
"', '", $xcu_arr) .
"'" .
"\n";
302 if (count($xcucode_arr) > 0) {
303 $returnString .=
"Command line X option exclusions: " 304 .
"'" . implode(
"', '", $xcucode_arr) .
"'" .
"\n";
306 $returnString .=
"In Migration CUs Ignored: " 307 .
"'" . implode(
"', '", $ignore_cu_arr) .
"'\n\n";
311 fprintf( $STDOUT, $returnString );
313 fprintf( $STAT, $returnString );
317 ############ print out processing parameters ######## 318 fprintf( $STAT,
"Command options: \n" );
319 fprintf( $STAT,
"\tCU Code: $cucode\n" );
320 fprintf( $STAT,
"\tlimit: $opt_l\n" );
321 fprintf( $STAT,
"\tnap: $opt_n\n" );
322 fprintf( $STAT,
"\tmember: $opt_m\n" );
323 fprintf( $STAT,
"\tpktstamp: $opt_p\n" );
324 fprintf( $STAT,
"\tskip load: $skipload\n" );
325 fprintf( $STAT,
"\tfetch only: $fetchonly\n" );
326 fprintf( $STAT,
"\tdbhost: $opt_d\n" );
327 fprintf( $STAT,
"\texclude CU: $sql_xcucodes\n" );
328 fprintf( $STAT,
"\ttimezone: $opt_t\n" );
329 fprintf( $STAT,
"\trunslot: $opt_r\n" );
330 fprintf( $STAT,
"\tdry run: " . ($dryRun ?
"true" :
"false") .
"\n" );
331 fprintf( $STAT,
"\nUsing run slot: $runslot\n\n" );
336 $string =
"Processing Timezone $opt_t\n";
337 fprintf( $STAT, $string );
339 fprintf( $STDOUT, $string );
343 $string =
"Processing CU $opt_c\n";
344 fprintf( $STAT, $string );
346 fprintf( $STDOUT, $string );
350 $string =
"Excluding CU $opt_x\n";
351 fprintf( $STAT, $string );
353 fprintf( $STDOUT, $string );
357 $string =
"Processing Member $opt_m\n";
358 fprintf( $STAT, $string );
360 fprintf( $STDOUT, $string );
364 $string =
"Limit=$limit\n";
365 fprintf( $STAT, $string );
367 fprintf( $STDOUT, $string );
371 $string =
"Nap=$nap\n";
372 fprintf( $STAT, $string );
374 fprintf( $STDOUT, $string );
378 $string =
"Using pktstamp $pktstamp\n";
379 fprintf( $STAT, $string );
381 fprintf( $STDOUT, $string );
386 if ( $action ==
"alerts" ) {
388 $cutoff = date(
"Ymd", time() - 7 * 24 * 60 * 60 );
391 $cutoff = date(
"Ymd", time() + 5 * 24 * 60 * 60 );
394 ############# configuration variables ########### 396 $config[
"skipload"] = $skipload;
397 $config[
"runslot"] = $runslot;
398 $config[
"cucode"] = $cucode;
399 $config[
"xcucode"] = $sql_xcucodes;
400 $config[
"member"] = $member;
401 $config[
"limit"] = $limit;
402 $config[
"nap"] = $nap;
403 $config[
"fetchonly"] = $fetchonly;
404 $config[
"pktstamp"] = $pktstamp;
405 $config[
"cutoff"] = $cutoff;
407 ####################### Globals 408 $gatheredStats = array();
409 $fetchStats = array();
411 ####################### Open Database 415 dmserror( $DMSMAIL,
'FATAL',
"Database connection failed" );
418 fprintf( $STAT,
"Connected to database.\n" );
423 ############# Process Stuff 424 if ( $action ==
"alerts" ) {
425 if ($opt_t ==
"" && $opt_c ==
"" && $cucode ==
"") {
426 fprintf($STAT,
"No valid Credit Unions found with current parameters.\n");
428 $numProcessed = ProcessAlerts($config);
430 }
else if ( $action ==
"scheduled" ) {
431 $numProcessed = ProcessScheduledTransfers( $config );
434 $now = date(
"D M d H:i:s Y" );
435 fprintf( $STAT,
"{$dryRunPrefix}Finished Processing $now\n" );
438 $time = $endtime - $starttime;
439 $processedString =
"\n{$dryRunPrefix}Processed $numProcessed accounts in $time seconds\n\n";
440 fprintf( $STAT, $processedString );
444 fprintf( $STDOUT, $processedString );
447 if ( count( $fetchStats ) > 0 ) {
448 fprintf( $STAT,
"Fetch statistics:\n");
449 foreach( $fetchStats as $statCode => $count ) {
450 fprintf( $STAT,
"\t$statCode: $count\n");
453 fprintf( $STAT,
"No Fetch stats gathered.\n");
455 fprintf( $STAT,
"\n");
457 if ( $action ==
"alerts" ) {
458 PrintGatheredAlertStats( $STAT, $gatheredStats );
459 }
else if ( $action ==
"scheduled" ) {
460 PrintGatheredTransferStats( $STAT, $gatheredStats );
546 function ProcessScheduledTransfers( $config ) {
548 global $dryRun, $dryRunPrefix;
553 global $memberSQL, $timezoneSQL;
554 global $gatheredStats, $fetchStats;
557 # ####################### # 558 # FAILED REPEATED TRANSFER MORATORIUM IN DAYS 559 # ####################### # 560 $FAILRPTAFTER =
'33';
562 # ####################### # 563 # FAILED REPEATED TRANSFER WARNING MSG IN DAYS 564 # ####################### # 568 $cuEmailCache = array();
571 if ( !$config[
"skipload"] ) {
573 $memSQL =
"DELETE FROM cutronus WHERE runslot = '{$config["runslot
"]}'; 574 DELETE FROM cutronab WHERE runslot = '{$config["runslot
"]}'; 575 DELETE FROM cutronah WHERE runslot = '{$config["runslot
"]}'; 576 DELETE FROM cutronlb WHERE runslot = '{$config["runslot
"]}'; 577 DELETE FROM cutronlh WHERE runslot = '{$config["runslot
"]}'; ";
579 fprintf( $STAT,
"Dry run: would be deleting from tables\n $memSQL\n" );
581 $rs = db_query( $memSQL, $dbh );
583 dmserror( $DMSMAIL,
'FATAL',
"Failed Deleting From Tables\n" . db_last_error( $rs ) );
587 $now = date(
"D M d H:i:s Y" );
588 fprintf( $STAT,
"Truncate Tables Complete $now\n" );
590 $CU2_PROCRECUR = 32; # Process Repeating Transfers flag
592 # ##################### 594 # SET UNSUCCESSFUL UPDATES TO INACTIVE 596 # select all active transfers that have failed for more than FAILRPTAFTER 597 # stopdate must NOT be exceeded 599 # Gather Email / members for credit union that transfer is set to inactive 600 # Email member that transfer is set to inacive 601 # SET stopdate to current day 604 # AFTER process of all records email each CU with list of Accounts 606 # ##################### 608 $failSQL =
"SELECT s.id, s.user_id, trim(s.cu), s.next_trigger_date, s.status, trim(a.pname) 609 FROM cu_scheduledtxn s 610 LEFT JOIN cuadmin a on a.cu = s.cu 611 WHERE date_part('day', current_date::timestamp - next_trigger_date::timestamp) > {$FAILRPTAFTER} 612 AND (s.end_date IS NULL OR s.end_date >= s.next_trigger_date) 613 AND a.livebatch = 'L' 615 AND coalesce(a.offlinestat, 'N') not in ('Y','U') 616 AND (a.flagset2::bigint & {$CU2_PROCRECUR}::bigint) = $CU2_PROCRECUR 618 ORDER BY s.cu, s.id; ";
620 $failRS = db_query( $failSQL, $dbh );
625 # LOOP through any returned rows 626 while ( $failRec = db_fetch_row( $failRS, $row++ ) ) {
632 $currCU = $failRec[2];
635 # Check for Credit Union 636 if ( !isset( $cuList[$currCU] ) ) {
637 # CU Code has not been added yet 638 # FETCH THE CU EMAIL ACCOUNT 639 $failCUMail = FetchCUEmail( $dbh, $currCU );
642 $failCUMail = ($failCUMail !=
"" ? $failCUMail : $DMSMAIL);
645 $cuList[$currCU][
"email"] = $failCUMail;
647 $cuList[$currCU][
"accounts"] =
"";
650 $failCUMail = $cuList[$currCU][
"email"];
654 if ( !isset( $cuEmailCache[$currCU] ) ) {
655 $cuEmailCache[$currCU][
"email"] = $failCUMail;
659 $userInfo = FetchUserInfo( $dbh, $currCU, $failRec[1] );
662 $cuList[$currCU][
"accounts"] .=
"Notice: A repeating transfer for user {$userInfo["user_name
"]} was set to inactive.\n";
665 fprintf( $STAT,
"Dry Run: Would send inactive email to {$userInfo["email
"] } (at $currCU):\n{$userInfo["email
"] }\n" );
668 if ( validateEmail( $userInfo[
"email"] ) ) {
669 # Email appears to be valid -- Send email with credit union name 670 MailUserInactive( $failCUMail, $failRec[5], $userInfo[
"email"] );
675 # Update Record in the database 676 $updSQL =
"UPDATE cu_scheduledtxn 678 end_date = current_date 679 WHERE id = '" . $failRec[0] .
"'; ";
681 $rs = db_query( $updSQL, $dbh );
683 dmserror( $DMSMAIL,
'FATAL',
"Failed Updating Deactivate Txns\n" . db_last_error() .
"\n$updSQL");
687 $updateMessage =
"{$dryRunPrefix}Updating repeating transfer {$failRec[0]} to inactive, user {$userInfo["user_name
"]} of {$currCU}\n";
688 fprintf( $STAT, $updateMessage );
692 # Send email to Credit Union 694 # ########################## 695 # EMAIL ANY CUs that have members drop off 696 # Loop through cuList 698 # Loop through each cucode mentioned 699 if ( count( $cuList ) > 0 ) {
700 foreach( $cuList as $thisCU => $info ) {
702 fprintf( $STAT,
"Dry Run: Email CU that account(s) dropped off: $thisCU, {$cuList[$thisCU]["accounts
"]}\n" );
704 $message =
"Hi,\n\nThe following user's had recurring transfer(s) were set to inactive.\n\n";
705 $message .=
"{$cuList[$thisCU]["accounts
"]}\n\n\n";
706 $message .=
"HomeCU";
708 MailCU( $pReplyEmail, $cuList[$thisCU][
"email"], $message );
724 $insert =
"INSERT INTO cutronus (runslot, cu, user_id, sched_id, accountnumber) ";
725 $select =
"SELECT distinct '{$config["runslot
"]}', s.cu, s.user_id, id, '' 726 FROM cu_scheduledtxn s 727 JOIN cuadmin a on a.cu = s.cu 728 AND a.livebatch = 'L' 729 AND coalesce(a.offlinestat, 'N') not in ('Y','U') 730 WHERE (a.flagset2::bigint & {$CU2_PROCRECUR}::bigint) = $CU2_PROCRECUR 731 AND s.next_trigger_date <= '{$TODAY}' 733 AND s.approved_status = 10 734 AND (s.end_date is NULL OR s.end_date >= s.next_trigger_date) 735 AND s.feature_code IN ('TRN', 'TRNM2M', 'TRNEXT', 'ACHCOL', 'ACHPMT') 736 $memberSQL $timezoneSQL";
738 if ( $config[
"cucode"] !=
"" ) { $select .=
" AND s.cu IN ({$config["cucode
"]}) "; }
739 if ( $config[
"xcucode"] !=
"" ) { $select .=
" AND s.cu NOT IN ({$config["xcucode
"]}) "; }
741 $shuffle =
"UPDATE cutronus SET shuffle = random() where runslot = '{$config["runslot
"]}'; ";
744 $sql =
"$insert $select; $shuffle";
745 $memRS = db_query( $sql, $dbh );
748 dmserror( $DMSMAIL,
'FATAL',
"Failed populating cutronus table with accounts to process\n" . db_last_error() .
"\n$sql\n" );
751 fprintf( $STAT,
" SQL to gather scheduled txns:\n\t\t\t $select\n" );
754 $now = date(
"D M d H:i:s Y" );
755 fprintf( $STAT,
"{$dryRunPrefix}Load Tables for Regular Accounts Complete $now\n" );
761 $memsql =
"SELECT s.cu, s.user_id, s.feature_code, s.txn_data, s.id, a.pname, an1.email, 762 s.approved_by, s.start_date, s.end_date, s.next_trigger_date, s.interval_count, s.repeating_parameters 763 FROM cu_scheduledtxn s 764 INNER JOIN cuadmin a on a.cu = s.cu 765 AND a.livebatch = 'L' and coalesce(a.offlinestat, 'N') not in ('Y','U') 766 AND (a.flagset2::bigint & {$CU2_PROCRECUR}::bigint) = $CU2_PROCRECUR 767 INNER JOIN cuadmnotify an1 ON an1.cu = s.cu 768 AND role = 'transfernotify' 769 WHERE s.next_trigger_date <= '{$TODAY}' 771 AND (s.end_date is NULL OR s.end_date >= s.next_trigger_date) 772 AND s.feature_code IN ('TRN', 'TRNM2M', 'TRNEXT', 'ACHCOL', 'ACHPMT') 773 $memberSQL $timezoneSQL";
775 if ( $config[
"cucode"] !=
"" ) { $memsql .=
" AND s.cu IN ({$config["cucode
"]}) "; }
776 if ( $config[
"xcucode"] !=
"" ) { $memsql .=
" AND s.cu NOT IN ({$config["xcucode
"]}) "; }
780 $memsql =
"SELECT tron.cu, tron.user_id, s.feature_code, s.txn_data, s.id, a.pname, an1.email, 781 s.approved_by, s.start_date, s.end_date, s.next_trigger_date, s.interval_count, s.repeating_parameters 783 INNER JOIN cu_scheduledtxn s ON s.id = tron.sched_id 784 INNER JOIN cuadmin a on a.cu = s.cu 785 INNER JOIN cuadmnotify an1 ON an1.cu = s.cu 786 AND role = 'transfernotify' 787 WHERE runslot = '{$config["runslot
"]}' ";
789 if ( $config[
"cucode"] !=
"" ) { $memsql .=
" AND tron.cu IN ({$config["cucode
"]}) "; }
790 if ( $config[
"xcucode"] !=
"" ) { $memsql .=
" AND tron.cu NOT IN ({$config["xcucode
"]}) "; }
793 $memsql .=
" order by shuffle ";
796 if ( $config[
"limit"] !=
"" ) { $memsql .=
" limit {$config["limit
"]} "; }
798 fprintf( $STAT,
" Using sql to process scheduled txns:\n\t\t\t" . $memsql .
"\n" );
800 $memRS = db_query( $memsql, $dbh );
803 dmserror( $DMSMAIL,
'FATAL',
"Failed Selecting Accounts to Process\n" . db_last_error() );
806 $now = date(
"D M d H:i:s Y" );
807 fprintf( $STAT,
"{$dryRunPrefix}Fetching Account Packets Begin $now\n" );
819 while ( $schedRow = db_fetch_assoc( $memRS, $row++ ) ) {
821 $currCU = trim( $schedRow[
"cu"] );
822 $userId = $schedRow[
"user_id"];
823 $featureCode = trim( $schedRow[
"feature_code"] );
824 $txnData = HCU_JsonDecode( $schedRow[
"txn_data"],
false );
825 $scheduleId = $schedRow[
"id"];
826 $pName = trim( $schedRow[
"pname"] );
827 $adminEmail = trim( $schedRow[
"email"] );
828 $approvedBy = $schedRow[
"approved_by"];
829 $startDate = $schedRow[
"start_date"];
830 $endDate = $schedRow[
"end_date"];
831 $nextTriggerDate = $schedRow[
"next_trigger_date"];
832 $intervalCount = $schedRow[
"interval_count"];
833 $repeatingParameters = HCU_JsonDecode( $schedRow[
"repeating_parameters"],
false );
834 $fromAccountKey = Array();
835 $toAccountKey = Array();
839 $type = isset( $txnData[
"txn"][
"type"] ) ? $txnData[
"txn"][
"type"] :
"";
841 $localTransCode = trim($txnData[
"txn"][
"transactioncode"]);
844 LoadCUAdmin( $dbh, $currCU, $HB_ENV );
849 $HB_ENV[
'Fset'] = $HB_ENV[
'flagset'];
850 $HB_ENV[
'Fset2'] = $HB_ENV[
'flagset2'];
851 $HB_ENV[
'Fset3'] = $HB_ENV[
'flagset3'];
855 $HB_ENV[
"Fmsg_tx"] = GetMsgTxValue(
'MSGTX_TMP_XAX_LD');
857 $HB_ENV[
'Fplog'] =
'';
860 AddToGatheredTransferStats( $gatheredStats, $currCU,
"count",
"" );
862 if ( $txnData ==
"" ) {
863 $errorMessage =
"Error extracting scheduled transaction data. CU: {$currCU}, User Id: {$usreId}";
865 fprintf( $STAT,
"Dry Run: Would send error email to HomeCU: $errorMessage\n" );
867 dmserror( $DMSMAIL,
'FATAL', $errorMessage );
871 if ( $repeatingParameters ==
"" ) {
872 $errorMessage =
"Error with scheduled transaction repeating parameters. CU: {$currCU}, User Id: {$usreId}, id: $scheduleId";
874 fprintf( $STAT,
"Dry Run: Would send error email to HomeCU: $errorMessage\n" );
876 dmserror( $DMSMAIL,
'FATAL', $errorMessage );
881 if ( $config[
"member"] !=
"") {
882 if ( $txnData[
"txn"][
"txFromAcct"] != $config[
"member"] )
continue;
890 if ( $featureCode ==
"TRN" ) {
893 $fromAccountId = $txnData[
"txn"][
"from"];
894 $toAccountId = $txnData[
"txn"][
"to"];
896 $fromAccountKey = BuildAccountKey($txnData,
"from");
897 $toAccountKey = BuildAccountKey($txnData,
"to");
899 }
else if ( $featureCode ==
"TRNEXT" ) {
900 if ( $type ==
"X2L" ) {
903 $toAccountId = $txnData[
"txn"][
"to"];
904 $toAccountKey = BuildAccountKey($txnData,
"to");
907 $fromAccountId = $txnData[
"txn"][
"from"];
909 $fromAccountKey = BuildAccountKey($txnData,
"from");
911 }
else if ( $featureCode ==
"TRNM2M" || $featureCode ==
"ACHPMT" ) {
913 $fromAccountId = $txnData[
"txn"][
"from"];
915 $fromAccountKey = BuildAccountKey($txnData,
"from");
916 }
else if ( $featureCode ==
"ACHCOL" ) {
919 $toAccountId = $txnData[
"txn"][
"to"];
920 $toAccountKey = BuildAccountKey($txnData,
"to");
923 $validAccess = UserHasRightsToTransfer( $dbh, $currCU, $userId, $fromAccountKey, $toAccountKey, $localTransCode);
925 if ( !$validAccess ) {
926 $failMsg =
"\nWarning: you no longer have rights to an account used in your repeating transfer.\n";
927 $failMsg .=
"If this isn't corrected within {$FAILRPTAFTER} days the transfer will be set inactive.\n";
930 $userInfo = FetchUserInfo( $dbh, $currCU, $userId );
933 if ( isset( $cuEmailCache[$currCU][
"email"] ) ) {
934 $failCUMail = $cuEmailCache[$currCU][
"email"];
936 $failCUMail = FetchCUEmail( $dbh, $currCU );
939 $failCUMail = ($failCUMail !=
"" ? $failCUMail : $DMSMAIL);
941 $cuEmailCache[$currCU][
"email"] = $failCUMail;
944 if ( validateEmail( $userInfo[
"email"] ) ) {
946 fprintf( $STAT,
"Dry Run: Would send error email to user: $failMsg\n" );
948 # Email appears to be valid -- Send email with credit union name 949 MailUserWarning( $failCUMail, $currCU, $userInfo[
"email"], $failMsg );
953 $accountInfoForMessage =
"FROM: $fromAccountId TO: $toAccountId";
954 $message =
"User {$userInfo["user_name
"]} no longer has rights to account ($accountInfoForMessage)\n";
955 AddToGatheredTransferStats( $gatheredStats, $currCU,
"rights", $message );
961 if (HCU_array_key_value(
"fromtype", $txnData[
'txn']) !=
'X') {
964 $account = HCU_array_key_value(
"frommember", $txnData[
'txn']);
965 $lockStatus = CheckIfAccountLocked( $dbh, $currCU, $account );
967 if ( $lockStatus ==
"" &&
968 (HCU_array_key_value(
"totype", $txnData[
'txn']) !=
'X') &&
969 (HCU_array_key_value(
"totype", $txnData[
'txn']) !=
'M') ) {
973 $account = HCU_array_key_value(
"tomember", $txnData[
'txn']);
974 $lockStatus = CheckIfAccountLocked( $dbh, $currCU, $account );
977 if ( $lockStatus !=
"" ) {
978 $lockType = $lockStatus ==
"R" ?
"Readonly" :
"Locked";
979 $failMsg =
"\nWarning: an account used in your repeating transfer is marked $lockType.\n";
980 $failMsg .=
"If this isn't corrected within {$FAILRPTAFTER} days the transfer will be set inactive.\n";
983 $userInfo = FetchUserInfo( $dbh, $currCU, $userId );
986 if ( isset( $cuEmailCache[$currCU][
"email"] ) ) {
987 $failCUMail = $cuEmailCache[$currCU][
"email"];
989 $failCUMail = FetchCUEmail( $dbh, $currCU );
992 $failCUMail = ($failCUMail !=
"" ? $failCUMail : $DMSMAIL);
994 $cuEmailCache[$currCU][
"email"] = $failCUMail;
997 if ( validateEmail( $userInfo[
"email"] ) ) {
999 fprintf( $STAT,
"Dry Run: Would send error email to user: $failMsg\n" );
1001 # Email appears to be valid -- Send email with credit union name 1002 MailUserWarning( $failCUMail, $currCU, $userInfo[
"email"], $failMsg );
1006 $accountInfoForMessage =
"FROM: $fromAccountId TO: $toAccountId";
1007 $message =
"User {$userInfo["user_name
"]} is using a $lockType account ($accountInfoForMessage)\n";
1008 AddToGatheredTransferStats( $gatheredStats, $currCU,
"rights", $message );
1014 if ( in_array( $featureCode, array(
"TRN",
"TRNM2M" ) ) ) {
1016 if ( $fromAccountId ==
"" ) {
1018 $errorMessage =
"Invalid transaction - missing From account\n";
1020 fprintf( $STAT,
"Dry Run: Would send error email to HomeCU: $errorMessage\n" );
1023 dmserror( $DMSMAIL,
'FATAL',
"$errorMessage\n" );
1028 if ( HaveAccountData( $dbh, $currCU, $fromAccountId, $config[
"runslot"] ) ) {
1037 if ( $config[
"nap"] > 0 ) {
1038 sleep( $config[
"nap"] );
1044 $HB_ENV[
"Cu"] = $currCU;
1045 $HB_ENV[
"cu"] = $currCU;
1046 $HB_ENV[
"Uid"] = $userId;
1049 $memberData = array(
"account" => $fromAccountKey[
'accountnumber'],
"cutoff" => $config[
"cutoff"],
"packetstamp" => $config[
"pktstamp"],
"email" =>
"NULL" );
1051 $fetchResp = FetchMemberDataTRON( $HB_ENV, $memberData );
1054 $status = $fetchResp[
"status"];
1056 if ( !isset( $fetchStats[
"Status_{$status}"] ) ) {
1057 $fetchStats[
"Status_{$status}"] = 1;
1059 $fetchStats[
"Status_{$status}"]++;
1063 $code = $fetchResp[
"code"];
1065 if ( $code ==
'200' || $code ==
'201' || $code ==
'202' ) {
1067 if ( $cucode !=
"" ) { sleep( $config[
"nap"] + 300 ); }
1068 }
else if ( $code !=
'000' ) {
1069 $reason = trim( $fetchResp[
"data"][
"requestDesc"] );
1070 if ( !strlen( $reason ) ) {
1071 $reason =
"Unknown reason";
1074 fprintf( $STAT,
"$row\tCU $currCU Member Account {$fromAccountKey['accountnumber']}\tFailed! $code - $reason\n" );
1077 if ( $code ==
'001' ) {
1078 # -- I want to send an email to the Credit Union 1079 # They have a user w/repeating transaction(s) that is/are NO longer set up 1080 # in the Credit Union but is/are still set up in HomeBanking 1081 $emailMsg =
"RECURRING TRANSACTION FAILED\n\n";
1082 $emailMsg .=
"Member {$fromAccountKey['accountnumber']} does not exist or is not set up on your core system.\n\n\n\n";
1083 $emailMsg .=
"($currCU: {$fromAccountKey['accountnumber']})";
1085 # FETCH THE CU EMAIL ACCOUNT 1086 $errCUMail = FetchCUEmail( $dbh, $currCU );
1088 $errCUMail = ($errCUMail >
"" ? $errCUMail : $DMSMAIL);
1091 fprintf( $STAT,
"Dry Run: Would send error email to CU: $emailMsg\n" );
1093 MailCU( $errCUMail, $errCUMail, $emailMsg );
1095 }
else if ( $code ==
"000" ) {
1096 $accountData = $fetchResp[
"data"][
"requestData"];
1098 $loadResp = UpdateTRONTables( $HB_ENV, $config[
"runslot"], $memberData, $accountData );
1100 if ( $loadResp[
"status"][
"code"] !=
"000" ) {
1101 $errorMessage =
"Failure loading TRON tables: {$loadResp["status
"]["error
"]}.";
1104 fprintf( $STAT,
"Dry Run: Would send error email to HomeCU: $errorMessage\n" );
1106 dmserror( $DMSMAIL,
'FATAL', $errorMessage );
1119 if ( !$config[
"fetchonly"] ) {
1125 if ( !is_array( $txnData ) ) {
1126 $errorMessage =
"Error processing scheduled transaction data. CU: {$currCU}, User Id: {$userId} No transaction data.";
1128 fprintf( $STAT,
"Dry Run: Would send error email to HomeCU: $errorMessage\n" );
1130 dmserror( $DMSMAIL,
'FATAL',
"$errorMessage\n" );
1134 $pName = ( $pName ==
"" ) ?
"HomeCU" : $pName;
1137 $HB_ENV[
"Cu"] = $currCU;
1138 $HB_ENV[
"cu"] = $currCU;
1139 $HB_ENV[
"Uid"] = $userId;
1141 $txnData[
"txn_id"] = $scheduleId;
1142 $txnData[
"approved_by"] = $approvedBy;
1143 $txnData[
"frequency"] = $repeatingParameters[
'interval'];
1144 $txnData[
"interval"] = $intervalCount;
1146 $transferResult = HandleTransferRequest( $dbh, $HB_ENV, $featureCode, $txnData, $dryRun );
1149 $userInfo = FetchUserInfo( $dbh, $currCU, $userId );
1151 if ( $transferResult[
"status"][
"code"] !=
"000" ) {
1153 $data =
"From account: {$txnData["txn
"]["from
"]}, To account: {$txnData["txn
"]["to
"]}, Amount: {$txnData["txn
"]["amount
"]}";
1154 $message =
"Unable to post transaction $scheduleId for CU: $currCU, user: {$userInfo["user_name
"]}\n";
1155 $message .=
"\t\t\t\tRequest=$featureCode\tData=({$data})\n";
1156 $message .=
"\t\t\t\tResponse: {$transferResult["status
"]["error
"]}\n";
1159 AddToGatheredTransferStats( $gatheredStats, $currCU,
"failed", $message );
1162 $interval = $repeatingParameters[
"interval"];
1165 $trigger = TxNextInterval( $startDate, $interval, $intervalCount + 1 );
1169 $message =
"Updating next transaction date ($trigger) txid $scheduleId for user {$userInfo["user_name
"]}.";
1173 $updated = UpdateNextTriggerDate( $dbh, $scheduleId, $trigger );
1176 dmserror( $DMSMAIL,
'FATAL',
"Error updating next trigger date for schedule id $scheduleId (cu: $currCU)\n" );
1181 AddToGatheredTransferStats( $gatheredStats, $currCU,
"success", $message );
1189 return $numProcessed;
1205 function GetCUAdminOfflineStatus($pDbh, $currCU) {
1206 $offlineStatSql =
"SELECT trim(offlinestat), trim(offlineblurb) 1208 WHERE cu = '$currCU'";
1210 $rs = db_query($offlineStatSql, $pDbh);
1213 dmserror( $DMSMAIL,
"FATAL",
"Unable to obtain offline status from database: {$currCU}.\n" . db_last_error() .
"\n$offlineStatSql\n" );
1215 $returnOfflineStat = array(
"offlinestat" =>
"unknown",
"offlineblurb" =>
"unknown" );
1217 $cuAdminRow = db_fetch_row( $rs );
1218 $thisOfflineStat = $cuAdminRow[0];
1220 # initial status "" is considered as "N" 1221 if ( $thisOfflineStat ==
"") {
1222 $thisOfflineStat =
"N";
1225 if ( $thisOfflineStat !=
"N") {
1226 $thisOfflineStat =
"Y";
1229 $returnOfflineStat = array(
"offlinestat" => $thisOfflineStat,
"offlineblurb" => $cuAdminRow[1] );
1232 return $returnOfflineStat;
1239 function ProcessAlerts( $config ) {
1241 global $dryRun, $dryRunPrefix;
1245 global $DMSMAIL, $ALERTMAIL;
1246 global $memberSQL, $timezoneSQL;
1247 global $gatheredStats, $fetchStats;
1249 $CU2_ALLOW_MBR_ALERTS = 33554432; # Process Alerts flag
1250 $CU2_ESCHEMA = 2097152; # Expanded loan history schema
1258 if ( !$config[
"skipload"] ) {
1261 $memSQL =
"DELETE FROM cutronus WHERE runslot = '{$config["runslot
"]}'; 1262 DELETE FROM cutronab WHERE runslot = '{$config["runslot
"]}'; 1263 DELETE FROM cutronah WHERE runslot = '{$config["runslot
"]}'; 1264 DELETE FROM cutronlb WHERE runslot = '{$config["runslot
"]}'; 1265 DELETE FROM cutronlh WHERE runslot = '{$config["runslot
"]}'; ";
1267 fprintf( $STAT,
"Dry run: would be deleting from tables\n $memSQL\n" );
1269 $rs = db_query( $memSQL, $dbh );
1271 dmserror( $DMSMAIL,
'FATAL',
"Failed Deleting From Tables\n" . db_last_error( $rs ) );
1274 fprintf( $STAT,
"Deleting from tables complete.\n" );
1279 # Sort of complex logic based on how several settings can determine the status of cucode 1280 # cucode can be set by either the runtime slot list OR on command line with -c 1281 # In theory the -t option is mutually exclusive to either -c or the runslot list 1283 # Therefore if cucode is blank AND if timezone is NOT set 1284 # Then set query for cu = '', this will prevent the query from returning ALL the CUs on the server 1285 # Problem was discovered when a runslot was being executed but no files existed. The cu query was left off 1286 # so ALL CUs were returned 1292 $cuSQL = ($config[
"cucode"] !=
"" ?
" AND a.cu IN ({$config["cucode
"]}) " :
"");
1293 $xcuSQL= ($config[
"xcucode"] !=
"" ?
" AND a.cu NOT IN ({$config["xcucode
"]}) " :
"");
1296 $insert =
"INSERT INTO cutronus (runslot, cu, user_id, sched_id, accountnumber) ";
1299 $select =
"SELECT DISTINCT '{$config["runslot
"]}', alert.cu, 0, 0, alert.accountnumber 1300 FROM cu_alerts alert 1301 JOIN cuadmin a on a.cu = alert.cu 1302 AND a.livebatch = 'L' 1303 AND coalesce(a.offlinestat, 'N') not in ('Y','U') 1304 AND (a.flagset2::bigint & {$CU2_ALLOW_MBR_ALERTS}::bigint) = {$CU2_ALLOW_MBR_ALERTS} 1305 $timezoneSQL $cuSQL $xcuSQL 1306 WHERE ((alert.alerttype IN ('B','T','L') AND (lastalert < CURRENT_DATE OR alert.lastalert IS NULL)) OR 1307 (alert.alerttype = 'C' AND alert.lastalert IS NULL)) ";
1310 $shuffle =
"UPDATE cutronus SET shuffle = random() where runslot = '{$config["runslot
"]}'; ";
1313 $sql =
"$insert $select; $shuffle";
1314 $memRS = db_query( $sql, $dbh );
1317 dmserror( $DMSMAIL,
'FATAL',
"Failed populating cutronus table with accounts to process\n" . db_last_error() .
"\n$sql\n" );
1320 fprintf( $STAT,
" SQL to gather alerts:\n\t\t\t $select\n" );
1323 $now = date(
"D M d H:i:s Y" );
1324 fprintf( $STAT,
"Load Tables Complete $now\n" );
1337 $memsql =
"SELECT trim(tron.cu) as cu, trim(tron.accountnumber) as accountnumber 1339 WHERE tron.runslot = '{$config["runslot
"]}'";
1341 if ( $config[
"cucode"] !=
"" ) { $memsql .=
" AND tron.cu in ({$config["cucode
"]}) "; }
1342 if ( $config[
"xcucode"] !=
"" ) { $memsql .=
" AND tron.cu not in ({$config["xcucode
"]}) "; }
1343 if ( $config[
"member"] !=
"" ) { $memsql .=
" AND accountnumber='{$config["member
"]}' "; }
1345 $memsql .=
" ORDER BY shuffle ";
1347 if ( $config[
"limit"] !=
"" ) { $memsql .=
" limit {$config["limit
"]} "; }
1349 fprintf( $STAT,
"Using sql: $memsql\n" );
1351 $memRS = db_query( $memsql, $dbh );
1353 $cuInfoCache = array();
1356 while ( $alertRow = db_fetch_assoc( $memRS, $row++ ) ) {
1358 $thisTimeStart = microtime(
true);
1359 $thisMessages = array();
1362 $currCU = strtoupper( $alertRow[
"cu"] );
1363 $accountNumber = $alertRow[
"accountnumber"];
1366 $offlineStat = GetCUAdminOfflineStatus($dbh, $currCU);
1368 if ( $offlineStat[
"offlinestat"] ==
"unknown" ) {
1369 dmserror( $DMSMAIL,
"FATAL",
"Unable to obtain offlinestat from database: {$currCU}.\n". db_last_error().
"\n" );
1372 $isCUOffline =
false;
1375 if ( $offlineStat[
"offlinestat"] !=
"N" ) {
1376 fprintf( $STAT,
"{$currCU} is offline (status: '".$offlineStat[
"offlinestat"].
"') ".$offlineStat[
"offlineblurb"].
"'\n" );
1377 $thisMessages[] =
"$row\tCU $currCU Account $accountNumber\tSkipped! Connection is down\n";
1379 $thisStat = array(
"time" => 0,
"messages" => $thisMessages );
1380 AddToGatheredAlertStats( $gatheredStats, $currCU,
"gathering", $thisStat );
1383 $isCUOffline =
true;
1389 if ( !$isCUOffline && !isset( $cuInfoCache[$currCU]) ) {
1392 $cuSQL =
"SELECT trim(pname) as pname, trim(user_name) as user_name, 1393 flagset, flagset2, flagset3, trim(orgname) as orgname 1395 WHERE cu = '$currCU' ";
1397 $rs = db_query( $cuSQL, $dbh );
1400 $errorMessage =
"Failed getting admin info: {$config["runslot
"]} \n" . db_last_error() .
" SQL: $cuSQL\n";
1401 dmserror( $DMSMAIL,
'WARN', $errorMessage );
1407 $adminRow = db_fetch_assoc( $rs, 0 );
1410 $sql =
"SELECT trim(email) as email, trim(role) as role FROM cuadmnotify 1411 WHERE cu = '$currCU' 1412 AND role IN ('alert', 'txtbanking') ";
1413 $rs = db_query( $sql, $dbh );
1417 $txtBankingNotify =
"";
1418 while ( $notifyRow = db_fetch_assoc( $rs, $row2++ ) ) {
1419 if ( $notifyRow[
"role"] ==
"alert" ) {
1420 $alertNotify = trim( $notifyRow[
"email"] );
1422 $txtBankingNotify = trim( $notifyRow[
"email"] );
1427 if ( strlen( $alertNotify ) == 0 ) {
1428 dmserror( $DMSMAIL,
'WARN',
"Failed getting ALERTMAIL {$config["runslot
"]} \n" . db_last_error() .
" SQL: $sql\n" );
1431 $alertNotify = $ALERTMAIL;
1434 $cuInfoCache[$currCU] = array(
1435 "alert" => $alertNotify,
1436 "txtbanking" => $txtBankingNotify,
1437 "flagset" => $adminRow[
"flagset"],
1438 "flagset2" => $adminRow[
"flagset2"],
1439 "flagset3" => $adminRow[
"flagset3"],
1440 "pname" => $adminRow[
"pname"],
1441 "user_name" => $adminRow[
"user_name"],
1442 "orgname" => $adminRow[
"orgname"]
1448 LoadCUAdmin( $dbh, $currCU, $HB_ENV );
1451 $thisSkip = $isCUOffline;
1454 if ( HaveAccountData( $dbh, $currCU, $accountNumber, $config[
"runslot"] ) ) {
1458 $lockLevel = CheckIfAccountLocked( $dbh, $currCU, $accountNumber );
1461 if ( $lockLevel ==
"L" ) {
1462 $thisMessages[] =
"$row\tCU $currCU Account $accountNumber\tSkipped! Account is locked ($lockLevel)\n";
1470 if ( $config[
"nap"] > 0 ) {
1471 sleep( $config[
"nap"] );
1475 $HB_ENV[
"Cu"] = $currCU;
1476 $HB_ENV[
"cu"] = $currCU;
1480 $memberData = array(
"account" => $accountNumber,
"cutoff" => $config[
"cutoff"],
"packetstamp" => $config[
"pktstamp"],
"email" =>
"NULL" );
1482 $fetchResp = FetchMemberDataTRON( $HB_ENV, $memberData );
1485 $status = $fetchResp[
"status"];
1487 if ( !isset( $fetchStats[
"Status_{$status}"] ) ) {
1488 $fetchStats[
"Status_{$status}"] = 1;
1490 $fetchStats[
"Status_{$status}"]++;
1494 $reason = $fetchResp[
"data"][
"requestDesc"];
1495 $now = date(
"D M d H:i:s Y" );
1496 $thisMessages[] =
"$row\tCU $currCU Account $accountNumber\t $status - $reason $now\n";
1499 $code = $fetchResp[
"code"];
1501 if ( $code ==
'200' || $code ==
'201' || $code ==
'202' ) {
1503 if ( $config[
"cucode"] !=
"" ) { sleep( $config[
"nap"] + 300 ); }
1504 }
else if ( $code !=
'000' ) {
1505 $reason = trim( $fetchResp[
"data"][
"requestDesc"] );
1506 if ( !strlen( $reason ) ) {
1507 $reason =
"Unknown reason";
1510 $thisMessages[] =
"$row\tCU $currCU Member Account {$accountNumber}\tFailed! $code - $reason\n";
1514 if ( $code ==
'001' ) {
1515 # -- I want to send an email to the Credit Union 1516 # They have a user with alerts on an account that is/are NO longer set up 1517 # in the Credit Union but is/are still set up in HomeBanking 1518 $emailMsg =
"PROCESSING ALERTS FAILED\n\n";
1519 $emailMsg .=
"Member Account {$accountNumber} does not exist or is not set up on your core system.\n\n\n\n";
1521 # FETCH THE CU EMAIL ACCOUNT 1522 $errCUMail = FetchCUEmail( $dbh, $currCU );
1524 $errCUMail = ($errCUMail >
"" ? $errCUMail : $DMSMAIL);
1527 fprintf( $STAT,
"Dry Run: Would send error email to CU: $emailMsg\n" );
1529 MailCU( $errCUMail, $errCUMail, $emailMsg );
1531 }
else if ( $code ==
"000" ) {
1532 $accountData = $fetchResp[
"data"][
"requestData"];
1534 $loadResp = UpdateTRONTables( $HB_ENV, $config[
"runslot"], $memberData, $accountData );
1536 if ( $loadResp[
"status"][
"code"] !=
"000" ) {
1537 $errorMessage =
"Failure loading TRON tables: {$loadResp["status
"]["error
"]}.";
1540 fprintf( $STAT,
"Dry Run: Would send error email to HomeCU: $errorMessage\n" );
1542 dmserror( $DMSMAIL,
'FATAL', $errorMessage );
1553 $thisTimeEnd = microtime(
true);
1554 $thisTime = $thisTimeEnd - $thisTimeStart;
1556 $thisStat = array(
"time" => $thisTime,
"messages" => $thisMessages );
1557 AddToGatheredAlertStats( $gatheredStats, $currCU,
"gathering", $thisStat );
1560 if ( !$thisSkip && !$config[
"fetchonly"] ) {
1563 $results = ProcessAlertsForAccount( $HB_ENV, $cuInfoCache[$currCU], $currCU, $accountNumber, $config );
1566 AddToGatheredAlertStats( $gatheredStats, $currCU,
"sent_stats", $results );
1567 AddToGatheredAlertStats( $gatheredStats, $currCU,
"sending", $results );
1573 return $numProcessed;
1579 function ProcessAlertsForAccount( $pHbEnv, $cuInfo, $currCU, $account, $config ) {
1584 $alertReturn = array(
"time" => 0,
"user_count" => 0,
"alert_count" => 0,
"messages" => array(),
"alert_stats" => array() );
1586 $thisTimeStart = microtime(
true);
1588 $dbh = $pHbEnv[
"dbh"];
1589 $orgname = $cuInfo[
"orgname"];
1592 $CU_CALCRUNBAL = 64;
1594 $ALERTFROMADDR =
"noreply@homecu.net";
1595 $ALERTFROMNAME = $orgname;
1598 $shortAlertMsg = array();
1599 $longAlertMsg = array();
1601 $sql =
"SELECT message, sms_message 1604 AND (startdate <= CURRENT_DATE AND CURRENT_DATE <= stopdate) 1607 $rs = db_query( $sql, $dbh );
1610 $errorMsg =
"Failed getting AlertMsgs {$config["runslot
"]} \n" . db_last_error() .
" SQL: $sql\n";
1611 dmserror( $DMSMAIL,
'WARN', $errorMsg );
1614 $alertReturn[
"messages"][] = $errorMsg;
1617 while ( $msgRow = db_fetch_assoc( $rs, $row++ ) ) {
1618 $longAlertMsg[] = $row[
"message"];
1619 $shortAlertMsg[] = $row[
"sms_message"];
1630 $select[
"CurrentBalance"] =
1631 "SELECT alert.id, alert.user_id, alert.emailtype, trim(alert.notifyto) as notifyto, 1632 trim(alert.provider_id) as provider_id, trim(alert.notifymsg) as notifymsg, 1633 0 as incamt, 0 as amount, 1634 alert.incbal, acct.amount as balance, alert.alerttype 1635 FROM cu_alerts alert 1636 JOIN cutronab acct ON acct.cu = alert.cu 1637 AND acct.accountnumber = alert.accountnumber 1638 AND acct.accounttype = alert.accounttype 1639 AND acct.certnumber = alert.certnumber 1640 AND acct.runslot = '{$config["runslot
"]}' 1641 AND acct.amount < alert.notifyamt 1642 WHERE alert.cu = '$currCU' 1643 AND alert.accountnumber='$account' 1644 AND (alert.lastalert IS NULL OR alert.lastalert < CURRENT_DATE) 1645 AND coalesce( alert.useavailbal, 0 ) = 0 1646 AND alert.alerttype = 'B' ";
1648 $update[
"CurrentBalance"] =
1649 "UPDATE cu_alerts SET lastalert = CURRENT_TIMESTAMP 1651 WHERE acct.cu = cu_alerts.cu 1652 AND acct.accountnumber = cu_alerts.accountnumber 1653 AND acct.accounttype = cu_alerts.accounttype 1654 AND acct.certnumber = cu_alerts.certnumber 1655 AND acct.runslot = '{$config["runslot
"]}' 1656 AND acct.amount < cu_alerts.notifyamt 1657 AND (cu_alerts.lastalert IS NULL OR cu_alerts.lastalert < CURRENT_DATE) 1658 AND cu_alerts.cu = '$currCU' 1659 AND cu_alerts.accountnumber = '$account' 1660 AND coalesce( cu_alerts.useavailbal, 0 ) = 0 1661 AND cu_alerts.alerttype = 'B' ";
1664 # Available Balance Alerts 1666 $select[
"AvailableBalance"] =
1667 "SELECT alert.id, alert.user_id, alert.emailtype, trim(alert.notifyto) as notifyto, 1668 trim(alert.provider_id) as provider_id, trim(alert.notifymsg) as notifymsg, 1669 0 as incamt, 0 as amount, 1670 alert.incbal, acct.available as balance, alert.alerttype 1671 FROM cu_alerts as alert 1672 JOIN cutronab as acct ON acct.cu = alert.cu 1673 AND acct.accountnumber = alert.accountnumber 1674 AND acct.accounttype = alert.accounttype 1675 AND acct.certnumber = alert.certnumber 1676 AND acct.runslot = '{$config["runslot
"]}' 1677 AND acct.available < alert.notifyamt 1678 WHERE alert.cu = '$currCU' 1679 AND alert.accountnumber ='$account' 1680 AND (alert.lastalert IS NULL OR alert.lastalert < CURRENT_DATE) 1681 AND coalesce( alert.useavailbal, 0 ) > 0 1682 AND alert.alerttype = 'B' ";
1684 $update[
"AvailableBalance"] =
1685 "UPDATE cu_alerts SET lastalert = CURRENT_TIMESTAMP 1687 WHERE acct.cu = cu_alerts.cu 1688 AND acct.accountnumber = cu_alerts.accountnumber 1689 AND acct.accounttype = cu_alerts.accounttype 1690 AND acct.certnumber = cu_alerts.certnumber 1691 AND acct.runslot = '{$config["runslot
"]}' 1692 AND acct.available < cu_alerts.notifyamt 1693 AND (cu_alerts.lastalert IS NULL OR cu_alerts.lastalert < CURRENT_DATE) 1694 AND cu_alerts.cu = '{$currCU}' 1695 AND cu_alerts.accountnumber = '$account' 1696 AND coalesce( cu_alerts.useavailbal, 0 ) > 0 1697 AND cu_alerts.alerttype = 'B' ";
1703 "SELECT alert.id, alert.user_id, alert.emailtype, trim(alert.notifyto) as notifyto, 1704 trim(alert.provider_id) as provider_id, trim(alert.notifymsg) as notifymsg, 1705 alert.incamt, acct.amount, 1706 0 incbal, 0 balance, alert.alerttype 1707 FROM cu_alerts as alert 1708 JOIN cutronah as acct ON acct.cu = alert.cu 1709 AND acct.accountnumber = alert.accountnumber 1710 AND acct.accounttype = alert.accounttype 1711 AND acct.certnumber = alert.certnumber 1712 AND trim(acct.checknumber) = trim(alert.notifychknum) 1713 AND acct.runslot = '{$config["runslot
"]}' 1714 WHERE alert.cu = '{$currCU}' 1715 AND alert.accountnumber = '$account' 1716 AND alert.lastalert IS NULL 1717 AND alert.alerttype = 'C' ";
1719 "UPDATE cu_alerts SET lastalert = CURRENT_TIMESTAMP 1720 FROM cutronah as acct 1721 WHERE acct.cu = cu_alerts.cu 1722 AND acct.accountnumber = cu_alerts.accountnumber 1723 AND acct.accounttype = cu_alerts.accounttype 1724 AND acct.certnumber = cu_alerts.certnumber 1725 AND acct.runslot = '{$config["runslot
"]}' 1726 AND acct.checknumber = cu_alerts.notifychknum 1727 AND cu_alerts.lastalert is null 1728 AND cu_alerts.cu = '{$currCU}' 1729 AND cu_alerts.accountnumber ='$account' 1730 AND cu_alerts.alerttype = 'C' ";
1732 $select[
"Payment"] =
1733 "SELECT alert.id, alert.user_id, alert.emailtype, trim(alert.notifyto) as notifyto, 1734 trim(alert.provider_id) as provider_id, trim(alert.notifymsg) as notifymsg, 1735 0 as incamt, 0 as amount, 1736 0 as incbal, 0 as balance, alert.alerttype 1737 FROM cu_alerts as alert 1738 JOIN cutronlb as loan ON loan.cu = alert.cu 1739 AND loan.accountnumber = alert.accountnumber 1740 AND loan.loannumber = alert.accounttype 1741 AND loan.runslot = '{$config["runslot
"]}' 1742 AND (loan.nextduedate - (coalesce(alert.notifyloandaysprior, 0) || ' days')::interval) < CURRENT_TIMESTAMP 1743 AND loan.currentbalance > 0 1744 WHERE alert.cu = '{$currCU}' 1745 AND alert.accountnumber = '$account' 1746 AND (alert.lastalert IS NULL OR alert.lastalert < CURRENT_DATE) 1747 AND alert.alerttype = 'L' ";
1748 $update[
"Payment"] =
1749 "UPDATE cu_alerts SET lastalert = CURRENT_TIMESTAMP 1750 FROM cutronlb as loan 1751 WHERE loan.cu = cu_alerts.cu 1752 AND loan.accountnumber = cu_alerts.accountnumber 1753 AND loan.loannumber = cu_alerts.accounttype 1754 AND loan.runslot = '{$config["runslot
"]}' 1755 AND (loan.nextduedate - (coalesce(cu_alerts.notifyloandaysprior, 0) || ' days')::interval) < CURRENT_TIMESTAMP 1756 AND (cu_alerts.lastalert IS NULL OR cu_alerts.lastalert < CURRENT_DATE) 1757 AND loan.currentbalance > 0 1758 AND cu_alerts.cu = '{$currCU}' 1759 AND cu_alerts.accountnumber='$account' 1760 AND cu_alerts.alerttype = 'L' ";
1762 # ################## 1764 # removed the comparison to ~*, this is a regular expression compare and the string in alert.notifydesc could contain 1765 # regular expression items ie ( ) {} [], this caused a problem when the member typed (: 1766 # also, the extra processing for re is not desired. found an equivalent with ilike 1767 # ~* alert.notifydesc 1768 # ilike '%' || alert.notifydesc || '%' 1769 # ################## 1772 $select[
"Transaction"] =
1773 "SELECT alert.id, alert.user_id, alert.emailtype, trim(alert.notifyto) as notifyto, 1774 trim(alert.provider_id) as provider_id, 1775 case when coalesce(inctransdesc, 0) = 1 1776 then trim(acct.description) 1777 else trim(alert.notifymsg) 1779 alert.incamt, acct.amount, 1780 alert.incbal, acct.balance, alert.alerttype 1781 FROM cu_alerts as alert 1782 JOIN cutronah as acct ON acct.cu = alert.cu 1783 AND acct.accountnumber = alert.accountnumber 1784 AND acct.accounttype = alert.accounttype 1785 AND acct.certnumber = alert.certnumber 1786 AND acct.description ilike '%' || alert.notifydesc || '%' 1787 AND acct.runslot = '{$config["runslot
"]}' 1788 WHERE alert.cu = '{$currCU}' 1789 AND alert.accountnumber = '$account' 1790 AND (coalesce( alert.notifyrange, 0 ) = 0 1791 OR (coalesce( alert.notifyrange, 0 ) > 0 AND abs(acct.amount) > alert.notifyamtmin AND abs(acct.amount) < alert.notifyamtmax)) 1792 AND ((alert.notifytranstype = 'B') 1793 OR (alert.notifytranstype = 'D' AND acct.amount > 0) 1794 OR (alert.notifytranstype = 'W' AND acct.amount < 0)) 1795 AND (alert.lasttrace IS NULL OR alert.lasttrace < acct.tracenumber) 1796 AND alert.alerttype = 'T' ";
1798 $update[
"Transaction"] =
1799 "UPDATE cu_alerts SET 1800 lastalert = CURRENT_TIMESTAMP, 1801 lasttrace = (SELECT max(tracenumber) 1802 FROM cutronah as hist 1803 WHERE hist.cu = acct.cu 1804 AND hist.accountnumber = acct.accountnumber 1805 AND hist.accounttype = acct.accounttype 1806 AND hist.certnumber = acct.certnumber 1807 AND hist.runslot = '{$config["runslot
"]}') 1808 FROM cutronah as acct 1809 WHERE acct.cu = cu_alerts.cu 1810 AND acct.runslot = '{$config["runslot
"]}' 1811 AND acct.accountnumber = cu_alerts.accountnumber 1812 AND acct.accounttype = cu_alerts.accounttype 1813 AND acct.certnumber = cu_alerts.certnumber 1814 AND acct.description ilike '%' || cu_alerts.notifydesc || '%' 1815 AND (coalesce( cu_alerts.notifyrange, 0 ) = 0 1816 OR (abs(acct.amount) > cu_alerts.notifyamtmin AND abs(acct.amount) < cu_alerts.notifyamtmax)) 1817 AND ((cu_alerts.notifytranstype = 'B') 1818 OR (cu_alerts.notifytranstype = 'D' AND acct.amount > 0) 1819 OR (cu_alerts.notifytranstype = 'W' AND acct.amount < 0)) 1820 AND (cu_alerts.lasttrace IS NULL OR cu_alerts.lasttrace < acct.tracenumber) 1821 AND cu_alerts.cu = '{$currCU}' 1822 AND cu_alerts.accountnumber='$account' 1823 AND cu_alerts.alerttype = 'T' ";
1826 $uniqueUserList = array();
1829 # Since the logic for each alert type is so close, we churn thru 1830 # a hash of selects/updates to process the alerts. 1832 #print STAT `date +'%a %b %d %T %Y %Z'`; 1833 foreach ( $select as $key => $query ) {
1834 $alertReturn[
"alert_stats"][
"sent.$key"] = 0;
1835 $alertReturn[
"alert_stats"][
"upd.$key"] = 0;
1837 $alertReturn[
"messages"][] =
"Processing $currCU $account $key Alerts";
1839 $rs = db_query( $query, $dbh );
1842 $errorMsg =
"Failed getting $key Alerts {$config["runslot
"]} \n" . db_last_error() .
" SQL: $query\n";
1843 dmserror( $DMSMAIL,
'WARN', $errorMsg );
1845 $alertReturn[
"messages"][] = $errorMsg;
1851 $alertIdList = array();
1854 while ( $alertRow = db_fetch_assoc( $rs, $row++ ) ) {
1855 $userId = $alertRow[
"user_id"];
1856 if ( !in_array( $userId, $uniqueUserList ) ) {
1857 $uniqueUserList[] = $userId;
1860 $alertReturn[
"alert_stats"][
"sent.$key"]++;
1862 $alertType = $alertRow[
"alerttype"];
1864 $msg = $alertRow[
"notifymsg"];
1867 if ( $alertType !=
"L" ) {
1868 if ( $alertRow[
"incamt"] > 0 ) {
1869 $msg .=
"\nAmount = {$alertRow["amount
"]}";
1872 if ( $alertType ==
"B" ) {
1873 $msg .=
"\nBalance = {$alertRow["balance
"]}";
1874 }
else if ( $alertType ==
"T" ) {
1877 if ( ($cuInfo[
"flagset"] & $CU_CALCRUNBAL) != $CU_CALCRUNBAL ) {
1878 if ( $alertRow[
"incbal"] > 0 ) {
1879 $msg .=
"\nBalance = {$alertRow["balance
"]}";
1885 $to = $alertRow[
"notifyto"];
1886 $alertLongCode = $cuInfo[
"txtbanking"];
1887 $alertMail = $cuInfo[
"alert"];
1889 $mask= GetMask($dbh, $pHbEnv[
"Cu"]);
1890 $mask= $mask[
"code"] != 0 ? array(
"start" => -2) : $mask[
"data"];
1891 $accountPortion= ApplyMask($account, $mask);
1893 if ( $alertRow[
"emailtype"] ==
'W' ) {
1898 switch( $alertType ) {
1900 $preamble .=
"Low Balance";
1903 $preamble .=
"Check Number";
1906 $preamble .=
"Loan Payment Due";
1909 $preamble .=
"Transaction Found";
1912 $msg =
"Account ending {$accountPortion} {$preamble}\n{$msg}";
1914 if ( isset( $shortAlertMsg[$msgPick] ) ) {
1915 $msg .=
"\n" . $shortAlertMsg[$msgPick];
1919 # Determine if I am sending this via Long code or mail 1923 if ($cuInfo[
'flagset3'] & GetFlagsetValue(
'CU3_LONGCODE_MFA')) {
1926 # check if CU has a longcode to use 1927 if ( preg_match(
"/^[+]{0,1}[0-9]{1,12}$/", $alertLongCode ) && $alertLongCode !=
'' ) {
1928 SmsLongcode(
'SMS', $alertLongCode, $to, $msg, $account,
'' );
1931 SmsInternalLongcode( $cuInfo[
"alert"], $to, $msg, $account, $ALERTFROMNAME );
1935 SmsLongcode(
'AWS', $alertLongCode, $to, $msg, $account,
"$ALERTFROMNAME" );
1942 switch( $alertRow[
"alerttype"] ) {
1944 $preamble .=
"The balance is below the specified amount.\n";
1947 $preamble .=
"A check with the specified check number has been found.\n";
1950 $preamble .=
"There is a loan payment due.\n";
1953 $preamble .=
"A transaction has been found with the specified phrase.\n";
1958 $msg =
"Account ending with $accountPortion has an alert.\n" 1962 .
"<pre>$msg</pre>\n";
1964 if ( isset( $longAlertMsg[$msgPick] ) ) {
1965 $msg .=
"<hr>" . $longAlertMsg[$msgPick++];
1968 HtmlMail( $alertMail, $to, $msg, $ALERTFROMADDR, $ALERTFROMNAME);
1972 $alertReturn[
"alert_count"]++;
1975 if ( $msgPick >= $numAlertMsgs ) {
1982 # print STAT "Updating $key Alerts. \n"; 1984 $rs = db_query( $update[$key], $dbh );
1986 # print $conn->errorMessage,"\n" 1988 $errorMsg =
"Failed updating $key Alerts {$config["runslot
"]} \n" . db_last_error() .
"SQL: {$update[$key]}\n";
1989 dmserror( $DMSMAIL,
'WARN', $errorMsg );
1991 $alertReturn[
"messages"][] = $errorMsg;
1995 # fprintf( $STAT, "$currCU $key Alert(s) Updated. $update[$key]\n" ); 1998 $alertReturn[
"alert_stats"][
"upd.$key"] += db_affected_rows( $rs );
2004 $alertReturn[
"user_count"] = count( $uniqueUserList );
2006 $thisTimeEnd = microtime(
true);
2008 $alertReturn[
"time"] = $thisTimeEnd - $thisTimeStart;
2010 return $alertReturn;
2019 function HaveAccountData( $pDbh, $pCurrCU, $pAccount, $pRunslot ) {
2020 $haveAccount =
false;
2022 if ( strpos( $pAccount,
"|" ) > 0 ) {
2023 $parts = explode(
"|", $pAccount );
2025 $account = $parts[1];
2026 $subAccount = $parts[2];
2028 $account = $pAccount;
2031 $sql =
"SELECT count(*) as count 2033 WHERE cu = '$pCurrCU' 2034 AND runslot = '$pRunslot' 2035 AND accountnumber = '$account'";
2037 $rs = db_query( $sql, $pDbh );
2039 $accountRow = db_fetch_row( $rs, 0 );
2041 $haveAccount = $accountRow[0] > 0;
2044 return $haveAccount;
2050 function UpdateTRONTables( $pEnv, $pRunSlot, $pMemberData, $pRawData ) {
2051 $returnError = array(
2052 "status" => array(
"code"=>
'000',
"error" =>
"" )
2057 $dbh = HCU_array_key_value(
'dbh', $pEnv);
2060 $startRs = db_work( $dbh, HOMECU_WORK_BEGIN );
2063 $pktInquiryNode = $pRawData->Inquiry;
2073 $updTableList = array(
"cutronab",
"cutronah",
"cutronlb" );
2074 $updTableMeta = array(
"cutronab" => array(
"node" =>
'AccountBalance' ),
2075 "cutronah" => array(
"node" =>
"AccountHistory"),
2076 "cutronlb" => array(
"node" =>
"LoanBalance") );
2079 foreach ( $updTableList as $updTableName ) {
2082 $sql =
"DELETE FROM $updTableName 2083 WHERE runslot = '$pRunSlot' 2084 AND cu = '{$pEnv["Cu
"]}' 2085 AND accountnumber = '" . prep_save( $pMemberData[
"account"], 12 ) .
"'";
2086 $result = db_query( $sql, $dbh );
2089 $cp =
"copy {$updTableName} from stdin with null as ''";
2090 $result = db_query( $cp, $dbh );
2093 $tblPktData = $pktInquiryNode->{ HCU_array_key_value(
'node', HCU_array_key_value( $updTableName, $updTableMeta ) ) };
2095 $dataRecords = explode(
"\n", $tblPktData);
2097 while (list($key, $line) = each($dataRecords)) {
2098 if ( trim( $line ) ==
"" ) {
2103 $line = preg_replace(
"/ ?\t ?/",
"\t", $line);
2104 $line = preg_replace(
"/ $/",
"", $line);
2105 $line = preg_replace(
"/\\0/",
" ", $line);
2108 # ADD RUNSLOT PRIOR TO CU CODE 2109 $line =
"{$pRunSlot}\t{$pEnv["Cu
"]}\t" . $line;
2111 pg_put_line( $dbh, $line .
"\n" );
2115 $endCopyRs = pg_put_line( $dbh,
"\\.\n" );
2117 if ( !$endCopyRs ) {
2119 throw new Exception (
"Error with the final pg_put_line");
2122 $resultsRs = pg_end_copy( $dbh );
2123 if ( !$resultsRs ) {
2124 throw new Exception (
"Error Performing the Copy");
2129 $commitRs = db_work( $dbh, HOMECU_WORK_COMMIT );
2132 throw new Exception (
"Failed to Commit Work");
2134 }
catch( Exception $e ) {
2135 $commitRs = db_work( $dbh, HOMECU_WORK_ROLLBACK );
2137 $returnError[
"status"][
"code"] =
"999";
2138 $returnError[
"status"][
"error"] = $e->getMessage();
2142 return $returnError;
2155 function HandleTransferRequest( $pDbh, $pEnv, $pFeatureCode, $pTxnData, $pDryRun ) {
2159 $returnError = array(
2160 "status" => array(
"code"=>
'000',
"error" =>
"" )
2164 $transData = array();
2166 $transactionCode =
"";
2169 $inTransaction =
false;
2170 $pTxnData[
"txn"][
"memo"] = trim($pTxnData[
"txn"][
"memo"]) !=
"" ? $pTxnData[
"txn"][
"memo"] :
"AUTO HB XFER";
2172 $transactionMemo =
"";
2174 if ( $pFeatureCode ==
"TRN" ) {
2175 $srcAcctId = explode(
"|", $pTxnData[
"txn"][
"from"]);
2176 $srcAcctKey = BuildAccountKey($pTxnData,
"from");
2178 $dstAcctId = explode(
"|", $pTxnData[
"txn"][
"to"]);
2179 $dstAcctKey = BuildAccountKey($pTxnData,
"to");
2182 $transData[
"acct_source"] = $pTxnData[
"txn"][
"from"];
2183 $transData[
"acct_dest"] = $pTxnData[
"txn"][
"to"];
2184 $transData[
'source_key'] = $srcAcctKey;
2185 $transData[
'dest_key'] = $dstAcctKey;
2188 $transactionMemo = $pTxnData[
"txn"][
"memo"];
2191 $misc1 = isset( $pTxnData[
"txn"][
"misc1"] ) && strlen( $pTxnData[
"txn"][
"misc1"] ) > 0 ? $pTxnData[
"txn"][
"misc1"] :
"";
2192 $transData[
'misc'] = $misc1;
2195 $parts = explode(
"|", $pTxnData[
"txn"][
"from"] );
2196 $fromMember = $srcAcctKey[
'accountnumber'];
2199 $referenceId = $pEnv[
"Uid"];
2200 }
else if ( $pFeatureCode ==
"TRNEXT" ) {
2201 $localAcctKey = array();
2203 if ( $pTxnData[
"txn"][
"type"] ==
"L2X" ) {
2204 $localAcct = $pTxnData[
"txn"][
"from"];
2205 $localAcctId = explode(
"|", $pTxnData[
"txn"][
"from"]);
2207 $localAcctKey = BuildAccountKey($pTxnData,
"from");
2208 $remoteAcct = BuildExtAcctData( $pDbh, $pEnv, $pTxnData[
"txn"][
"to"],
"CR" );
2211 $referenceId = $pTxnData[
"txn"][
"to"];
2213 $localAcct = $pTxnData[
"txn"][
"to"];
2214 $localAcctId = explode(
"|", $pTxnData[
"txn"][
"to"]);
2216 $localAcctKey = BuildAccountKey($pTxnData,
"to");
2217 $remoteAcct = BuildExtAcctData( $pDbh, $pEnv, $pTxnData[
"txn"][
"from"],
"DB" );
2220 $referenceId = $pTxnData[
"txn"][
"from"] ;
2224 $transactionMemo = $pTxnData[
"txn"][
"memo"];
2226 if ( $pTxnData[
"txn"][
"type"] ==
"L2X" ) {
2227 $transData[
"acct_source"] = $localAcct;
2228 $transData[
"acct_dest"] = $remoteAcct;
2229 $transData[
'source_key'] = $localAcctKey;
2232 $parts = explode(
"|", $localAcct );
2233 $fromMember = $localAcctKey[
'accountnumber'];
2235 $transData[
"acct_source"] = $remoteAcct;
2236 $transData[
"acct_dest"] = $localAcct;
2237 $transData[
'dest_key'] = $localAcctKey;
2242 }
else if ( $pFeatureCode ==
"TRNM2M" ) {
2243 $localAcct = $pTxnData[
"txn"][
"from"];
2244 $localAcctId = explode(
"|", $pTxnData[
"txn"][
"from"]);
2246 $localAcctKey = BuildAccountKey($pTxnData,
"from");
2247 $transData[
"acct_source"] = $pTxnData[
"txn"][
"from"];
2248 $transData[
'source_key'] = $localAcctKey;
2251 $parts = explode(
"|", $pTxnData[
"txn"][
"from"] );
2252 $fromMember = $localAcctKey[
'accountnumber'];
2255 $remoteAcct = BuildM2MAcctData( $pDbh, $pEnv, $pTxnData[
"txn"][
"to"],
"DB" );
2257 $destId =
"M|{$remoteAcct["rdfi
"]["rdfi_account
"]}|{$remoteAcct["rdfi
"]["rdfi_account_type
"]}";
2258 $remoteAcctKey = BuildM2MAccountKey($remoteAcct);
2259 $transData[
"acct_dest"] = $destId;
2260 $transData[
'dest_key'] = $remoteAcctKey;
2263 $transactionMemo = $pTxnData[
"txn"][
"memo"];
2266 $transData[
'misc'] = $remoteAcctKey[
"name"];
2269 $referenceId = $pTxnData[
"txn"][
"to"] ;
2270 }
else if ( $pFeatureCode ==
"ACHCOL" || $pFeatureCode ==
"ACHPMT" ) {
2271 $localAcctKey = array();
2272 if ( $pTxnData[
"txn"][
"type"] ==
"L2R" ) {
2273 $localAcct = $pTxnData[
"txn"][
"from"];
2274 $localAcctId = explode(
"|", $localAcct);
2276 $localAcctKey[
'accountnumber'] = $pTxnData[
'txn'][
'frommember'];
2277 $localAcctKey[
'recordtype'] = $localAcctId[0];
2278 if ($localAcctId[0] ==
"D") {
2279 $localAcctKey[
'accounttype'] = $localAcctId[2];
2280 $localAcctKey[
'certnumber'] = $localAcctId[3];
2281 }
else if ($localAcctId[0] ==
"L") {
2282 $localAcctKey[
'loannumber'] = $localAcctId[2];
2284 $remoteAcct = BuildACHData( $pDbh, $pEnv, $pTxnData[
"txn"][
"to"] );
2287 $remoteAcct[
"rdfi"][
"rdfi_txn_type"] =
"CR";
2290 $referenceId = $pTxnData[
"txn"][
"to"];
2292 $localAcct = $pTxnData[
"txn"][
"to"];
2293 $localAcctId = explode(
"|", $localAcct);
2294 $localAcctKey[
'accountnumber'] = $pTxnData[
'txn'][
'tomember'];
2295 $localAcctKey[
'recordtype'] = $localAcctId[0];
2296 if ($localAcctId[0] ==
"D") {
2297 $localAcctKey[
'accounttype'] = $localAcctId[2];
2298 $localAcctKey[
'certnumber'] = $localAcctId[3];
2299 }
else if ($localAcctId[0] ==
"L") {
2300 $localAcctKey[
'loannumber'] = $localAcctId[2];
2302 $remoteAcct = BuildACHData( $pDbh, $pEnv, $pTxnData[
"txn"][
"from"] );
2305 $remoteAcct[
"rdfi"][
"rdfi_txn_type"] =
"DB";
2308 $referenceId = $pTxnData[
"txn"][
"from"] ;
2312 $emailNotify = $remoteAcct[
'remote_entity'][
'notify'] ==
"t" ? 1 : 0;
2314 unset($remoteAcct[
'remote_entity'][
'notify']);
2317 $transactionMemo = $pTxnData[
"txn"][
"memo"];
2319 if ( isset( $pTxnData[
"txn"][
"addenda"] ) && $pTxnData[
"txn"][
"addenda"] !=
"" ) {
2320 $remoteAcct[
"rdfi"][
"addenda"] = $pTxnData[
"txn"][
"addenda"];
2323 if ( $pTxnData[
"txn"][
"type"] ==
"L2R" ) {
2324 $transData[
"acct_source"] = $localAcct;
2325 $transData[
"acct_dest"] = $remoteAcct;
2326 $transData[
'source_key'] = $localAcctKey;
2327 $transData[
'dest_key'] = array();
2330 $parts = explode(
"|", $localAcct );
2331 $fromMember = $localAcctKey[
'accountnumber'];
2333 $transData[
"acct_source"] = $remoteAcct;
2334 $transData[
"acct_dest"] = $localAcct;
2335 $transData[
'source_key'] = array();
2336 $transData[
'dest_key'] = $localAcctKey;
2343 $errorMessage =
"Unknown feature code: $pFeatureCode.";
2346 $returnError[
"status"][
"code"] =
"999";
2347 $returnError[
"status"][
"error"] = $errorMessage;
2350 dmserror( $DMSMAIL,
'FATAL', $errorMessage );
2351 return $returnError;
2358 $userSql =
"SELECT user_name 2359 FROM {$pEnv["Cu
"]}user 2360 WHERE user_id = {$pEnv["Uid
"]} ";
2362 $userRS = db_query( $userSql, $pDbh );
2363 $userRow = db_fetch_row( $userRS, 0 );
2365 fprintf( $STAT,
"Dry Run: Recording transfer for CU: {$pEnv["Cu
"]}, User: {$userRow[0]}, Feature: $pFeatureCode, Amount: {$pTxnData["txn
"]['amount']}, TxnId: {$pTxnData["txn_id
"]} \n" );
2369 $permissionInputs = array(
"feature" => $pFeatureCode );
2370 $permissionInputs[
"amount"] = $pTxnData[
"txn"][
'amount'];
2372 switch ($pFeatureCode) {
2374 $permissionInputs[
"account"] = $pTxnData[
"txn"][
"frommember"];
2375 $permissionInputs[
"accounttype"] = $pTxnData[
"txn"][
"fromsuffix"];
2378 if ($pTxnData[
"txn"][
"type"] ==
"X2L") {
2379 $permissionInputs[
"account"] = $pEnv[
"Uid"];
2380 $permissionInputs[
"accounttype"] = $pTxnData[
"txn"][
"from"];
2382 $sourceParts = explode(
"|", $pTxnData[
"txn"][
"from"]);
2383 $permissionInputs[
"account"] = $sourceParts[1];
2384 $permissionInputs[
"accounttype"] = $sourceParts[2];
2388 $sourceParts = explode(
"|", $pTxnData[
"txn"][
"from"]);
2389 $permissionInputs[
"account"] = $sourceParts[1];
2390 $permissionInputs[
"accounttype"] = $sourceParts[2];
2394 $sourceParts = explode(
"|", $pTxnData[
"txn"][
"to"]);
2395 $permissionInputs[
"account"] = $sourceParts[1];
2396 $permissionInputs[
"accounttype"] = $sourceParts[2];
2399 $sourceParts = explode(
"|", $pTxnData[
"txn"][
"from"]);
2400 $permissionInputs[
"account"] = $sourceParts[1];
2401 $permissionInputs[
"accounttype"] = $sourceParts[2];
2405 $limitTestResult = Perm_CheckLimits( $pDbh, $pEnv, $permissionInputs );
2407 if ($limitTestResult[
"status"][
"code"] !=
"000") {
2408 throw new Exception(
"Scheduled Transfer Error: " . $limitTestResult[
"status"][
"error"]);
2413 if ($pFeatureCode ==
"ACHPMT") {
2414 $memberInfoParams = array(
2415 "member"=>$localAcctKey[
'accountnumber'],
2420 $memberInfo = FindMemberAccounts($pEnv, $memberInfoParams);
2421 if ($memberInfo[
'code'] !=
"000") {
2422 throw new Exception($memberInfo[
'error']);
2425 $memberAccts = $memberInfo[
'data'][
'accounts'];
2431 if (HCU_array_key_exists(
"deposit", $memberAccts)) {
2432 foreach ($memberAccts[
'deposit'] as $key => $value) {
2434 $acctNum = $value[
'accountnumber'];
2435 $acctType = $value[
'accounttype'];
2436 $acctCert = $value[
'certnumber'];
2441 ($acctNum == $localAcctKey[
'accountnumber']) &&
2442 ($acctType == $localAcctKey[
'accounttype']) &&
2443 ($acctCert == $localAcctKey[
'certnumber']);
2447 $acctAvailable = doubleval($value[
'available']);
2453 $acctAmount = doubleval($pTxnData[
'txn'][
'amount']);
2454 if ($acctAvailable < $acctAmount) {
2455 throw new Exception(
"Scheduled Transfer Error: Transfer exceeds available funds.");
2460 $txnRs = db_work( $pDbh, HOMECU_WORK_BEGIN);
2461 $inTransaction =
true;
2466 $recordVariables = array();
2467 $recordVariables[
"txFeatureCode"] = $pFeatureCode;
2468 $recordVariables[
"txPostedBy"] = $pEnv[
"Uid"];
2471 $recordVariables[
"txAuthAccount"] = $fromMember;
2472 $recordVariables[
"txTransCode"] = trim( $pTxnData[
"txn"][
"transactioncode"] );
2473 $recordVariables[
"txComment"] = trim( $transactionMemo );
2475 $recordVariables[
"txReferenceId"] = $referenceId;
2476 $recordVariables[
"txAmount"] = $pTxnData[
"txn"][
'amount'];
2477 $recordVariables[
"txNotify"] = $emailNotify;
2480 $jsonTransData = HCU_JsonEncode( $transData );
2481 $recordVariables[
"txData"] = $jsonTransData;
2486 $transMeta = array();
2487 $transMeta[
"source"] = $pTxnData[
"txn_id"];
2488 $transMeta[
"recurr"] = $pTxnData[
"frequency"] ==
"OneTime" ?
"no" :
"yes";
2489 $transMeta[
"interval"] = $pTxnData[
"interval"];
2490 $jsonTransMeta = HCU_JsonEncode($transMeta);
2491 $recordVariables[
"txMeta"] = $jsonTransMeta;
2494 $transferResult = RecordTransfer( $pDbh, $pEnv, $recordVariables );
2496 if ( $transferResult[
"status"][
"code"] ==
"000" ) {
2498 $transHeaderId = $transferResult[
"data"][
"id"];
2499 $approvalInfo = array(
"txId" => $transHeaderId,
2500 "txApprover" => $pTxnData[
"approved_by"] );
2503 $transferResult = MarkTransferApproved( $pDbh, $pEnv, $approvalInfo );
2506 if ( $transferResult[
"status"][
"code"] ==
"000" &&
2507 ( $pFeatureCode ==
"TRN" || $pFeatureCode ==
"TRNM2M" ) ) {
2509 $transferRecord = array();
2511 $transferRecord[
"acct_source"] = $transData[
"acct_source"];
2512 $transferRecord[
"acct_dest"] = $transData[
"acct_dest"];
2513 $transferRecord[
"misc"] = $transData[
"misc"];
2514 $transferRecord[
"accountnumber"] = $fromMember;
2515 $transferRecord[
"transactioncode"] = $pTxnData[
"txn"][
"transactioncode"];
2516 $transferRecord[
"memo"] = trim( $transactionMemo );
2517 $transferRecord[
"amount"] = $pTxnData[
"txn"][
"amount"];
2519 $transferResult = PostInternalTransfer( $pEnv, $transferRecord );
2522 if ( $transferResult[
"status"][
"code"] ===
"000" ) {
2524 $sql =
"UPDATE {$pEnv["Cu
"]}transhdr SET 2525 processed_by = '*sched*', 2526 processed_date = now(), 2527 processed_status = 20 2528 WHERE id = $transHeaderId";
2530 $rs = db_query( $sql, $pDbh );
2535 if ( $transferResult[
"status"][
"code"] !==
"000" ) {
2536 $errorMessage =
"Feature: $pFeatureCode, UserId: {$pEnv["Uid
"]}; Error Message: ";
2537 for ( $i = 0; $i < count( $transferResult[
"status"][
"errors"] ); $i++ ) {
2538 $errorMessage .= $transferResult[
"status"][
"errors"][$i] .
" ";
2540 throw new Exception(
"Scheduled Transfer Error: $errorMessage" );
2544 $commitRs = db_work( $pDbh, HOMECU_WORK_COMMIT );
2547 throw new Exception (
"Failed to Commit Work");
2551 }
catch( Exception $e ) {
2552 $errorMessage = $e->getMessage();
2554 $returnError[
"status"][
"code"] =
"999";
2555 $returnError[
"status"][
"error"] = $errorMessage;
2557 if ( $inTransaction ) {
2558 db_work( $pDbh, HOMECU_WORK_ROLLBACK );
2562 return $returnError;
2566 function BuildExtAcctData( $pDbh, $pEnv, $pAcctId, $pTxnType ) {
2570 $extSQL =
"SELECT display_name, remote_info 2571 FROM {$pEnv["Cu
"]}extaccount 2572 WHERE id = {$pAcctId}";
2574 $rs = db_query( $extSQL, $pDbh );
2576 dmserror( $DMSMAIL,
"WARN",
"Unable to read {$pEnv["Cu
"]}extaccount for userId {$pEnv["Uid
"]}, id $pAcctId.\n" . db_last_error() );
2578 $extRow = db_fetch_assoc( $rs );
2580 $extData = HCU_JsonDecode( $extRow[
"remote_info"],
false );
2582 dmserror( $DMSMAIL,
"WARN",
"Unable to parse json for {$pEnv["Cu
"]}extaccount (for userId {$pEnv["Uid
"]}), id $pAcctId.\n" . db_last_error() );
2592 $extDFI = array(
"rdfi_routing" => $extData[
"rdfi"][
"routing"],
2593 "rdfi_account" => $extData[
"rdfi"][
"account"],
2594 "rdfi_account_type" => $extData[
"rdfi"][
"type"],
2595 "rdfi_txn_type" => $pTxnType,
2597 $remoteEntity = array (
"name" => $extData[
"rdfi"][
"name"],
2598 "entry_id" => $pAcctId,
2599 "display_name" => $extRow[
"display_name"] );
2601 $extInfo[
"rdfi"] = $extDFI;
2602 $extInfo[
"remote_entity"] = $remoteEntity;
2610 function BuildM2MAcctData( $pDbh, $pEnv, $pAcctId, $pTxnType ) {
2614 $extSQL =
"SELECT display_name, remote_info 2615 FROM {$pEnv["Cu
"]}extaccount 2616 WHERE id = {$pAcctId}";
2618 $rs = db_query( $extSQL, $pDbh );
2620 dmserror( $DMSMAIL,
"WARN",
"Unable to read {$pEnv["Cu
"]}extaccount for userId {$pEnv["Uid
"]}, id $pAcctId.\n" . db_last_error() );
2622 $extRow = db_fetch_assoc( $rs );
2624 $extData = HCU_JsonDecode( $extRow[
"remote_info"],
false );
2626 dmserror( $DMSMAIL,
"WARN",
"Unable to parse json for {$pEnv["Cu
"]}extaccount (for userId {$pEnv["Uid
"]}), id $pAcctId.\n" . db_last_error() );
2636 $extDFI = array(
"rdfi_account" => $extData[
"rdfi"][
"account"],
2637 "rdfi_account_type" => $extData[
"rdfi"][
"type"],
2638 "rdfi_txn_type" => $pTxnType,
2640 $remoteEntity = array (
"name" => $extData[
"rdfi"][
"name"],
2641 "entry_id" => $pAcctId,
2642 "display_name" => $extRow[
"display_name"] );
2644 $extInfo[
"rdfi"] = $extDFI;
2645 $extInfo[
"remote_entity"] = $remoteEntity;
2653 function BuildACHData( $pDbh, $pEnv, $pAcctId ) {
2657 $achSQL =
"SELECT ach_name, address, dfi_data, email_notify 2658 FROM {$pEnv["Cu
"]}achpartner 2659 WHERE id = {$pAcctId}";
2661 $rs = db_query( $achSQL, $pDbh );
2663 dmserror( $DMSMAIL,
"WARN",
"Unable to read {$pEnv["Cu
"]}achpartner for userId {$pEnv["Uid
"]}, id $pAcctId.\n" . db_last_error() );
2665 $achRow = db_fetch_assoc( $rs );
2667 $achDFI = HCU_JsonDecode( $achRow[
"dfi_data"],
false );
2668 $achAddress = HCU_JsonDecode( $achRow[
"address"],
false );
2669 if ( !$achDFI || !$achAddress ) {
2670 dmserror( $DMSMAIL,
"WARN",
"Unable to parse json for {$pEnv["Cu
"]}achpartner (for userId {$pEnv["Uid
"]}), id $pAcctId.\n" . db_last_error() );
2681 $achData = array(
"rdfi_routing" => $achDFI[
"dfi_routing"],
2682 "rdfi_account" => $achDFI[
"dfi_account"],
2683 "rdfi_account_type" => $achDFI[
"dfi_account_type"],
2684 "rdfi_txn_type" =>
"",
2686 $remoteEntity = array (
"name" => $achRow[
"ach_name"],
2687 "address1" => $achAddress[
"address1"],
2688 "address2" => $achAddress[
"address2"],
2689 "email" => $achAddress[
"email"],
2690 "notify" => $achRow[
'email_notify'] );
2692 $achInfo[
"rdfi"] = $achData;
2693 $achInfo[
"remote_entity"] = $remoteEntity;
2717 function UserHasRightsToTransfer( $dbh, $cu, $userId, $pFromAcctKey, $pToAcctKey, $pTransCode ) {
2722 if (count($pFromAcctKey) == 0 && count($pToAcctKey) == 0) {
2723 throw new Exception (
"No Valid Accounts");
2727 $tranCodeXLookup = Array(
"XA",
"XP");
2730 if (count($pFromAcctKey)) {
2731 $fromAcct = FindUserAccountExists($dbh, $cu, $userId, $pFromAcctKey[
'recordtype'], $pFromAcctKey[
'accountnumber'],
2732 ($pFromAcctKey[
'recordtype'] ==
"D" ? $pFromAcctKey[
'accounttype'] : $pFromAcctKey[
'loannumber']),
2733 ($pFromAcctKey[
'recordtype'] ==
"D" ? $pFromAcctKey[
'certnumber'] :
'')
2735 if ($fromAcct ===
false) {
2736 dmserror( $GLOBALS[
'DMSMAIL'],
"WARN",
"Unable to read {$cu}useraccount for userId $userId, account {$pFromAcctKey['accountnumber']}, accounttype {$pFromAcctKey['accounttype']}, recordtype {$pFromAcctKey['recordtype']}. \n" . db_last_error() );
2737 $hasFromRights =
false;
2741 if (count($pToAcctKey) == 0) {
2743 $hasFromRights = HCU_array_key_value(
"ext_withdraw", $fromAcct[
'data']) ===
't';
2746 $hasFromRights = HCU_array_key_value(
"int_withdraw", $fromAcct[
'data']) ===
't';
2751 $hasFromRights =
true;
2755 if (count($pToAcctKey)) {
2757 if (in_array($pTransCode, $tranCodeXLookup)) {
2767 $localAcctNbr = $pFromAcctKey[
'accountnumber'];
2768 $localAcctSfx = ($pToAcctKey[
'recordtype'] ==
"D" ? $pToAcctKey[
'accounttype'] : $pToAcctKey[
'loannumber']) .
'#' . $pToAcctKey[
'accountnumber'];
2770 $localRecType = ($pToAcctKey[
'recordtype'] ==
"D" ?
'T' :
'P');
2772 $localAcctNbr = $pToAcctKey[
'accountnumber'];
2773 $localAcctSfx = ($pToAcctKey[
'recordtype'] ==
"D" ? $pToAcctKey[
'accounttype'] : $pToAcctKey[
'loannumber']);
2774 $localAcctCrt = ($pToAcctKey[
'recordtype'] ==
"D" ? $pToAcctKey[
'certnumber'] :
'');
2775 $localRecType = $pToAcctKey[
'recordtype'];
2778 $toAcct = FindUserAccountExists($dbh, $cu, $userId, $localRecType, $localAcctNbr, $localAcctSfx, $localAcctCrt);
2779 if ($toAcct ===
false) {
2780 dmserror( $GLOBALS[
'DMSMAIL'],
"WARN",
"Unable to read {$cu}useraccount for userId $userId, account {$localAcctNbr}, accounttype {$localAcctSfx}, recordtype {$localAcctCrt}. \n" . db_last_error() );
2781 $hasToRights =
false;
2785 if (count($pFromAcctKey) == 0) {
2787 $hasToRights = HCU_array_key_value(
"ext_deposit", $toAcct[
'data']) ===
't';
2790 $hasToRights = HCU_array_key_value(
"int_deposit", $toAcct[
'data']) ===
't';
2795 $hasToRights =
true;
2799 $hasRights = $hasFromRights && $hasToRights;
2800 }
catch( Exception $e ) {
2811 function UpdateNextTriggerDate( $pDbh, $pScheduleId, $pTrigger ) {
2812 $updateResult =
false;
2815 $quotedTriggerDate = $pTrigger ?
"'$pTrigger'" :
"NULL";
2817 $sql =
"UPDATE cu_scheduledtxn 2818 SET next_trigger_date = $quotedTriggerDate, interval_count = interval_count + 1 2819 WHERE id = $pScheduleId";
2821 $rs = db_query( $sql, $pDbh );
2823 $updateResult = $rs !=
false;
2825 return $updateResult;
2833 function SmsMailTransfer( $from, $to, $message, $acct ) {
2836 $to = str_replace(
";",
",", $to );
2838 $fromParts = explode(
";", $from );
2839 $fromMail = $fromParts[0];
2841 $date = date(
"D M d H:i:s Y" );
2843 $headers =
"From: $fromMail\r\n";
2845 $subject =
"Credit Union Recurring Transaction";
2847 $body =
"$message\r\n\r\n$date";
2850 $notify->mailto = $to;
2851 $notify->mailfrom = $fromMail;
2852 $notify->subject = $subject;
2853 $notify->msgbody = $body;
2854 $notify->callingfunction = __FUNCTION__;
2855 $notify->file = __FILE__;
2856 $notify->SendMail();
2861 function GetNextLongCode() {
2862 global $gRoundRobinCounter;
2863 global $LONGCODE_ROUNDROBIN;
2865 $idx = $gRoundRobinCounter % count( $LONGCODE_ROUNDROBIN );
2866 $gRoundRobinCounter++;
2868 return $LONGCODE_ROUNDROBIN[$idx];
2872 function SmsInternalLongcode( $from, $to, $message, $acct, $orgname ) {
2873 $nextLongCode = GetNextLongCode();
2875 SmsLongcode(
'SMS', $nextLongCode, $to, $message, $acct,
"($from) " . $orgname );
2879 function HtmlMail( $from, $to, $message, $hdrFromAddr, $hdrFromName) {
2881 $date = date(
"D M d H:i:s Y" );
2883 $subject =
"Credit Union Alert";
2885 $body =
"<html><body>$message<br /><br /><span style='font-style: italic'>$date</span></body></html>";
2888 $notify->mailto = $to;
2889 $notify->mailfrom = $hdrFromAddr;
2890 $notify->mailfromname = $hdrFromName;
2891 $notify->subject = $subject;
2892 $notify->htmlMsgbody = $body;
2893 $notify->callingfunction = __FUNCTION__;
2894 $notify->file = __FILE__;
2895 $notify->SendMail();
2899 function SmsLongcode( $pType, $from, $to, $message, $acct, $orgname ) {
2901 # SEND using LONG CODE 2902 $smsMsg = ($orgname !=
'' ?
"Account Alert from $orgname\n\n" . $message :
"Credit Union Alert\n" . $message);
2905 # -- Need to escape new lines so the perl long code script will keep the string on one line 2906 # When broken up it causes problems on the command line call 2909 if ($pType ==
'SMS') {
2911 SendLongCodeSMS ($GLOBALS[
'HOMECU_LONGCODE_API_KEY'], $GLOBALS[
'HOMECU_LONGCODE_URL'], $from, $to, $smsMsg);
2912 } elseif($pType ==
'AWS') {
2914 $msg_response = SendAwsSMS($to, $orgname, $smsMsg);
2920 function FetchCUEmail( $dbh, $cu ) {
2925 $sql =
"SELECT rtrim(email) 2928 AND role = 'transfernotify'";
2929 $rs = db_query( $sql, $dbh );
2931 dmserror( $DMSMAIL,
"WARN",
"Unable to get CU's transfernotify email: {$cu}. \n" . db_last_error() );
2933 $cuRow = db_fetch_row( $rs );
2934 $cuEmail = $cuRow[0];
2941 function FetchUserInfo( $dbh, $cu, $userId ) {
2944 $returnInfo = array();
2945 $sql =
"SELECT user_name, email 2947 WHERE user_id = $userId";
2948 $rs = db_query( $sql, $dbh );
2950 dmserror( $DMSMAIL,
"WARN",
"Unable to get user name and email: {$cu}, user_id: {$userId}. \n" . db_last_error() );
2951 $returnInfo = array(
"user_name" =>
"unknown",
"email" =>
"unknown" );
2953 $cuRow = db_fetch_row( $rs );
2954 $returnInfo = array(
"user_name" => $cuRow[0],
"email" => $cuRow[1] );
2961 function MailCU( $pFromMail, $pCUMail, $pMessage ) {
2963 $fromParts = explode(
";", $pFromMail );
2964 $fromMail = $fromParts[0];
2967 $to = str_replace(
";",
",", $pCUMail );
2969 $date = date(
"D M d H:i:s Y" );
2971 $subject =
"HomeCU Member Processing Issue";
2973 $body =
"$pMessage\r\n\r\n$date";
2976 $notify->mailto = $to;
2977 $notify->mailfrom = $fromMail;
2978 $notify->subject = $subject;
2979 $notify->msgbody = $body;
2980 $notify->callingfunction = __FUNCTION__;
2981 $notify->file = __FILE__;
2982 $notify->SendMail();
2987 function MailUserInactive( $CUMAIL, $cuName, $userEmail ) {
2989 $parts = explode(
";", $CUMAIL );
2990 $fromMail = $parts[0];
2992 $date = date(
"D M d H:i:s Y" );
2993 $subject =
"$cuName recurring transfers";
2996 $body =
"This notice is to inform you your recurring transfer was set to inactive.\n\n";
2997 $body .=
"If you want to manually transfer these funds please call the credit union to reschedule your recurring transfer. \n\n";
2998 $body .=
"$cuName\n\n$date";
3001 $notify->header =
"Content-Type: text/html";
3002 $notify->mailto = $userEmail;
3003 $notify->mailfrom = $fromMail;
3004 $notify->subject = $subject;
3005 $notify->msgbody = $body;
3006 $notify->callingfunction = __FUNCTION__;
3007 $notify->file = __FILE__;
3008 $notify->cu = $cuName;
3009 $notify->SendMail();
3013 function MailUserWarning( $CUMAIL, $cuName, $userEmail, $message ) {
3015 $parts = explode(
";", $CUMAIL );
3016 $fromMail = $parts[0];
3018 $date = date(
"D M d H:i:s Y" );
3019 $subject =
"$cuName recurring transfers";
3022 $body =
"$message\n\n$cuName\n\n$date";
3025 $notify->mailto = $userEmail;
3026 $notify->mailfrom = $fromMail;
3027 $notify->subject = $subject;
3028 $notify->msgbody = $body;
3029 $notify->callingfunction = __FUNCTION__;
3030 $notify->file = __FILE__;
3031 $notify->cu = $cuName;
3032 $notify->SendMail();
3036 function dmserror( $email, $errorType, $errorMessage ) {
3042 $email = str_replace(
";",
",", $email );
3044 $subject =
"Subject: HomeCU Live Background Processing Error";
3047 $body =
"An error occured in " . __FILE__ .
" during background processing.\n\n";
3048 $body .=
"Error message: $errorMessage\n\n";
3049 $body .=
"Timestamp: " . date(
"D M d, Y G:i" );
3052 $notify->mailto = $email;
3053 $notify->subject = $subject;
3054 $notify->msgbody = $body;
3055 $notify->callingfunction = __FUNCTION__;
3056 $notify->file = __FILE__;
3057 $notify->SendMail();
3059 $stderr = fopen(
"php://stderr",
"w" );
3062 $stderr = fopen(
"php://stdout",
"w" );
3065 fwrite( $stderr,
"\nERROR OCCURRED DURING BACKGROUND PROCESSING!\n\n" );
3066 fwrite( $stderr,
"$errorMessage\n" );
3068 if ( $errorType ==
"FATAL" ) {
3075 # LOAD CREDIT UNION BLACK LIST 3076 # data is one line per credit union 3085 function ReturnBlackList() {
3086 global $WORKINGDIRECTORY;
3089 $blacklistFile= $WORKINGDIRECTORY .
"/alerts.blacklist.conf";
3093 if (file_exists( $blacklistFile)) {
3094 $cuList = file($blacklistFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
3095 # LOOP THROUGH EACH RECORD IN BLACKLIST 3096 for ( $i = 0; $i < count($cuList); $i++ ) {
3099 $returnCUList[] = trim(strtoupper($cuList[$i]));
3103 return $returnCUList;
3107 # ###################### 3108 # LOAD CREDIT UNION INCLUDE LIST 3109 # one line per credit union in format CUCODE ; time1; time2; ... timeN; 3110 # ###################### 3111 # Usage $x = ReturnRunSlotList('0815'); 3112 # param1 - currRunSlot - string - this is the 4 character runslot to match in the include file 3113 # returns list of quoted CU codes. 3114 function ReturnRunSlotList( $pCurrRunSlot ) {
3115 global $WORKINGDIRECTORY;
3117 $runslitFile = $WORKINGDIRECTORY .
"/alerts.runslotlist.conf";
3121 # OPEN THE FILE / RETRIEVE CONTENTS 3122 if ( file_exists( $runslitFile ) ) {
3123 $slotList = file( $runslitFile );
3124 # LOOP through each record in the INCLUSION File 3125 for ( $i = 0; $i < count( $slotList ); $i++ ) {
3126 $line = trim( $slotList[$i] );
3128 $parts = explode(
";", $line );
3130 # Match the appropriate time slot 3131 # each line of file should be formatted as 3132 # Be sure to put the credit union in the blacklist file if you do NOT want it to run with timezone 3133 # CUCODE ;0600;0815; 3135 # CUCODE ;0430;1100; 3136 $cuCode = trim( $parts[0] );
3138 for ( $s = 1; $s < count( $parts ); $s++ ) {
3139 if ( trim( $parts[$s] ) == trim( $pCurrRunSlot ) ) {
3140 $returnCUList .= ( $returnCUList !=
"" ?
", " :
"" ) .
"'" . strtoupper( $cuCode ) .
"'";
3148 return $returnCUList;
3152 function AddToGatheredTransferStats( &$pHolderArray, $pCurrCU, $pSlot, $pMessage ) {
3153 if ( !isset( $pHolderArray[$pCurrCU ] ) ) {
3155 $pHolderArray[$pCurrCU] = array(
"count" => 0,
3156 "failed" => array(
"count" => 0,
"messages" => array() ),
3157 "rights" => array(
"count" => 0,
"messages" => array() ),
3158 "success" => array(
"count" => 0,
"messages" => array() ),
3162 if ( $pSlot ==
"count" ) {
3163 $pHolderArray[$pCurrCU][
"count"]++;
3164 }
else if ( in_array( $pSlot, array(
"failed",
"rights",
"success" ) ) ) {
3166 $pHolderArray[$pCurrCU][$pSlot][
"count"]++;
3167 $pHolderArray[$pCurrCU][$pSlot][
"messages"][] = $pMessage;
3169 $pHolderArray[$pCurrCU][
"unknown"]++;
3176 function PrintGatheredTransferStats( $pOutputHandle, $pHolderArray ) {
3177 $output = $pOutputHandle ? $pOutputHandle : fopen(
'php://stdout',
'w');
3180 $padding = str_repeat(
" ", 15 );
3183 fprintf( $output,
"Credit Union transactions processed:\n" );
3184 fprintf( $output,
"CU\t\tCount\tMessages\n" );
3185 foreach( $pHolderArray as $thisCU => $cuStats ) {
3186 $thisCUPrint = substr( $thisCU . $padding, 0, 15 );
3187 fprintf( $output,
"$thisCUPrint\t{$pHolderArray[$thisCU]["count
"]}\n" );
3190 if ( isset( $pHolderArray[$thisCU][
"failed"] ) && $pHolderArray[$thisCU][
"failed"][
"count"] > 0 ) {
3191 $failedInfo = $pHolderArray[$thisCU][
"failed"];
3192 fprintf( $output,
"\n$padding\t\tNumber of failures: {$failedInfo["count
"]}\n" );
3194 for ( $i = 0; $i < count( $failedInfo[
"messages"] ); $i++ ) {
3195 fprintf( $output,
"$padding\t\t{$failedInfo["messages
"][$i]}\n" );
3200 if ( isset( $pHolderArray[$thisCU][
"success"] ) && $pHolderArray[$thisCU][
"success"][
"count"] > 0 ) {
3201 $successInfo = $pHolderArray[$thisCU][
"success"];
3202 fprintf( $output,
"\n$padding\t\tNumber of successful updates: {$successInfo["count
"]}\n" );
3204 for ( $i = 0; $i < count( $successInfo[
"messages"] ); $i++ ) {
3205 fprintf( $output,
"$padding\t\t{$successInfo["messages
"][$i]}\n" );
3210 if ( isset( $pHolderArray[$thisCU][
"rights"] ) && $pHolderArray[$thisCU][
"rights"][
"count"] > 0 ) {
3211 $rightsInfo = $pHolderArray[$thisCU][
"rights"];
3212 fprintf( $output,
"\n$padding\t\tNumber of access rights issues: {$rightsInfo["count
"]}\n" );
3214 for ( $i = 0; $i < count( $rightsInfo[
"messages"] ); $i++ ) {
3215 fprintf( $output,
"$padding\t\t{$rightsInfo["messages
"][$i]}\n" );
3220 if ( isset( $pHolderArray[$thisCU][
"unkonwn"] ) && $pHolderArray[$thisCU][
"unknown"] > 0 ) {
3221 $unknownCount = $pHolderArray[$thisCU][
"unknown"];
3222 fprintf( $output,
"\n$padding\t\tNumber of unknown statistic calls (need to fix): {$unknownCount}\n" );
3232 function AddToGatheredAlertStats( &$pHolderArray, $pCurrCU, $pCategory, $pResults ) {
3233 if ( !isset( $pHolderArray[$pCurrCU ] ) ) {
3235 $pHolderArray[$pCurrCU] = array(
"gathering" => array(
"time" => 0,
"count" => 0,
"messages" => array() ),
3236 "sending" => array(
"time" => 0,
"user_count" => 0,
"alert_count" => 0,
"messages" => array() ),
3237 "sent_stats" => array(),
3241 if ( $pCategory ==
"gathering" ) {
3243 $pHolderArray[$pCurrCU][
"gathering"][
"count"]++;
3245 $pHolderArray[$pCurrCU][
"gathering"][
"time"] += $pResults[
"time"];
3248 if ( count( $pResults[
"messages"] ) > 0 ) {
3249 $pHolderArray[$pCurrCU][
"gathering"][
"messages"] = array_merge( $pHolderArray[$pCurrCU][
"gathering"][
"messages"], $pResults[
"messages"] );
3251 }
else if ( $pCategory ==
"sending" ) {
3253 $pHolderArray[$pCurrCU][
"sending"][
"user_count"] += $pResults[
"user_count"];
3254 $pHolderArray[$pCurrCU][
"sending"][
"alert_count"] += $pResults[
"alert_count"];
3256 $pHolderArray[$pCurrCU][
"sending"][
"time"] += $pResults[
"time"];
3259 if ( count( $pResults[
"messages"] ) > 0 ) {
3260 $pHolderArray[$pCurrCU][
"sending"][
"messages"] = array_merge( $pHolderArray[$pCurrCU][
"sending"][
"messages"], $pResults[
"messages"] );
3262 }
else if ( $pCategory ==
"sent_stats" ) {
3264 $arrayKeys = array_keys( $pResults[
"alert_stats"] );
3265 for ( $i = 0; $i < count( $arrayKeys ); $i++ ) {
3267 if ( !isset( $pHolderArray[$pCurrCU][
"sent_stats"][$arrayKeys[$i]] ) ) {
3268 $pHolderArray[$pCurrCU][
"sent_stats"][$arrayKeys[$i]] = 0;
3272 $pHolderArray[$pCurrCU][
"sent_stats"][$arrayKeys[$i]] += $pResults[
"alert_stats"][$arrayKeys[$i]];
3275 $pHolderArray[$pCurrCU][
"unknown"]++;
3282 function PrintGatheredAlertStats( $pOutputHandle, $pHolderArray ) {
3283 $output = $pOutputHandle ? $pOutputHandle : fopen(
'php://stdout',
'w');
3286 fprintf( $output,
"Credit Union Alerts Processed:\n" );
3288 foreach( $pHolderArray as $thisCU => $cuStats ) {
3289 fprintf( $output,
"{$thisCU}\n" );
3291 $timeGathering = round( $pHolderArray[$thisCU][
"gathering"][
"time"], 1 );
3292 fprintf( $output,
"\tGathered Count\t{$pHolderArray[$thisCU]["gathering
"]["count
"]}\t{$timeGathering} seconds\n" );
3295 if ( isset( $pHolderArray[$thisCU][
"gathering"][
"messages"] ) &&
3296 count( $pHolderArray[$thisCU][
"gathering"][
"messages"] ) > 0 ) {
3297 fprintf( $output,
"\tGathering Messages\n" );
3299 for ( $i = 0; $i < count( $pHolderArray[$thisCU][
"gathering"][
"messages"] ); $i++ ) {
3300 fprintf( $output,
"\t\t{$pHolderArray[$thisCU]["gathering
"]["messages
"][$i]}\n" );
3304 $timeSending = round( $pHolderArray[$thisCU][
"sending"][
"time"], 1 );
3305 fprintf( $output,
"\tSent Alerts\t{$pHolderArray[$thisCU]["sending
"]["alert_count
"]}\tSent Users\t{$pHolderArray[$thisCU]["sending
"]["user_count
"]}\t{$timeSending} seconds\n" );
3308 if ( isset( $pHolderArray[$thisCU][
"sending"][
"messages"] ) &&
3309 count( $pHolderArray[$thisCU][
"sending"][
"messages"] ) > 0 ) {
3310 fprintf( $output,
"\tSending Messages\n" );
3312 for ( $i = 0; $i < count( $pHolderArray[$thisCU][
"sending"][
"messages"] ); $i++ ) {
3313 fprintf( $output,
"\t\t{$pHolderArray[$thisCU]["sending
"]["messages
"][$i]}\n" );
3319 $statisticTitle = substr(
"Statistics" . str_repeat(
" ", $nameWidth ), 0, $nameWidth );
3320 fprintf( $output,
"\t{$statisticTitle}\tCount\n" );
3322 $stats = array_keys( $pHolderArray[$thisCU][
"sent_stats"] );
3323 for ( $i = 0; $i < count( $stats ); $i++ ) {
3325 $statistic = substr( $stats[$i] . str_repeat(
" ", $nameWidth ), 0, $nameWidth );
3326 fprintf( $output,
"\t{$statistic}\t{$pHolderArray[$thisCU]["sent_stats
"][$stats[$i]]}\n" );
3352 function BuildAccountKey($pTxnData, $pKey) {
3356 if (HCU_array_key_exists(
"txn", $pTxnData)) {
3358 "acctid" => ($pKey ==
"from" ?
"from" :
"to"),
3359 "member" => ($pKey ==
"from" ?
"frommember" :
"tomember"),
3360 "accounttype" => ($pKey ==
"from" ?
"fromsuffix" :
"tosuffix"),
3361 "recordtype" => ($pKey ==
"from" ?
"fromtype" :
"totype")
3364 $acctId = HCU_AcctIdExplode(HCU_array_key_value($lookup[
"acctid"], $pTxnData[
"txn"]));
3366 $acctKey[
'accountnumber'] = HCU_array_key_value($lookup[
"member"], $pTxnData[
'txn']);
3368 $acctKey[
'recordtype'] = HCU_array_key_value($lookup[
"recordtype"], $pTxnData[
'txn']);
3370 if ($acctKey[
'recordtype'] ==
"D") {
3371 $acctKey[
'accounttype'] = HCU_array_key_value($lookup[
"accounttype"], $pTxnData[
'txn']);
3372 $acctKey[
'certnumber'] = $acctId[
"segment4"];
3374 }
else if ($acctKey[
'recordtype'] ==
"L" || $acctKey[
'recordtype'] ==
"C") {
3375 $acctKey[
'loannumber'] = HCU_array_key_value($lookup[
"accounttype"], $pTxnData[
'txn']);
3377 $acctKey[
'recordtype'] =
"L";
3402 function BuildM2MAccountKey( $pAcctData ) {
3405 $acctKey[
'accountnumber'] = $pAcctData[
"rdfi"][
"rdfi_account"];
3406 $acctKey[
'accounttype'] = $pAcctData[
"rdfi"][
"rdfi_account_type"];
3407 $acctKey[
'display_name'] = $pAcctData[
"remote_entity"][
"display_name"];
3408 $acctKey[
'name'] = $pAcctData[
"remote_entity"][
"name"];
3409 $acctKey[
'addenda'] = $pAcctData[
"rdfi"][
"addenda"];
3410 $acctKey[
'ext_id'] = $pAcctData[
"remote_entity"][
"entry_id"];
3427 function ReturnIgnoreList($dbh) {
3430 $SYS_TYPE_CLOSED = 64;
3431 $SYS_TYPE_UPG_TEST = 128;
3432 $SYS_TYPE_UPG_BETA = 256;
3435 $sql =
"select user_name from cuinfo" .
3436 " where (coalesce(system_options, 0) & $SYS_TYPE_CLOSED) = 0" .
3437 " and ((coalesce(system_options, 0) & $SYS_TYPE_UPG_TEST) <> 0" .
3438 " or (coalesce(system_options, 0) & $SYS_TYPE_UPG_BETA) <> 0)" .
3439 " order by user_name";
3441 $sth = db_query($sql, $dbh);
3443 throw new Exception (
"Select query failed.", 2);
3446 $results = db_fetch_all($sth);
3447 $results = $results ===
false ? array() : $results;
3449 if (count($results) > 0) {
3450 foreach ( $results as $cuName) {
3452 $returnCUList[] = trim(strtoupper($cuName[
"user_name"]));
3456 return $returnCUList;