Odyssey
cu_data.i
1 <?php
2 
3 /**
4  * Gather the lise of accounts the User is allowed to either transfer into or out of
5  *
6  * @param integer $dbh - Current database handle
7  * @param array $HB_ENV - Current Environment Array
8  * @param string $Acctid - Specify an acctid to return -- this will return only the matching AcctId
9  * @param boolean $showZeroBalance - Include Zero Balance in the list
10  * @param integer $pUserIdOverride - When set this will get load the specified User ID instead of the Uid in HB_ENV
11  *
12  * @return array
13  * [acctlist] Array of available accounts with the AcctId as the key
14  */
15 function TX_list($dbh, &$HB_ENV, $Acctid="", $showZeroBalance = false, $pUserIdOverride=0) {
16 
17  // returns array of transfer accounts
18 
19  /** LOAD CU SETTINGS FROM HB_ENV ** */
20  $Cu = $HB_ENV['Cu'];
21 
22  $live = $HB_ENV['live'];
23  $Fmsg_tx = $HB_ENV['Fmsg_tx'];
24 
25  $Fset = $HB_ENV['Fset'];
26  $Fset2 = $HB_ENV['Fset2'];
27  $Fset3 = $HB_ENV["Fset3"];
28  $MC= HCU_array_key_value('MC', $HB_ENV) ? $HB_ENV["MC"] : new hcu_talk_base( "en_US" );
29 
30  $txlist = array();
31  $xalist = array();
32  $errors = array();
33 
34 
35  if ($pUserIdOverride == 0) {
36  /* NORMAL METHOD -- LOAD Uid FROM HB_ENV */
37  $Uid = intval($HB_ENV["Uid"]);
38 
39  $userEmail = $HB_ENV['Ml'];
40  $userFplog = $HB_ENV['Fplog'];
41  } else {
42  /* OVERRIDE USER ID */
43  $Uid = intval($pUserIdOverride);
44  /** Get the Email, Last Login for the override user **/
45 
46 
47  $userInfo = GetUserInfo($dbh, $HB_ENV, $MC, Array("user_id" => $Uid, "cu" => $Cu));
48  if ($userInfo['status']['code'] === '000') {
49  $userEmail = HCU_array_key_value('cuusers_email', $userInfo['data']);
50  $userFplog = HCU_array_key_value('cuusers_lastlogin', $userInfo['data']); // ** using the lastlogin because this is NOT for the current user session.
51 
52 
53  } else {
54  $errors[] = "User Not Found";
55  }
56 
57 
58  }
59 
60 
61 
62  $cuTz = GetCreditUnionTimezone($dbh, $Cu);
63 
64  // This is to help make a unique key per account the user could have in their from/to lists.
65  $validationKey = GetValidationKey();
66 
67  // no account identifier - retrieve the whole list
68 
69  // fetch the list of allowable transactions
70  $txncodes = Get_HaveTrans($dbh,$HB_ENV);
71 
72  /**
73  * **
74  * ** Fetch deposit accounts
75  * **
76  */
77 
78  if (!$live) {
79  $pending = Get_ReqTotals($dbh,$HB_ENV);
80  } else {
81  $pending = Array();
82 
83  $userData = Array (
84  'email' => $userEmail,
85  'lastlogin' => $userFplog
86  );
87 
88  /*
89  * FOR Live CU Load all the member account related to the current user
90  */
91  $dataResp = LoadUserData($HB_ENV, $Uid, $userData);
92  $requestDate = HCU_array_key_value("requestDate", $dataResp['data']);
93  $requestDesc = HCU_array_key_value("requestDesc", $dataResp['data']);
94  if ($dataResp['code'] == '999') {
95  // ** Error -
96  $balances['status']['code'] = '999';
97  $balances['status']['severity'] = 'ERROR';
98  $balances['status']['errors'][] = 'System Unavailable';
99  $HB_ENV['stale'] = 1;
100  } else {
101  // ** Success
102  $HB_ENV['lastupdate'] = $requestDate;
103  }
104 
105  if ($dataResp['code'] != '900') { // * Don't update packetStatus for 'too soon'
106 
107  $HB_ENV['packetStatus'] = Array(
108  'status' => $dataResp['code'],
109  'asofdate' => $requestDate,
110  'reason' => $requestDesc
111  );
112  }
113  /* Finished loading Account/Loan data */
114 
115  /* Load Cross Account Authority Packet */
116  /*
117  * Check if the CU3_API_XAC flag (Request XAC Packet) is set
118  * AND the Fmsg_tx does not contain the value for Successful XAC Load bit
119  */
120 
121  if ((($HB_ENV['Fset3'] & GetFlagsetValue('CU3_API_XAC')) && ($HB_ENV['Fmsg_tx'] & GetMsgTxValue('MSGTX_TMP_XAX_LD')) == 0)) {
122  /*
123  * mws 1/6/16
124  *
125  * Changing functionality from classic
126  * Classic - Once a cross account check fails, we quit trying to update cross accounts
127  * New Functionality - We retry getting the cross account. -- And show the message as returned, but do NOT
128  * change the livepacketstatus cookie.
129  * This will allow any connectivity problems to correct themselves if they are small
130  *
131  *
132  * Fetch a packet if we have NOT gotten a success packet - signified by the value 32 in msg_tx
133  *
134  */
135  if (($Fmsg_tx & GetMsgTxValue('MSGTX_TMP_XAX_LD')) == 0) {
136 
137  // ** need e-mail passed to function
138  $userData = Array("email" => $HB_ENV['Ml']);
139  // ** REMOVE list($xstat, $xdata, $xreason) = LoadCrossAcctData($HB_ENV, $Uid, $userData);
140  $xaResp = LoadCrossAcctData($HB_ENV, $Uid, $userData);
141 
142  if ($xaResp['code'] == '000') {
143  /* * SUCCESS * */
144  $nflag = $Fmsg_tx | GetMsgTxValue('MSGTX_TMP_XAC_RQ') + GetMsgTxValue('MSGTX_TMP_XAX_LD');
145  } else {
146  /* * FAILURE * */
147  $nflag = $Fmsg_tx | GetMsgTxValue('MSGTX_TMP_XAC_RQ');
148  }
149 
150  // ** New value to return to caller
151  $Fmsg_tx = $nflag;
152  }
153 
154  // ** Evaluate msg_tx after XA Request -- If 32 is not set then we know it was not received correctly
155  // ** Report the error to the screen
156  if (($Fmsg_tx & GetMsgTxValue('MSGTX_TMP_XAX_LD')) == 0) {
157  # Didn't get a packet -- set an error
158  $errors[]="System Unavailable";
159  if ($xreason != '') {
160  $HB_ENV['packetStatus']['reason'] = $xreason;
161  } else {
162  $HB_ENV['packetStatus']['reason'] = 'System Temporarily Down - Unable to contact core system.';
163  }
164  }
165  $txreturn['status']['Fmsg_tx']=$Fmsg_tx;
166  }
167  }
168 
169  if (count($errors) > 0) {
170  // ** ERRORS FOUND -- SET Return array and EXIT
171  $txreturn['status']['code']='999';
172  $txreturn['status']['severity']='ERROR';
173  $txreturn['status']['errors']=$errors;
174  } else {
175 
176  /*
177  * For oid ordering I need to add the tables OID to the respective tables so I can
178  * sort off them.
179  */
180  $bal_oid_select = "";
181  $xa_oid_select = "";
182  if (($Fset2 & GetFlagsetValue("CU2_SORTORDER6")) == GetFlagsetValue("CU2_SORTORDER6")) {
183  $bal_oid_select = ", ab.oid ";
184  $xa_oid_select = ", ca.oid ";
185  }
186  // get deposit balance accounts that the user can work with
187  // adding in micraccount for Bill Pay - ENR
188  $sqltx = "SELECT trim(ua.display_name) as display_name, trim(ab.description) as description,
189  trim(ab.micraccount),
190  trim(ab.accounttype) as accounttype, ua.certnumber, ab.deposittype, ab.amount,
191  ab.available, trim(ua.accountnumber) as accountnumber, ua.view_balances,
192  ua.int_deposit, ua.int_withdraw, ua.ext_deposit, ua.ext_withdraw, may_deposit, may_withdraw,
193  coalesce(ab.balance_stamp, ma.balance_stamp) as balance_stamp, ma.balance_attempt,
194  ma.restrictions, ua.display_order, btrim(ab.accounttype, 'DIS'), 'balance' as tablesrc, null as permaccount {$bal_oid_select}
195  FROM {$Cu}useraccounts ua
196 
197  INNER JOIN {$Cu}accountbalance ab ON ab.accountnumber = ua.accountnumber
198  AND ab.accounttype = ua.accounttype
199  AND ab.certnumber = ua.certnumber
200  AND ab.deposittype IN ('Y','S','N')
201 
202  INNER JOIN {$Cu}memberacct as ma ON ma.accountnumber = ua.accountnumber
203  WHERE ua.user_id = {$Uid}
204  AND ua.recordtype = 'D'
205  AND (ua.int_deposit = 't' OR ua.int_withdraw = 't')";
206 
207  /*
208  * Add query for Cross Accounts if enabled.
209  * Enabled by Allowing XA type transfers
210  * AND loading data from XAC Packet
211  *
212  * Add 'null' for micraccount to balance UNION
213  */
214  // Cross accounts does not use micraccounts but null is needed to have the same number of columns.
215  if (HCU_array_key_value("XA", $txncodes) && ($Fset3 & GetFlagsetValue("CU3_API_XAC"))) {
216  $sqltx .= "
217  UNION ALL
218 
219  SELECT trim(ua.display_name) as display_name, trim(ca.description) as description,
220  null, trim(ca.accounttype) as accounttype, ua.certnumber, ca.deposittype, 0 as amount,
221  0 as available, trim(ca.tomember) as accountnumber, ua.view_balances,
222  ua.int_deposit, ua.int_withdraw, ua.ext_deposit, ua.ext_withdraw, true as may_deposit, false as may_withdraw,
223  NULL as balance_stamp, NULL as balance_attempt,
224  ma.restrictions as restrictions, ua.display_order, btrim(ca.accounttype, 'DIS'), 'cross' as tablesrc, ca.accountnumber as permaccount {$xa_oid_select}
225  FROM {$Cu}useraccounts ua
226 
227  INNER JOIN {$Cu}crossaccounts as ca ON ua.accountnumber = ca.accountnumber
228  AND trim(ca.accounttype) || '#' || trim(ca.tomember) = ua.accounttype
229  AND ca.deposittype IN ('Y','S','N')
230  INNER JOIN {$Cu}memberacct as ma ON ma.accountnumber = ua.accountnumber
231 
232  WHERE ua.user_id = {$Uid}
233  AND ua.recordtype = 'T'
234  AND ua.int_deposit = 't'";
235  }
236 
237  // ** Determine Ordering
238  if (($Fset & GetFlagsetValue("CU_SORTORDER4")) == GetFlagsetValue("CU_SORTORDER4")) {
239  // $sqltx .= " order by ua.display_order, btrim(ab.accounttype,'DIS'),ua.accountnumber, ab.certnumber";
240  // 20, 21, 4
241  $sqltx .= " ORDER BY 20, 21, 9, 4;";
242  } elseif (($Fset2 & GetFlagsetValue("CU2_SORTORDER6")) == GetFlagsetValue("CU2_SORTORDER6")) {
243  $sqltx .= " order by 20, 22, 24";
244  } else {
245  // $sqltx .= " order by ua.display_order, btrim(ab.accounttype, 'DIS'), ua.accountnumber, ab.certnumber";
246  // 20, 4, 5
247  $sqltx .= " ORDER BY 20, 4, 5, 9";
248  }
249 
250  $sthtx = db_query($sqltx,$dbh);
251  /**
252  * Return a line for each account.
253  */
254  for ($trow=0; list($display,$desc,$micra,$type,$certnumber,$deposittype, $balance,$available, $acct,$view_b,$int_d,$int_w, $ext_d, $ext_w, $may_d, $may_w, $acct_balance_stamp,
255  $acct_balance_attempt, $restrictions, $dispOrder, $acctDIS, $tableSrc, $permAccount) = db_fetch_array($sthtx,$trow); $trow++) {
256  // make sure internal transfers are allowed, even if cross account
257  if ( !($txncodes["AT"] || $txncodes["XA"]) ) continue;
258 
259  // locked or readonly accounts cannot be in this list
260  if ( $restrictions == "L" || $restrictions == "R" ) continue;
261 
262  $acctGroup = $MC->msg("Deposit Accounts", HCU_DISPLAY_AS_RAW);
263 
264  // For the most part we want to add to the txlist, except for when there are both XA and regular records for the same key.
265  // Replace the "continue" which skips the record and goes to the next in the record set with the boolean and then check boolean when adding it.
266  $addToTxList = true;
267  $addToXAList = false;
268 
269  if ($tableSrc == 'cross') {
270 
271  $addToXAList = true;
272  $trust = "transfer";
273  // ** The query has set the accountnumber to the proper destination -- Use the value coming from the query.
274  $jacct = $acct;
275  $jtype = $type;
276  $permAccount = trim($permAccount);
277 
278  /*
279  * ** PREVENT CROSS ACCOUNT OVERWRITING PERMISSIONS **
280  * The tx_list does not have a key that is unique enough to identify the difference between
281  * an account that has a cross account transfer to a different account and an additional
282  * account setup in Access Control.
283  * In this scenario the Cross Account permissions will trump the other permissions (however,
284  * the overwrite is most likely determiend by the ordered list). What we want to prevent is
285  * the Cross Account overriding permissions already set. If a full account permission override
286  * a Cross Account, then that is probably okay.
287  * Search for the index key here.
288  * D|AcctNumber|SubAcct|0
289  * IF FOUND
290  * then <continue> (skip)
291  * IF NOT FOUND
292  * then add
293  */
294  $listAryKey = "D|$jacct|$jtype|$certnumber";
295  if (HCU_array_key_exists($listAryKey, $txlist)) {
296  $addToTxList = false;
297  }
298 
299  } else {
300  if (strpos($type,"@")) {
301  list($jtype,$jacct) = explode("@",$type);
302  $trust = 'joint';
303  } else {
304  $jtype = $type;
305  $jacct = $acct; // ** ALWAYS USE THE ACCOUNT NUMBER COMING BACK FROM DATABASE
306  $trust = 'primary';
307  }
308  $permAccount = $acct;
309  }
310  $tokn = sha1("{$jacct}{$jtype}D{$Cu}{$validationKey}");
311 
312  // Does this have a pending value
313  $pend = sprintf("%.2f", HCU_array_key_value("D|$jacct|$jtype|$certnumber", $pending));
314 
315  $available = sprintf("%.2f", ($available + $pend));
316 
317  $balanceAmt = sprintf("%.2f", $balance);
318  $toFlag = ($int_d == "t" || $ext_d == "t") && $may_d == "t" ? "Y" : "N";
319  $fromFlag = ($int_w == "t" || $ext_w == "t") && $may_w == "t" ? ($available > 0 || $showZeroBalance ? "Y" : "N") : "N";
320 
321  $txlistRecord = array();
322 
323  $txlistRecord['suffix'] = $type;
324  //micraccount - ENR
325  $txlistRecord['micraccount'] = $micra;
326  // ENR
327  $txlistRecord['acctclass'] = "D";
328  $txlistRecord['description'] = getAccountDescription($dbh, $HB_ENV["Cu"], $acct, $desc, $type, $display, $Fset3);
329  $txlistRecord['unitokn'] = $tokn;
330  $txlistRecord['deposittype'] = $deposittype;
331  if ($view_b == "t") {
332  $txlistRecord['available'] = $available;
333  $txlistRecord['balance'] = $balanceAmt;
334  $txlistRecord['pending'] = $pend;
335  } else {
336  $txlistRecord['available'] = 0;
337  $txlistRecord['balance'] = 0;
338  $txlistRecord['pending'] = 0;
339  }
340  $txlistRecord['from'] = $fromFlag;
341  $txlistRecord['from_int'] = ($int_w == "t" ? "Y" : "N");
342  $txlistRecord['from_ext'] = ($ext_w == "t" ? "Y" : "N");
343  $txlistRecord['to'] = $toFlag;
344  $txlistRecord['to_int'] = ($int_d == "t" ? "Y" : "N");
345  $txlistRecord['to_ext'] = ($ext_d == "t" ? "Y" : "N");
346  $txlistRecord['trust'] = $trust;
347  $txlistRecord['view_balances'] = ($view_b == "t" ? "Y" : "N");
348 
349 
350  $txlistRecord['member'] = $permAccount;
351  // ** Mws 7/2017 -- set tomember to -1 to see if it causes failure
352  // -- eventually this column can be removed
353  $txlistRecord['tomember'] = '-1';
354 
355  /* Build Account Group */
356  $txlistRecord['item-group'] = "1 - $acctGroup";
357 
358  if ($live) {
359  $txlistRecord['as_of_date'] = GetDateFormatTimezone($acct_balance_stamp, 'm/d/Y h:i A', $cuTz);
360  $txlistRecord['out_of_sync'] = ($acct_balance_stamp < $acct_balance_attempt);
361 
362  } else {
363  $txlistRecord['as_of_date'] = "";
364  $txlistRecord['out_of_sync'] = false;
365  }
366 
367  // Cross accounts are always in the $xalist but only in the txlist if there is no regular record with the key.
368  if ($addToTxList) {
369  $txlist["D|$jacct|$jtype|$certnumber"] = $txlistRecord;
370  }
371  if ($addToXAList) {
372  // This is needed in the case of a circular reference. The regular key is not unique enough.
373  if (!HCU_array_key_exists($permAccount, $xalist)) {
374  $xalist[$permAccount] = array();
375  }
376  $xalist[$permAccount]["D|$jacct|$jtype|$certnumber"] = $txlistRecord;
377  }
378 
379 
380  }
381 
382  /**
383  * **
384  * ** Loan balance accounts
385  * **
386  */
387  $customWhere = '';
388  /**
389  * TEMPORARY
390  * FISRTAM needs to NOT be able to make payments to their CRCD sub accounts
391  * The proper payment method is to use the "Sweep Accounts".
392  * This is a work-around until we can get a middle-ware to online solution.
393  * 12/14/17
394  */
395  if ($Cu == 'FIRSTAM') {
396  $customWhere = " AND substring(lb.loannumber, 1, 5) <> 'CRCD:' ";
397  }
398  $sqltx = "SELECT trim(description) as description, trim(ua.display_name) as display_name,
399  trim(loannumber) as loannumber, trim(ua.accountnumber) as accountnumber,
400  int_deposit, int_withdraw, ext_deposit, ext_withdraw, view_balances,
401  currentbalance, paymentamount, creditlimit,
402  cbtype, misc1, payoff, may_addon, may_payment,
403  interestrate, unpaidinterest,
404  date_part('day',(now()-lastpaymentdate)) as unpaiddays,
405  coalesce(lb.balance_stamp, ma.balance_stamp) as balance_stamp, ma.balance_attempt,
406  ma.restrictions, ua.display_order, btrim(loannumber,'LC'),
407  'balance' as tablesrc, null as permaccount
408  FROM {$Cu}useraccounts ua
409  INNER JOIN {$Cu}loanbalance lb on lb.accountnumber = ua.accountnumber
410  and lb.loannumber = ua.accounttype
411  and (cbtype is null or cbtype <> 'X')
412  INNER JOIN {$Cu}memberacct as ma ON ma.accountnumber = ua.accountnumber
413 
414  WHERE ua.user_id = {$Uid}
415  AND ua.recordtype = 'L'
416  ${customWhere}
417  AND (ua.int_deposit = 't' OR ua.int_withdraw = 't')
418  ";
419 
420  /*
421  * Add query for Cross Accounts if enabled.
422  * Enabled by Allowing XA type transfers
423  * AND loading data from XAC Packet
424  */
425  if (HCU_array_key_value("XP", $txncodes) && ($Fset3 & GetFlagsetValue("CU3_API_XAC"))) {
426  $sqltx .= "
427  UNION ALL
428 
429  SELECT trim(ca.description) as description, trim(ua.display_name) as display_name,
430  trim(ca.accounttype) as loannumber, trim(ca.tomember) as accountnumber,
431  ua.int_deposit, ua.int_withdraw, ua.ext_deposit, ua.ext_withdraw, ua.view_balances,
432  0 as currentbalance, 0 as paymentamount, 0 as creditlimit,
433  '' as cbtype, ca.misc1 as misc1, 0 as payoff, false as may_addon, true as may_payment,
434  0 as interestrate, 0 as unpaidinterest,
435  0 as unpaiddays,
436  0 as balance_stamp, 0 as balance_attempt,
437  ma.restrictions as restrictions, ua.display_order, btrim(ca.accounttype,'LC'),
438  'cross' as tablesrc, ca.accountnumber as permaccount
439  FROM {$Cu}useraccounts ua
440 
441  INNER JOIN {$Cu}crossaccounts as ca ON ua.accountnumber = ca.accountnumber
442  AND trim(ca.accounttype) || '#' || trim(ca.tomember) = ua.accounttype
443  AND ca.deposittype IN ('L')
444  INNER JOIN {$Cu}memberacct as ma ON ma.accountnumber = ua.accountnumber
445 
446 
447  WHERE ua.user_id = {$Uid}
448  AND ua.recordtype = 'P'
449  AND ua.int_deposit = 't'
450  ";
451  }
452 
453  if ($Fset & GetFlagsetValue('CU_LNSORT2')) {
454  // $loanOrderBy = " ORDER BY ua.display_order, btrim(loannumber,'LC'), ua.accountnumber";
455  $loanOrderBy = " ORDER BY 24, 25, 4";
456  } else {
457  // $loanOrderBy = " ORDER BY ua.display_order, loannumber, ua.accountnumber";
458  $loanOrderBy = " ORDER BY 24, 3, 4";
459  }
460 
461  $sqltx .= $loanOrderBy;
462 
463  $sthtx = db_query($sqltx,$dbh);
464  /*
465  * Return a line for each account.
466  */
467  // save any credit cards to add after the loans
468  $ccList = array();
469  $loanList = array();
470  $xaList = array();
471  for ($row=0; $lnrow=db_fetch_array($sthtx,$row); $row++) {
472  // locked or readonly accounts cannot be in this list
473  if ( $lnrow["restrictions"] == "L" || $lnrow["restrictions"] == "R" ) continue;
474 
475  // ** Key account number for this LOAN record
476  $loanAcctNbr = trim($lnrow['accountnumber']);
477  $permacct = $loanAcctNbr;
478 
479  if ( $lnrow["cbtype"] == "18" && ($Fset2 & GetFlagsetValue("CU2_SPEC18")) == GetFlagsetValue("CU2_SPEC18") ) {
480  $cctype = "C";
481  $acctGroup = "3 - " . $MC->msg("Credit Card Accounts", HCU_DISPLAY_AS_RAW);
482  } else {
483  $cctype = "L";
484  $acctGroup = "2 - " . $MC->msg("Loan Accounts", HCU_DISPLAY_AS_RAW);
485  }
486 
487  // handle this - type 18 and neither set then skip this entry (original logic only got these entries if the flag checks passed)
488  if ( $cctype == "C" && !isset($txncodes["CC"]) && !isset($txncodes["CE"]) ) {
489  continue;
490  }
491 
492  // For the most part we want to add to the txlist, except for when there are both XA and regular records for the same key.
493  // Replace the "continue" which skips the record and goes to the next in the record set with the boolean and then check boolean when adding it.
494  $addToTxList = true;
495  $addToXAList = false;
496 
497  $type = $lnrow['loannumber'];
498 
499  $balance = $lnrow["view_balances"] == 't' ? $lnrow['currentbalance'] : 0.00;
500  $payment = $lnrow['paymentamount'];
501  $creditlimit = sprintf("%.2f", $lnrow['creditlimit']);
502  $available = $lnrow["view_balances"] == 't' ? ($creditlimit - $balance) : 0.00;
503  $available = sprintf("%.2f", ($available < 0 ? 0 : $available));
504 
505 
506  $cbtype = $lnrow['cbtype'];
507  if ($live) {
508  $misc1 = $lnrow['misc1'];
509  $payoff = $lnrow['payoff'];
510  } else {
511  $rate = $lnrow['interestrate'];
512  $rate = (empty($rate) ? 0 : $rate);
513  $unpaid = $lnrow['unpaidinterest'];
514  $unpaid = (empty($unpaid) ? 0 : $unpaid);
515  $days = intval($lnrow['unpaiddays']);
516  $days = ($days < 0 ? 0 : $days);
517  $misc1 = ''; // Default Value for misc1 (batch not used)
518 
519  $payoff = (((($rate / 100) * $balance) / 365) * $days) + $unpaid + $balance;
520  }
521  // ** Format Payoff
522  if(empty($payoff) || $payoff == 0) {
523  $payoff = 'N/A';
524  } else {
525  $payoff = sprintf("%.2f", $payoff);
526  }
527 
528  $misc1 = ("$misc1" == '' ? '-' : $misc1);
529  if ($lnrow['tablesrc'] == 'cross') {
530 
531  $addToXAList = true;
532  $trust = 'transfer';
533  $jtype = $type;
534  // ** Use the Account Number from the record
535  $jacct = $loanAcctNbr;
536  $permacct = $lnrow["permaccount"];
537 
538 
539  /*
540  * ** PREVENT CROSS ACCOUNT OVERWRITING PERMISSIONS **
541  * The tx_list does not have a key that is unique enough to identify the difference between
542  * an account that has a cross account transfer to a different account and an additional
543  * account setup in Access Control.
544  * In this scenario the Cross Account permissions will trump the other permissions (however,
545  * the overwrite is most likely determiend by the ordered list). What we want to prevent is
546  * the Cross Account overriding permissions already set. If a full account permission override
547  * a Cross Account, then that is probably okay.
548  * Search for the index key here.
549  * D|AcctNumber|SubAcct|0
550  * IF FOUND
551  * then <continue> (skip)
552  * IF NOT FOUND
553  * then add
554  */
555  $listAryKey = "$cctype|$jacct|$jtype";
556 
557  if ( $cctype === "C" ) {
558  if (HCU_array_key_exists($listAryKey, $ccList)) {
559  $addToTxList = false;
560  }
561 
562  } else {
563  if (HCU_array_key_exists($listAryKey, $loanList)) {
564  $addToTxList = false;
565  }
566  }
567 
568  } else {
569  if (strpos($type,"@")) {
570  list($jtype,$jacct) = explode("@",$type);
571  $trust='joint';
572  } else {
573  $jtype = $type;
574  // ** Use the Account Number from the record
575  $jacct = $loanAcctNbr;
576  $jacct = $lnrow['accountnumber']; // Always use accountnumber from database
577  $trust='primary';
578  }
579  }
580  $pend = sprintf("%.2f", HCU_array_key_value("L|$jacct|$jtype", $pending));
581 
582  // figure out the From and To logic
583  $from = "N";
584  if ( ($lnrow["int_withdraw"] == 't' || $lnrow["ext_withdraw"] == 't') &&
585  $lnrow["may_addon"] == 't' &&
586  ((HCU_array_key_value('LA', $txncodes) && $cctype == "L") || (HCU_array_key_value('CA', $txncodes) && $cctype == "C")) ) {
587  // only show if has an available balance or showing zero balances
588  $from = ($available > 0 || $showZeroBalance ? "Y" : "N");
589  }
590  $to = "N";
591  if ( ($lnrow["int_deposit"] == 't' || $lnrow["ext_deposit"] == 't') &&
592  ($lnrow["may_payment"] == 't' && HCU_array_key_value('LP', $txncodes)) ) {
593  if ( ($cctype == "C" &&
594  ($Fset2 & GetFlagsetValue("CU2_CC18SHOWZERO")) != GetFlagsetValue("CU2_CC18SHOWZERO") &&
595  // adding a check for balance == 0
596  $balance == 0)
597  // Or a non-cross account loan with a zero balance. For cross accounts, the balance is not known so it's zero.
598  || ($cctype == "L" && $balance == 0 && $lnrow["tablesrc"] !== "cross")) {
599  // if not set, don't show zero balance credit card accounts
600  $to = "N";
601  } else {
602  $to = "Y";
603  }
604  }
605 
606  $indexString = "$cctype|$jacct|$jtype";
607 
608  $tokn=sha1("{$jacct}{$jtype}L{$Cu}{$validationKey}");
609  $dataHolder = array();
610 
611  $dataHolder['suffix'] = $type;
612  $dataHolder['micra'] = $micra;
613  $dataHolder['acctclass'] = $cctype;
614  $dataHolder['description'] = getAccountDescription($dbh, $HB_ENV["Cu"], $loanAcctNbr, $lnrow['description'], $type, $lnrow['display_name'], $Fset3);
615  $dataHolder['unitokn'] = $tokn;
616  $dataHolder['available'] = $available;
617  $dataHolder['pending'] = $pend;
618  $dataHolder['from'] = $from;
619  $dataHolder['from_int'] = ($lnrow["int_withdraw"] == "t" ? "Y" : "N");
620  $dataHolder['from_ext'] = ($lnrow["ext_withdraw"] == "t" ? "Y" : "N");
621 
622  $dataHolder['to'] = $to;
623 
624  // only check db setting if $to is Y, otherwise default to N
625  $dataHolder['to_int'] = ($to == "Y" ? ($lnrow["int_deposit"] == "t" ? "Y" : "N") : "N");
626  $dataHolder['to_ext'] = ($to == "Y" ? ($lnrow["ext_deposit"] == "t" ? "Y" : "N") : "N");
627 
628  $dataHolder['misc1'] = $misc1;
629  $dataHolder['trust'] = $trust;
630  $dataHolder['view_balances'] = ($lnrow["view_balances"] == "t" ? "Y" : "N");
631  $permacct = trim($permacct);
632  $dataHolder['member'] = $permacct;
633  // ** Mws 7/2017 -- set tomember to -1 to see if it causes failure
634  // -- eventually this column can be removed
635  $dataHolder['tomember'] = '-1';
636 
637  /* Build Account Group */
638  $dataHolder['item-group'] = $acctGroup;
639 
640  if ($live) {
641  $dataHolder['as_of_date'] = GetDateFormatTimezone($lnrow['balance_stamp'], 'm/d/Y h:i A', $cuTz);
642  $dataHolder['out_of_sync'] = ($lnrow['balance_stamp'] < $lnrow['balance_attempt']);
643  } else {
644  $dataHolder['as_of_date'] = "";
645  $dataHolder['out_of_sync'] = false;
646  }
647 
648 
649  // only show some things depending on what can be done
650  if ( $cctype == "L" || ($cctype == "C" && ( $txncodes["CC"] || $txncodes["CE"] ) ) ) {
651  $dataHolder['payoff'] = $payoff;
652  $dataHolder['paymentdue'] = $payment;
653  $dataHolder['balance'] = sprintf("%.2f", $balance);
654  }
655 
656  if ($addToTxList) {
657  if ( $cctype === "C" ) {
658  $ccList[$indexString] = $dataHolder;
659  } else {
660  $loanList[$indexString] = $dataHolder;
661  }
662  }
663 
664  if ($addToXAList) {
665  // This is needed in the case of a circular reference. The regular key is not unique enough.
666  if (!HCU_array_key_exists($permacct, $xalist)) {
667  $xalist[$permacct] = array();
668  }
669  $xalist[$permacct][$indexString] = $dataHolder;
670  }
671 
672  }
673 
674  // add the loan items and then the cc items
675  $txlist = array_merge( $txlist, $loanList, $ccList );
676 
677  /**
678  * **
679  * ** Other Accounts
680  * **
681  */
682  $othList = array();
683  foreach ($txncodes as $tcode => $value) {
684 
685  $dataHolder = array();
686  $indexString = "O|$Uid|$tcode";
687  $acctGroup = $MC->msg("Misc. Transfers", HCU_DISPLAY_AS_RAW);
688  $othIdKey = $Uid;
689 
690  // check for special handling
691  // - Values 1 and 2
692  if (in_array($value[1], Array(1, 2))) {
693 
694  /**
695  * **
696  * ** OTHER TRANSACTION TYPE DESCRIPTION
697  * **
698  */
699  $desc = ($value[2] > '' ? $value[2] : $value[0] );
700  $desc = htmlspecialchars($desc, ENT_QUOTES);
701 
702  $tokn = sha1("{$Uid}{$tcode}O{$Cu}{$validationKey}");
703 
704 
705  $dataHolder['suffix'] = "$tcode";
706  $dataHolder['micra'] = "$micra";
707  $dataHolder['acctclass'] = "O";
708  $dataHolder['description'] = "$desc";
709  $dataHolder['unitokn'] = "$tokn";
710 
711  /* OTHER ACCOUNTS MAY ONLY BE TRANSFERRED INTO FOR INTERNAL PURPOSES */
712  $dataHolder['to'] = "Y";
713  $dataHolder['to_int'] = "Y";
714  $dataHolder['to_ext'] = "N";
715  $dataHolder['from'] = "N";
716  $dataHolder['from_int'] = "N";
717  $dataHolder['from_ext'] = "N";
718  $dataHolder['view_balances'] = "N";
719 
720 
721  $dataHolder['trust'] = "primary";
722  $dataHolder['member'] = $othIdKey;
723  // ** Mws 7/2017 -- set tomember to -1 to see if it causes failure
724  // -- eventually this column can be removed
725  $dataHolder['tomember'] = '-1';
726  $dataHolder['as_of_date'] = "";
727  $dataHolder['out_of_sync'] = false;
728 
729  $dataHolder['item-group'] = "4 - $acctGroup";
730 
731 
732  $othList[$indexString] = $dataHolder;
733  }
734  }
735 
736  $txlist = array_merge($txlist, $othList);
737 
738  /**
739  * **
740  * ** External Accounts
741  * **
742  */
743  // get any external accounts to add
744  $extAcctList = Get_ExternalAccounts( $dbh, $HB_ENV );
745  $extList = array();
746  $acctGroup = $MC->msg("EXT External Accounts", HCU_DISPLAY_AS_RAW);
747 
748  $extIdKey = $Uid;
749  for ( $i = 0; $i < count( $extAcctList ); $i++ ) {
750 
751  $dataHolder = Array();
752 
753  $tokn = sha1("{$Uid}{$extAcctList[$i]["id"]}X{$Cu}{$validationKey}");
754  $desc = $extAcctList[$i]["display_name"];
755  $desc = htmlspecialchars( $desc,ENT_QUOTES );
756 
757  // use the maximum amount for the available amount
758  $available = $extAcctList[$i]["max_amount"];
759 
760  $indexString = "X|{$Uid}|{$extAcctList[$i]["id"]}";
761 
762  $dataHolder['acctclass'] = "X";
763  $dataHolder['suffix'] = "";
764  $dataHolder['micra'] = $micra;
765  $dataHolder['description'] = $desc;
766  $dataHolder['unitokn'] = $tokn;
767  $dataHolder['available'] = $available;
768  /* EXTERNAL ACCOUNTS HAVE NO INTERNAL TRANSFER ABILITY */
769 
770  $dataHolder['to'] = "Y";
771  $dataHolder['to_int'] = "N";
772  $dataHolder['to_ext'] = "Y";
773  $dataHolder['from'] = "Y";
774  $dataHolder['from_int'] = "N";
775  $dataHolder['from_ext'] = "Y";
776  $dataHolder['trust'] = "transfer";
777  $dataHolder['view_balances'] = "N";
778  $dataHolder['member'] = $extIdKey;
779  $dataHolder['as_of_date'] = "";
780  $dataHolder['out_of_sync'] = false;
781 
782  $dataHolder['item-group'] = "5 - $acctGroup";
783 
784  $extList[$indexString] = $dataHolder;
785  }
786 
787  $txlist = array_merge( $txlist, $extList );
788 
789  /**
790  * **
791  * ** Member 2 Member Accounts
792  * **
793  */
794  // get any M2M accounts to add
795  // ** Should we check the feature is enabled
796  $acctList = Get_M2MAccounts( $dbh, $HB_ENV );
797  $m2mList = array();
798  $acctGroup = $MC->msg("Other Member Accounts", HCU_DISPLAY_AS_RAW);
799 
800  $extIdKey = $Uid;
801  for ( $i = 0; $i < count( $acctList ); $i++ ) {
802  $dataHolder = Array();
803 
804  $tokn = sha1("{$Uid}{$acctList[$i]["id"]}X{$Cu}{$validationKey}");
805 
806  $desc = $acctList[$i]["display_name"];
807  $desc = htmlspecialchars( $desc,ENT_QUOTES );
808 
809  // use the maximum amount for the available amount
810  $available = sprintf("%.2f", $acctList[$i]["max_amount"]);
811 
812  $indexString = "M|{$Uid}|{$acctList[$i]["id"]}";
813 
814  $dataHolder['acctclass'] = "M";
815  $dataHolder['suffix'] = "";
816  $dataHolder['micra'] = $micra;
817  $dataHolder['description'] = $desc;
818  $dataHolder['unitokn'] = $tokn;
819  $dataHolder['available'] = $available;
820  $dataHolder['to'] = "Y";
821  $dataHolder['to_int'] = "Y"; // M2M is internal to the CU
822  $dataHolder['to_ext'] = "N";
823 
824  $dataHolder['from'] = "N"; // never from
825  $dataHolder['from_int'] = "N";
826  $dataHolder['from_ext'] = "N";
827  $dataHolder['trust'] = "transfer";
828  $dataHolder['view_balances'] = "N";
829 
830  $dataHolder['member'] = $extIdKey;
831  $dataHolder['as_of_date'] = "";
832  $dataHolder['out_of_sync'] = false;
833 
834  $dataHolder['item-group'] = "6 - $acctGroup";
835 
836  $m2mList[$indexString] = $dataHolder;
837  }
838 
839  $txlist = array_merge( $txlist, $m2mList );
840 
841  if (!empty($Acctid)) {
842  # got an account identifier - return one only
843 
844  $txreturn['acctlist'] = $txlist[$Acctid];
845  } else {
846  $txreturn['acctlist'] = $txlist;
847  }
848 
849  // If XA and XP are not valid for the credit union, this will be an empty array.
850  $txreturn["xacctlist"] = $xalist;
851 
852  $txreturn['status']['code']='0';
853  $txreturn['status']['severity']='INFO';
854  }
855 
856  return ($txreturn);
857 }
858 
859 function Get_HaveTrans($dbh,$HB_ENV) {
860 # returns list of transaction types the cu supports
861 $Cu=$HB_ENV['Cu'];
862  # fetch transactions types
863 
864  $sqltx= "select ht.trancode as txncode,
865  trim(t.trandesc) as txndesc,
866  t.specialproc as txnspec,
867  trim(ht.cudesc) as txncudesc
868  from cutrans t, cuhavetrans ht
869  where ht.cu='$Cu'
870  and ht.trancode = t.trancode";
871 
872  $txsth = db_query($sqltx,$dbh);
873  $txncodes = array();
874  for ($trow=0;
875  list($code, $desc, $spec, $cudesc) = db_fetch_array($txsth,$trow);
876  $trow++) {
877  $txncodes[$code] =array($desc,$spec,$cudesc);
878  }
879  db_free_result($txsth);
880 
881  # if type 18 loans are to be passed as CP transaction, make sure we have a
882  # description for that transaction code.
883 
884  if ( HCU_array_key_exists( "CC" , $txncodes) && !HCU_array_key_exists( "CP" , $txncodes) ) {
885  $txncodes["CP"] =array('Credit Card Payment',0,'');
886  }
887  return ($txncodes);
888 }
889 
890 function Get_ReqTotals($dbh,$HB_ENV) {
891 # returns array of BATCH pending transaction totals by dp account/loan
892 $Cu=$HB_ENV['Cu'];
893 $Cn=$HB_ENV['Cn'];
894 $Uid=$HB_ENV['Uid'];
895 $pending=array();
896 #
897 # consider any pending txns originated by this member
898 # or originated from this account by a joint owner.
899 # Do NOT consider the "to" portion for joint or cross, just the "from"
900 
901 // users can have access to multiple accounts, we must select transactions
902 // determined by the accounts this user has in the useraccounts table.
903 
904 // select all unique accountnumber by user_id
905  $sql = "
906  SELECT DISTINCT ON (ur.accountnumber) ur.accountnumber
907  FROM {$Cu}useraccounts ur
908  WHERE ur.user_id=$Uid";
909  $sth = db_query($sql, $dbh);
910 
911  // because of the LIKE statement below, it is rather difficult
912  // to use the IN clause. so we use a loop.
913  $sql = "";
914  for ($row = 0; list($acct) = db_fetch_array($sth,$row); $row++) {
915  $sqlAcct = trim($acct);
916  $sql .= "
917  SELECT TRIM(tr.accountnumber), TRIM(tr.transactioncode), TRIM(tr.reference1), TRIM(tr.memberto), TRIM(tr.reference2), tr.amount
918  FROM {$Cu}transaction tr
919  WHERE (tr.accountnumber = '{$sqlAcct}' OR TRIM(tr.reference1) LIKE '%@{$sqlAcct}')
920  AND tr.id > ALL (
921  SELECT MAX(id)
922  FROM {$Cu}transaction
923  WHERE accountnumber='CHECKPOINT'
924  AND reference1='PHASE II'
925  );";
926  }
927  $sth = db_query($sql,$dbh);
928 
929  for ($row=0; list($memfrom,$tc,$ftype,$memto,$ttype,$amount) = db_fetch_array($sth,$row); $row++) {
930 
931  if (strpos($ftype,"@")) {
932  list($smplfacct,$smplfmem) = explode("@",$ftype);
933  $smplfmem = trim($smplfmem);
934  } else {
935  $smplfacct = trim($ftype);
936  $smplfmem = $memfrom;
937  }
938  if (strpos($ttype,"@")) {
939  list($smpltacct,$smpltmem) = explode("@",$ttype);
940  $smpltmem = trim($smpltmem);
941  } else {
942  $smpltacct = trim($ttype);
943  $smpltmem = ("$memto" == "" ? $memfrom : $memto);
944  }
945 
946  $depositKeyF = "D|$smplfmem|$smplfacct|0";
947  $depositKeyT = "D|$smpltmem|$smpltacct|0";
948  $loanKeyT = "L|$smpltmem|$smpltacct";
949  $loanKeyF = "L|$smplfmem|$smplfacct";
950 
951  !HCU_array_key_exists($depositKeyF, $pending) ? $pending[$depositKeyF] = 0 : null; // If the key doesn't exist, create it before usage.
952  $pending[$depositKeyF] -= $amount;
953  if ($tc == 'AT') {
954  !HCU_array_key_exists($depositKeyT, $pending) ? $pending[$depositKeyT] = 0 : null; // If the key doesn't exist, create it before usage.
955  $pending[$depositKeyT] += $amount;
956 
957  // ** This is for a Loan Add-on -- a decrease to the available total
958  } elseif ($tc == 'LA') {
959  // ** FROM A LOAN
960  !HCU_array_key_exists($loanKeyF, $pending) ? $pending[$loanKeyF] = 0 : null; // If the key doesn't exist, create it before usage.
961  $pending[$loanKeyF] -= $amount;
962  // ** TO A DEPOSIT
963  !HCU_array_key_exists($depositKeyT, $pending) ? $pending[$depositKeyT] = 0 : null; // If the key doesn't exist, create it before usage.
964  $pending[$depositKeyT] += $amount;
965  } elseif ($tc == 'LP') {
966  !HCU_array_key_exists($loanKeyT, $pending) ? $pending[$loanKeyT] = 0 : null; // If the key doesn't exist, create it before usage.
967  $pending[$loanKeyT] += $amount;
968  }
969  }
970  return ($pending);
971 }
972 
973 // Get the pending requested transaction for batch accounts that are not locked.
974 function Get_ReqDetails($dbh,$HB_ENV,$Acctid="") {
975 # returns array of BATCH pending requested transactions by dp account/loan
976 $Cu=$HB_ENV['Cu'];
977 $Cn=$HB_ENV['Cn'];
978 $live=$HB_ENV['live'];
979 $pending=array();
980 $txreturn=array();
981 
982  if ($live == 1) {
983  $txreturn['status']['code']='100';
984  $txreturn['status']['severity']='INFO';
985  $txreturn['status']['message']='Feature Not Activated';
986  } else {
987 
988 $txncodes=Get_HaveTrans($dbh,$HB_ENV);
989 #
990 # override the default descriptions for AT, CW and LC transaction types
991 #
992 if ( HCU_array_key_exists( "AT" , $txncodes) ) $txncodes['AT'][0]='Transfer';
993 if ( HCU_array_key_exists( "CW" , $txncodes) ) $txncodes['CW'][0]='Check Withdrawal';
994 if ( HCU_array_key_exists( "LC" , $txncodes) ) $txncodes['LC'][0]='Check Withdrawal from Loan Add-on';
995 #
996 # ea txncode is an array of desc, spec, cudesc where
997 # spec is the special processing flag and cudesc is the override description
998 # check ea entry and override description if special processing is set
999 #
1000  foreach ($txncodes as $tcode => $value) {
1001  if ($value[1] == 1) {
1002  $desc=($value[2] > '' ? $value[2] : $value[0] );
1003  $txncodes[$tcode][0]=$desc;
1004  }
1005  }
1006 
1007  // get the account information from the passed in id
1008  $tbl = substr( $Acctid, 0, 1 );
1009  if ( $tbl == 'D' ) {
1010  list( $gettbl, $getacct, $gettype, $getcert) = explode( "|", $Acctid );
1011  } elseif ( $tbl == 'L' || $tbl == 'C' ) {
1012  list( $gettbl, $getacct, $gettype) = explode( "|",$Acctid );
1013  } else {
1014  // this will result in nothing getting returned
1015  $getacct = "";
1016  }
1017 
1018 #
1019 # consider any pending txns originated by this member
1020 # or originated from this account by a joint owner.
1021 # Do NOT consider the "to" portion for joint or cross, just the "from"
1022 
1023 #
1024  $sql = "select tr.id as id,
1025  trim(tr.accountnumber) as memfrom,
1026  trim(tr.reference1) as ftype,
1027  trim(f.description) as fdesc,
1028  trim(tr.reference2) as ttype,
1029  trim(t.description) as tdesc,
1030  tr.transactioncode as tc,
1031  tr.amount as amount,
1032  trim(tr.memberto) as memberto,
1033  to_char(tr.date,'YYYY-MM-DD') as date
1034  from {$Cu}transaction tr,
1035  {$Cu}accountbalance f,
1036  {$Cu}accountbalance t,
1037  {$Cu}memberacct ma
1038  where id > ALL (select MAX(id)
1039  from {$Cu}transaction tr2
1040  where tr2.accountnumber='CHECKPOINT'
1041  and reference1='PHASE II')
1042  and tr.accountnumber='$getacct'
1043  and tr.accountnumber = f.accountnumber
1044  and tr.reference1=f.accounttype
1045  and (tr.memberto = t.accountnumber or
1046  (tr.memberto is null and tr.accountnumber = t.accountnumber))
1047  and tr.reference2=t.accounttype
1048  AND ma.accountnumber = tr.accountnumber
1049  AND coalesce(ma.restrictions, '') != 'L'
1050  and upper(f.deposittype) in ('Y','N','S')
1051  and upper(t.deposittype) in ('Y','N','S')
1052  and tr.transactioncode in ('AT')
1053  UNION ALL
1054  select tr.id as id,
1055  trim(tr.accountnumber) as memfrom,
1056  trim(tr.reference1) as ftype,
1057  trim(f.description) as fdesc,
1058  trim(tr.reference2) as ttype,
1059  trim(t.description) as tdesc,
1060  tr.transactioncode as tc,
1061  tr.amount as amount,
1062  trim(tr.memberto) as memberto,
1063  to_char(tr.date,'YYYY-MM-DD') as date
1064  from {$Cu}transaction tr,
1065  {$Cu}accountbalance f,
1066  {$Cu}loanbalance t,
1067  {$Cu}memberacct ma
1068  where id > ALL (select MAX(id)
1069  from {$Cu}transaction tr2
1070  where tr2.accountnumber='CHECKPOINT'
1071  and reference1='PHASE II')
1072  and tr.accountnumber='$getacct'
1073  and tr.accountnumber = f.accountnumber
1074  and tr.reference1=f.accounttype
1075  and (tr.memberto = t.accountnumber or
1076  (tr.memberto is null and tr.accountnumber = t.accountnumber))
1077  and tr.reference2=t.loannumber
1078  AND ma.accountnumber = tr.accountnumber
1079  AND coalesce(ma.restrictions, '') != 'L'
1080  and upper(f.deposittype) in ('Y','N','S')
1081  and tr.transactioncode in ('LP')
1082  UNION ALL
1083  select tr.id as id,
1084  trim(tr.accountnumber) as memfrom,
1085  trim(tr.reference1) as ftype,
1086  trim(f.description) as fdesc,
1087  trim(tr.reference2) as ttype,
1088  trim(t.description) as tdesc,
1089  tr.transactioncode as tc,
1090  tr.amount as amount,
1091  trim(tr.memberto) as memberto,
1092  to_char(tr.date,'YYYY-MM-DD') as date
1093  from {$Cu}transaction tr,
1094  {$Cu}loanbalance f,
1095  {$Cu}accountbalance t,
1096  {$Cu}memberacct ma
1097  where id > ALL (select MAX(id)
1098  from {$Cu}transaction tr2
1099  where tr2.accountnumber='CHECKPOINT'
1100  and reference1='PHASE II')
1101  and tr.accountnumber='$getacct'
1102  and tr.accountnumber=f.accountnumber
1103  and tr.reference1=f.loannumber
1104  and (tr.memberto = t.accountnumber or
1105  (tr.memberto is null and tr.accountnumber = t.accountnumber))
1106  and tr.reference2=t.accounttype
1107  AND ma.accountnumber = tr.accountnumber
1108  AND coalesce(ma.restrictions, '') != 'L'
1109  and upper(t.deposittype) in ('Y','N','S')
1110  and tr.transactioncode in ('LA')
1111  UNION ALL
1112  select tr.id as id,
1113  trim(tr.accountnumber) as memfrom,
1114  trim(tr.reference1) as ftype,
1115  trim(f.description) as fdesc,
1116  trim(tr.reference2) as ttype,
1117  NULL as tdesc,
1118  tr.transactioncode as tc,
1119  tr.amount as amount,
1120  trim(tr.memberto) as memberto,
1121  to_char(tr.date,'YYYY-MM-DD') as date
1122  from {$Cu}transaction tr, {$Cu}accountbalance f,
1123  {$Cu}memberacct ma
1124  where id > ALL (select MAX(id)
1125  from {$Cu}transaction tr2
1126  where tr2.accountnumber='CHECKPOINT'
1127  and reference1='PHASE II')
1128  and tr.accountnumber='{$getacct}'
1129  and tr.accountnumber=f.accountnumber
1130  and tr.reference1=f.accounttype
1131  AND ma.accountnumber = tr.accountnumber
1132  AND coalesce(ma.restrictions, '') != 'L'
1133  and upper(f.deposittype) in ('Y','N','S')
1134  and tr.transactioncode in ('CW','CP','VP','VC','VG','MP','GM')
1135  UNION ALL
1136  select tr.id as id,
1137  trim(tr.accountnumber) as memfrom,
1138  trim(tr.reference1) as ftype,
1139  trim(f.description) as fdesc,
1140  trim(tr.reference2) as ttype,
1141  NULL as tdesc,
1142  tr.transactioncode as tc,
1143  tr.amount as amount,
1144  trim(tr.memberto) as memberto,
1145  to_char(tr.date,'YYYY-MM-DD') as date
1146  from {$Cu}transaction tr, {$Cu}loanbalance f,
1147  {$Cu}memberacct ma
1148  where id > ALL (select MAX(id)
1149  from {$Cu}transaction tr2
1150  where tr2.accountnumber='CHECKPOINT'
1151  and reference1='PHASE II')
1152  and tr.accountnumber='{$getacct}'
1153  and tr.accountnumber=f.accountnumber
1154  and tr.reference1=f.loannumber
1155  and tr.transactioncode = 'LC'
1156  AND ma.accountnumber = tr.accountnumber
1157  AND coalesce(ma.restrictions, '') != 'L'";
1158 #
1159  $sth = db_query($sql,$dbh);
1160 
1161  for ($row=0; $drow = db_fetch_array($sth,$row); $row++) {
1162  $id=$drow['id'];
1163  // ** BEFORE it's used, encode the description with UTF-8 Encoding.
1164  // * setting it here eliminates the need to set it each time it's called in this loop
1165  $drow['fdesc'] = utf8_encode($drow['fdesc']);
1166  $drow['tdesc'] = utf8_encode($drow['tdesc']);
1167 
1168  if (strpos($drow['ftype'],"@")) {
1169  list($smplfacct,$smplfmem) = explode("@",$drow['ftype']);
1170  $smplfmem = trim($smplfmem);
1171  } else {
1172  $smplfacct = trim($drow['ftype']);
1173  $smplfmem = $drow['memfrom'];
1174  }
1175  if (strpos($drow['ttype'],"@")) {
1176  list($smpltacct,$smpltmem) = explode("@",$drow['ttype']);
1177  $smpltmem = trim($smpltmem);
1178  } else {
1179  $smpltacct = trim($drow['ttype']);
1180  $smpltmem = ("${drow['memberto']}" == "" ? $drow['memfrom'] : $drow['memberto']);
1181  }
1182  $tc=$drow['tc'];
1183  switch($tc) {
1184  case 'AT':
1185  $fromto="D|D";
1186  break;
1187  case 'LP':
1188  $fromto="D|L";
1189  break;
1190  case 'LA':
1191  $fromto="L|D";
1192  break;
1193  case 'LC':
1194  $fromto="L|O";
1195  break;
1196  default: # CW CP VP VC VG MP GM etc.
1197  $fromto="D|O";
1198  break;
1199  }
1200  $txdesc=$txncodes[$tc][0];
1201  $ftxdesc = "$txdesc from $smplfacct ${drow['fdesc']}";
1202  $ttxdesc = "$txdesc to" . ($smpltmem == $smplfmem ? "" : " $smpltmem") . " $smpltacct ${drow['tdesc']}";
1203 
1204  if (substr($fromto,0,1) == 'L') {
1205  // ** FROM A LOAN
1206  $pending["L|$smplfmem|$smplfacct"][$id]['id'] = $drow['id'];
1207  $pending["L|$smplfmem|$smplfacct"][$id]['tc'] = $drow['tc'];
1208  $pending["L|$smplfmem|$smplfacct"][$id]['memfrom'] = $smplfmem;
1209  $pending["L|$smplfmem|$smplfacct"][$id]['facct'] = $smplfacct;
1210  $pending["L|$smplfmem|$smplfacct"][$id]['memberto'] = $smpltmem;
1211  $pending["L|$smplfmem|$smplfacct"][$id]['tacct'] = $smpltacct;
1212  $pending["L|$smplfmem|$smplfacct"][$id]['amount'] = sprintf("%.2f",(-1 * $drow['amount']));
1213  $pending["L|$smplfmem|$smplfacct"][$id]['postdate'] = $drow['date'];
1214  $pending["L|$smplfmem|$smplfacct"][$id]['txdesc'] = $ttxdesc;
1215  } else {
1216  // ** FROM A DEPOSIT
1217  $pending["D|$smplfmem|$smplfacct|0"][$id]['id'] = $drow['id'];
1218  $pending["D|$smplfmem|$smplfacct|0"][$id]['tc'] = $drow['tc'];
1219  $pending["D|$smplfmem|$smplfacct|0"][$id]['memfrom'] = $smplfmem;
1220  $pending["D|$smplfmem|$smplfacct|0"][$id]['facct'] = $smplfacct;
1221  $pending["D|$smplfmem|$smplfacct|0"][$id]['memberto'] = $smpltmem;
1222  $pending["D|$smplfmem|$smplfacct|0"][$id]['tacct'] = $smpltacct;
1223  $pending["D|$smplfmem|$smplfacct|0"][$id]['amount'] = sprintf("%.2f",(-1 * $drow['amount']));
1224  $pending["D|$smplfmem|$smplfacct|0"][$id]['postdate'] = $drow['date'];
1225  $pending["D|$smplfmem|$smplfacct|0"][$id]['txdesc'] = $ttxdesc;
1226  }
1227  if (substr($fromto,2,1) == 'L') {
1228  // ** TO A LOAN
1229  $pending["L|$smpltmem|$smpltacct"][$id]['id'] = $drow['id'];
1230  $pending["L|$smpltmem|$smpltacct"][$id]['tc'] = $drow['tc'];
1231  $pending["L|$smpltmem|$smpltacct"][$id]['memfrom'] = $smplfmem;
1232  $pending["L|$smpltmem|$smpltacct"][$id]['facct'] = $smplfacct;
1233  $pending["L|$smpltmem|$smpltacct"][$id]['memberto'] = $smpltmem;
1234  $pending["L|$smpltmem|$smpltacct"][$id]['tacct'] = $smpltacct;
1235  $pending["L|$smpltmem|$smpltacct"][$id]['amount'] = $drow['amount'];
1236  $pending["L|$smpltmem|$smpltacct"][$id]['amount'] = sprintf("%.2f",$drow['amount']);
1237  $pending["L|$smpltmem|$smpltacct"][$id]['postdate'] = $drow['date'];
1238  $pending["L|$smpltmem|$smpltacct"][$id]['txdesc'] = $ftxdesc;
1239 
1240  } elseif (substr($fromto,2,1) == 'D') {
1241 
1242  // ** TO A DEPOSIT
1243  $pending["D|$smpltmem|$smpltacct|0"][$id]['id'] = $drow['id'];
1244  $pending["D|$smpltmem|$smpltacct|0"][$id]['tc'] = $drow['tc'];
1245  $pending["D|$smpltmem|$smpltacct|0"][$id]['memfrom'] = $smplfmem;
1246  $pending["D|$smpltmem|$smpltacct|0"][$id]['facct'] = $smplfacct;
1247  $pending["D|$smpltmem|$smpltacct|0"][$id]['memberto'] = $smpltmem;
1248  $pending["D|$smpltmem|$smpltacct|0"][$id]['tacct'] = $smpltacct;
1249  $pending["D|$smpltmem|$smpltacct|0"][$id]['amount'] = sprintf("%.2f",$drow['amount']);
1250  $pending["D|$smpltmem|$smpltacct|0"][$id]['postdate'] = $drow['date'];
1251  $pending["D|$smpltmem|$smpltacct|0"][$id]['txdesc'] = $ftxdesc;
1252 
1253  }
1254  }
1255  if (!empty($Acctid)) {
1256  # got an account identifier - return one only
1257  if (HCU_array_key_value( $Acctid , $pending ) > 0) {
1258  $txreturn['acctlist'][$Acctid] = HCU_array_key_value( $Acctid , $pending );
1259  }
1260  } else {
1261  $txreturn['acctlist']=$pending;
1262  }
1263 
1264  $txreturn['status']['code']='0';
1265  $txreturn['status']['severity']='INFO';
1266 }
1267  return ($txreturn);
1268 }
1269 
1270 /* Get the externals accounts set up for this user. Make sure they have rights to the feature.
1271  *
1272  * Returns: List of external accounts. Empty array if no list or accounts.
1273  */
1274 function Get_ExternalAccounts( $pDbh, $pHBEnv ) {
1275  $retList = array();
1276 
1277  try {
1278  // Verify the user can access this feature.
1279  $permissionInputs = array( "feature" => FEATURE_EXTERNAL_TRANSFERS );
1280  $accessRights = Perm_AccessRights( $pDbh, $pHBEnv, $permissionInputs );
1281 
1282  if ( !$accessRights["create"] ) {
1283  // * Rights NOT set
1284  throw new Exception( json_encode( $pHBEnv["MC"]->msg('Rights not set', HCU_DISPLAY_AS_HTML) ), 915 );
1285  }
1286 
1287  // get the limits to know the max amount
1288  // unresolved - return an error or bit limit or 0?
1289  $limits = Perm_GetValidationLimits( $pDbh, $pHBEnv, $permissionInputs );
1290  $maxLimit = ( $limits !== false ? $limits["amount_per_transaction"] : 0 );
1291 
1292  // get the list of active accounts for the user
1293  $SQL = "SELECT id, display_name
1294  FROM {$pHBEnv["Cu"]}extaccount ea
1295  WHERE ea.user_id = {$pHBEnv["Uid"]}
1296  AND status = 'a'
1297  AND type = 'EXT'
1298  ORDER BY display_name, id
1299  ";
1300  $rs = db_query( $SQL, $pDbh );
1301 
1302  // cycle through the rows
1303  $row = 0;
1304  $return = array();
1305  while ( $extRow = db_fetch_array( $rs, $row++ ) ) {
1306  $displayName = trim( $extRow["display_name"] );
1307 
1308  $retList[] = array( "id" => $extRow["id"],
1309  "display_name" => $displayName,
1310  "max_amount" => $maxLimit );
1311  }
1312 
1313  } catch (Exception $ex) {
1314  // any error just returns empty list
1315  $retList = array();
1316  }
1317 
1318  return $retList;
1319 } // end Get_ExternalAccounts
1320 
1321 /* Get the M2M accounts set up for this user. Make sure they have rights to the feature.
1322  *
1323  * Returns: List of M2M accounts. Empty array if no list or accounts.
1324  */
1325 function Get_M2MAccounts( $pDbh, $pHBEnv ) {
1326  $retList = array();
1327 
1328  try {
1329  // Verify the user can access this feature.
1330  $permissionInputs = array( "feature" => FEATURE_M2M_TRANSFERS );
1331  $accessRights = Perm_AccessRights( $pDbh, $pHBEnv, $permissionInputs );
1332 
1333  if ( !$accessRights["create"] ) {
1334  // * Rights NOT set
1335  throw new Exception( json_encode( $pHBEnv["MC"]->msg('Rights not set', HCU_DISPLAY_AS_HTML) ), 915 );
1336  }
1337 
1338  // get the limits to know the max amount
1339  // unresolved - return an error or bit limit or 0?
1340  $limits = Perm_GetValidationLimits( $pDbh, $pHBEnv, $permissionInputs );
1341  $maxLimit = ( $limits !== false ? $limits["amount_per_transaction"] : 0 );
1342 
1343  // get the list of active accounts for the user
1344  $SQL = "SELECT id, display_name
1345  FROM {$pHBEnv["Cu"]}extaccount ea
1346  WHERE ea.user_id = {$pHBEnv["Uid"]}
1347  AND status = 'a'
1348  AND type = 'M2M'
1349  ORDER BY display_name, id
1350  ";
1351  $rs = db_query( $SQL, $pDbh );
1352 
1353  // cycle through the rows
1354  $row = 0;
1355  $return = array();
1356  while ( $extRow = db_fetch_array( $rs, $row++ ) ) {
1357  $displayName = trim( $extRow["display_name"] );
1358 
1359  $retList[] = array( "id" => $extRow["id"],
1360  "display_name" => $displayName,
1361  "max_amount" => $maxLimit );
1362  }
1363 
1364  } catch (Exception $ex) {
1365  // any error just returns empty list
1366  $retList = array();
1367  }
1368 
1369  return $retList;
1370 } // end Get_M2MAccounts
1371 
1372 
1373 /**
1374  * This will return all accounts for this user.
1375  *
1376  * @param integer $dbh -- Current database handle
1377  * @param array $HB_ENV -- (by reference) - Home Banking Environment array
1378  * @param string $callerContext -- caller context: 20191202 -
1379  * CU3_EXCLUDE_XAC_FROM_PROFILE_DESCRIPTIONS flag allows to
1380  * include/exclude cross accounts from being listed in the profile
1381  * descritpion screen. (a) Default: ""; (b) 'acct_desc_read' for profile
1382  * description.
1383  *
1384  * @return array
1385  * returns array of account / loan balances
1386  *
1387  */
1388 function Get_Balances($dbh,&$HB_ENV, $callerContext="") {
1389 
1390  $Cu = HCU_array_key_exists("Cu", $HB_ENV) ? trim($HB_ENV["Cu"]) : "";
1391  $Cn = HCU_array_key_exists("Cn", $HB_ENV) ? trim($HB_ENV["Cn"]) : "";
1392 
1393  $Uid = HCU_array_key_exists("Uid", $HB_ENV) ? trim($HB_ENV["Uid"]) : "";
1394  $live = HCU_array_key_exists("live", $HB_ENV) ? trim($HB_ENV["live"]) : "";
1395  $Fset = HCU_array_key_exists("Fset", $HB_ENV) ? intval($HB_ENV["Fset"]) : 0;
1396  $Fset2 = HCU_array_key_exists("Fset2", $HB_ENV) ? intval($HB_ENV["Fset2"]) : 0;
1397  $Fset3 = HCU_array_key_exists("Fset3", $HB_ENV) ? intval($HB_ENV["Fset3"]) : 0;
1398 
1399  $Clw = HCU_array_key_exists("Clw", $HB_ENV) ? intval($HB_ENV["Clw"]) : 300;
1400 
1401  $balances = array('status' => Array('code' => '000', 'severity' => '', 'errors' => Array()));
1402  $pending = array();
1403  $doEncrypt = HCU_array_key_exists("doEncrypt", $HB_ENV) ? $HB_ENV["doEncrypt"] : false;
1404 
1405  $cuTz = GetCreditUnionTimezone($dbh, $Cu);
1406 
1407  /* GET LIST OF ALLOWED TRANSACTION CODES */
1408  $txncodes = Get_HaveTrans($dbh, $HB_ENV);
1409 
1410  if ($live) {
1411 
1412  $userData = Array (
1413  'email' => $HB_ENV['Ml'],
1414  'lastlogin' => $HB_ENV['Fplog']
1415  );
1416 
1417  $dataResp = LoadUserData($HB_ENV, $Uid, $userData);
1418 
1419  $requestDate = HCU_array_key_value("requestDate", $dataResp['data']);
1420  $requestDesc = HCU_array_key_value("requestDesc", $dataResp['data']);
1421  if ($dataResp['code'] == '999') {
1422  // ** Error -
1423  $balances['status']['code'] = '999';
1424  $balances['status']['severity'] = 'ERROR';
1425  $balances['status']['errors'][] = 'System Unavailable';
1426  $HB_ENV['stale'] = 1;
1427  } else {
1428  // ** Success
1429 
1430  $HB_ENV['lastupdate'] = $requestDate;
1431  }
1432  if ($dataResp['code'] != '900') { // * Don't update packetStatus for 'too soon'
1433 
1434  $HB_ENV['packetStatus'] = Array(
1435  'status' => $dataResp['code'],
1436  'asofdate' => $requestDate,
1437  'reason' => $requestDesc
1438  );
1439  }
1440 
1441  }
1442 
1443  /*
1444  * Get alternate history URL 8/7/13 used for credit cards, may be used for
1445  * mortgage accounts, can't imagine any dp acct usage so only pass hisinfo
1446  * for loan accounts. Process as json array if possible, tolerate old-style
1447  * entries HOMECU or plain URL for legacy ccinfourl usage
1448  *
1449  */
1450  $hissql= "select ccinfourl from cuadmin
1451  where cu='$Cu'";
1452 
1453  $sth = db_query($hissql,$dbh);
1454 
1455  if ($sth) {
1456  list($hisinfo) = db_fetch_array($sth,0);
1457  }
1458  $hinfo = array(); // set default
1459  db_free_result($sth);
1460  if (!empty($hisinfo)) {
1461  // legacy usage preserved
1462  if (strtolower($hisinfo) === 'homecu' || substr(strtolower($hisinfo), 0, 4) === 'http') {
1463  $hinfo = array('18' => $hisinfo);
1464  } else {
1465  // try json
1466  $hinfo = HCU_JsonDecode($hisinfo);
1467  }
1468  }
1469 
1470  // set the default dp sort order
1471  // $orderby = "order by ua.display_order, ua.accounttype, ua.accountnumber, ua.certnumber";
1472  $orderby = "ORDER BY 11, 2, 1, 3";
1473 
1474  // then override it if a flag is set
1475  // only SORTORDER4 and SORTORDER 6 change the dp balances sort order
1476  if ($Fset & GetFlagsetValue('CU_SORTORDER4') ) {
1477  //$orderby = "order by ua.display_order, btrim(ua.accounttype,'DIS'),ua.accountnumber, ua.certnumber";
1478  $orderby = "ORDER BY 11, 23, 1, 3 ";
1479  }
1480 
1481  $bal_oid_select = "";
1482  $xa_oid_select = "";
1483  if ($Fset2 & GetFlagsetValue('CU2_SORTORDER6')) {
1484  $orderby = "order by 11, 24, 25 ";
1485  $bal_oid_select = ", ab.oid ";
1486  $xa_oid_select = ", ca.oid ";
1487  }
1488 
1489  $appendCrossAccounts = false;
1490  // Add query for Cross Accounts if enabled. Enabled by Allowing XA
1491  // type transfers AND loading data from XAC Packet
1492  if (HCU_array_key_value("XA", $txncodes) && ($Fset3 & GetFlagsetValue("CU3_API_XAC"))) {
1493  if ($callerContext == "acct_desc_read") {
1494  // For profile description screen; include XACs only if
1495  // CU3_EXCLUDE_XAC_FROM_PROFILE_DESCRIPTIONS is NOT set
1496  if (!($Fset3 & GetFlagsetValue("CU3_EXCLUDE_XAC_FROM_PROFILE_DESCRIPTIONS"))) {
1497  $appendCrossAccounts = true;
1498  }
1499  }
1500  // $callerContext = "" (default)
1501  else {
1502  $appendCrossAccounts = true;
1503  }
1504  }
1505 
1506  $sql = "select trim(ua.accountnumber) as accountnumber,
1507  trim(ua.accounttype) as accounttype,
1508  ua.certnumber,
1509  upper(deposittype) as deposittype,
1510  trim(description) as description,
1511  amount,
1512  ytdinterest,
1513  lastyrinterest,
1514  available,
1515  trim(micraccount) as micraccount,
1516  display_order as displayorder,
1517  display_name as displayname,
1518  recordtype,
1519  view_balances,
1520  view_transactions,
1521  int_deposit,
1522  int_withdraw,
1523  ext_deposit,
1524  ext_withdraw,
1525  coalesce(ab.balance_stamp, ma.balance_stamp) as balance_stamp,
1526  ma.balance_attempt,
1527  ma.restrictions,
1528  btrim(ab.accounttype, 'DIS'),
1529  'balance' as tablesrc {$bal_oid_select}
1530 
1531  FROM {$Cu}useraccounts ua
1532  INNER JOIN {$Cu}accountbalance as ab ON ab.accountnumber = ua.accountnumber
1533  AND ab.accounttype = ua.accounttype
1534  AND ab.certnumber = ua.certnumber
1535  INNER JOIN {$Cu}memberacct as ma ON ma.accountnumber = ua.accountnumber
1536  WHERE ua.user_id = $Uid
1537  AND ua.recordtype = 'D'
1538  ";
1539 
1540  if($appendCrossAccounts) {
1541  $sql .= "
1542  UNION ALL
1543 
1544  SELECT
1545  trim(ua.accountnumber) as accountnumber,
1546  trim(ua.accounttype) as accounttype,
1547  ua.certnumber,
1548  upper(ca.deposittype) as deposittype,
1549  trim(ca.description) as description,
1550  0 as amount,
1551  0 as ytdinterest,
1552  0 as lastyrinterest,
1553  0 as available,
1554  '' as micraccount,
1555  ua.display_order as displayorder,
1556  ua.display_name as displayname,
1557  ua.recordtype,
1558  ua.view_balances,
1559  ua.view_transactions,
1560  ua.int_deposit,
1561  ua.int_withdraw,
1562  ua.ext_deposit,
1563  ua.ext_withdraw,
1564  0 as balance_stamp,
1565  ma.balance_attempt,
1566  ma.restrictions,
1567  btrim(ca.accounttype, 'DIS'),
1568  'cross' as tablesrc {$xa_oid_select}
1569  FROM {$Cu}useraccounts ua
1570 
1571  INNER JOIN {$Cu}crossaccounts as ca ON ca.accountnumber = ca.accountnumber
1572  AND trim(ca.accounttype) || '#' || trim(ca.tomember) = ua.accounttype
1573  AND ca.deposittype IN ('Y','S','N')
1574  INNER JOIN {$Cu}memberacct as ma ON ma.accountnumber = ua.accountnumber
1575 
1576  WHERE ua.user_id = {$Uid}
1577  AND ua.recordtype = 'T'
1578  AND ua.int_deposit = 't'
1579  ";
1580  }
1581  // ** Append the ORDER BY statement
1582  $sql .= $orderby;
1583 
1584  // where clause when credit cards are loans
1585  $whcc = ($Fset2 & GetFlagsetValue('CU2_SPEC18') ? " and (cbtype <> '18' or cbtype is null) " : "");
1586 
1587  // set the default loan sort order
1588  // $lorderby = " order by ua.display_order, loannumber, ua.accountnumber";
1589  $lorderby = " ORDER BY 15, 2, 1";
1590 
1591  // then override it if a flag is set
1592  // only LNSORT2 changes the ln balances sort order
1593  if ($Fset & GetFlagsetValue('CU_LNSORT2')) {
1594  // $lorderby = " order by ua.display_order, btrim(loannumber,'LC'), ua.accountnumber";
1595  $lorderby = " ORDER BY 11, 29, 1 ";
1596  }
1597 
1598  // sql to fetch loans
1599  $loan_sql = "SELECT
1600  trim(ua.accountnumber) as accountnumber,
1601  trim(loannumber) as loannumber,
1602  coalesce(currentbalance,0) as currentbalance,
1603  coalesce(payoff,0) as payoff,
1604  coalesce(unpaidinterest,0) as unpaidinterest,
1605  date_part('day',(now()-lastpaymentdate)) as unpaiddays,
1606  paymentamount,
1607  to_char(nextduedate,'YYYY-MM-DD') as nextduedate,
1608  trim(description) as description,
1609  coalesce(interestrate,0) as interestrate,
1610  creditlimit,
1611  ytdinterest,
1612  lastyrinterest,
1613  cbtype,
1614  display_order as displayorder,
1615  display_name as displayname,
1616  recordtype,
1617  case when nextduedate < CURRENT_DATE
1618  and currentbalance > 0
1619  and paymentamount > 0
1620  then 1 else 0 end as pastdue,
1621  to_char(lastpaymentdate,'YYYY-MM-DD') as lastpaymentdate,
1622  view_balances,
1623  view_transactions,
1624  int_deposit,
1625  int_withdraw,
1626  ext_deposit,
1627  ext_withdraw,
1628  coalesce(lb.balance_stamp, ma.balance_stamp) as balance_stamp,
1629  ma.balance_attempt,
1630  ma.restrictions,
1631  btrim(loannumber,'LC'),
1632  'balance' as tablesrc
1633  FROM {$Cu}useraccounts ua
1634  INNER JOIN {$Cu}loanbalance lb ON lb.accountnumber = ua.accountnumber
1635  AND lb.loannumber = ua.accounttype
1636  INNER JOIN {$Cu}memberacct as ma ON ma.accountnumber = ua.accountnumber
1637 
1638  WHERE ua.user_id = $Uid
1639  AND ua.recordtype = 'L'
1640  $whcc
1641  ";
1642 
1643  // Add query for Cross Accounts if enabled. Enabled by Allowing XA
1644  // type transfers AND loading data from XAC Packet
1645  if($appendCrossAccounts) {
1646  $loan_sql .= "
1647  UNION ALL
1648 
1649  SELECT
1650  trim(ua.accountnumber) as accountnumber,
1651  trim(ua.accounttype) as loannumber,
1652  0 as currentbalance,
1653  0 as payoff,
1654  0 as unpaidinterest,
1655  0 as unpaiddays,
1656  0 as paymentamount,
1657  '' as nextduedate,
1658  trim(ca.description) as description,
1659  0 as interestrate,
1660  0 as creditlimit,
1661  0 as ytdinterest,
1662  0 as lastyrinterest,
1663  '' as cbtype,
1664  ua.display_order as displayorder,
1665  ua.display_name as displayname,
1666  ua.recordtype,
1667  0 as pastdue,
1668  '' as lastpaymentdate,
1669  ua.view_balances,
1670  ua.view_transactions,
1671  ua.int_deposit,
1672  ua.int_withdraw,
1673  ua.ext_deposit,
1674  ua.ext_withdraw,
1675  0 as balance_stamp,
1676  ma.balance_attempt,
1677  ma.restrictions,
1678  btrim(ca.accounttype,'LC'),
1679  'cross' as tablesrc
1680  FROM {$Cu}useraccounts ua
1681 
1682  INNER JOIN {$Cu}crossaccounts as ca ON ca.accountnumber = ca.accountnumber
1683  AND trim(ca.accounttype) || '#' || trim(ca.tomember) = ua.accounttype
1684  AND ca.deposittype IN ('L')
1685  INNER JOIN {$Cu}memberacct as ma ON ma.accountnumber = ua.accountnumber
1686 
1687  WHERE ua.user_id = {$Uid}
1688  AND ua.recordtype = 'P'
1689  AND ua.int_deposit = 't'
1690  ";
1691  }
1692 
1693  $loan_sql .= $lorderby;
1694  // sql to fetch creditcards (they are in the loan table)
1695 
1696  $cc_sql = "SELECT
1697  ua.accountnumber,
1698  trim(loannumber) as loannumber,
1699  currentbalance,
1700  payoff,
1701  paymentamount,
1702  to_char(nextduedate,'YYYY-MM-DD') as nextduedate,
1703  description,
1704  interestrate,
1705  creditlimit,
1706  ytdinterest,
1707  lastyrinterest,
1708  cbtype,
1709  display_order as displayorder,
1710  display_name as displayname,
1711  recordtype,
1712  case when nextduedate < CURRENT_DATE
1713  and currentbalance > 0
1714  and paymentamount > 0
1715  then 1 else 0 end as pastdue,
1716  to_char(lastpaymentdate,'YYYY-MM-DD') as lastpaymentdate,
1717  view_balances,
1718  view_transactions,
1719  int_deposit,
1720  int_withdraw,
1721  ext_deposit,
1722  ext_withdraw,
1723  coalesce(lb.balance_stamp, ma.balance_stamp) as balance_stamp,
1724  ma.balance_attempt,
1725  ma.restrictions,
1726  btrim(loannumber,'LC'),
1727  'balance' as tablesrc
1728  FROM {$Cu}useraccounts ua
1729  INNER JOIN {$Cu}loanbalance lb ON lb.accountnumber = ua.accountnumber
1730  AND lb.loannumber = ua.accounttype
1731  INNER JOIN {$Cu}memberacct as ma ON ma.accountnumber = ua.accountnumber
1732  WHERE user_id = $Uid
1733  AND cbtype = '18'
1734  $lorderby ";
1735 
1736 
1737  // Run all the sql and see if we got anything
1738 
1739  $sthdp = db_query($sql,$dbh);
1740  $sthln = db_query($loan_sql,$dbh);
1741  $sthcc = db_query($cc_sql,$dbh);
1742 
1743  if (!(db_num_rows($sthdp)) && !(db_num_rows($sthcc)) && !(db_num_rows($sthln))) {
1744  // error, no rows
1745  $balances['status']['code']='999';
1746  $balances['status']['severity']='ERROR';
1747  $balances['status']['errors'][]='No Accounts Available';
1748  } else {
1749  $balances['status']['code']='000';
1750  $balances['status']['severity']='SUCCESS';
1751  for ($row=0;$drow=db_fetch_array($sthdp,$row);$row++) {
1752  $accounttype=$drow['accounttype'];
1753 
1754  $cert=$drow['certnumber'];
1755 
1756  if ($drow['tablesrc'] == 'cross') {
1757  $trust = "transfer";
1758  } else {
1759  if (strpos($accounttype,"@")) {
1760  $trust = 'joint';
1761  } else {
1762  $trust = 'primary';
1763  }
1764  }
1765 
1766  $key= "D|" . trim($drow["accountnumber"]) . "|$accounttype|$cert";
1767 
1768  // show some basic account info regardless if locked
1769  $displayname= trim($drow['displayname']);
1770  $description= trim($drow["description"]);
1771  $accountnumber= trim($drow['accountnumber']);
1772 
1773  $balances['dp'][$key]['displayname'] = $displayname;
1774  // * Cross Accounts will not show the '#' overloaded value when on the displayed value
1775  $displayAcctNbr = '';
1776  $displayAcctType = '';
1777  if (strpos($accounttype,"#")) {
1778  list($displayAcctType, $displayAcctNbr) = explode("#",$accounttype);
1779  } else {
1780  $displayAcctNbr = $accountnumber;
1781  $displayAcctType = $accounttype;
1782  }
1783  $balances['dp'][$key]['description'] = getAccountDescription($dbh, $HB_ENV["Cu"], $displayAcctNbr, $description, $displayAcctType, "", $Fset3, $cert);
1784  $balances['dp'][$key]['displaydesc'] = getAccountDescription($dbh, $HB_ENV["Cu"], $displayAcctNbr, $description, $displayAcctType, $displayname, $Fset3, $cert);
1785 
1786  $balances['dp'][$key]['displayorder'] = $drow['displayorder'];
1787  $balances['dp'][$key]['recordtype'] = $drow['recordtype'];
1788  $balances['dp'][$key]['accountnumber'] = $accountnumber;
1789 
1790  $balances['dp'][$key]['view_balances'] = ($drow['view_balances'] == 't');
1791  $balances['dp'][$key]['view_transactions'] = $drow['restrictions'] == "L" ? false : ($drow['view_transactions'] == 't');
1792  $balances['dp'][$key]['int_deposit'] = $drow['restrictions'] == "L" ? false : ($drow['int_deposit'] == 't');
1793  $balances['dp'][$key]['int_withdraw'] = $drow['restrictions'] == "L" ? false : ($drow['int_withdraw'] == 't');
1794  $balances['dp'][$key]['ext_deposit'] = $drow['restrictions'] == "L" ? false : ($drow['ext_deposit'] == 't');
1795  $balances['dp'][$key]['ext_withdraw'] = $drow['restrictions'] == "L" ? false : ($drow['ext_withdraw'] == 't');
1796 
1797  // -- moved encryption value here as it is needed by the Profile Description screen for referencing the accounts
1798  $balances['dp'][$key]['encryption']= $doEncrypt ? HCU_PayloadEncode($Cu, explode("|", $key)) : null;
1799 
1800  // if account is locked then only show that it is locked
1801  // ** Also, SKIP if the sub-account does NOT have view_balances enabled
1802  $balances['dp'][$key]['restrictions'] = $drow['restrictions'];
1803  $balances['dp'][$key]['trust'] = "$trust";
1804  if ( $drow['restrictions'] == "L" || $drow['view_balances'] != 't') {
1805  // set these to get the header to show correctly
1806  $balances['dp'][$key]['currentbal'] = 0;
1807  if ($Fset & GetFlagsetValue('CU_SHOWAVAILABLE'))
1808  $balances['dp'][$key]['availablebal'] = 0;
1809 
1810  continue;
1811  }
1812 
1813 
1814  $balances['dp'][$key]['accounttype']=$drow['accounttype'];
1815  $balances['dp'][$key]['certnumber']=$drow['certnumber'];
1816  $balances['dp'][$key]['deposittype']=$drow['deposittype'];
1817  $balances['dp'][$key]['currentbal']=$drow['amount'];
1818  if ($Fset & GetFlagsetValue('CU_SHOWAVAILABLE'))
1819  $balances['dp'][$key]['availablebal']=$drow['available'];
1820  if ($Fset & GetFlagsetValue('CU_SHOWDEPDIVIDEND')) {
1821  $balances['dp'][$key]['ytdinterest']=$drow['ytdinterest'];
1822  if (!($Fset & GetFlagsetValue('CU_HIDE_PYR')))
1823  $balances['dp'][$key]['lastyrinterest']=$drow['lastyrinterest'];
1824  }
1825  $balances['dp'][$key]['micraccount']=$drow['micraccount'];
1826  // need code to get holdtotal / pendtotal
1827  if ($Fset2 & GetFlagsetValue('CU2_SHOWHOLD')) {
1828  $pending=Get_HoldTotal($dbh,$HB_ENV,$key);
1829  if (empty($pending[$key])) {
1830  $holdtotal = '0.00';
1831  } else {
1832  $holdtotal=sprintf("%.2f",$pending[$key]['total']);
1833  }
1834  $balances['dp'][$key]['holdtotal']="$holdtotal";
1835  }
1836  if ($Fset2 & GetFlagsetValue('CU2_SHOWPEND')) {
1837  $pending=Get_PendTotal($dbh,$HB_ENV,$key);
1838  if (empty($pending[$key])) {
1839  $pendtotal = '0.00';
1840  } else {
1841  $pendtotal=sprintf("%.2f",$pending[$key]['total']);
1842  }
1843  $balances['dp'][$key]['pendtotal']="$pendtotal";
1844  }
1845 
1846  if ($live) {
1847  $balances['dp'][$key]['as_of_date'] = GetDateFormatTimezone($drow['balance_stamp'], 'm/d/Y h:i A', $cuTz);
1848 
1849  $balances['dp'][$key]['out_of_sync'] = ($drow['balance_stamp'] < $drow['balance_attempt']);
1850 
1851  } else {
1852  $balances['dp'][$key]['as_of_date'] = "";
1853  $balances['dp'][$key]['out_of_sync'] = false;
1854  }
1855  }
1856 
1857  for ($row=0;$drow=db_fetch_array($sthln,$row);$row++) {
1858  $loan=$drow['loannumber'];
1859 
1860  if ($drow['tablesrc'] == 'cross') {
1861  $trust = "transfer";
1862  } else {
1863  if (strpos($loan,"@")) {
1864  $trust = 'joint';
1865  } else {
1866  $trust = 'primary';
1867  }
1868  }
1869 
1870 
1871  $rate = 0;
1872  if ($live) {
1873  $payoff=$drow['payoff'];
1874  } else {
1875  $rate = $drow['interestrate'];
1876  $rate = (empty($rate) ? 0 : $rate);
1877  $unpaid = $drow['unpaidinterest'];
1878  $unpaid = (empty($unpaid) ? 0 : $unpaid);
1879  $days = $drow['unpaiddays'];
1880  $days = (empty($days) ? 0 : $days);
1881  if($days < 0) {
1882  $days = 0;
1883  }
1884  $payoff = (((($rate/100)*$drow['currentbalance'])/365)*$days)+$unpaid+$drow['currentbalance'];
1885  }
1886  $tenday = (((($drow['interestrate']/100)*$drow['currentbalance'])/365)*10) + (empty($payoff) ? 0 : $payoff );
1887 
1888  if (empty($payoff) || $payoff == 0) {
1889  $payoff = 'N/A';
1890  } else {
1891  $payoff=sprintf("%.2f",$payoff);
1892  }
1893  if ($drow['currentbalance'] <= 0 ) {
1894  $tenday = "N/A";
1895  } else {
1896  $tenday = ((empty($tenday) || $tenday==0 || $drow['cbtype']=='18') ? '#Call Us#' : sprintf("%.2f",$tenday));
1897  }
1898 
1899  if ($Fset2 & GetFlagsetValue('CU2_CALL_PAYOFF')) {
1900  $payoff='#Call Us#';
1901  // let tenday run independent of payoff flag
1902  }
1903  $limit = $drow['creditlimit'];
1904  $balance = $drow['currentbalance'];
1905  $available = ($limit - $balance < 0 ? 0 : $limit - $balance);
1906 
1907  $key= "L|" . trim($drow["accountnumber"]) . "|$loan";
1908  $keyEncrypt = HCU_PayloadEncode($Cu, explode("|",$key));
1909 
1910 
1911 
1912 
1913  // show some basic account info regardless if locked
1914  $displayname = trim($drow['displayname']);
1915  $description = trim($drow["description"]);
1916  $accountnumber = trim($drow['accountnumber']);
1917 
1918  $balances['ln'][$key]['displayname'] = $displayname;
1919  // * Cross Accounts will not show the '#' overloaded value when on the displayed value
1920  $displayAcctNbr = '';
1921  $displayAcctType = '';
1922  if (strpos($loan,"#")) {
1923  list($displayAcctType, $displayAcctNbr) = explode("#",$loan);
1924  } else {
1925  $displayAcctNbr = $accountnumber;
1926  $displayAcctType = $loan;
1927  }
1928  $balances['ln'][$key]['description'] = getAccountDescription($dbh, $HB_ENV["Cu"], $displayAcctNbr, $description, $displayAcctType, "", $Fset3);
1929  $balances['ln'][$key]['displaydesc'] = getAccountDescription($dbh, $HB_ENV["Cu"], $displayAcctNbr, $description, $displayAcctType, $displayname, $Fset3);
1930 
1931 
1932 
1933 
1934 
1935 
1936 
1937 /*
1938  // show some basic account info regardless if locked
1939  $displayname= trim($drow['displayname']);
1940  $description= trim($drow['description']);
1941  $accountnumber= trim($drow['accountnumber']);
1942 
1943  $balances['ln'][$key]['displayname'] = $displayname;
1944  $balances['ln'][$key]['description'] = getAccountDescription($dbh, $HB_ENV["Cu"], $accountnumber, $description, $loan, "", $Fset3);
1945  $balances['ln'][$key]['displaydesc'] = getAccountDescription($dbh, $HB_ENV["Cu"], $accountnumber, $description, $loan, $displayname, $Fset3);
1946 */
1947 
1948  $balances['ln'][$key]['displayorder'] = $drow['displayorder'];
1949  $balances['ln'][$key]['recordtype'] = $drow['recordtype'];
1950  $balances['ln'][$key]['accountnumber'] = trim($drow['accountnumber']);
1951 
1952  $balances['ln'][$key]['view_balances'] = ($drow['view_balances'] == 't');
1953  $balances['ln'][$key]['view_transactions'] = $drow['restrictions'] == "L" ? false : ($drow['view_transactions'] == 't');
1954  $balances['ln'][$key]['int_deposit'] = $drow['restrictions'] == "L" ? false : ($drow['int_deposit'] == 't');
1955  $balances['ln'][$key]['int_withdraw'] = $drow['restrictions'] == "L" ? false : ($drow['int_withdraw'] == 't');
1956  $balances['ln'][$key]['ext_deposit'] = $drow['restrictions'] == "L" ? false : ($drow['ext_deposit'] == 't');
1957  $balances['ln'][$key]['ext_withdraw'] = $drow['restrictions'] == "L" ? false : ($drow['ext_withdraw'] == 't');
1958 
1959  // if account is locked then only show that it is locked
1960  $balances['ln'][$key]['restrictions'] = $drow['restrictions'];
1961  if ( $drow['restrictions'] == "L" ) {
1962  // these are to get the client column headers to display
1963  $balances['ln'][$key]['currentbal'] = 0;
1964 
1965  $balances['ln'][$key]['paymentamount'] = 0;
1966 
1967  continue;
1968  }
1969 
1970  $balances['ln'][$key]['encryption']= $doEncrypt ? $keyEncrypt : null;
1971 
1972  $balances['ln'][$key]['loan']=$drow['loannumber'];
1973  $balances['ln'][$key]['currentbal']=$drow['currentbalance'];
1974  if (!($Fset2 & GetFlagsetValue('CU2_HIDE_PAYOFF')))
1975  $balances['ln'][$key]['payoff']=$payoff;
1976 
1977  if ($Fset2 & GetFlagsetValue('CU2_10DAYPAY'))
1978  $balances['ln'][$key]['tenday'] = $tenday;
1979 
1980  $balances['ln'][$key]['paymentamount'] = $drow['paymentamount'];
1981 
1982  if (!($Fset & GetFlagsetValue('CU_HIDELOANDATE'))) {
1983  if (trim($drow['nextduedate']) == '' || $payoff == 'N/A') {
1984  $drow['nextduedate'] = 'N/A';
1985  }
1986  $balances['ln'][$key]['nextduedate'] = $drow['nextduedate'];
1987  if (($drow['pastdue']) && !($Fset2 & GetFlagsetValue('CU2_HIDE_PASTDUE'))) {
1988  $balances['ln'][$key]['pastdue'] = $drow['pastdue'];
1989  }
1990  }
1991 
1992  $balances['ln'][$key]['trust']="$trust";
1993  if ($Fset & GetFlagsetValue('CU_SHOWLNRATE'))
1994  $balances['ln'][$key]['interestrate']=$drow['interestrate'];
1995 
1996  $balances['ln'][$key]['creditlimit']=$drow['creditlimit'];
1997  // ** Only pass available bal IF credit limit is set for Loans. This should help prevent
1998  // * loans such as car loans from showing an avaiable as usually they have a credit limit of 0
1999  if ($Fset & GetFlagsetValue('CU_SHOWAVAILABLE') && floatval($drow['creditlimit']) > 0)
2000  $balances['ln'][$key]['availablebal']=$available;
2001 
2002  if ($Fset & GetFlagsetValue('CU_SHOWLNINTEREST')) {
2003  $balances['ln'][$key]['ytdinterest']=$drow['ytdinterest'];
2004 
2005  if (!($Fset & GetFlagsetValue('CU_HIDE_PYR')))
2006  $balances['ln'][$key]['lastyrinterest']=$drow['lastyrinterest'];
2007  }
2008  $balances['ln'][$key]['type']=$drow['cbtype'];
2009  $balances['ln'][$key]['cbtype']=$drow['cbtype'];
2010 
2011  if (HCU_array_key_exists('cbtype', $drow) && HCU_array_key_exists($drow['cbtype'], $hinfo)) {
2012  // if the url has the #acctid# placeholder, replace it with the ecrypted account id.
2013  $hisLink = str_replace("#acctid#", urlencode($keyEncrypt), $hinfo[$drow['cbtype']]);
2014  $balances['ln'][$key]['hisinfo'] = $hisLink;
2015  } else {
2016  $balances['ln'][$key]['hisinfo']="";
2017  }
2018  $balances['ln'][$key]['lastpaymentdate']=$drow['lastpaymentdate'];
2019  // need code to get holdtotal / pendtotal
2020  // get holds only -- no ACH pending for loans
2021 
2022  if ($Fset2 & GetFlagsetValue('CU2_SHOWHOLD')) {
2023  $pending=Get_HoldTotal($dbh,$HB_ENV,$key);
2024  if (empty($pending[$key])) {
2025  $holdtotal = '0.00';
2026  } else {
2027  $holdtotal=sprintf("%.2f",$pending[$key]['total']);
2028  }
2029  $balances['ln'][$key]['holdtotal']="$holdtotal";
2030  }
2031  $balances['ln'][$key]['restrictions'] = $drow['restrictions'];
2032 
2033  if ($live) {
2034  $balances['ln'][$key]['as_of_date'] = GetDateFormatTimezone($drow['balance_stamp'], 'm/d/Y h:i A', $cuTz);
2035  $balances['ln'][$key]['out_of_sync'] = ($drow['balance_stamp'] < $drow['balance_attempt']);
2036 
2037  } else {
2038  $balances['ln'][$key]['as_of_date'] = "";
2039  $balances['ln'][$key]['out_of_sync'] = false;
2040  }
2041  }
2042  if ($Fset2 & GetFlagsetValue('CU2_SPEC18')) {
2043  for ($row = 0; $drow = db_fetch_array($sthcc, $row); $row++) {
2044  $loan = $drow['loannumber'];
2045 
2046  if (strpos($loan, "@")) {
2047  $trust = 'joint';
2048  } else {
2049  $trust = 'primary';
2050  }
2051  $limit = $drow['creditlimit'];
2052  $balance = $drow['currentbalance'];
2053  $available = ($limit - $balance < 0 ? 0 : $limit - $balance);
2054  $available = (($Fset2 & GetFlagsetValue('CU2_CALL_CCAVAIL')) ? "#Call Us#" : sprintf("%.2f", $available));
2055 
2056  $key = "C|" . trim($drow["accountnumber"]) . "|$loan";
2057  $keyEncrypt = HCU_PayloadEncode($Cu, explode("|",$key));
2058 
2059  // show some basic account info regardless if locked
2060  $displayname= trim($drow['displayname']);
2061  $description= trim($drow['description']);
2062  $accountnumber= trim($drow['accountnumber']);
2063 
2064  $balances['cc'][$key]['displayname'] = $displayname;
2065  $balances['cc'][$key]['description'] = getAccountDescription($dbh, $HB_ENV["Cu"], $accountnumber, $description, $loan, "", $Fset3);
2066  $balances['cc'][$key]['displaydesc'] = getAccountDescription($dbh, $HB_ENV["Cu"], $accountnumber, $description, $loan, $displayname, $Fset3);
2067 
2068  $balances['cc'][$key]['displayorder'] = $drow['displayorder'];
2069  $balances['cc'][$key]['recordtype'] = $drow['recordtype'];
2070  $balances['cc'][$key]['accountnumber'] = trim($drow['accountnumber']);
2071 
2072  $balances['cc'][$key]['view_balances'] = ($drow['view_balances'] == 't');
2073  $balances['cc'][$key]['view_transactions'] = $drow['restrictions'] == "L" ? false : ($drow['view_transactions'] == 't');
2074  $balances['cc'][$key]['int_deposit'] = $drow['restrictions'] == "L" ? false : ($drow['int_deposit'] == 't');
2075  $balances['cc'][$key]['int_withdraw'] = $drow['restrictions'] == "L" ? false : ($drow['int_withdraw'] == 't');
2076  $balances['cc'][$key]['ext_deposit'] = $drow['restrictions'] == "L" ? false : ($drow['ext_deposit'] == 't');
2077  $balances['cc'][$key]['ext_withdraw'] = $drow['restrictions'] == "L" ? false : ($drow['ext_withdraw'] == 't');
2078 
2079  // if account is locked then only show that it is locked
2080  $balances['cc'][$key]['restrictions'] = $drow['restrictions'];
2081  if ( $drow['restrictions'] == "L" ) {
2082  // these are so the correct column headers show up
2083  $balances['cc'][$key]['currentbal'] = 0;
2084  $balances['cc'][$key]['paymentamount'] = 0;
2085 
2086  continue;
2087  }
2088 
2089  $balances['cc'][$key]['encryption'] = $doEncrypt ? $keyEncrypt : null;
2090 
2091  $balances['cc'][$key]['loan'] = $drow['loannumber'];
2092 
2093  $balances['cc'][$key]['trust'] = "$trust";
2094  $balances['cc'][$key]['type'] = $drow['cbtype'];
2095  $balances['cc'][$key]['cbtype']=$drow['cbtype'];
2096 
2097  if (HCU_array_key_exists('cbtype', $drow) && HCU_array_key_exists($drow['cbtype'], $hinfo)) {
2098  // if the url has the #acctid# placeholder, replace it with the ecrypted account id.
2099  $hisLink = str_replace("#acctid#", urlencode($keyEncrypt), $hinfo[$drow['cbtype']]);
2100  $balances['cc'][$key]['hisinfo'] = $hisLink;
2101  } else {
2102  $balances['cc'][$key]['hisinfo']="";
2103  }
2104  if (($Fset2 & GetFlagsetValue('CU2_CC18NOINFO')) != GetFlagsetValue('CU2_CC18NOINFO')) {
2105  $balances['cc'][$key]['currentbal'] = $drow['currentbalance'];
2106  if ($live && ($Fset2 & $GLOBALS['CU2_SHOWCCSB']) == $GLOBALS['CU2_SHOWCCSB']) {
2107  $balances['cc'][$key]['stmntbal'] = $drow['payoff'];
2108  }
2109  if (($Fset2 & $GLOBALS['CU2_HIDE_CCAVAIL']) != $GLOBALS['CU2_HIDE_CCAVAIL']) {
2110  $balances['cc'][$key]['available'] = $available; // ** Deprecated -- do not use
2111  // ** ADD availablebal so it's the same as the other types.
2112  $balances['cc'][$key]['availablebal'] = $available;
2113  }
2114 
2115  $balances['cc'][$key]['paymentamount'] = $drow['paymentamount'];
2116  if (!($Fset & GetFlagsetValue('CU_HIDELOANDATE'))) {
2117  /** MWS 1/30/14 - The following condition was checking to see if 'payoff' was zero
2118  * And if it was then it was setting value to N/A
2119  * Looking at the current script Balances, it does a comparison to the balance
2120  * field. Part of the problem, is that payoff will ALWAYS be zero for batch as
2121  * it is a live field.
2122  */
2123  if (trim($drow['nextduedate']) == '' || $drow['currentbalance'] == 0) {
2124  $drow['nextduedate'] = 'N/A';
2125  }
2126  $balances['cc'][$key]['nextduedate'] = $drow['nextduedate'];
2127  if (($drow['pastdue']) && !($Fset2 & GetFlagsetValue('CU2_HIDE_PASTDUE'))) {
2128  $balances['cc'][$key]['pastdue'] = $drow['pastdue'];
2129  }
2130  }
2131  if ($Fset2 & GetFlagsetValue('CU2_SHOWCCRATE')) {
2132  $balances['cc'][$key]['interestrate'] = $drow['interestrate'];
2133  }
2134  $balances['cc'][$key]['creditlimit'] = $drow['creditlimit'];
2135  if ($Fset & GetFlagsetValue('CU_SHOWLNINTEREST')) {
2136  $balances['cc'][$key]['ytdinterest'] = $drow['ytdinterest'];
2137  if (!($Fset & GetFlagsetValue('CU_HIDE_PYR')))
2138  $balances['cc'][$key]['lastyrinterest'] = $drow['lastyrinterest'];
2139  }
2140  if ($Fset2 & GetFlagsetValue('CU2_SHOWCCLPAY')) {
2141  $balances['cc'][$key]['lastpaymentdate'] = $drow['lastpaymentdate'];
2142  }
2143  // need code to get holdtotal / pendtotal
2144  // get holds only -- no ACH pending for loans
2145 
2146  if ($Fset2 & GetFlagsetValue('CU2_SHOWHOLD')) {
2147  $pending = Get_HoldTotal($dbh, $HB_ENV, $key);
2148  if (empty($pending[$key])) {
2149  $holdtotal = '0.00';
2150  } else {
2151  $holdtotal = sprintf("%.2f", $pending[$key]['total']);
2152  }
2153  $balances['cc'][$key]['holdtotal'] = "$holdtotal";
2154  }
2155  if ($live) {
2156  $balances['cc'][$key]['as_of_date'] = GetDateFormatTimezone($drow['balance_stamp'], 'm/d/Y h:i A', $cuTz);
2157  $balances['cc'][$key]['out_of_sync'] = ($drow['balance_stamp'] < $drow['balance_attempt']);
2158 
2159  } else {
2160  $balances['cc'][$key]['as_of_date'] = "";
2161  $balances['cc'][$key]['out_of_sync'] = false;
2162  }
2163  }
2164  }
2165  }
2166  }
2167  return ($balances);
2168 }
2169 
2170 /**
2171  * returns array of account / loan transactions for specified Acctid
2172  * @param object $dbh
2173  * @param array $HB_ENV
2174  * @param string $Acctid
2175  * @param string $DTSTART
2176  * @param string $DTEND
2177  * @param array $pAdvSearch
2178  * @return array
2179  * @throws Exception
2180  */
2181 function Get_History($dbh,&$HB_ENV,$Acctid,$DTSTART="",$DTEND="",$pAdvSearch=[]) {
2182 
2183  $Cu = $HB_ENV['Cu'];
2184  $Uid = $HB_ENV["Uid"];
2185  $live = $HB_ENV['live'];
2186  $Fset = $HB_ENV['Fset'];
2187  $Fset2 = $HB_ENV['Fset2'];
2188  $history = [];
2189  $errors = [];
2190  global $chk_key;
2191 
2192  if ($live) {
2193 
2194  $userData = [
2195  'email' => $HB_ENV['Ml'],
2196  'lastlogin' => $HB_ENV['Fplog']
2197  ];
2198 
2199  $dataResp = LoadUserData($HB_ENV, $Uid, $userData);
2200  $requestDate = HCU_array_key_value("requestDate", $dataResp['data']);
2201  $requestDesc = HCU_array_key_value("requestDesc", $dataResp['data']);
2202 
2203  if ($dataResp['code'] == '999') {
2204  // ** Error -
2205  $balances['status']['code'] = '999';
2206  $balances['status']['severity'] = 'ERROR';
2207  $balances['status']['errors'][] = 'System Unavailable';
2208  $HB_ENV['stale'] = 1;
2209 
2210  } else {
2211  // ** Success
2212  $HB_ENV['lastupdate'] = $requestDate;
2213  }
2214 
2215  if ($dataResp['code'] != '900') { // * Don't update packetStatus for 'too soon'
2216 
2217  $HB_ENV['packetStatus'] = [
2218  'status' => $dataResp['code'],
2219  'asofdate' => $requestDate,
2220  'reason' => $requestDesc
2221  ];
2222  }
2223  }
2224 
2225  date_default_timezone_set('UTC');
2226  if (empty($DTSTART) || !strtotime($DTSTART)) {
2227  $errors[]="Invalid Start Date";
2228  }
2229  if (empty($DTEND) || !strtotime($DTEND)) {
2230  $errors[]="Invalid End Date";
2231  }
2232  if ( strtotime($DTSTART) > strtotime($DTEND)) {
2233  $errors[]="Invalid Date Range";
2234  }
2235  if (count($errors) > 0) {
2236  $history['status']['code'] = '999';
2237  $history['status']['severity'] ='ERROR';
2238  $history['status']['errors'] = $errors;
2239 
2240  } else {
2241  $sqlstart = (date('Y-m-d',strtotime($DTSTART)));
2242  $sqlend = (date('Y-m-d',strtotime($DTEND)));
2243  $currentdate = date('Y-m-d');
2244 
2245  $date_clause=" and date >= '$sqlstart 00:00:00' ";
2246  if ($sqlend < $currentdate) {
2247  $date_clause .= "and date <= '$sqlend 23:59:59' ";
2248  }
2249 
2250  $tbl=substr($Acctid,0,1);
2251 
2252  switch ($tbl) {
2253 
2254  case 'D':
2255  list($gettbl,$getacct,$gettype,$getcert) = explode("|",$Acctid);
2256 
2257  # deposit accounts
2258  # set the default dp sort order
2259  $orderby = "order by date desc, tracenumber desc";
2260 
2261  # then override it if a flag is set
2262  if (($Fset & $GLOBALS['CU_SORTORDER1']) == $GLOBALS['CU_SORTORDER1']) {
2263  $orderby = "order by tracenumber desc";
2264  }
2265 
2266  # only SORTORDER2 and SORTORDER5 change the dp history sort order
2267  if (($Fset & $GLOBALS['CU_SORTORDER2']) == $GLOBALS['CU_SORTORDER2']) {
2268  $orderby = "order by date desc, sortkey desc";
2269  }
2270 
2271  if (($Fset & $GLOBALS['CU_SORTORDER5']) == $GLOBALS['CU_SORTORDER5']) {
2272  $orderby = "order by date desc, oid desc";
2273  }
2274 
2275  # running balance calc if $CU_CALCRUNBAL
2276  # need deposittype from accountbalance table to determine checking?
2277  # micr overrides? alternate rt will be handled in ImageSRC
2278 
2279  $dp_bal = "select deposittype,amount,
2280  (select sum(amount) from {$Cu}accounthistory
2281  where accountnumber='" . prep_save($getacct) . "' and accounttype='" . prep_save($gettype) . "'
2282  and date >'" . prep_save($sqlend) . " 23:59:59' and certnumber=" . prep_save(intval($getcert)) . "
2283  ) as txnsum
2284  from {$Cu}accountbalance
2285  where accountnumber='" . prep_save($getacct) . "'
2286  and accounttype='" . prep_save($gettype) . "'
2287  and certnumber=" . prep_save(intval($getcert)) . " ";
2288 
2289  $sthbal = db_query($dp_bal,$dbh);
2290 
2291  if (!($sthbal)) {
2292  # error, query failed
2293  $history['status']['code'] = '999';
2294  $history['status']['severity'] = 'ERROR';
2295  $history['status']['errors'][] = db_last_error();
2296  $history['status']['errors'][] = "$dp_bal";
2297 
2298  } else {
2299  $drow = db_fetch_array($sthbal,0);
2300  $deptype = $drow['deposittype'];
2301  $seedbal = ($currentdate == $sqlend ? $drow['amount'] : $drow['amount'] - $drow['txnsum']);
2302 
2303  $advSql = "";
2304  // see if doing an advanced search
2305  if ( count( $pAdvSearch ) > 0 ) {
2306  // blank out the balance info
2307  $seedbal = 0;
2308 
2309  if ( HCU_array_key_exists("fdesc", $pAdvSearch) && strlen( $pAdvSearch["fdesc"] ) > 0 ) {
2310  $advSql .= " and description ~* '{$pAdvSearch["fdesc"]}'";
2311  }
2312  if ( HCU_array_key_exists("findamt", $pAdvSearch) && strlen( $pAdvSearch["findamt"] ) > 0 ) {
2313  $advSql .= " and abs(amount)=cast('{$pAdvSearch["findamt"]}' as numeric)";
2314  }
2315  if ( HCU_array_key_exists("check", $pAdvSearch) && strlen( $pAdvSearch["check"] ) > 0 && $deptype == "Y" ) {
2316  $advSql .= " and trim(checknumber)='{$pAdvSearch["check"]}'";
2317  }
2318  }
2319 
2320  // ** 12/16/2014 mws changing the column label 'date' to 'mdydate', this is causing an
2321  // ** error in the order by as it uses the formatted value rather than the
2322  // ** table value as desired
2323  $dp_sql = "select trim(accounttype) as accounttype,
2324  certnumber,
2325  trim(checknumber) as checknumber,
2326  to_char(date,'YYYY-MM-DD') as ymddate,
2327  amount,
2328  trim(description) as description,
2329  trim(sortkey) as sortkey,
2330  balance,
2331  trim(tracenumber) as tracenumber
2332  from {$Cu}accounthistory
2333  where accountnumber='" . prep_save($getacct) . "'
2334  and certnumber=" . prep_save(intval($getcert)) . "
2335  and accounttype='" . prep_save($gettype) . "'
2336  $date_clause
2337  $advSql ";
2338 
2339  $dp_sql .= $orderby;
2340  $sthdp = db_query($dp_sql,$dbh);
2341 
2342  if (!($sthdp)) {
2343  # error, query failed
2344  $history['status']['code'] = '999';
2345  $history['status']['severity'] = 'ERROR';
2346  $history['status']['errors'][] = db_last_error();
2347  $history['status']['errors'][] = "$dp_sql";
2348 
2349  } else {
2350  $history['status']['code'] = '000';
2351  $history['status']['severity'] = 'SUCCESS';
2352  $history['status']['startdate'] = $sqlstart;
2353  $history['status']['stopdate'] = $sqlend;
2354  $history['status']['txnsum'] = $drow['txnsum'];
2355  $history['status']['startbal'] = $drow['amount'];
2356  $history['status']['seedbal'] = $seedbal;
2357 
2358 
2359  if (($Fset & $GLOBALS['CU_CALCRUNBAL']) == $GLOBALS['CU_CALCRUNBAL'] )
2360  $runbal = $seedbal;
2361 
2362  for ($row=0;$drow = db_fetch_array($sthdp,$row);$row++) {
2363  // ** BEFORE it's used, encode the description with UTF-8 Encoding.
2364  // * setting it here eliminates the need to set it each time it's called in this loop
2365  $drow['description'] = utf8_encode($drow['description']);
2366  $accounttype = $drow['accounttype'];
2367  $cert = $drow['certnumber'];
2368 
2369  if (strpos($accounttype,"@")) {
2370  $trust = 'joint';
2371  } else {
2372  $trust = 'primary';
2373  }
2374 
2375  $trace = "T" . $drow['tracenumber'];
2376  $amount = $drow['amount'];
2377  $amount = str_replace(",","",str_replace("$","",$amount));
2378  $amount = sprintf("%.2f",$amount);
2379 
2380  if (($Fset & $GLOBALS['CU_CALCRUNBAL']) == $GLOBALS['CU_CALCRUNBAL'] ) {
2381  $balance = $runbal;
2382  $runbal -= $drow['amount'];
2383  } else {
2384  $balance = $drow['balance'];
2385  }
2386 
2387  $history[$Acctid][$trace]['accounttype'] = $drow['accounttype'];
2388  $history[$Acctid][$trace]['certnumber'] = $drow['certnumber'];
2389  $history[$Acctid][$trace]['amount'] = $amount;
2390  $history[$Acctid][$trace]['balance'] = sprintf("%.2f",$balance);
2391  // * 12/16/2014 - Reference the new ymddate label
2392  $history[$Acctid][$trace]['date'] = $drow['ymddate'];
2393 
2394  if ($deptype == "Y") {
2395 
2396  $history[$Acctid][$trace]['checkno']=$drow['checknumber'];
2397 
2398  if (((($Fset & $GLOBALS['CU_SHOWIMAGES']) == $GLOBALS['CU_SHOWIMAGES'])) &&
2399  $drow['checknumber'] > 0) {
2400  $history[$Acctid][$trace]['ckitem'] =
2401  hcu_encrypturl("{$Cu}|{$getacct}|${accounttype}|${cert}|${drow['tracenumber']}",$chk_key);
2402  $history[$Acctid][$trace]['ckhash'] =
2403  sha1("{$Cu}{$getacct}{$accounttype}{$cert}{$drow['tracenumber']}cierto");
2404  }
2405  }
2406 
2407  $history[$Acctid][$trace]['description'] = $drow['description'];
2408  $history[$Acctid][$trace]['traceno'] = $drow['tracenumber'];
2409  }
2410  }
2411  }
2412 
2413  break;
2414 
2415  case 'L':
2416  # loans
2417  list($gettbl,$getacct,$getloan) = explode("|",$Acctid);
2418 
2419  # set the default loan sort order
2420  $lorderby = " order by date desc, tracenumber desc";
2421 
2422  # none of the loan sort order flags change the ln history sort
2423  $ln_bal = "select currentbalance,
2424  (select sum(principleamount) from {$Cu}loanhistory
2425  where accountnumber='" . prep_save($getacct) . "' and loannumber='" . prep_save($getloan) . "'
2426  and date >'" . prep_save($sqlend) . " 23:59:59'
2427  ) as txnsum
2428  from {$Cu}loanbalance
2429  where accountnumber='" . prep_save($getacct) . "'
2430  and loannumber='" . prep_save($getloan) . "' ";
2431 
2432  $sthbal = db_query($ln_bal,$dbh);
2433 
2434  if (!($sthbal)) {
2435  # error, query failed
2436  $history['status']['code'] = '999';
2437  $history['status']['severity'] = 'ERROR';
2438  $history['status']['errors'][] = db_last_error();
2439  $history['status']['errors'][] = "$ln_bal";
2440 
2441  } else {
2442  $drow = db_fetch_array($sthbal,0);
2443  $seedbal = ($currentdate == $sqlend ? $drow['currentbalance'] : $drow['currentbalance'] - $drow['txnsum']);
2444 
2445  // ** 12/16/2014 mws changing the column label 'date' to 'mdydate', this is causing an
2446  // ** error in the order by as it uses the formatted value rather than the
2447  // ** table value as desired
2448  $ln_sql = "select trim(loannumber) as loannumber,
2449  to_char(date,'YYYY-MM-DD') as ymddate,
2450  principleamount as principle,
2451  interestamount as interest,
2452  balance as balance,
2453  trim(description) as description,
2454  trim(tracenumber) as tracenumber ";
2455 
2456  if (($Fset2 & $GLOBALS['CU2_ESCHEMA']) == $GLOBALS['CU2_ESCHEMA'] )
2457  $ln_sql .= ",fee as fee, escrow as escrow";
2458 
2459  $ln_sql .= " from {$Cu}loanhistory
2460  where accountnumber='" . prep_save($getacct) . "'
2461  and loannumber='" . prep_save($getloan) . "'";
2462 
2463  $ln_sql .= $date_clause;
2464  $ln_sql .= $lorderby;
2465 
2466  $sthln = db_query($ln_sql,$dbh);
2467 
2468  if (!($sthln)) {
2469  # error, query failed
2470  $history['status']['code'] = '999';
2471  $history['status']['severity'] = 'ERROR';
2472  $history['status']['errors'][] = db_last_error();
2473  $history['status']['errors'][] = $ln_sql;
2474 
2475  } else {
2476  $history['status']['code'] = '000';
2477  $history['status']['severity'] = 'SUCCESS';
2478  $history['status']['startdate'] = $sqlstart;
2479  $history['status']['stopdate'] = $sqlend;
2480  $history['status']['txnsum'] = $drow['txnsum'];
2481  $history['status']['startbal'] = $drow['currentbalance'];
2482  $history['status']['seedbal'] = $seedbal;
2483 
2484  if (($Fset & $GLOBALS['CU_CALCRUNBAL']) == $GLOBALS['CU_CALCRUNBAL'] )
2485  $runbal = $seedbal;
2486 
2487  for ($row=0;$drow = db_fetch_array($sthln,$row);$row++) {
2488 
2489  // ** BEFORE it's used, encode the description with UTF-8 Encoding.
2490  // * setting it here eliminates the need to set it each time it's called in this loop
2491  $drow['description'] = utf8_encode($drow['description']);
2492  $loan = $drow['loannumber'];
2493  $trace = "T" . $drow['tracenumber'];
2494 
2495  if (strpos($loan,"@")) {
2496  $trust = 'joint';
2497  } else {
2498  $trust = 'primary';
2499  }
2500 
2501  $escrow = 0;
2502  $fee = 0;
2503 
2504  if (($Fset2 & $GLOBALS['CU2_ESCHEMA']) == $GLOBALS['CU2_ESCHEMA'] ) {
2505  if (($Fset2 & $GLOBALS['CU2_SHOW_LN_ESCROW']) == $GLOBALS['CU2_SHOW_LN_ESCROW'])
2506  $escrow=$drow['escrow'];
2507 
2508  if (($Fset2 & $GLOBALS['CU2_SHOW_LN_FEE']) == $GLOBALS['CU2_SHOW_LN_FEE'])
2509  $fee=$drow['fee'];
2510  }
2511 
2512  $principle = $drow['principle'];
2513  $principle = str_replace(",","",str_replace("$","",$principle));
2514  $interest = $drow['interest'];
2515  $interest = str_replace(",","",str_replace("$","",$interest));
2516  $escrow = str_replace(",","",str_replace("$","",$escrow));
2517  $fee = str_replace(",","",str_replace("$","",$fee));
2518 
2519  if (($Fset & $GLOBALS['CU_CALCRUNBAL']) == $GLOBALS['CU_CALCRUNBAL'] ) {
2520  $balance = $runbal;
2521  $runbal -= $drow['principle'];
2522  } else {
2523  $balance = $drow['balance'];
2524  }
2525 
2526  $balance = str_replace(",","",str_replace("$","",$balance));
2527  $totalpay = sprintf("%.2f",(abs($principle) + abs($interest) + abs($escrow) + abs($fee)));
2528  $principle = sprintf("%.2f",$principle);
2529  $interest = sprintf("%.2f",$interest);
2530  $escrow = sprintf("%.2f",$escrow);
2531  $fee = sprintf("%.2f",$fee);
2532 
2533  $history[$Acctid][$trace]['loan'] = $drow['loannumber'];
2534  $history[$Acctid][$trace]['traceno'] = $drow['tracenumber'];
2535 
2536  if (($Fset & $GLOBALS['CU_SHOWLNTXNDESC']) == $GLOBALS['CU_SHOWLNTXNDESC'])
2537  $history[$Acctid][$trace]['description'] = $drow['description'];
2538 
2539  // ** 12/16/2014 mws - reference the new ymddate field returned in query
2540  $history[$Acctid][$trace]['date'] = $drow['ymddate'];
2541 
2542  if (($Fset2 & $GLOBALS['CU2_ESCHEMA']) == $GLOBALS['CU2_ESCHEMA']
2543  && ($Fset2 & $GLOBALS['CU2_SHOW_LN_ESCROW']) == $GLOBALS['CU2_SHOW_LN_ESCROW'])
2544  $history[$Acctid][$trace]['escrow'] = $escrow;
2545 
2546  if (($Fset2 & $GLOBALS['CU2_ESCHEMA']) == $GLOBALS['CU2_ESCHEMA']
2547  && ($Fset2 & $GLOBALS['CU2_SHOW_LN_FEE']) == $GLOBALS['CU2_SHOW_LN_FEE'])
2548  $history[$Acctid][$trace]['fee'] = $fee;
2549 
2550  if (($Fset & $GLOBALS['CU_SHOWLNTXNSPLIT'])==$GLOBALS['CU_SHOWLNTXNSPLIT']) {
2551  $history[$Acctid][$trace]['principal'] = $principle;
2552  $history[$Acctid][$trace]['interest'] = $interest;
2553  }
2554 
2555  $history[$Acctid][$trace]['totalpay'] = $totalpay;
2556 
2557  if (($Fset & $GLOBALS['CU_LNBALUNUSABLE'])!=$GLOBALS['CU_LNBALUNUSABLE']) {
2558  $history[$Acctid][$trace]['balance'] = $balance;
2559  }
2560  }
2561  }
2562  }
2563  break;
2564 
2565  case 'C':
2566  # loans shown as credit cards
2567  list($gettbl,$getacct,$getloan) = explode("|",$Acctid);
2568 
2569  # set the default loan sort order
2570  $lorderby = " order by date desc, tracenumber desc";
2571 
2572  # none of the loan sort order flags change the ln history sort
2573  $cc_bal="select currentbalance,
2574  (select sum(principleamount) from {$Cu}loanhistory
2575  where accountnumber='" . prep_save($getacct) . "' and loannumber='" . prep_save($getloan) . "'
2576  and date >'" . prep_save($sqlend) . " 23:59:59'
2577  ) as txnsum
2578  from {$Cu}loanbalance
2579  where accountnumber='" . prep_save($getacct) . "'
2580  and loannumber='" . prep_save($getloan) . "' ";
2581 
2582  $sthbal = db_query($cc_bal,$dbh);
2583 
2584  if (!($sthbal)) {
2585  # error, query failed
2586  $history['status']['code'] = '999';
2587  $history['status']['severity'] = 'ERROR';
2588  $history['status']['errors'][] = db_last_error();
2589  $history['status']['errors'][] = "$cc_bal";
2590 
2591  } else {
2592  $drow = db_fetch_array($sthbal,0);
2593  $seedbal = ($currentdate == $sqlend ? $drow['currentbalance'] : $drow['currentbalance'] - $drow['txnsum']);
2594 
2595  // ** 12/16/2014 mws changing the column label 'date' to 'mdydate', this is causing an
2596  // ** error in the order by as it uses the formatted value rather than the
2597  // ** table value as desired
2598  $cc_sql="select trim(loannumber) as loannumber,
2599  to_char(date,'YYYY-MM-DD') as ymddate,
2600  principleamount as principle,
2601  interestamount as interest,
2602  trim(tracenumber) as tracenumber,
2603  balance,
2604  trim(description) as description ";
2605 
2606  if (($Fset2 & $GLOBALS['CU2_ESCHEMA']) == $GLOBALS['CU2_ESCHEMA'])
2607  $cc_sql .= ",fee as fee";
2608 
2609  $cc_sql .= " from {$Cu}loanhistory
2610  where accountnumber='" . prep_save($getacct) . "' and loannumber = '" . prep_save($getloan) . "' ";
2611  $cc_sql .= $date_clause;
2612  $cc_sql .= $lorderby;
2613 
2614  $sthcc = db_query($cc_sql,$dbh);
2615 
2616  if (!($sthcc)) {
2617  # error, query failed
2618  $history['status']['code'] = '999';
2619  $history['status']['severity'] = 'ERROR';
2620  $history['status']['errors'][] = db_last_error();
2621  $history['status']['errors'][] = $cc_sql;
2622 
2623  } else {
2624  $history['status']['code'] = '000';
2625  $history['status']['severity'] = 'SUCCESS';
2626  $history['status']['startdate'] = $sqlstart;
2627  $history['status']['stopdate'] = $sqlend;
2628  $history['status']['txnsum'] = $drow['txnsum'];
2629  $history['status']['startbal'] = $drow['currentbalance'];
2630  $history['status']['seedbal'] = $seedbal;
2631 
2632  if (($Fset & $GLOBALS['CU_CALCRUNBAL']) == $GLOBALS['CU_CALCRUNBAL'] )
2633  $runbal = $seedbal;
2634 
2635  for ($row=0;$drow = db_fetch_array($sthcc,$row);$row++) {
2636 
2637  // ** BEFORE it's used, encode the description with UTF-8 Encoding.
2638  // * setting it here eliminates the need to set it each time it's called in this loop
2639  $drow['description'] = utf8_encode($drow['description']);
2640  $loan = $drow['loannumber'];
2641  $trace = "T" . $drow['tracenumber'];
2642 
2643  $history[$Acctid][$trace]['loan'] = $drow['loannumber'];
2644  $history[$Acctid][$trace]['traceno'] = $drow['tracenumber'];
2645 
2646  if (($Fset & $GLOBALS['CU_SHOWLNTXNDESC'])==$GLOBALS['CU_SHOWLNTXNDESC'])
2647  $history[$Acctid][$trace]['description']=$drow['description'];
2648 
2649  // * 12/16/2014 - mws - reference the new ymddate in the query
2650  $history[$Acctid][$trace]['date']=$drow['ymddate'];
2651 
2652  if (($Fset & $GLOBALS['CU_CALCRUNBAL']) == $GLOBALS['CU_CALCRUNBAL'] ) {
2653  $balance = $runbal;
2654  $runbal -= $drow['principle'];
2655 
2656  } else {
2657  $balance = $drow['balance'];
2658  }
2659 
2660  $principle = $drow['principle'];
2661  $interest = $drow['interest'];
2662  $description = $drow['description'];
2663  $fee = 0;
2664 
2665  if (($Fset2 & $GLOBALS['CU2_ESCHEMA']) == $GLOBALS['CU2_ESCHEMA']) {
2666  if (($Fset2 & $GLOBALS['CU2_SHOW_LN_FEE']) == $GLOBALS['CU2_SHOW_LN_FEE'])
2667  $fee=$drow['fee'];
2668  }
2669 
2670  $principle = str_replace(",","",str_replace("$","",$principle));
2671  $interest = str_replace(",","",str_replace("$","",$interest));
2672  $fee = str_replace(",","",str_replace("$","",$fee));
2673  $totalpay = sprintf("%.2f",(abs($principle) + abs($interest) + abs($fee)));
2674  $principle = sprintf("%.2f",$principle);
2675  $interest = sprintf("%.2f",$interest);
2676  $fee = sprintf("%.2f",$fee);
2677 
2678  if (($Fset2 & $GLOBALS['CU2_ESCHEMA']) == $GLOBALS['CU2_ESCHEMA'] && ($Fset2 & $GLOBALS['CU2_SHOW_LN_FEE']) == $GLOBALS['CU2_SHOW_LN_FEE'])
2679  $history[$Acctid][$trace]['fee'] = $fee;
2680 
2681  if (($Fset & $GLOBALS['CU_SHOWLNTXNSPLIT'])==$GLOBALS['CU_SHOWLNTXNSPLIT']) {
2682  $history[$Acctid][$trace]['principal'] = $principle;
2683  $history[$Acctid][$trace]['interest'] = $interest;
2684  }
2685 
2686  $history[$Acctid][$trace]['totalpay'] = $totalpay;
2687  if (($Fset & $GLOBALS['CU_LNBALUNUSABLE'])!=$GLOBALS['CU_LNBALUNUSABLE']) {
2688  $history[$Acctid][$trace]['balance']=$balance;
2689  }
2690  }
2691  }
2692  }
2693  break;
2694 
2695  default:
2696  # unknown account requested, set error
2697  }
2698  }
2699 
2700  return ($history);
2701 }
2702 
2703 /**
2704  * returns Pending Total for specified Acctid
2705  * @param object $dbh
2706  * @param array $HB_ENV
2707  * @param string $Acctid
2708  * @return array
2709  */
2710 function Get_PendTotal($dbh,$HB_ENV,$Acctid) {
2711 
2712  $Cu = $HB_ENV['Cu'];
2713  $Fset2 = $HB_ENV['Fset2'];
2714  $pending = [];
2715 
2716  if (($Fset2 & $GLOBALS['CU2_SHOWPEND']) != $GLOBALS['CU2_SHOWPEND']) {
2717  $pending['status']['code'] = '100';
2718  $pending['status']['severity'] = 'INFO';
2719  $pending['status']['message'] = 'Feature Not Activated';
2720 
2721  } else {
2722 
2723  $tbl=substr($Acctid,0,1);
2724 
2725  switch ($tbl) {
2726  case 'L':
2727  case 'D':
2728  case 'C':
2729 
2730  if ($tbl == 'D') {
2731  list($gettbl,$getacct,$gettype,$getcert) = explode("|",$Acctid);
2732  $getcert = " and certnumber=" . prep_save(intval($getcert)) . " ";
2733  $gethold = " and holdtype = 'd' ";
2734 
2735  } elseif ($tbl == 'L' || $tbl == 'C') {
2736  list($gettbl,$getacct,$gettype) = explode("|",$Acctid);
2737  $getcert = "";
2738  $gethold = " and holdtype = 'l' ";
2739  }
2740 
2741  $dp_sql="select sum(amount) as total
2742  from {$Cu}holds
2743  where accountnumber='" . prep_save($getacct) . "'
2744  and accounttype='" . prep_save($gettype) . "' $gethold $getcert";
2745 
2746  $sthdp = db_query($dp_sql,$dbh);
2747 
2748  if (!($sthdp)) {
2749  # error, query failed
2750  $pending['status']['code'] = '999';
2751  $pending['status']['severity'] = 'ERROR';
2752  $pending['status']['errors'][] = db_last_error();
2753 
2754  } else {
2755  $pending['status']['code'] = '000';
2756  $pending['status']['severity'] = 'SUCCESS';
2757 
2758  for ($row=0;$drow = db_fetch_array($sthdp,$row);$row++) {
2759  $total = $drow['total'];
2760  $total = sprintf("%.2f",$total);
2761  $pending["$Acctid"]['total'] = $total;
2762  }
2763  }
2764  break;
2765 
2766  default:
2767  # unknown account requested, set error
2768  $pending['status']['code'] = '999';
2769  $pending['status']['severity'] = 'ERROR';
2770  $pending['status']['errors'][] = 'Unknown Account Requested';
2771  }
2772  }
2773 
2774  return ($pending);
2775 }
2776 
2777 /**
2778  * Get the pending details for accounts that are not locked.
2779  * returns array of account / loan transactions for specified Acctid
2780  * @param object $dbh
2781  * @param array $HB_ENV
2782  * @param string $Acctid
2783  * @return array
2784  */
2785 function Get_PendDetails($dbh,$HB_ENV,$Acctid) {
2786 
2787  $Cu = $HB_ENV['Cu'];
2788  $Fset2 = $HB_ENV['Fset2'];
2789  $history = [];
2790 
2791  if (($Fset2 & $GLOBALS['CU2_SHOWPEND']) != $GLOBALS['CU2_SHOWPEND']) {
2792  $history['status']['code'] = '100';
2793  $history['status']['severity'] = 'INFO';
2794  $history['status']['message'] = 'Feature Not Activated';
2795  } else {
2796 
2797  $tbl=substr($Acctid,0,1);
2798 
2799  switch ($tbl) {
2800  case 'L':
2801  case 'D':
2802  case 'C':
2803 
2804  if ($tbl == 'D') {
2805  list($gettbl,$getacct,$gettype,$getcert) = explode("|",$Acctid);
2806  $getcert = " and certnumber=" . prep_save(intval($getcert)) . " ";
2807  $gethold = " and holdtype = 'd' ";
2808 
2809  } elseif ($tbl == 'L' || $tbl == 'C') {
2810  list($gettbl,$getacct,$gettype) = explode("|",$Acctid);
2811  $getcert = "";
2812  $gethold= " and holdtype = 'l' ";
2813  }
2814 
2815  # accounttype,certnumber,date desc, tracenumber desc
2816  #$orderby = "order by accounttype, certnumber, date desc, tracenumber desc";
2817 
2818  /*
2819  * changed 2/12/13 to use expiredate rather than postdate for pending transactions
2820  * vendors appear to be sending expiredate as the date the txn will post to
2821  * member account
2822  *
2823  * Still sending titled as 'postdate' so mobile / app code doesn't have to
2824  * change
2825  */
2826  $orderby = "order by expiredate desc, tracenumber desc";
2827 
2828  $dp_sql="select trim(h.accounttype) as accounttype,
2829  h.certnumber, trim(h.accountnumber) as accountnumber,
2830  to_char(h.expiredate,'YYYY-MM-DD') as expiredate,
2831  h.amount,
2832  trim(h.description) as description,
2833  trim(h.tracenumber) as tracenumber
2834  from {$Cu}holds h
2835  INNER JOIN {$Cu}memberacct ma ON ma.accountnumber = h.accountnumber
2836  AND coalesce(ma.restrictions, '') != 'L'
2837  where h.accountnumber='" . prep_save($getacct) . "'
2838  and h.accounttype='" . prep_save($gettype) . "' ";
2839  $dp_sql .= "$getcert $gethold $orderby";
2840 
2841  $sthdp = db_query($dp_sql,$dbh);
2842 
2843  if (!($sthdp)) {
2844  # error, query failed
2845  $history['status']['code'] = '999';
2846  $history['status']['severity'] = 'ERROR';
2847  $history['status']['errors'][] = db_last_error();
2848 
2849  } else {
2850  $history['status']['code'] = '000';
2851  $history['status']['severity'] = 'SUCCESS';
2852 
2853  for ($row=0;$drow = db_fetch_array($sthdp,$row);$row++) {
2854 
2855  $accounttype = $drow['accounttype'];
2856  $acct = $drow['accountnumber'];
2857  $trace = "T" . $drow['tracenumber'];
2858  $amount = $drow['amount'];
2859  $amount = sprintf("%.2f",$amount);
2860 
2861  if ($tbl == 'D') {
2862  $cert = $drow['certnumber'];
2863  $tblkey = "$tbl|$acct|$accounttype|$cert";
2864  } else {
2865  $tblkey = "$tbl|$acct|$accounttype";
2866  }
2867 
2868  $history["$tblkey"][$trace]['accounttype'] = $drow['accounttype'];
2869 
2870  if ($tbl == "D") {
2871  $history["$tblkey"][$trace]['certnumber'] = $drow['certnumber'];
2872  }
2873 
2874  $history["$tblkey"][$trace]['amount'] = $amount;
2875  /*
2876  * see notes above. As of 2/12/13 this is expiredate
2877  * masquerading as postdate for pending txns only
2878  */
2879  $history["$tblkey"][$trace]['postdate'] = $drow['expiredate'];
2880  $history["$tblkey"][$trace]['description'] = $drow['description'];
2881  $history["$tblkey"][$trace]['traceno'] = $drow['tracenumber'];
2882 
2883  }
2884  }
2885  break;
2886 
2887  default:
2888  # unknown account requested, set error
2889  $history['status']['code'] = '999';
2890  $history['status']['severity'] = 'ERROR';
2891  $history['status']['errors'][] = 'Unknown Account Requested';
2892  }
2893  }
2894 
2895  return ($history);
2896 }
2897 
2898 /**
2899  * returns ACH Hold Total for specified Acctid
2900  * @param object $dbh
2901  * @param array $HB_ENV
2902  * @param string $Acctid
2903  * @return array
2904  */
2905 function Get_HoldTotal($dbh,$HB_ENV,$Acctid) {
2906 
2907  $Cu = $HB_ENV['Cu'];
2908  $Fset2 = $HB_ENV['Fset2'];
2909  $pending = [];
2910 
2911  if (($Fset2 & $GLOBALS['CU2_SHOWHOLD']) != $GLOBALS['CU2_SHOWHOLD'] ) {
2912  $pending['status']['code'] = '100';
2913  $pending['status']['severity'] = 'INFO';
2914  $pending['status']['message'] = 'Feature Not Activated';
2915 
2916  } else {
2917 
2918  $tbl=substr($Acctid,0,1);
2919 
2920  switch ($tbl) {
2921  case 'L':
2922  case 'D':
2923  case 'C':
2924 
2925  if ($tbl == 'D') {
2926  list($gettbl,$getacct,$gettype,$getcert) = explode("|",$Acctid);
2927  $getcert= " and certnumber=" . prep_save(intval($getcert)) . " ";
2928  $gethold= " and holdtype = 'D' ";
2929 
2930  } elseif ($tbl == 'L' || $tbl == 'C') {
2931  list($gettbl,$getacct,$gettype) = explode("|",$Acctid);
2932  $getcert = "";
2933  $gethold= " and holdtype = 'L' ";
2934  }
2935 
2936  $dp_sql="select sum(amount) as total
2937  from {$Cu}holds
2938  where accountnumber='" . prep_save($getacct) . "'
2939  and accounttype='" . prep_save($gettype) . "' $gethold $getcert";
2940 
2941  $sthdp = db_query($dp_sql,$dbh);
2942 
2943  if (!($sthdp)) {
2944  # error, query failed
2945  $pending['status']['code'] = '999';
2946  $pending['status']['severity'] = 'ERROR';
2947  $pending['status']['errors'][] = db_last_error();
2948 
2949  } else {
2950  $pending['status']['code'] = '000';
2951  $pending['status']['severity'] = 'SUCCESS';
2952 
2953  for ($row=0;$drow=db_fetch_array($sthdp,$row);$row++) {
2954 
2955  $total = $drow['total'];
2956  $total = sprintf("%.2f",$total);
2957  $pending["$Acctid"]['total'] = $total;
2958  }
2959  }
2960  break;
2961 
2962  default:
2963  # unknown account requested, set error
2964  $pending['status']['code'] = '999';
2965  $pending['status']['severity'] = 'ERROR';
2966  $pending['status']['errors'][] = 'Unknown Account Requested';
2967  }
2968  }
2969 
2970  return ($pending);
2971 }
2972 
2973 /**
2974  * Get the hold details for accounts that are not locked
2975  * returns array of account / loan transactions for specified Acctid
2976  * @param object $dbh
2977  * @param array $HB_ENV
2978  * @param string $Acctid
2979  * @return array
2980  */
2981 function Get_HoldDetails($dbh,$HB_ENV,$Acctid) {
2982 
2983  $Cu = $HB_ENV['Cu'];
2984  $Fset2 = $HB_ENV['Fset2'];
2985  $history = [];
2986 
2987  if (($Fset2 & $GLOBALS['CU2_SHOWHOLD']) != $GLOBALS['CU2_SHOWHOLD']) {
2988  $history['status']['code'] = '100';
2989  $history['status']['severity'] = 'INFO';
2990  $history['status']['message'] = 'Feature Not Activated';
2991 
2992  } else {
2993 
2994  $tbl=substr($Acctid,0,1);
2995 
2996  switch ($tbl) {
2997  case 'L':
2998  case 'D':
2999  case 'C':
3000 
3001  if ($tbl == 'D') {
3002  list($gettbl,$getacct,$gettype,$getcert) = explode("|",$Acctid);
3003  $getcert= " and certnumber=" . prep_save(intval($getcert)) . " ";
3004  $gethold= " and holdtype = 'D' ";
3005 
3006  } elseif ($tbl == 'L' || $tbl == 'C') {
3007  list($gettbl,$getacct,$gettype) = explode("|",$Acctid);
3008  $getcert = "";
3009  $gethold= " and holdtype = 'L' ";
3010  }
3011 
3012  # accounttype,certnumber,date desc, tracenumber desc
3013  $orderby = "order by postdate desc, tracenumber desc";
3014 
3015  $dp_sql="select trim(h.accounttype) as accounttype,
3016  h.certnumber,
3017  to_char(h.postdate,'YYYY-MM-DD') as postdate,
3018  h.amount,
3019  trim(h.description) as description,
3020  trim(h.tracenumber) as tracenumber
3021  from {$Cu}holds h
3022  INNER JOIN {$Cu}memberacct ma ON ma.accountnumber = h.accountnumber
3023  AND coalesce(ma.restrictions, '') != 'L'
3024  where h.accountnumber='" . prep_save($getacct) . "'
3025  and h.accounttype='" . prep_save($gettype) . "' ";
3026 
3027  $dp_sql .= "$getcert $gethold $orderby";
3028  $sthdp = db_query($dp_sql,$dbh);
3029 
3030  if (!($sthdp)) {
3031  # error, query failed
3032  $history['status']['code'] = '999';
3033  $history['status']['severity'] = 'ERROR';
3034  $history['status']['errors'][] = db_last_error();
3035 
3036  } else {
3037  $history['status']['code'] = '000';
3038  $history['status']['severity'] = 'SUCCESS';
3039 
3040  for ($row=0;$drow = db_fetch_array($sthdp,$row);$row++) {
3041 
3042  $accounttype = $drow['accounttype'];
3043  $trace = "T" . $drow['tracenumber'];
3044  $amount = $drow['amount'];
3045  $amount = sprintf("%.2f",$amount);
3046 
3047  if ($tbl == 'D') {
3048  $cert = $drow['certnumber'];
3049  $tblkey = "$tbl|$getacct|$accounttype|$cert";
3050  } else {
3051  $tblkey = "$tbl|$getacct|$accounttype";
3052  }
3053 
3054  $history["$tblkey"][$trace]['accounttype'] = $drow['accounttype'];
3055 
3056  if ($tbl == "D") {
3057  $history["$tblkey"][$trace]['certnumber']=$drow['certnumber'];
3058  }
3059 
3060  $history["$tblkey"][$trace]['amount'] = $amount;
3061  $history["$tblkey"][$trace]['postdate'] = $drow['postdate'];
3062  $history["$tblkey"][$trace]['description'] = $drow['description'];
3063  $history["$tblkey"][$trace]['traceno'] = $drow['tracenumber'];
3064 
3065  }
3066  }
3067  break;
3068  default:
3069  # unknown account requested, set error
3070  $history['status']['code'] = '999';
3071  $history['status']['severity'] = 'ERROR';
3072  $history['status']['errors'][] = 'Unknown Account Requested';
3073  }
3074  }
3075 
3076  return ($history);
3077 }
3078 
3079 function Get_OverMicr($dbh,$HB_ENV,$Acctid) {
3080 # returns array of micr settings and overrides for member
3081 $Cu=$HB_ENV['Cu'];
3082 $Cn=$HB_ENV['Cn'];
3083 $Fset=$HB_ENV['Fset'];
3084 $Fset2=$HB_ENV['Fset2'];
3085 $micrs=array();
3086 
3087 list($gettbl,$getacct,$gettype,$getcert) = explode("|",$Acctid);
3088 
3089 // reconsider this test....
3090 // might need override micrs for bill pay, shouldn't matter if check images are
3091 // on or not
3092 //
3093  if (($Fset & $GLOBALS['CU_SHOWIMAGES']) != $GLOBALS['CU_SHOWIMAGES']) {
3094  # return error -- cu not set for images
3095  $micrs['status']['code']='999';
3096  $micrs['status']['severity']='ERROR';
3097  $micrs['status']['errors'][]="CU not set up for image retrieval";
3098  } else {
3099  # adjust this to send back the default settings as well as overrides
3100  #$sql = "select trim(rt), trim(img) from cuadmin where cu='$Cu'";
3101 
3102  $sql = "select trim(accounttype), trim(rt), trim(micraccount)
3103  from {$Cu}accountbalance, cuadmin
3104  where cu='$Cu' and deposittype='Y' and accountnumber='$getacct'
3105  and accounttype='$gettype' and certnumber=$getcert";
3106 
3107  $sth = db_query($sql,$dbh);
3108  if (db_num_rows($sth) == 0 ) {
3109  # return error -- account not found
3110  $micrs['status']['code']='999';
3111  $micrs['status']['severity']='ERROR';
3112  $micrs['status']['errors'][]="Account not found";
3113  } else {
3114  list($osfx, $ort, $omicr) = db_fetch_array($sth,0);
3115 
3116  $micrs['prime']['accounttype'] = "$osfx";
3117  $micrs['prime']['rt'] = "$ort";
3118  $micrs['prime']['micr'] = "$omicr";
3119 
3120  $sql = "select trim(accounttype), trim(rt),
3121  trim(micraccount), startcheck
3122  from cuovermicr where cu='$Cu' and accountnumber='$getacct'
3123  and accounttype='$gettype'
3124  order by startcheck desc";
3125  $sth = db_query($sql,$dbh);
3126 
3127  for ($row=0;list($osfx, $ort, $omicr, $ostart) =
3128  db_fetch_array($sth,$row); $row++) {
3129  $micrs['oride'][$row]['accounttype'] = "$osfx";
3130  $micrs['oride'][$row]['rt'] = "$ort";
3131  $micrs['oride'][$row]['micr'] = "$omicr";
3132  $micrs['oride'][$row]['startcheck'] = $ostart;
3133  }
3134  }
3135  }
3136  return ($micrs);
3137 }
3138 
3139 function Get_PrimaryChecking($dbh, $HB_ENV) {
3140 # returns list of checking accounts w/ non-blank micrs
3141 // modified 1/30/15 - return accounts first, then look for override micr
3142 // if micr is blank, but only get override with same rt as primary
3143 #
3144 # includes primary accounts only (accounttype not containing '@')
3145 
3146  $Cu = $HB_ENV['Cu'];
3147  $Cn = $HB_ENV['Cn'];
3148  $accts = array();
3149 #
3150  $sql = "select trim(accountnumber) as accountnumber,
3151  trim(accounttype) as accounttype,
3152  certnumber,
3153  trim(description) as description,
3154  trim(micraccount) as micraccount
3155  from ${Cu}accountbalance
3156  where accountnumber='$Cn' and deposittype='Y'
3157  and accounttype not like '%@%'
3158  $orderby";
3159 
3160 # Run the sql and see if we got anything
3161 
3162  $sthdp = db_query($sql, $dbh);
3163 
3164  if (db_num_rows($sthdp)) {
3165  for ($row = 0; $drow = db_fetch_array($sthdp, $row); $row++) {
3166  // ** BEFORE it's used, encode the description with UTF-8 Encoding.
3167  // * setting it here eliminates the need to set it each time it's called in this loop
3168  $drow['description'] = utf8_encode($drow['description']);
3169 
3170  $accounttype = $drow['accounttype'];
3171  $cert = $drow['certnumber'];
3172  $micraccount = $drow['micraccount'];
3173  if (strpos($accounttype, "@")) {
3174  $trust = 'joint';
3175  } else {
3176  $trust = 'primary';
3177  }
3178  if (trim($micraccount) == '') {
3179  $sqlmicr = "select trim(o.micraccount) as omicr
3180  from cuovermicr o join cuadmin a on o.cu = a.cu
3181  where o.cu='$Cu' and o.accountnumber='$Cn'
3182  and o.accounttype='$accounttype' and o.rt=a.rt
3183  order by o.startcheck desc limit 1";
3184  $sthmicr = db_query($sqlmicr, $dbh);
3185  if (db_num_rows($sthmicr) == 1) {
3186  list ($micraccount) = db_fetch_row($sthmicr, 0);
3187  $drow['micraccount'] = $micraccount;
3188  }
3189  }
3190  if (trim($micraccount) != '') {
3191  $accts['dp']["D|$Cn|$accounttype|$cert"]['accounttype'] = $drow['accounttype'];
3192  $accts['dp']["D|$Cn|$accounttype|$cert"]['certnumber'] = $drow['certnumber'];
3193  $accts['dp']["D|$Cn|$accounttype|$cert"]['description'] = $drow['description'];
3194  $accts['dp']["D|$Cn|$accounttype|$cert"]['micraccount'] = $drow['micraccount'];
3195  $accts['dp']["D|$Cn|$accounttype|$cert"]['trust'] = "$trust";
3196  $accts['dp']["D|$Cn|$accounttype|$cert"]['displaydesc'] =
3197  ($cert == 0 ? "{$drow['description']} - $accounttype" : "{$drow['description']} # $cert - $accounttype");
3198  }
3199  }
3200  }
3201  if (sizeof($accts['dp'])) {
3202  $accts['status']['code'] = '000';
3203  $accts['status']['severity'] = 'SUCCESS';
3204  } else {
3205  # error, no rows
3206  $accts['status']['code'] = '999';
3207  $accts['status']['severity'] = 'ERROR';
3208  $accts['status']['errors'][] = 'No Accounts Available';
3209  }
3210  return ($accts);
3211 }
3212 
3213 /* Test if account is locked or read-only and return the lock level.
3214  */
3215 function CheckIfAccountLocked( $dbh, $currCU, $accountNumber ) {
3216  $lockStatus = "L"; // default to locked in case something untoward happens
3217 
3218  // get the restrictions on the account
3219  $accountSQL = "SELECT restrictions
3220  FROM {$currCU}memberacct
3221  WHERE accountnumber = '$accountNumber'";
3222 
3223  $rs = db_query( $accountSQL, $dbh );
3224  if ( !$rs ) {
3225  dmserror( $DMSMAIL, "WARN", "Unable to read {$currCU}memberacct for account $accountNumber. \n" . db_last_error() );
3226  } else {
3227  $accountRow = db_fetch_assoc( $rs );
3228 
3229  $lockStatus = trim( $accountRow["restrictions"] );
3230  }
3231 
3232  return $lockStatus;
3233 
3234 } // end CheckIfAccountLocked
3235 
3236 
3237 // Sort the estatements table of contents by period end (descending) and description.
3238 function SortEstmt( $a, $b ) {
3239  $result = strcmp( $b["PerEnd"], $a["PerEnd"] );
3240  if ( $result == 0 ) {
3241  $result = strcmp( $a["PerDesc"], $b["PerDesc"] );
3242  }
3243 
3244  return $result;
3245 }
3246 
3247 
3248 
3249 /**
3250  *
3251  *
3252  *
3253  * @param integer $dbh - Current integer pointer to the database handle
3254  * @param array $HB_ENV - Current HB Environment array
3255  * @param class $MC - Current language class
3256  * Returns:
3257  * Y - CU has e-statements turned on
3258  * member has the estmt_flat set to 'Y'
3259  * there is a statement file for the member
3260  * N - CU has e-statements turned off OR
3261  * member has the estmt_flat set to 'N'
3262  * W - CU has e-statements turned on
3263  * member has the estmt_flat set to 'Y'
3264  * there is NO statement file for the member
3265  * false - All parts of the function will execute
3266  *
3267  * @return array
3268  * HomeCU [status]
3269  * [code] {000, 999}
3270  * [errors] {array of strings}
3271  *
3272  * [estmt] - Current estmt flag for the Current Member
3273  * [enrolled] - Current estmt flag for the Current Member
3274  * [pdflinks] - pdf links for the credit union
3275  * [toclinks] - toc links for current member, if they have estatements to view
3276  * [notifyemail] - Notify email for the credit union
3277  * [sslformsdir] - The ssl forms directory, location to save ssl forms
3278  *
3279  * Data returned is a string value from the core if the
3280  * value was posted. EMPTY if not posted
3281  */
3282 function Get_Estmt($dbh, $HB_ENV, $MC, $pAcct) {
3283  # not finished with this, but moving on...
3284  # needs to check cuthird for field list override,
3285  # populate 'Wait' message (estmt_flag=Y but no statement file)
3286  # use mobile fragments instead of desktop
3287  $Cu = $HB_ENV['Cu'];
3288  $Cn = $HB_ENV['Cn'];
3289  $Flang = $HB_ENV['Flang'];
3290  $chome = $HB_ENV['chome'];
3291  $email = $HB_ENV['Ml'];
3292  $live = $HB_ENV['live'];
3293 
3294  $errors = array();
3295  $stmt = Get_EstmtEnrollStatus($dbh, $HB_ENV, $MC, $pAcct);
3296  if ($stmt['status']['code'] === '000') {
3297  try {
3298 
3299  // add the pdf links and Table of Contents
3300  $pdffound = 0;
3301  # populate list of PDF links to be offered
3302  $pdfnews = "/home/$chome/public_html/pdf/newsletter.pdf";
3303  $pdfkids = "/home/$chome/public_html/pdf/kidsnews.pdf";
3304  $pdfprime = "/home/$chome/public_html/pdf/primenews.pdf";
3305  $pdfsenior = "/home/$chome/public_html/pdf/seniornews.pdf";
3306  $pdfteen = "/home/$chome/public_html/pdf/teennews.pdf";
3307  $pdfins = "/home/$chome/public_html/pdf/insert.pdf";
3308  $pdffee = "/home/$chome/public_html/pdf/fees.pdf";
3309  $pdfprivacy = "/home/$chome/public_html/pdf/privacy.pdf";
3310  $pdfpath = $HB_ENV["fi_path"] . "pdf";
3311 
3312  $pdflinks = array();
3313  if (is_readable("$pdfnews")) {
3314  $title = $MC->msg('Newsletter');
3315  $pdflinks[] = array('pdftitle' => $title, 'pdfpath' => "$pdfpath/newsletter.pdf");
3316  $pdffound++;
3317  }
3318  if (is_readable("$pdfkids")) {
3319  $title = $MC->msg('Youth Newsletter');
3320  $pdflinks[] = array('pdftitle' => $title, 'pdfpath' => "$pdfpath/kidsnews.pdf");
3321  $pdffound++;
3322  }
3323  if (is_readable("$pdfteen")) {
3324  $title = $MC->msg('Teen Newsletter');
3325  $pdflinks[] = array('pdftitle' => $title, 'pdfpath' => "$pdfpath/teennews.pdf");
3326  $pdffound++;
3327  }
3328  if (is_readable("$pdfprime")) {
3329  $title = $MC->msg('Prime Newsletter');
3330  $pdflinks[] = array('pdftitle' => $title, 'pdfpath' => "$pdfpath/primenews.pdf");
3331  $pdffound++;
3332  }
3333  if (is_readable("$pdfsenior")) {
3334  $title = $MC->msg('Senior Newsletter');
3335  $pdflinks[] = array('pdftitle' => $title, 'pdfpath' => "$pdfpath/seniornews.pdf");
3336  $pdffound++;
3337  }
3338 
3339  if (is_readable("$pdfins")) {
3340  $title = $MC->msg('Statement Insert');
3341  $pdflinks[] = array('pdftitle' => $title, 'pdfpath' => "$pdfpath/insert.pdf");
3342  $pdffound++;
3343  }
3344 
3345  if (is_readable("$pdffee")) {
3346  $title = $MC->msg('Fee Schedule');
3347  $pdflinks[] = array('pdftitle' => $title, 'pdfpath' => "$pdfpath/fees.pdf");
3348  $pdffound++;
3349  }
3350 
3351  if (is_readable("$pdfprivacy")) {
3352  $title = $MC->msg('Privacy Policy');
3353  $pdflinks[] = array('pdftitle' => $title, 'pdfpath' => "$pdfpath/privacy.pdf");
3354  $pdffound++;
3355  }
3356 
3357  $estmt = $stmt['status']['estmt'];
3358  switch ($estmt) {
3359  case 'Y':
3360  // See if reading statements directly from the core
3361  if ( $HB_ENV["Fset3"] & GetFlagsetValue("CU3_ESTMNT_CORE") ) {
3362 
3363  $mbrData = Array (
3364  'member' => "$pAcct"
3365  );
3366  // ** Don't Set email at this time
3367  $getEsResp = GetMemberES($HB_ENV, $mbrData);
3368 
3369  if ($getEsResp['code'] != '000') {
3370  $reason = $getEsResp['error'];
3371  $errorMsg = $MC->msg('Unable retrieve estatement') . " $reason";
3372  throw new Exception( $errorMsg );
3373  }
3374  $TOC = HCU_array_key_value("TOC", $getEsResp["data"]);
3375 
3376  for ( $i = 0; $i < count( $TOC ); $i++ ) {
3377  $PerDesc = $TOC[$i]["Description"];
3378  $PerId = $TOC[$i]["ID"];
3379  $PerTokn = sha1("{$Cn}{$PerDesc}{$Cu}");
3380  $PerEnd = $TOC[$i]["PeriodEnd"];
3381  $PerType = $TOC[$i]["Type"];
3382 
3383  switch ($PerType) {
3384  case "M":
3385  case "CM":
3386  $PeriodType = 'Monthly';
3387  break;
3388  case "Q":
3389  case "CQ":
3390  $PeriodType = 'Quarterly';
3391  break;
3392  case "SA":
3393  case "CA":
3394  $PeriodType = 'Semi-Annual';
3395  break;
3396  case "T":
3397  $PeriodType = 'Tax Form';
3398  break;
3399  default:
3400  $PeriodType = 'Unknown';
3401  break;
3402  }
3403 
3404  // format the period end to be consistent with what the zip file provides: yyyymm
3405  $PeriodEnd = str_replace(array('/','-'), '', $PerEnd);
3406  $PeriodEnd = substr( $PeriodEnd, 0, 6 );
3407  $toclinks[] = array("PerDesc" => "$PerDesc", "PerType" => "$PeriodType", "PerTypeText" => $MC->msg($PeriodType, HCU_DISPLAY_AS_RAW),
3408  "PerEnd" => "$PeriodEnd", "PerKey" => "$PerId", "PerTokn" => $PerTokn);
3409  }
3410  } else {
3411  $stmntdir = "/home/$chome/stmnt/history/";
3412  $stmntdir .= substr($pAcct, 0, 1);
3413  $stmntfile = "$stmntdir/$pAcct";
3414 
3415  if (is_readable($stmntfile)) {
3416  $toclinks = array();
3417  # populate TOC
3418  // open file for reading
3419  $zp = gzopen($stmntfile, "r");
3420 
3421  // read the TOC open mark
3422  $TOCmark = gzgets($zp, 4096);
3423 
3424  // output until end of the TOC and close it.
3425  while ($buf = gzgets($zp, 4096)) {
3426  $buf = preg_replace("/^> /", "", $buf);
3427  if (trim($buf) == "") { continue; }
3428  if ($buf == $TOCmark) {
3429  break;
3430  }
3431  list($bd, $ldTime, $ldProc, $PerEnd, $PerType, $PerDesc) = explode("\t", $buf);
3432  if ("$ldTime" != "") {
3433  $tokn = sha1("${Cn}${PerDesc}${Cu}");
3434  $perid = urlencode(rtrim($buf));
3435  $pertokn = $tokn;
3436  $perdesc = "$PerDesc";
3437  switch ($PerType) {
3438  case "M":
3439  case "CM":
3440  $pertype = 'Monthly';
3441  break;
3442  case "Q":
3443  case "CQ":
3444  $pertype = 'Quarterly';
3445  break;
3446  case "SA":
3447  case "CA":
3448  $pertype = 'Semi-Annual';
3449  break;
3450  case "T":
3451  $pertype = 'Tax Form';
3452  break;
3453  }
3454  $toclinks[] = array("PerDesc" => "$perdesc", "PerType" => "$pertype", "PerTypeText" => $MC->msg($pertype, HCU_DISPLAY_AS_RAW),
3455  "PerEnd" => "$PerEnd", "PerKey" => "$perid", "PerTokn" => $pertokn);
3456  }
3457  }
3458  } else {
3459  $estmt = 'W';
3460  }
3461  }
3462  break;
3463  case 'N':
3464  # populate 'Click Here to enroll' msg noestmntfrag.html
3465  break;
3466  }
3467  $stmt['status']['code'] = '000';
3468  $stmt['status']['severity'] = 'INFO';
3469  $stmt['estmt']['enrolled'] = $estmt;
3470 
3471  // ** set the ['status']['estmt'] as well, it is being used by some scripts,
3472  // ** So make sure it has the correct setting
3473  $stmt['status']['estmt'] = $estmt;
3474 
3475  $stmt['estmt']['pdflinks'] = $pdflinks;
3476  if ($estmt == 'Y') {
3477  if (is_array($toclinks)) {
3478  usort( $toclinks, "SortEstmt" );
3479  }
3480  $stmt['estmt']['toclinks'] = $toclinks;
3481  }
3482  } catch (Exception $e) {
3483  $stmt['status']['code'] = '999';
3484  $stmt['status']['severity'] = 'ERROR';
3485  $stmt['status']['errors'][] = $e->getMessage();
3486  $stmt['estmt'] = array();
3487  }
3488  }
3489 
3490  return ($stmt);
3491 }
3492 
3493 /**
3494  *
3495  *
3496  *
3497  * @param integer $dbh - Current integer pointer to the database handle
3498  * @param array $HB_ENV - Current HB Environment array
3499  * @param class $MC - Current language class
3500  * Returns:
3501  * Y - CU has e-statements turned on
3502  * member has the estmt_flat set to 'Y'
3503  * there is a statement file for the member
3504  * N - CU has e-statements turned off OR
3505  * member has the estmt_flat set to 'N'
3506  * W - CU has e-statements turned on
3507  * member has the estmt_flat set to 'Y'
3508  * there is NO statement file for the member
3509  * false - All parts of the function will execute
3510  *
3511  * @return array
3512  * HomeCU [status]
3513  * [code] {000, 999}
3514  * [errors] {array of strings}
3515  *
3516  * [estmt] - Current estmt flag for the Current Member
3517  * [enrolled] - Current estmt flag for the Current Member
3518  * [pdflinks] - pdf links for the credit union
3519  * [toclinks] - toc links for current member, if they have estatements to view
3520  * [notifyemail] - Notify email for the credit union
3521  * [sslformsdir] - The ssl forms directory, location to save ssl forms
3522  *
3523  * Data returned is a string value from the core if the
3524  * value was posted. EMPTY if not posted
3525  */
3526 function Get_EstmtEnrollStatus($dbh, $HB_ENV, $MC, $pAcct) {
3527  # not finished with this, but moving on...
3528  # needs to check cuthird for field list override,
3529  # populate 'Wait' message (estmt_flag=Y but no statement file)
3530  # use mobile fragments instead of desktop
3531  $Cu = $HB_ENV['Cu'];
3532  $Cn = $HB_ENV['Cn'];
3533  $Flang = $HB_ENV['Flang'];
3534  $chome = $HB_ENV['chome'];
3535  $email = $HB_ENV['Ml'];
3536  $live = $HB_ENV['live'];
3537 
3538  $errors = array();
3539  $stmt = array();
3540  try {
3541  $sql = "SELECT email
3542  FROM cuadmnotify
3543  WHERE cu = '{$HB_ENV['Cu']}'
3544  AND role = 'agree'";
3545  $emRs = db_query($sql, $dbh);
3546  list($notifyEmail) = db_fetch_array($emRs);
3547  db_free_result($emRs);
3548  /*
3549  * Define the location of the sslforms directory
3550  */
3551  $sslFormsDir = "/home/{$HB_ENV['chome']}/sslforms/";
3552 
3553  // ** Check the Email exists and directory has sufficient rights
3554  if (trim($notifyEmail) == '' || !(is_writable($sslFormsDir))) {
3555  throw new Exception($MC->msg('Feature Not Set') . '. ' . $MC->msg('Contact CU'), 1);
3556  }
3557 
3558  if ( ($HB_ENV["Fset3"] & GetFlagsetValue("CU3_ESTMNT_CORE")) == 0 ) {
3559  /*
3560  * Define the location of the stmnt directory
3561  * NOTE: This is a separate check because if direct from core there is no need for this directory
3562  */
3563  $sslStmntDir = "/home/{$HB_ENV['chome']}/stmnt/";
3564  if (!(is_writable($sslStmntDir))) {
3565  throw new Exception($MC->msg('Feature Not Set') . '. ' . $MC->msg('Contact CU'), 2);
3566  }
3567  }
3568 
3569  // ** Set the notifyemail and sslFormsDir
3570  $stmt['estmt']['notifyemail'] = trim($notifyEmail);
3571  $stmt['estmt']['sslformsdir'] = $sslFormsDir;
3572 
3573  $sql = "select coalesce(estmnt_flag, 'N')
3574  from {$HB_ENV["Cu"]}memberacct
3575  where accountnumber = '$pAcct'";
3576 
3577  $sth = db_query($sql, $dbh);
3578  if (!$sth) {
3579  throw new Exception($MC->msg('Unable retrieve estatement') . ': ' . db_last_error(), 3);
3580  }
3581  list($estmt) = db_fetch_array($sth, 0);
3582  $estmt = (strtoupper($estmt) == 'Y' ? 'Y' : 'N');
3583  $stmt['status']['estmt'] = $estmt;
3584 
3585  if ($estmt == "Y" && !($HB_ENV["Fset3"] & GetFlagsetValue("CU3_ESTMNT_CORE"))) {
3586  $stmntdir = "/home/$chome/stmnt/history/";
3587  $stmntdir .= substr($pAcct, 0, 1);
3588  $stmntfile = "$stmntdir/$pAcct";
3589  if (!is_readable($stmntfile)) {
3590  $estmt = 'W';
3591  }
3592  }
3593 
3594  $stmt['status']['code'] = '000';
3595  $stmt['status']['severity'] = 'INFO';
3596  $stmt['estmt']['enrolled'] = $estmt;
3597 
3598  // ** set the ['status']['estmt'] as well, it is being used by some scripts,
3599  // ** So make sure it has the correct setting
3600  $stmt['status']['estmt'] = $estmt;
3601 
3602  } catch (Exception $e) {
3603  $stmt['status']['code'] = '999';
3604  $stmt['status']['severity'] = 'ERROR';
3605  $stmt['status']['errors'][] = $e->getMessage();
3606  $stmt['estmt'] = array();
3607  }
3608 
3609  return ($stmt);
3610 }
3611 
3612 function Create_PDF_Statement($stId, $pHB_ENV, $pMC, $pAcct) {
3613 
3614  $CHome = $pHB_ENV["chome"];
3615  $Cu = $pHB_ENV["Cu"];
3616  $Cn = $pHB_ENV["Cn"];
3617 
3618  $stmt = array();
3619  $errors = array();
3620 
3621  $txtFBG = false;
3622 
3623  // used to suppress the following WeasyPrint related UserWarning for
3624  // CORELATION_XML related pdf generation process:
3625  // UserWarning: There are known rendering problems and missing features
3626  // with cairo < 1.15.4.
3627  $pythonUserWarningFlag = false;
3628 
3629  if ($pHB_ENV["Fset3"] & GetFlagsetValue("CU3_ESTMNT_CORE")) {
3630 
3631  $mbrData = Array (
3632  'member' => "$pAcct",
3633  'statement-id' => "$stId"
3634  );
3635 
3636  $getEsResp = GetMemberES($pHB_ENV, $mbrData);
3637 
3638  if ($getEsResp['code'] == '000') {
3639  $fileContents = base64_decode(HCU_array_key_value("statement", $getEsResp["data"]));
3640 
3641  if ($fileContents == "") {
3642  $errors[] = $pMC->msg('Statement Not Found');
3643  } else {
3644  header("Content-type: application/pdf"); // add here more headers for diff. extensions
3645  header("Content-Disposition: inline; filename=\"statement.pdf\""); // use 'attachment' to force a download
3646  header('Content-Transfer-Encoding: binary');
3647 
3648  print $fileContents;
3649  }
3650  } else {
3651  // need to give "custom" messages depending on the error
3652  $reason = $getEsResp["error"];
3653  $errorMsg = $pMC->msg('Unable retrieve estatement') . " $reason";
3654  $errors[] = $errorMsg;
3655  }
3656  } else {
3657  // decode st_id
3658  $stIdParts = explode("/", $stId);
3659  $stId = trim($stIdParts[0]);
3660  $stId = urldecode($stId);
3661 
3662  // point to correct file parts
3663  $stmntTmp = "/home/$CHome/tmp";
3664  $stmntDir = "/home/$CHome/stmnt/history/";
3665  $stmntBaseDir = "/home/{$CHome}/stmnt/";
3666  $stmntDir .= substr($pAcct, 0, 1);
3667  $fileName = "{$stmntDir}/{$pAcct}";
3668  $pdfDefsFile = "/home/$CHome/bin/pdfdefs";
3669  $stPerArray = explode("\t", $stId);
3670  $stPerType = $stPerArray[4];
3671 
3672  if (substr($stPerType, 0, 1) == 'C') {
3673  # if credit card statement type, use ccdisclaimer
3674  $disclaimerFile = "/home/$CHome/bin/disclaimerCC";
3675  } else if (substr($stPerType, 0, 1) == 'T') {
3676  // no disclaimer for tax files
3677  $disclaimerFile = "";
3678  } else {
3679  $disclaimerFile = "/home/$CHome/bin/disclaimer";
3680  }
3681 
3682  if ($stId == "") {
3683  $errors[] = $pMC->msg('Statement Not Found');
3684  $found = false;
3685  $stmnterrmsg = "Bad cookie data, empty value for: st_id";
3686  $stmnterrlog = fopen("$stmntTmp/statement_retrieve_failure.log", "a");
3687  chmod("$stmntTmp/statement_retrieve_failure.log", 0666);
3688  $stmnterrtime = time();
3689  $stmntexternalref = "";
3690  fwrite($stmnterrlog, implode("\t", array($stmnterrtime, date('Y-m-d_H:i:s', $stmnterrtime), getmypid(), "cu_data.i:Create_PDF_Statement", $CHome, $Cn, $stmntexternalref, $stId, $stmnterrmsg)) . "\n");
3691  fclose($stmnterrlog);
3692  } elseif (count(explode("\t", $stId)) < 6) {
3693  $errors[] = $pMC->msg('Statement Not Found');
3694  $found = false;
3695  $stmnterrmsg = "Bad cookie data, missing TAB delimiters in value for: st_id";
3696  $stmnterrlog = fopen("$stmntTmp/statement_retrieve_failure.log", "a");
3697  chmod("$stmntTmp/statement_retrieve_failure.log", 0666);
3698  $stmnterrtime = time();
3699  $stmntexternalref = "";
3700  fwrite($stmnterrlog, implode("\t", array($stmnterrtime, date('Y-m-d_H:i:s', $stmnterrtime), getmypid(), "cu_data.i:Create_PDF_Statement", $CHome, $Cn, $stmntexternalref, $stId, $stmnterrmsg)) . "\n");
3701  fclose($stmnterrlog);
3702  } elseif (is_readable($fileName)) {
3703  // open the statement history file
3704  # find the desired statement info (also checks to see if PDF already generated)
3705  // open file for reading
3706  $zp = gzopen($fileName, "rb");
3707 
3708  // read until the $st_id mark
3709  $found = false;
3710  while ($buf = gzgets($zp, 4096)) {
3711 
3712  if (trim($buf) == $stId) {
3713  $found = true;
3714  break;
3715  }
3716  }
3717  if ($found == false) {
3718  $stmnterrmsg = "Bad cookie data, no matching period found using value for: st_id";
3719  $stmnterrlog = fopen("$stmntTmp/statement_retrieve_failure.log", "a");
3720  chmod("$stmntTmp/statement_retrieve_failure.log", 0666);
3721  $stmnterrtime = time();
3722  $stmntexternalref = "";
3723  fwrite($stmnterrlog, implode("\t", array($stmnterrtime, date('Y-m-d_H:i:s', $stmnterrtime), getmypid(), "cu_data.i:Create_PDF_Statement", $CHome, $Cn, $stmntexternalref, $stId, $stmnterrmsg)) . "\n");
3724  fclose($stmnterrlog);
3725  }
3726 
3727  $pdfExternal = "";
3728  $pdfMissing = "";
3729  $txtExternal = "";
3730  $txtMissing = "";
3731  $txtInternal = "";
3732  if ($found) {
3733  $myPID = getmypid();
3734  $fpCommandFile = fopen("$stmntTmp/t$myPID", "wb");
3735 
3736  if ($fpCommandFile) {
3737 
3738  $statementCore = "";
3739  // output until end of the statement and close it.
3740  // if determine PDF already created leave early
3741  while ($buf = gzgets($zp, 4096)) {
3742  if (trim($buf) == $stId) {
3743  break;
3744  }
3745 
3746  // see if the pdf has already been generated
3747  if (preg_match("/^DMS PDF:/", $buf)) {
3748  $pdfExternal = true;
3749  $txtInternal = "";
3750  break;
3751  }
3752 
3753  // see if the txt has been externally saved
3754  if (preg_match("/^DMS TXT:/", $buf)) {
3755  $txtExternal = true;
3756  $txtInternal = "";
3757  break;
3758  }
3759  // check for Full-body generation using newer PDF::Create util
3760  if (preg_match("/^DMS~FBG:/", $buf)) {
3761  $txtFBG = true;
3762  // get the filename to read in the existing PDF
3763  preg_match("/^DMS~FBG:(.+)$/", $buf, $matches);
3764  # discard the marker line - the generation scripts trip on it
3765  $buf = substr($buf,strlen($matches[0])+1);
3766  $fbgPDFScript = trim($matches[1]);
3767  # drop the ending backtic
3768  $fbgPDFScript = substr($fbgPDFScript,0,strlen($fbgPDFScript)-1);
3769  # if script isn't specified, set a default
3770  if (empty($fbgPDFScript)) {
3771  $fbgPDFScript = "/home/$CHome/bin/pdfFBG.pl";
3772  }
3773  }
3774 
3775  if (preg_match("/^DMS~XML:/", $buf)) {
3776  $txtFBG = true;
3777  $pythonUserWarningFlag = true;
3778  // get the filename to read in the existing PDF
3779  preg_match("/^DMS~XML:(.+)$/", $buf, $matches);
3780  # discard the marker line - the generation scripts trip on it
3781  $buf = substr($buf,strlen($matches[0])+1);
3782  $fbgPDFScript = trim($matches[1]);
3783  # drop the ending backtic
3784  $fbgPDFScript = substr($fbgPDFScript,0,strlen($fbgPDFScript)-1);
3785  # if script isn't specified, set a default
3786  if (empty($fbgPDFScript)) {
3787  $fbgPDFScript = "/usr/local/bin/xmlestatement_generate_otf -dl -b /home/" . strtolower($Cu) . " OnTheFly " . strtoupper($Cu) . " pb";
3788  }
3789  }
3790 
3791  $statementCore .= $buf;
3792  $txtInternal = true;
3793  }
3794 
3795  gzclose($zp);
3796 
3797  if ($pdfExternal) {
3798 
3799  // get the filename to read in the existing PDF
3800  preg_match("/^DMS PDF:(.+)$/", $buf, $matches);
3801  $retrieveFromS3 = false;
3802  $s3Presign = false;
3803 
3804 
3805  $externalPDFRef = trim($matches[1]);
3806  $externalPDFFileName = $stmntBaseDir . trim($matches[1]);
3807 
3808  if (is_readable($externalPDFFileName)) {
3809  $fileContents = file_get_contents($externalPDFFileName);
3810  if ($fileContents == "") {
3811  $retrieveFromS3 = true;
3812  $fileContents = data_from_EStateGet($externalPDFFileName, $presignurl=$s3Presign);
3813  }
3814  } else {
3815  $retrieveFromS3 = true;
3816  $fileContents = data_from_EStateGet($externalPDFFileName, $presignurl=$s3Presign);
3817  }
3818  if ($fileContents == "") {
3819  $errors[] = $pMC->msg('Statement Not Found');
3820  $pdfMissing = true;
3821  $stmnterrmsg = "Failed reading (local and S3) file: $externalPDFFileName";
3822  $stmnterrlog = fopen("$stmntTmp/statement_retrieve_failure.log", "a");
3823  chmod("$stmntTmp/statement_retrieve_failure.log", 0666);
3824  $stmnterrtime = time();
3825  $stmntexternalref = $externalPDFRef;
3826  fwrite($stmnterrlog, implode("\t", array($stmnterrtime, date('Y-m-d_H:i:s', $stmnterrtime), getmypid(), "cu_data.i:Create_PDF_Statement", $CHome, $Cn, $stmntexternalref, $stId, $stmnterrmsg)) . "\n");
3827  fclose($stmnterrlog);
3828  } else {
3829  if ($s3Presign && $retrieveFromS3) {
3830  header("Location: " . $fileContents);
3831  } else {
3832  header("Content-type: application/pdf"); // add here more headers for diff. extensions
3833  header("Content-Disposition: inline; filename=\"statement.pdf\""); // use 'attachment' to force a download
3834  header('Content-Transfer-Encoding: binary');
3835  print $fileContents;
3836  }
3837  }
3838  }
3839 
3840  if ($txtExternal) {
3841 
3842  // get the filename to read for external TXT data
3843  preg_match("/^DMS TXT:(.+)$/", $buf, $matches);
3844 
3845  $externalTXTRef = trim($matches[1]);
3846  $externalTXTFileName = $stmntBaseDir . trim($matches[1]);
3847 
3848  if (is_readable($externalTXTFileName)) {
3849  $statementCore = file_get_contents($externalTXTFileName);
3850  if ($statementCore == "") {
3851  $statementCore = data_from_EStateGet($externalTXTFileName);
3852  }
3853  } else {
3854  $statementCore = data_from_EStateGet($externalTXTFileName);
3855  }
3856  if ($statementCore == "") {
3857  $errors[] = $pMC->msg('Statement Not Found');
3858  $txtMissing = true;
3859  $stmnterrmsg = "Failed reading (local and S3) file: $externalTXTFileName";
3860  $stmnterrlog = fopen("$stmntTmp/statement_retrieve_failure.log", "a");
3861  chmod("$stmntTmp/statement_retrieve_failure.log", 0666);
3862  $stmnterrtime = time();
3863  $stmntexternalref = $externalTXTRef;
3864  fwrite($stmnterrlog, implode("\t", array($stmnterrtime, date('Y-m-d_H:i:s', $stmnterrtime), getmypid(), "cu_data.i:Create_PDF_Statement", $CHome, $Cn, $stmntexternalref, $stId, $stmnterrmsg)) . "\n");
3865  fclose($stmnterrlog);
3866  }
3867  }
3868 
3869  if ($txtInternal == true || ( $txtExternal == true && $txtMissing != true )) {
3870  /*
3871  * mws - Moved this code to the else statement.
3872  * The pdfdefs file will NOT exist for CUs that have PDFs created already.
3873  * So we don't read until we know this is a pdf we build
3874  * Adding logic to verify the file can be read to prevent any problems
3875  * trying to read a file that does NOT exist
3876  */
3877  // copy the defs for the CU
3878  if (is_readable($pdfDefsFile) && $txtFBG != true) {
3879  $defsFile = file_get_contents($pdfDefsFile);
3880  } else {
3881  $defsFile = false;
3882  }
3883  if ($defsFile !== false) {
3884  fwrite($fpCommandFile, $defsFile);
3885  }
3886 
3887  // create the rest of the PDF build commands
3888  fwrite($fpCommandFile, $statementCore);
3889 
3890  if (strlen($disclaimerFile) > 0 && is_readable($disclaimerFile) && $txtFBG != true) {
3891  $disclaimerFileContents = file_get_contents($disclaimerFile);
3892  }
3893  if ($defsFile !== false)
3894  fwrite($fpCommandFile, $disclaimerFileContents);
3895 
3896  fclose($fpCommandFile);
3897 
3898  if ($txtFBG == true) {
3899  list($Tscript,$Topts) = explode(' ', $fbgPDFScript, 2);
3900  if (!is_executable("$Tscript")) {
3901  $errors[] = $pMC->msg('Feature Not Set') . ' (missing script)';
3902  }
3903  }
3904  if (count($errors) == 0) {
3905  // now, generate the PDF using the PDF writer
3906  // NOTE: Since this may have binary data it needs to be output directly to the browser
3907  header("Content-type: application/pdf"); // add here more headers for diff. extensions
3908  header("Content-Disposition: inline; filename=\"statement.pdf\""); // use 'attachment' to force a download
3909  header('Content-Transfer-Encoding: binary');
3910 
3911  if ($txtFBG == true) {
3912  if ($pythonUserWarningFlag) {
3913  passthru("python3 -W ignore::UserWarning $fbgPDFScript $stmntTmp/t$myPID -");
3914  } else {
3915  passthru("$fbgPDFScript $stmntTmp/t$myPID");
3916  }
3917  } else {
3918  passthru("/opt/odyssey/tools/bin/pdffile.cgi $stmntTmp/t$myPID -");
3919  }
3920  }
3921  }
3922  // remove the temp file
3923  unlink("$stmntTmp/t$myPID");
3924  }
3925  } else {
3926  $errors[] = $pMC->msg('Statement Not Found');
3927  }
3928  } else {
3929  // if no statement history flag as an error
3930  $errors[] = $pMC->msg('Statement Missing');
3931  }
3932  }
3933 
3934  if (count($errors)) {
3935  $stmt["status"]["code"] = '999';
3936  $stmt["status"]["severity"] = 'Error';
3937  $stmt["estmt"]["stId"] = "$stId";
3938  $stmt["errors"] = $errors;
3939  $stmt["estmt"]["contents"] = "";
3940  } else {
3941  $stmt["status"]["code"] = '0';
3942  $stmt["status"]["severity"] = 'INFO';
3943  }
3944 
3945  return $stmt;
3946 }
3947 
3948 function data_from_EStateGet( $EStateGet_file, $presignurl=false ) {
3949 
3950  $EStateGet_data = "";
3951 
3952  $cmd = "/opt/odyssey/tools/bin/EStateGetFromS3.py -f " . $EStateGet_file;
3953  if ($presignurl) {
3954  $cmd .= " " . "-p";
3955  }
3956 
3957  $EStateGet_fd = popen($cmd, 'r');
3958  while ($EStateGet_buf = fread($EStateGet_fd,2096)){
3959  $EStateGet_data .= $EStateGet_buf;
3960  }
3961  pclose($EStateGet_fd);
3962  return $EStateGet_data;
3963 }
3964 
3965 
3966 /**
3967  *
3968  * @param integer $p_dbh - handle to the current connection of the database
3969  * @param class $p_hb_env - Current HB_ENV array, by reference
3970  * @param class $p_mc - Current object for MC Language class
3971  * @param string $p_device - {M,R,C,D,P}Pass in the device type
3972  * M - Mobile Device
3973  * R - Responsive (Updated Mobile) Device
3974  * C - Classic device
3975  * P - Iphone App Device
3976  * D - Desktop (NEW) Presentation
3977  * @param string $p_noticefor - This field will be used when we want to retrieve notices
3978  * - for a script. BLANK if no notice to be retrieved
3979  * {S, M, B, Disclaimer Name)
3980  * S - To Retrieve ALL Surveys ONLY
3981  * M - To Retrieve ALL Marketing Messages ONLY
3982  * B - To Retrieve ALL Survey/Marketing
3983  * Otherwise, if a value is sent, I will send that to the
3984  * disclaimer notice function
3985  *
3986  * @param int $p_fulldetail - {0,1} - Defaults to FULL DETAIL (1)
3987  * 0 - Do not include the notice_text in the returned array (useful for save operations)
3988  * 1 - INCLUDE the notice TEXT in notice_text
3989  * @param int $p_noticeid- This is if I want a SPECIFIC noticeid loaded (for survey/marketing messages)
3990  * @return
3991  *
3992  * Returns an array
3993  *
3994  * HB_ENV options -- There are options that can be set in HB_ENV to suppress certain
3995  * types of messages to retrieve. By default all messages are retrieved
3996  * To suppress a type of message, set the following value to TRUE to suppress
3997  * the corresponding message
3998  * messageSuppressPromo - Suppreses Promo Message
3999  * messageSuppressSurvey - Suppress Popup Survey Message
4000  * messageSuppressMsg - Suppress Popup ONLY Marketing Message
4001  * (Emebedded will still be retrieved)
4002  *
4003  *
4004  * [popup]
4005  * [id]
4006  * [type]
4007  *
4008  * [notice]
4009  * [mode]
4010  * [link_target]
4011  * [link_text]
4012  *
4013  *
4014  *
4015  * ALL NOTICE TYPES Return the following array structure
4016  * [status]
4017  * [code] HB Standard codes 000 success, 999 error
4018  * [severity] {SUCCESS, ERROR}
4019  * [errors] List of errors if any exist
4020  * [notice]
4021  * * This is a numerically indexed array containing the following fields
4022  * [notice_type] {N,S,M,C} - The type of notice
4023  * N - Screen notice, often a disclosure
4024  * S - Survey notice
4025  * M - Marketing Message
4026  * B - Both (Marketing/Survey)
4027  * PROMO - Promo Only
4028  * PRM - Get Promo / Marketing Messages
4029  * PRS - Get Promo / Surveys
4030  * ALL - All (Marketing/Survey/Promo)
4031  * C - CU CMS Fragment
4032  *
4033  * [notice_id] This is a unique value for the particular notice
4034  * * For Survey/Marketing messages, this is the surveyid from the cusurvey table
4035  * * For notices, this is a predetermined constant (NOT the actual filename)
4036  * [notice_text] This is the text of the notice, ONLY returned if p_inctext is set to 1
4037  * [notice_linktarget] This is the link target for the notice, destination for the click
4038  * [notice_linkdisplay] The display value for the link
4039  * [notice_posttarget] This is the expected link to post results to
4040  * [notice_intro] This is the intro message for the notice -- PRIMARILY for survey types (S)
4041  * [notice_title] If a title is being used for displaying the notice, this should be the title being used (optional to show)
4042  * ** NOTE, it is up to the presentation whether or not to show a link
4043  * [notice_msg_tx] This is the msg_tx constant associated with this notice
4044  * [notice_donotshowtext] IF set, this is the text to show on the form, whether to set the option for NOT showing again
4045  * [notice_msg_tx_show] {0,1,2} Does the member get the option for the msg_tx (Which controls a sort of don't show me again)
4046  * 0 - THERE IS NO OPTION for msg_tx. NO HIDDEN OR VISIBLE ENTRY
4047  * 1 - the member should see the Don't Show Me Again option (use the notice_donotshowtext for display value)
4048  * 2 - The member should NOT see the don't show me again option, so this would be a hidden value in most html
4049  * ** FOR both options of notice_msg_tx_show, the returned value should be 1
4050  * ** THE NAME OF THE FIELD IS {notice_msg_show}
4051  * [notice_msg_tx_perm] {1,0} Does the msg_tx constant affect the Ticket ONLY (0) or does it also affect the cuusers table (1)
4052  * 0 - ONLY the Ticket will be updated for the member, no saving to cuusers table
4053  * 1 - Update the Member Ticket as well as the cuusers table
4054  * [notice_popup] Should the message be automatically popped up?
4055  *
4056  * [notice_answertype] {O, M}
4057  * O - The member may select ONLY ONE answer from the provided list
4058  * M - The member may select ONE OR MORE from the provided list
4059  * * Using the option "M", we can trick marketing messages into showing a 'Don't Show Me Again Option'
4060  * [notice_suppressresponse] {Y, N}
4061  * Y - This type of notice will have a response when Update_NoticeInfo is called. A copy of the notice structure
4062  * will be returned in [response][notice_results]
4063  * N - This type of notice will have NO response and the platform should just close action
4064  * [notice_answervotes_ttl The total number of votes cast for any notice (That has answers) APPLIES to SURVEY TYPES
4065  * [notice_answervotes_ttldisplay] The label for the total votes
4066  * ** For certain notices, the member will have answers they can submit back to the server
4067  * [notice_answers][] Array of the following structure
4068  * [answer_id] The Answerid from the cusurveydetail (for surveys) .. Marketing messages will use
4069  * [answer_text] The display text for the answer
4070  * [answer_votes] The number of votes cast for an answer
4071  * [answer_pct] The percentage of votes from the TOTAL cast for this answer
4072  * ** NOTE: The name of answers when they are posted back to the server should ALWAYS BE "notice_answer_{answer_id}"
4073  *
4074  *
4075  */
4076 function Get_NoticeInfo($p_dbh, $p_hb_env, $p_mc, $p_device, $p_noticefor, $p_fulldetail = 1, $p_noticeid = -1) {
4077 
4078  $retStatus_ary = Array('status' => Array('code'=>'000', 'severity'=>'SUCCESS', 'errors' => Array()), 'notice' => Array());
4079 
4080  switch ($p_noticefor) {
4081  case 'ALL':
4082  case 'PROMO':
4083  // ** For these two types, ALSO include the PROMO messages
4084  if (!array_key_exists('messageSuppressPromo', $p_hb_env) || !$p_hb_env['messageSuppressPromo']) {
4085  $HBPromoMsg_ary = Get_CMSFragFile($p_dbh, $p_hb_env, $p_mc, $p_device, $p_noticefor, $p_fulldetail, $p_noticeid);
4086  if ($HBPromoMsg_ary['status']['code'] == '000') {
4087  // NO ERRORS
4088  if (count($HBPromoMsg_ary['notice']) > 0) {
4089  // ** Add the notices I found to the array
4090  $retStatus_ary['notice'] = array_merge($retStatus_ary['notice'], $HBPromoMsg_ary['notice']);
4091  }
4092  }
4093  }
4094  if ($p_noticefor == 'PROMO') {
4095  break;
4096  } else {
4097  $p_noticefor = 'B';
4098  }
4099  case 'M':
4100  case 'S':
4101  case 'B':
4102  // ** LOOKUP ANY SURVEY / MARKETING
4103  $HBSurveyMsg_ary = Get_HBSurveyMsg($p_dbh, $p_hb_env, $p_mc, $p_device, $p_noticefor, $p_fulldetail, $p_noticeid);
4104  if ($HBSurveyMsg_ary['status']['code'] == '000') {
4105  // NO ERRORS
4106  if (count($HBSurveyMsg_ary['notice']) > 0) {
4107  // ** Add the notices I found to the array
4108  $retStatus_ary['notice'] = array_merge($retStatus_ary['notice'], $HBSurveyMsg_ary['notice']);
4109  }
4110  }
4111  break;
4112  case 'transfer':
4113  case 'estatement':
4114  // ** LEGACY fragment version
4115  // ** LOOKUP ANY NOTICE INFORMAITON
4116  // ** ONLY Look for file notification IF we did not look for a specific notice
4117  if ($p_noticefor != '' && $p_noticeid == -1) {
4118  $NoticeStatus_ary = Get_HBNoticeFile($p_hb_env, $p_mc, $p_device, $p_noticefor, $p_fulldetail);
4119 
4120  if ($NoticeStatus_ary['status']['code'] == '000') {
4121  // ** We have notices.. Send back information here
4122  if (count($NoticeStatus_ary['notice']) > 0) {
4123  // ** return the information -- 1 should all that is returned anyways...
4124  //$retStatus_ary['notice'][] = $NoticeStatus_ary['notice'];
4125  $retStatus_ary['notice'] = array_merge($retStatus_ary['notice'], $NoticeStatus_ary['notice']);
4126  }
4127  }
4128 
4129  }
4130  break;
4131  case 'updatecms':
4132  case 'viewcms':
4133  case 'loadcms':
4134  // * *USED TO LOOKUP A SPECIFIC CMS DOC ID
4135  default:
4136  //
4137  if ($p_noticefor != '') {
4138  $NoticeStatus_ary = Get_CMSFragFile($p_dbh, $p_hb_env, $p_mc, $p_device, $p_noticefor, $p_fulldetail, $p_noticeid);
4139  if ($NoticeStatus_ary['status']['code'] == '000') {
4140  // ** We have notices.. Send back information here
4141  if (count($NoticeStatus_ary['notice']) > 0) {
4142  // ** return the information -- 1 should all that is returned anyways...
4143  $retStatus_ary['notice'] = array_merge($retStatus_ary['notice'], $NoticeStatus_ary['notice']);
4144  }
4145  }
4146  }
4147 
4148  }
4149  return $retStatus_ary;
4150 }
4151 
4152 
4153 /**
4154  *
4155  * @param integer $p_dbh - handle to the current connection of the database
4156  * @param array $p_hb_env -- Current array for HB_ENV
4157  * REQUIRED
4158  * Cu - Credit Union Code
4159  * Cn - Member Number
4160  * chome - Credit union home directory
4161  * Flang - Current Language setting
4162  * homebankingpath - The path to the hcubin for current cu
4163  * loginpath - directory where current platform login script exists
4164  * @param class $p_mc -- This is the current object for MC Language
4165  * @param string $p_device -- Pass in the device type, ** NOTE - NOT USED AT THIS TIME
4166  * @param string $p_noticefor -- This is the "form" I want to lookup if it has a notice
4167  * ALSO - Can be either updatecms or viewcms
4168  * updatecms - This is used to lookup a document
4169  * for the purpose of updating the cucmsresponse
4170  * table. The p_noticeid must be entered with the docsid
4171  * viewcms - This is used to lookup a document
4172  * for the purpose of viewing.
4173  * It will not worry about if the member responded.
4174  * The p_noticeid must be entered with the docsid
4175  * loadcms - The purpose of this option (should be last)
4176  * is to allow the loading of a CMS document by
4177  * docid, but then load all parameters, not just
4178  * the notice_text
4179  * @param integer $p_inctext -- {0, 1}
4180  * 0 - do not return the file contents
4181  * 1 - return the file contents in the field notice_text
4182  * @return array
4183  * Structure follows:
4184  *
4185  * Returns the following array structure
4186  * [status]
4187  * [code] HB Standard codes 000 success, 999 error
4188  * [severity] ** DEPRECATED -- NO LONGER USED
4189  * [errors] List of errors if any exist
4190  * [notice]
4191  * ** RETURNS ARRAY AS DEFINED BY Get_NoticeInfo
4192  *
4193  * Fragment files are a predetermined script. If it is NOT found then there is nothing to display
4194  *
4195  */
4196 function Get_CMSFragFile($p_dbh, $p_hb_env, $p_mc, $p_device, $p_noticefor, $p_inctext, $p_noticeid = -1) {
4197  $retStatus_ary = Array('status' => Array('code'=>'000', 'errors' => Array()), 'notice' => Array());
4198 
4199  $tmp_Notices_tmpl = Array(
4200  "notice_type"=>"",
4201  "notice_subtype" => "",
4202  "notice_id" => "",
4203  "notice_text" => "",
4204  "notice_linktarget" => "",
4205  "notice_linkdisplay" => "",
4206  "notice_posttarget" => "",
4207  "notice_intro" => "",
4208  "notice_title" => "",
4209  "notice_msg_tx" => "",
4210  "notice_donotshowtext" => "",
4211  "notice_msg_tx_show" => "",
4212  "notice_msg_tx_perm" => "",
4213  "notice_popup" => 0,
4214  "notice_answertype" => "",
4215  "notice_positive_caption" => "",
4216  "notice_negative_caption" => "",
4217  "notice_answers" => Array()
4218  );
4219  $tmp_Notices = Array();
4220  $tmp_Answers_tmpl = Array (
4221  "answer_id" => "",
4222  "answer_text" => ""
4223  );
4224 
4225  $tmp_Answer = Array();
4226 
4227  $tmp_ViewNotice = Array(
4228  "docsid" => '',
4229  "Cu" => '',
4230  "chome" => '',
4231  "device" => '',
4232  "Flang" => ''
4233  );
4234 
4235 
4236  /* **
4237  * Setup default values for the string replace for custom content
4238  * these values -- If any of these values are already set, then use those values
4239  * **
4240  */
4241  $defaultStrReplace = Array("CULOGIN" => strtolower($p_hb_env['Cu']),
4242  "CUNAME" => HCU_array_key_exists("orgname", $p_hb_env) ? trim($p_hb_env['orgname']) : "",
4243  "CUSERVER" => HCU_array_key_exists("cuhost", $p_hb_env) ? $p_hb_env['cuhost'] : "",
4244  "DBPREFIX" => $p_hb_env['Cu'],
4245  "HCUDIR" => 'banking'
4246  );
4247 
4248  if ( !is_array( HCU_array_key_value( "noticeStrReplace", $p_hb_env ) ) ) {
4249  // ** Use the defaults
4250  $p_hb_env['noticeStrReplace'] = $defaultStrReplace;
4251 
4252  } else {
4253  // ** Merge the arrays together
4254  $p_hb_env['noticeStrReplace'] = array_merge($defaultStrReplace, $p_hb_env['noticeStrReplace']);
4255  }
4256 
4257  // * A generic updatecms was created -- When this is used in conjunction with
4258  // * a notice_id, it will lookup a specific record based on docs id rather
4259  // * than the docsname
4260  if ($p_noticefor === 'updatecms') {
4261  $accountnumber = HCU_array_key_value("notice_accountnumber", $p_hb_env["HCUPOST"]);
4262  $sql = "SELECT cucmsdocs.docsid, cucmsdocs.docsname, cucmsdocs.docsdesc,
4263  cucmsdocs.docsdefaultavail, cucmsdocs.docsresponsetype,
4264  cucmsdocs.docsdisplaytext, cucmsdocs.docsdisplaylink,
4265  cucmsfrags.cu, cucmsfrags.fragusedefault, cucmsfrags.fraguselink,
4266  cucmsfrags.fragclearresponse, coalesce((SELECT 'Y'
4267  FROM cucmsresponse
4268  WHERE cu = '" . prep_save($p_hb_env['Cu'], 10) . "' AND user_id = {$p_hb_env['Uid']}
4269  " . ($accountnumber === false ? "" : "AND trim(accountnumber) = '" . prep_save(trim($accountnumber), 12) . "'") . "
4270  AND cucmsresponse.docsid = cucmsdocs.docsid)::text, 'N') as responseexists
4271  FROM cucmsfrags
4272  JOIN cucmsdocs on cucmsdocs.docsid = cucmsfrags.docsid
4273  WHERE cucmsdocs.docsid = '" . intval($p_noticeid) . "'
4274  AND cucmsfrags.cu = '" . prep_save($p_hb_env['Cu'], 10) . "'
4275  AND (docsresponsetype = 'N'
4276  OR (fraguselink = 'Y'
4277  OR (docsresponsetype in ('D', 'T', 'F', 'A', 'E', 'P'))
4278  )); ";
4279 
4280  } elseif ($p_noticefor === 'viewcms' || $p_noticefor === 'loadcms') {
4281  $sql = "SELECT cucmsdocs.docsid, cucmsdocs.docsname, cucmsdocs.docsdesc,
4282  cucmsdocs.docsdefaultavail, cucmsdocs.docsresponsetype,
4283  cucmsdocs.docsdisplaytext, cucmsdocs.docsdisplaylink,
4284  cucmsfrags.cu, cucmsfrags.fragusedefault, cucmsfrags.fraguselink,
4285  cucmsfrags.fragclearresponse
4286  FROM cucmsfrags
4287  JOIN cucmsdocs on cucmsdocs.docsid = cucmsfrags.docsid
4288  WHERE cucmsdocs.docsid = '" . intval($p_noticeid) . "'
4289  AND cucmsfrags.cu = '" . prep_save($p_hb_env['Cu'], 10) . "' ";
4290 
4291  } elseif ($p_noticefor == 'ALL' || $p_noticefor == 'PROMO') {
4292  // Promos are also stored in the cucms tables, this query may return
4293  // mutliple records
4294  //
4295  // * ONLY return records that have NOT been responded too
4296 
4297  // * ONLY return records for estatements if the user has access
4298  // * to estatements
4299  $permissionInputs = array( "feature" => FEATURE_ESTATEMENTS );
4300  $permissionEstmt = Perm_AccessRights( $p_dbh, $p_hb_env, $permissionInputs );
4301 
4302 
4303  $Uid = (int) $p_hb_env['Uid'];
4304 
4305  $sql = "
4306  WITH base AS (
4307  SELECT
4308  d.docsid, d.docsname, d.docsdesc, d.docsdefaultavail, d.docsresponsetype, d.docsdisplaytext, d.docsdisplaylink, f.cu, f.fragusedefault, f.fraguselink, f.fragclearresponse, r.responseon
4309  FROM cucmsfrags f
4310  INNER JOIN cucmsdocs d
4311  ON f.docsid = d.docsid
4312  LEFT JOIN cucmsresponse r
4313  ON f.docsid = r.docsid
4314  AND r.cu = f.cu
4315  AND r.user_id = $Uid
4316  WHERE d.docsresponsetype IN ('A', 'E', 'P')
4317  AND (
4318  (f.fragstartdate IS null AND f.fragenddate IS NULL)
4319  OR
4320  (f.fragstartdate > now() AND f.fragenddate <= now())
4321  )
4322  AND f.cu = '{$p_hb_env['Cu']}'
4323  AND r.responseon IS NULL
4324  )";
4325 
4326  $sql .= "SELECT * FROM base b WHERE b.docsresponsetype <> 'E'";
4327 
4328  if ($permissionEstmt['access']) {
4329  $sql .= "
4330  UNION ALL
4331  SELECT b.* FROM base b
4332  INNER JOIN (
4333  SELECT bool_and(COALESCE(estmnt_flag, 'N') <> 'Y') AS estmt_unset
4334  FROM {$p_hb_env['Cu']}memberacct ma
4335  WHERE EXISTS (
4336  SELECT 'FOUND'
4337  FROM {$p_hb_env['Cu']}useraccounts ua
4338  WHERE ma.accountnumber = ua.accountnumber
4339  AND ua.user_id = $Uid)
4340  ) t
4341  ON b.docsresponsetype = 'E'
4342  AND t.estmt_unset";
4343  }
4344  } else {
4345  /*
4346  * Changing the query to now always return the information needed to evaluate
4347  * the Fragment. The following code will decide what to return
4348  *
4349  */
4350  $Uid = (int) HCU_array_key_value( "Uid", $p_hb_env );
4351  $sql = "SELECT cucmsdocs.docsid, cucmsdocs.docsname, cucmsdocs.docsdesc,
4352  cucmsdocs.docsdefaultavail, cucmsdocs.docsresponsetype,
4353  cucmsdocs.docsdisplaytext, cucmsdocs.docsdisplaylink,
4354  cucmsfrags.cu, cucmsfrags.fragusedefault, cucmsfrags.fraguselink,
4355  cucmsfrags.fragclearresponse, cucmsresponse.responseon
4356  FROM cucmsfrags
4357  JOIN cucmsdocs on cucmsdocs.docsid = cucmsfrags.docsid
4358  LEFT JOIN cucmsresponse on cucmsresponse.docsid = cucmsfrags.docsid
4359  AND cucmsresponse.cu = cucmsfrags.cu
4360  AND cucmsresponse.user_id = $Uid
4361  WHERE cucmsdocs.docsname = '" . prep_save($p_noticefor) . "'
4362  AND cucmsfrags.cu = '" . prep_save($p_hb_env['Cu'], 10) . "'; ";
4363  }
4364  // ** Evaluate the records returned. Technically there should only be one record
4365  // * per doc type
4366  $fragRs = db_query($sql, $p_dbh);
4367 
4368  if (db_num_rows($fragRs) > 0) {
4369  $fragIdx = 0;
4370 
4371  // ** Loop through the list of messages, there should be only ONE row
4372  // * for most types, the exception is where the docresponsetype is {A,E,P}
4373  // * this if for Promo messages
4374  while ($fragRow = db_fetch_assoc($fragRs, $fragIdx)) {
4375  // ** Need to reset the Array each time.
4376  $tmp_Notices = $tmp_Notices_tmpl;
4377  $tmp_Notices['notice_type'] = 'C';
4378 
4379  // ** Now Locate the fragment
4380  // Are we using the Default?
4381 
4382  if ($p_inctext == 1) {
4383  // * I should be ALWAYS able to use the cucmsdocs.docsname from the dB
4384  // * it will prevent any issues when I have special code when using viewcms/udpatecms
4385  if ($fragRow['fragusedefault'] == 'Y') {
4386  $fragFileDir= "/home/homecu/public_html/bankingIncludes";
4387  $fragFileName = "skel_" . trim($fragRow['docsname']); // Look for skel_xxx name
4388  } else {
4389  $fragFileDir = "/home/{$p_hb_env['chome']}/public_html/bankingIncludes";
4390  $fragFileName = trim($fragRow['docsname']) . ".html"; // Look for .html as extension
4391  }
4392 
4393  // ** Now decide the language we get
4394  $fragFilePath = '';
4395  if (is_readable($fragFileDir . "/" . $p_hb_env['Flang'] . "/" . $fragFileName)) {
4396  $fragFilePath = $fragFileDir . "/" . $p_hb_env['Flang'] . "/" . $fragFileName;
4397  } else if (is_readable($fragFileDir . "/en_US/" . $fragFileName)) {
4398  $fragFilePath = $fragFileDir . "/en_US/" . $fragFileName;
4399  } else {
4400  // ** NO FILE TO READ
4401  }
4402 
4403  /*
4404  * Setup the tmp_Notices array
4405  */
4406 
4407  // * if a path is set, then load
4408  // ** ONLY include text if it requested
4409  if ($fragFilePath != '' && is_readable($fragFilePath)) {
4410  // ** Set the notice text
4411  $tmp_Notices['notice_text'] = file_get_contents($fragFilePath);
4412 
4413  // see if there are any substitutions for keywords
4414  $substList = HCU_array_key_exists("noticeStrReplace", $p_hb_env) ? $p_hb_env["noticeStrReplace"] : null;
4415 
4416  // Instead of an array with a replace and whatnot, strreplace is a replace pairs whatnot so strtr works for translation.
4417  if (isset($substList) && is_array($substList))
4418  {
4419  $tmp_Notices["notice_text"]= strtr($tmp_Notices["notice_text"], $substList);
4420  }
4421  }
4422  }
4423 
4424  $tmp_Notices['notice_subtype'] = $fragRow['docsresponsetype'];
4425  $tmp_Notices['notice_id'] = $fragRow['docsid'];
4426 
4427  if ($p_noticefor != 'viewcms') {
4428  /*
4429  * Notice Link Information
4430  */
4431  /*
4432  * Create URL Hashed Value for Lookup
4433  */
4434  $tmp_ViewNotice['docsid'] = $fragRow['docsid'];
4435  $tmp_ViewNotice['Cu'] = $p_hb_env['Cu'];
4436  $tmp_ViewNotice['device'] = $p_device;
4437  $tmp_ViewNotice['chome'] = $p_hb_env['chome'];
4438  $tmp_ViewNotice['Flang'] = $p_hb_env['Flang'];
4439 
4440  $encryptedDocDetails= HCU_PayloadEncode($p_hb_env['Cu'], $tmp_ViewNotice);
4441 
4442  // ** Should this ALWAYS LINK to /hcubinX/hcuWebView ?
4443  $tmp_Notices['notice_linktarget'] = $p_hb_env['homebankingpath'] . '/hcuWebView.prg?x=' . urlencode($encryptedDocDetails) . '&cu=' . $p_hb_env['Cu'];
4444 
4445  $tmp_Notices["notice_responseexists"] = HCU_array_key_value("responseexists", $fragRow);
4446 
4447  if ($fragRow['fraguselink'] == 'Y') {
4448  $tmp_Notices['notice_linkdisplay'] = ($fragRow['docsdisplaylink'] == 'Y' ? $p_mc->msg($fragRow['docsdisplaytext']) : '');
4449  }
4450 
4451 
4452  /*
4453  * Notice POSTING Target
4454  */
4455  if ($fragRow['docsresponsetype'] !== 'N') {
4456  // ** If docs responsetype is N, then we do NOT expect any posting for this type
4457  // * of notice
4458 
4459  // ** Depending on Device - the post target is different
4460  switch ($p_device) {
4461  case "D":
4462  // ** Desktop UPGRADE
4463  $tmp_Notices['notice_posttarget'] = $p_hb_env['loginpath'] . "/hcuViewNotice.prg?cu={$p_hb_env['Cu']}";
4464  break;
4465  case "M":
4466  case "R":
4467  // * Mobile Web App
4468  $tmp_Notices['notice_posttarget'] = $p_hb_env['loginpath'] . "/notices?cu={$p_hb_env['Cu']}";
4469  break;
4470  case "P":
4471  // * Native App
4472  $tmp_Notices['notice_posttarget'] = $p_hb_env['loginpath'] . "/notices?cu={$p_hb_env['Cu']}";
4473  break;
4474  case "C":
4475  // * Classic
4476  $tmp_Notices['notice_posttarget'] = $p_hb_env['loginpath'] . "/hcuViewNotice.prg?cu={$p_hb_env['Cu']}";
4477  break;
4478  }
4479 
4480  }
4481 
4482  $tmp_Notices['notice_intro'] = '';
4483  $tmp_Notices['notice_title'] = '';
4484 
4485  // msg_tx setup - NOT USED FOR THESE types
4486  if (in_array($fragRow['docsresponsetype'], Array('A', 'E', 'P'))) {
4487  $tmp_Notices['notice_msg_tx'] = 16384;
4488  } else {
4489  $tmp_Notices['notice_msg_tx'] = '';
4490  }
4491  $tmp_Notices['notice_msg_tx_show'] = '';
4492  $tmp_Notices['notice_donotshowtext'] = '';
4493 
4494  //** notice_popup - If they are required to answer then this
4495  // will be a popup
4496  if (HCU_array_key_value('responseon', $fragRow) == '' && in_array($fragRow['docsresponsetype'], Array('D', 'T', 'A', 'E', 'P'))) {
4497  // * If the response portion is blank, then I want to trigger as popup
4498  // * IF the type is a TERMS or DISCLOSURE
4499  if (HCU_array_key_exists("Fmsg_tx", $p_hb_env) && (($p_hb_env['Fmsg_tx'] & $tmp_Notices['notice_msg_tx']) == 0 )) {
4500  // This notice should be seen as a pop-up
4501  $tmp_Notices['notice_popup'] = 1;
4502  }
4503  }
4504  $tmp_Notices['notice_answertype'] = 'M';
4505  $tmp_Notices['notice_suppressresponse'] = 'Y';
4506 
4507 
4508  if ($fragRow['docsresponsetype'] == 'T') {
4509  $tmp_Answer = $tmp_Answers_tmpl;
4510  // Use Docs ID for answer
4511  $tmp_Answer['answer_id'] = $fragRow['docsid'];
4512  $tmp_Answer['answer_text'] = $p_mc->msg('I Accept the Terms');
4513 
4514  $tmp_Notices['notice_answers'][] = $tmp_Answer;
4515 
4516  // ** SET the Positive (Accept) / Negative (Decline) Text
4517  $tmp_Notices['notice_positive_caption'] = $p_mc->msg('Accept');
4518  $tmp_Notices['notice_negative_caption'] = $p_mc->msg('Cancel');
4519  // neutral is for notice-only display
4520  $tmp_Notices['notice_neutral_caption'] = $p_mc->msg('Close');
4521  } else if (in_array($fragRow['docsresponsetype'], Array('D', 'A', 'E', 'P'))) {
4522  $tmp_Answer = $tmp_Answers_tmpl;
4523  // Use Docs ID for answer
4524  $tmp_Answer['answer_id'] = $fragRow['docsid'];
4525  $tmp_Answer['answer_text'] = $p_mc->msg('Dont Tell Me Again');
4526 
4527  $tmp_Notices['notice_answers'][] = $tmp_Answer;
4528 
4529  // ** For Disclosures, ONLY send positive button
4530  // As of 10/29/14 send "Close" for estatement promos
4531  $tmp_Notices['notice_positive_caption'] = $fragRow['docsresponsetype'] == "E" ? $p_mc->msg('Close') : $p_mc->msg('Continue');
4532  // neutral is for notice-only display
4533  $tmp_Notices['notice_neutral_caption'] = $p_mc->msg('Close');
4534  } else {
4535  // currently (12/16/2013) this is the Notice only case
4536  // ** ELSE send a Close for the button
4537  $tmp_Notices['notice_neutral_caption'] = $p_mc->msg('Close');
4538  }
4539  }
4540 
4541  // ** Never add anything to the fragment, that is up to the presentation
4542  // ** ONLY Return the
4543  $retStatus_ary['notice'][$fragIdx] = $tmp_Notices;
4544  $fragIdx++;
4545  }
4546  } else {
4547  // ** NO Records to be found
4548  // ** Set status to 999 ??
4549 
4550  }
4551 
4552  return $retStatus_ary;
4553 }
4554 
4555 
4556 /**
4557  *
4558  * @param array $p_hb_env -- Current array for HB_ENV
4559  * @param class $p_mc -- This is the current object for MC Language
4560  * @param string $p_device -- Pass in the device type, ** NOTE - NOT USED AT THIS TIME
4561  * @param string $p_noticefor -- This is the "form" I want to lookup if it has a notice
4562  * @param integer $p_inctext -- {0, 1}
4563  * 0 - do not return the file contents
4564  * 1 - return the file contents in the field notice_text
4565  * @return array
4566  * Structure follows:
4567  *
4568  * Returns the following array structure
4569  * [status]
4570  * [code] HB Standard codes 000 success, 999 error
4571  * [severity] {SUCCESS, ERROR}
4572  * [errors] List of errors if any exist
4573  * [notice]
4574  * ** RETURNS ARRAY AS DEFINED BY Get_NoticeInfo
4575  *
4576  * Notices are a predetermined script. If it's not one of the predetermined, then do NOT allow
4577  */
4578 function Get_HBNoticeFile($p_hb_env, $p_mc, $p_device, $p_noticefor, $p_inctext) {
4579 // ** This will either return the text or a link. This is pulled out from the other
4580  // ** Function to all
4581 
4582  $retStatus_ary = Array('status' => Array('code'=>'000', 'severity'=>'SUCCESS', 'errors' => Array()), 'notice' => Array());
4583 
4584  $tmp_Notices = Array(
4585  "notice_type"=>"",
4586  "notice_id" => "",
4587  "notice_text" => "",
4588  "notice_linktarget" => "",
4589  "notice_linkdisplay" => "",
4590  "notice_posttarget" => "",
4591  "notice_intro" => "",
4592  "notice_title" => "",
4593  "notice_msg_tx" => "",
4594  "notice_donotshowtext" => "",
4595  "notice_msg_tx_show" => "",
4596  "notice_msg_tx_perm" => "",
4597  "notice_popup" => 0,
4598  "notice_answertype" => "",
4599  "notice_answers" => Array()
4600  );
4601 
4602  // ** First check if the noticefor is set.. IF NOT THEN EXIT
4603  $tmp_Notices['notice_type'] = 'N';
4604  $tmp_Notices['notice_id'] = $p_noticefor;
4605 
4606  $notice_link = '';
4607  if ($p_noticefor != '') {
4608  $notice_filename = "";
4609 
4610  switch ($p_noticefor) {
4611  case "transfer":
4612  switch ($p_device) {
4613  case 'P':
4614  case 'M':
4615  case 'R':
4616  $notice_filename = "mblTransfer";
4617  break;
4618  case 'C':
4619  $notice_filename = "Transfer";
4620  break;
4621  }
4622  $tmp_Notices['notice_msg_tx'] = 1;
4623  $tmp_Notices['notice_msg_tx_show'] = 1;
4624  $tmp_Notices['notice_msg_tx_perm'] = 1;
4625  $tmp_Notices['notice_linkdisplay'] = $p_mc->msg('Transfer Notices');
4626  $tmp_Notices['notice_donotshowtext'] = $p_mc->msg('Dont Tell Me Again');
4627  $tmp_Notices['notice_title'] = $p_mc->msg('Transfer Notices');
4628  break;
4629  case "estatement":
4630  switch ($p_device) {
4631  case 'P':
4632  case 'M':
4633  case 'R':
4634  $notice_filename = "mblEStatement";
4635  break;
4636  case 'C':
4637  $notice_filename = "EStatement";
4638  break;
4639  }
4640  $tmp_Notices['notice_msg_tx'] = 2;
4641  $tmp_Notices['notice_msg_tx_show'] = 1;
4642  $tmp_Notices['notice_msg_tx_perm'] = 1;
4643  $tmp_Notices['notice_donotshowtext'] = $p_mc->msg('Dont Tell Me Again');
4644  $tmp_Notices['notice_linkdisplay'] = $p_mc->msg('E-Statement Message');
4645  $tmp_Notices['notice_title'] = $p_mc->msg('Message');
4646  break;
4647  default:
4648  $retStatus_ary['status']['code'] = '999';
4649  $retStatus_ary['status']['severity'] = 'ERROR';
4650  $retStatus_ary['status']['errors'][] = 'Unknown notice parameter';
4651 
4652  // ** IMMEDIATELY RETURN -- NO SENSE BEING HERE
4653  return $retStatus_ary;
4654  }
4655 
4656  // ** Fragment Directory
4657  $fragdir = "/home/{$p_hb_env['chome']}/public_html/";
4658  $fragfile = $notice_filename;
4659  // ** Fragment File Language Extension
4660  $fragext = (trim($p_hb_env['Flang']) == "en_US" ? "" : "_" . substr($p_hb_env['Flang'], 0,strpos($p_hb_env['Flang'],"_")) );
4661  $fragfilename = ($fragext > "" && is_readable("{$fragdir}{$fragfile}{$fragext}.html") ? "{$fragfile}{$fragext}.html" : "{$fragfile}.html");
4662 
4663  // ** reset the fragment file to be the Directory/Filename
4664  $fragfile = $fragdir . $fragfilename;
4665 
4666  if (is_readable($fragfile)) {
4667  $notice_link = $p_hb_env['loginpath'] . "/notices?cu={$p_hb_env['Cu']}&Flang={$p_hb_env['Flang']}";
4668 
4669  if ($p_inctext == 1) {
4670  $tmp_Notices['notice_text'] = file_get_contents($fragfile);
4671  }
4672 
4673  } else {
4674  $retStatus_ary['status']['code'] = '999';
4675  $retStatus_ary['status']['severity'] = 'ERROR';
4676  $retStatus_ary['status']['errors'][] = 'Unable to read notice file.';
4677  }
4678 
4679  // ** Build the notices array
4680  if ($notice_link != '') {
4681  // ** FOR DIRECT LINK -- WE WILL add an option to end for VIEWING
4682  // * Add the options for viewing
4683  $notice_param = "&notice_type=N&notice_id={$p_noticefor}&notice_device={$p_device}";
4684  // ** If need be we can later allow different platform/devices link to different places
4685  //$tmp_Notices['notice_linktarget'] = $notice_Link . $notice_param;
4686  $tmp_Notices['notice_linktarget'] = $p_hb_env['cupublic'] . "/" . $fragfilename;
4687 
4688  $tmp_Notices['notice_posttarget'] = $notice_link;
4689  }
4690 
4691  if (($p_hb_env['Fmsg_tx'] & $tmp_Notices['notice_msg_tx']) == 0 ) {
4692  // This notice should be seen as a pop-up
4693  $tmp_Notices['notice_popup'] = 1;
4694  }
4695 
4696  }
4697 
4698  // ** SET the notices in the returned array
4699  $retStatus_ary['notice'][] = $tmp_Notices;
4700 
4701  return $retStatus_ary;
4702 }
4703 
4704 // p_noticefor -- this is to identify the requesting frm
4705 /**
4706  *
4707  * @param integer $p_dbh - handle to the current connection of the database
4708  * @param array $p_hb_env -- Current array for HB_ENV
4709  * @param class $p_mc -- This is the current object for MC Language
4710  * @param string $p_device -- Pass in the device type, ** NOTE - NOT USED AT THIS TIME
4711  * @param string $p_noticefor -- This is the requesting form.. ONLY CERTAIN
4712  * FORMS will return portions of notices
4713  * @param int $p_fulldetail - {0,1} - Defaults to FULL DETAIL (1)
4714  * 0 - Do not include the notice_text in the returned array (useful for save operations)
4715  * 1 - INCLUDE the notice TEXT in notice_text
4716  * @param int $p_noticeid -- This is to specify a CERTAIN notice rather than a random
4717  * -- USEFUL when processing answers
4718  * @param string $p_action - This could be {"SHOW", "RESULTS"}
4719  * SHOW - {DEFAULT} Return the options to SHOW the Message
4720  * RESULTS - This applies only to surveys, but return
4721  * the information for the RESULTS of active surveys
4722 
4723  * SPECIAL HB_ENV PARAMETERS
4724  * messageSuppressSurvey - {true/FALSE} When true -- DO NOT SHOW Surveys in results
4725  * messageSuppressMsg - {true/FALSE} When true -- DO NOT SHOW POPUP MESSAGES - ONLY INCLUDE EMBEDDED
4726 
4727  * @return array
4728  * Returns the following array structure
4729  * [status]
4730  * [code] HB Standard codes 000 success, 999 error
4731  * [severity] {SUCCESS, ERROR}
4732  * [errors] List of errors if any exist
4733  * [notice]
4734  * ** RETURNS ARRAY AS DEFINED BY Get_NoticeInfo
4735  *
4736 
4737  */
4738 function Get_HBSurveyMsg($p_dbh, $p_hb_env, $p_mc, $p_device, $p_noticefor, $p_fulldetail = 1, $p_noticeid = -1, $p_action = "SHOW") {
4739  $retStatus_ary = Array('status' => Array('code'=>'000', 'severity'=>'SUCCESS', 'errors' => Array()), 'notice' => Array());
4740 
4741  $messageSuppressSurvey = (key_exists('messageSuppressSurvey', $p_hb_env) ? $p_hb_env['messageSuppressSurvey'] : false);
4742  $messageSuppressMsg = (key_exists('messageSuppressMsg', $p_hb_env) ? $p_hb_env['messageSuppressMsg'] : false);
4743 
4744  $tmp_Notices = Array();
4745  $tmp_Notices_tmpl = Array(
4746  "notice_type"=>"",
4747  "notice_id" => "",
4748  "notice_text" => "",
4749  "notice_linktarget" => "",
4750  "notice_linkdisplay" => "",
4751  "notice_posttarget" => "",
4752  "notice_intro" => "",
4753  "notice_title" => "",
4754  "notice_msg_tx" => "",
4755  "notice_donotshowtext" => "",
4756  "notice_msg_tx_show" => "",
4757  "notice_msg_tx_perm" => "",
4758  "notice_popup" => 0,
4759  "notice_positive_caption" => "",
4760  "notice_negative_caption" => "",
4761  "notice_answertype" => "",
4762  "notice_answers" => Array()
4763  );
4764 
4765  $tmp_Answers_tmpl = Array (
4766  "answer_id" => "",
4767  "answer_text" => ""
4768  );
4769  $tmp_Answer = Array();
4770  // ** FOR the purpose of fetching the RESULTS of a survey/message.
4771  // ** Add more elements here
4772  if ($p_action == "RESULTS") {
4773  $tmp_Notices_tmpl = array_merge($tmp_Notices_tmpl, Array("notice_suppressresponse" => "", "notice_answervotes_ttl" => "","notice_answervotes_ttldisplay" => ""));
4774  $tmp_Answers_tmpl = array_merge($tmp_Answers_tmpl, Array("answer_votes" => "","answer_pct" => ""));
4775  }
4776 
4777  // preset some options based on if this is for Mobile / Desktop
4778 
4779  // ** Mobile will ALWAYS RETURN ONE ONLY
4780 
4781  // ** DESKTOP will include all??
4782  $sql = "";
4783  $sql_criteria = "";
4784  $sql_employee = "";
4785  if (HCU_array_key_value('employee', $p_hb_env) == 'Y') {
4786  // ** ONLY return results that employees may see
4787  $sql_employee = " AND m.employee = 'Y' ";
4788  }
4789 
4790  $sql_embed = "";
4791  // ** NOT Sure if this is how I want to handle this
4792  if ($p_noticefor != '' && $p_device == 'C') {
4793  // ** ONLY FOR DESKTOP --
4794  // ** Honour the 'include in balances' flag
4795  // ** MOBILE DOES NOT honour this.. It will include them all in the same list
4796  if ($p_noticefor == 'Balances') {
4797  $sql_embed = " AND inc_balances = 'Y' ";
4798  }
4799  } elseif($p_device == 'C') {
4800  // * FOR DESKTOP -- ONLY include if we are
4801  $sql_embed = " AND (inc_balances is null or inc_balances <> 'Y') ";
4802  }
4803 
4804  // ** FOR MOBILE -- IT INCLUDES BOTH TYPE -- BUT EXITS ABOVE IF we are NOT in menu
4805 
4806  // ** SELECT the survey type {S - Survey / M - Marketing Message}
4807  if ($p_noticefor == 'S' && !$messageSuppressSurvey) {
4808  // ** ALL SURVEYS SKIPPED
4809  $sql_criteria .= " AND (surveytype is null or surveytype < 1) ";
4810  } elseif ($p_noticefor == 'M') {
4811  // ** Marketing Message - Check Suppress Value --
4812  // ** IF SUPPRESSED - ONLY show embedded
4813  if ($messageSuppressMsg) {
4814  // ** ONLY SHOW EMBEDDED
4815  $sql_criteria .= " AND (surveytype = 1 AND inc_balances = 'Y') ";
4816  } else {
4817  $sql_criteria .= " AND surveytype = 1 ";
4818  }
4819  } else {
4820  // ** B - BOTH types by default
4821 
4822  if ($messageSuppressMsg && $messageSuppressSurvey) {
4823  // ** BOTH ARE SUPPRESSED -- ONLY SHOW EMBEDDED MESSAGES
4824  $sql_criteria .= " AND (surveytype = 1 AND inc_balances = 'Y') ";
4825  } else {
4826  if ($messageSuppressSurvey) {
4827  // ** ONLY SUPPRESS SURVEY TYPES
4828  $sql_criteria .= " AND (surveytype is not null and surveytype > 0) ";
4829  } elseif ($messageSuppressMsg) {
4830  // ** ONLY SUPPRESS POPUP MSG -- INCLUDE Survey Types and Embedded Messages
4831  $sql_criteria .= " AND ((surveytype is null or surveytype < 1) OR (surveytype = 1 AND inc_balances = 'Y')) ";
4832  }
4833  }
4834  }
4835 
4836 
4837 
4838 
4839  // ** LOOKUP the header information for the notice--this will determine if more than
4840  // * One are being shown
4841 
4842  // ** IF p_noticeid is specified then QUERY THAT ID SPECIFICALLY
4843  // ** OTHERWISE WHERE ANSWER DOES NOT EXIST FOR MEMBER
4844  if ($p_noticeid > 0){
4845  // ** DO NOT INCLUDE DATE CRITERIA -- IF we know the noticeid to lookup
4846  $sql_criteria .= " AND m.surveyid = " . intval($p_noticeid) . " ";
4847  } else {
4848 
4849  $sql_criteria .= "
4850  AND (startdate <= CURRENT_DATE and stopdate >= CURRENT_DATE)
4851  AND NOT EXISTS (
4852  SELECT *
4853  FROM cusurveysays s
4854  WHERE s.surveyid = m.surveyid
4855  AND s.user_id = '{$p_hb_env['Uid']}') ";
4856  }
4857 
4858 
4859  /**
4860  *
4861  * Offset the sql query to the credit unions local time. This will do a better job of
4862  * handling the start/stop date for marketing messages.
4863  * This started to be a problem as the database is running in UTC and we have clients
4864  * in the PACIFIC time zone.
4865  * Use 'SET LOCAL' so the timezone change does not affect other query results.
4866  *
4867  */
4868  $tzOffset = '';
4869  if (HCU_array_key_exists('tz', $p_hb_env) && trim($p_hb_env['tz']) != '') {
4870  $tzOffset = "SET LOCAL TIME ZONE '" . trim($p_hb_env['tz']) . "'; ";
4871  }
4872 
4873  $sql = "
4874  $tzOffset
4875  SELECT m.surveyid, m.qstyle, q.question, m.inc_balances, i.surveyintro , m.surveytype,
4876  m.dontshow, m.surveytitle
4877  FROM cusurveymaster as m
4878  JOIN cusurveyquest as q ON m.surveyid = q.surveyid AND m.cu = q.cu AND q.language = '{$p_hb_env['Flang']}'
4879  LEFT JOIN cusurveyintro as i on i.cu = m.cu AND i.language = '{$p_hb_env['Flang']}'
4880 
4881  WHERE
4882  runstat = 1
4883  AND m.cu='{$p_hb_env['Cu']}'
4884  {$sql_employee}
4885  {$sql_criteria}
4886 
4887  ";
4888  switch ($p_device) {
4889  case 'M':
4890  // ** MOBILE
4891  // ** FOR MOBILE -- COMBINE TOGETHER -- RANDOMLY CHOOSE ONE FROM EITHER TYPE
4892 
4893  $sql .= "
4894  ORDER BY random(), m.surveyid
4895  LIMIT 1
4896  ";
4897  // ** ALWAYS RETURNS ALL -- ORDERED RANDOMLY -- the presentation will decide
4898  // * What to show
4899 
4900 
4901  break;
4902  case 'R':
4903  // ** Responsive Mobile - Return all, the function Return_NoticeDialogs will limit the response
4904  break;
4905  case 'C':
4906  // ** Classic DESKTOP
4907  // ** FOR DESKTOP -- query separately UNION together to create list
4908 
4909  // ** LATER FOR DESKTOP -- WE MAY NEED To accomodate showing results after the
4910  // member has answered the survey, and up to 30 days after the survey has 'stopped'
4911 
4912  break;
4913  case 'P':
4914  $sql .= "
4915  ORDER BY random()
4916  LIMIT 1
4917  ";
4918  default:
4919  }
4920 
4921  if ($sql != '') {
4922  // * We have a query
4923  // * grab the results
4924  $notice_rs = db_query(($sql), $p_dbh);
4925  $notice_idx = 0;
4926  if ($notice_rs) {
4927  // * For Surveys, I will want to grab the answers. I can do that here..
4928  while ($notice_row = db_fetch_assoc($notice_rs, $notice_idx)) {
4929  $tmp_Notices[$notice_idx] = $tmp_Notices_tmpl;
4930 
4931 
4932 
4933  // ** Determine Notice type (S - Survey - M - Marketing Message)
4934  $tmp_Notices[$notice_idx]['notice_type'] = (intval($notice_row['surveytype']) == 1 ? 'M' : 'S');
4935  // ** Set the field surveyid as the notice_id being passed back
4936  $tmp_Notices[$notice_idx]['notice_id'] = $notice_row['surveyid'];
4937  // ** The text is located in the question field
4938  $tmp_Notices[$notice_idx]['notice_text'] = $notice_row['question'];
4939  // ** AT THIS TIME THESE ARE BLANK -- LATER THEY MAY BE direct LINKS to the Survey
4940  $tmp_Notices[$notice_idx]['notice_linktarget'] = "";
4941  $tmp_Notices[$notice_idx]['notice_linkdisplay'] = "";
4942 
4943  // * Record WHERE to post the answers
4944  if ($p_device == 'D') {
4945  $tmp_Notices[$notice_idx]['notice_posttarget'] = $notice_link = $p_hb_env['loginpath'] . "/hcuViewNotice.prg?cu={$p_hb_env['Cu']}";
4946  } else {
4947  $tmp_Notices[$notice_idx]['notice_posttarget'] = $notice_link = $p_hb_env['loginpath'] . "/notices?cu={$p_hb_env['Cu']}&Flang={$p_hb_env['Flang']}";
4948  }
4949  // ** Survey INTRO is from a different table, AND at this time only for surveys
4950  // ** LEFT JOIN the table and include here
4951  $tmp_Notices[$notice_idx]['notice_intro'] = $notice_row['surveyintro'];
4952 
4953  // ** CREATE THE TITLE to be on the survey
4954  // ** Later we may need to put the product name here 9/14/2012
4955  if (intval($notice_row['surveytype']) == 1) {
4956  // ** FOR MARKETING MESSAGES ONLY
4957  $tmp_Notices[$notice_idx]['notice_title'] = ($notice_row['surveytitle'] == '' ? $p_mc->msg('Message') : $notice_row['surveytitle']);
4958  // *SET THE msg_tx value
4959  $tmp_Notices[$notice_idx]['notice_msg_tx'] = 256;
4960  // ** Determine how the answers will be displayed
4961  // * FOR NOW -- MARKETING is M (multiple) can be answerd.. BUT THERE IS ONLY ONE -- SHOWS A CHECKBOX rather than RADIO
4962  $tmp_Notices[$notice_idx]['notice_answertype'] = "M";
4963  $tmp_Notices[$notice_idx]["notice_suppressresponse"] = "Y"; // ALWAYS SUPPRESS MARKETING MESSAGES
4964 
4965  } else {
4966  $tmp_Notices[$notice_idx]['notice_title'] = $p_mc->msg('Survey');
4967  $tmp_Notices[$notice_idx]['notice_msg_tx'] = 8;
4968  // ** SURVEY is O - ONLY ONE .. WILL SHOW RADIO
4969  $tmp_Notices[$notice_idx]['notice_answertype'] = "O";
4970  $tmp_Notices[$notice_idx]["notice_suppressresponse"] = $notice_row['dontshow']; // ** Grab suppress FLAG from cusurveymaster
4971  }
4972  $tmp_Notices[$notice_idx]['notice_msg_tx_perm'] = 0;
4973  $tmp_Notices[$notice_idx]['notice_msg_tx_show'] = 2; // POST THE FIELD, HIDE ELEMENT FROM MEMBER
4974 
4975  // ** NOT NEEDED WHEN WE ARE NOT SHOWING FIELD
4976  $tmp_Notices[$notice_idx]['notice_donotshowtext'] = "";
4977 
4978  if (($p_hb_env['Fmsg_tx'] & $tmp_Notices[$notice_idx]['notice_msg_tx']) == 0 ) {
4979  if ($p_device == 'M' && intval($notice_row['surveytype']) != 1) {
4980  // ** ALL MOBILE SURVEYS WILL BE A POPUP
4981  $tmp_Notices[$notice_idx]['notice_popup'] = 1;
4982  } elseif (($p_device == 'D' || $p_device = 'R') && intval($notice_row['surveytype']) != 1) {
4983  // ** For Survey types with the NEW upgrade, set the popup = 1 for ALL types
4984  $tmp_Notices[$notice_idx]['notice_popup'] = 1;
4985  } else {
4986  // ** FOR DESKTOP I WILL USE INFORMATION FROM TABLE
4987  // * POPUP if inc_balances is 'N'
4988  $tmp_Notices[$notice_idx]['notice_popup'] = ($notice_row['inc_balances'] == 'Y' ? 0 : 1);
4989  }
4990  } else {
4991  // The member has already pressed close once. Do not bug them again until the next login
4992  // * SET the value to -1 , so I know that the message should not be viewed again.
4993  // * But for type Mkt Message and device 'D' upgrade desktop, set the value to 0
4994  // * for the notice_popup
4995  if (intval($notice_row['surveytype']) == 1 && $notice_row['inc_balances'] == 'Y') {
4996  $tmp_Notices[$notice_idx]['notice_popup'] = 0;
4997  } else {
4998  $tmp_Notices[$notice_idx]['notice_popup'] = 1;
4999  }
5000  }
5001  // ** SEPARATELY -- RETRIEVE ANSWERS
5002  if (intval($notice_row['surveytype']) == 1) {
5003  // ** FOR MARKETING MESSAGES ONLY
5004  // * THEY WILL ALWAYS HAVE ONE ANSWER -- THE
5005  $tmp_Answer = $tmp_Answers_tmpl;
5006  // ** USE SURVEY_ID FOR ANSWER
5007  $tmp_Answer['answer_id'] = $tmp_Notices[$notice_idx]['notice_id'];
5008  $tmp_Answer['answer_text'] = $p_mc->msg('Dont Tell Me Again');
5009 
5010  $tmp_Notices[$notice_idx]['notice_answers'][] = $tmp_Answer;
5011 
5012  $tmp_Notices[$notice_idx]["notice_positive_caption"] = $p_mc->msg('Close');
5013  $tmp_Notices[$notice_idx]["notice_negative_caption"] = $p_mc->msg('Dont show me again');
5014 
5015  } else {
5016  $tmp_Notices[$notice_idx]["notice_positive_caption"] = $p_mc->msg('Cast my Vote');
5017  $tmp_Notices[$notice_idx]["notice_negative_caption"] = 'Vote Later'; //$p_mc->msg('Vote Later');
5018 
5019  if ($p_action == "SHOW") {
5020  // ** QUERY THE DETAIL FOR THE SURVEY WE ARE LOOKING AT
5021  $sql = "SELECT *
5022  FROM cusurveydetail
5023  WHERE cu = '{$p_hb_env['Cu']}'
5024  AND surveyid = {$notice_row['surveyid']}
5025  AND language = '{$p_hb_env['Flang']}'
5026  ORDER BY answerid
5027  ";
5028 
5029  $answer_rs = db_query($sql, $p_dbh);
5030  $answer_idx = 0;
5031  while ($answer_row = db_fetch_assoc($answer_rs, $answer_idx)) {
5032  $tmp_Answer = $tmp_Answers_tmpl;
5033  // ** USE SURVEY_ID FOR ANSWER
5034  $tmp_Answer['answer_id'] = $answer_row['answerid'];
5035  if (function_exists('hcu_displayHtml')) {
5036  $tmp_Answer['answer_text'] = hcu_displayHtml($answer_row['answertext']);
5037  } else {
5038  $tmp_Answer['answer_text'] = dms_disphtml($answer_row['answertext']);
5039  }
5040 
5041  $tmp_Notices[$notice_idx]['notice_answers'][] = $tmp_Answer;
5042 
5043  $answer_idx++;
5044  }
5045  db_free_result($answer_rs);
5046  } elseif ($p_action == "RESULTS") {
5047  $answervotes_ttl = 0;
5048  // ** DO NOT JOIN cusurveysays on language.. RETURN ALL language results
5049  $sql = "
5050  SELECT answerid, answertext,
5051  (SELECT count(*)
5052  FROM cusurveysays
5053  WHERE cusurveysays.cu = cusurveydetail.cu
5054  AND cusurveysays.surveyid = cusurveydetail.surveyid
5055  AND cusurveysays.answerid = cusurveydetail.answerid) as answervotes
5056  FROM cusurveydetail
5057  WHERE cu = '{$p_hb_env['Cu']}'
5058  AND surveyid = {$notice_row['surveyid']}
5059  AND language = '{$p_hb_env['Flang']}'
5060  ";
5061 
5062  $answer_rs = db_query($sql, $p_dbh);
5063  $answer_idx = 0;
5064  while ($answer_row = db_fetch_assoc($answer_rs, $answer_idx)) {
5065  $tmp_Answer = $tmp_Answers_tmpl;
5066  // ** USE SURVEY_ID FOR ANSWER
5067  $tmp_Answer['answer_id'] = $answer_row['answerid'];
5068  if (function_exists('hcu_displayHtml')) {
5069  $tmp_Answer['answer_text'] = hcu_displayHtml($answer_row['answertext']);
5070  } else {
5071  $tmp_Answer['answer_text'] = dms_disphtml($answer_row['answertext']);
5072  }
5073  $tmp_Answer['answer_votes'] = intval($answer_row['answervotes']);
5074  $answervotes_ttl += intval($answer_row['answervotes']);
5075 
5076  $tmp_Notices[$notice_idx]['notice_answers'][] = $tmp_Answer;
5077 
5078  $answer_idx++;
5079  }
5080  db_free_result($answer_rs);
5081 
5082  // ** Before I go, I want to loop through all the answers
5083  // * COUNT THEM
5084  // * DETERMINE A PERCENTAGE
5085  // ** Set the TOTAL VOTES
5086  $tmp_Notices[$notice_idx]['notice_answervotes_ttl'] = $answervotes_ttl;
5087  $tmp_Notices[$notice_idx]['notice_answervotes_ttldisplay'] = $p_mc->msg('total votes');
5088  if (count($tmp_Notices[$notice_idx]['notice_answers']) > 0) {
5089  foreach ($tmp_Notices[$notice_idx]['notice_answers'] as $answer_key => $answer_row) {
5090  if ($answervotes_ttl == 0) {
5091  // ** TRY AND PREVENT DIVIDE BY ZERO
5092  $tmp_Notices[$notice_idx]['notice_answers'][$answer_key]['answer_pct'] = 0;
5093  } else {
5094  $tmp_Notices[$notice_idx]['notice_answers'][$answer_key]['answer_pct'] =
5095  number_format(floatval($answer_row['answer_votes'] / $answervotes_ttl) * 100, 1);
5096  }
5097  }
5098  }
5099  }
5100  }
5101  // INCREMENT INDEX to fetch next row
5102  $notice_idx++;
5103  }
5104 
5105  }
5106 
5107  }
5108  $retStatus_ary['notice'] = $tmp_Notices;
5109  return $retStatus_ary;
5110 }
5111 
5112 /**
5113  *
5114  * Update_NoticeInfo
5115  * This function will allow us to post the results of a notice window and
5116  * update the necessary fields
5117  *
5118  * @param integer $p_dbh - handle to the current connection of the database
5119  * @param class $p_hb_env - Current HB_ENV array, by reference
5120  * @param class $p_mc - Current object for MC Language class
5121  *
5122  * @return array following structure
5123  * [status]
5124  * [code] HB Standard codes 000 success, 100 NO NOTICE RECORDS, 999 error
5125  * [severity] {SUCCESS, ERROR}
5126  * [errors] List of errors if any exist
5127  * [response]
5128  * [notice_action] --
5129  * 'CLOSE' -- The survey window should close
5130  * 'DISPLAY' -- The survey window should show the display results
5131  * [notice_results] -- THIS IS THE NOTICE ARRAY FROM Get_NoticeInfo
5132  *
5133  *
5134  * The following fields are expected in the field HB_ENV['HCUPOST']
5135  *
5136  * notice_type {M, S, N}
5137  * M - Marketing Message
5138  * S - Survey Message
5139  * N - Notice (from a file)
5140  * C - CMS Fragment Disclosure/Terms Notice
5141  *
5142  * notice_id for M,S this is an integer
5143  * for N this is a string identifier
5144  *
5145  * notice_link {1,0} - This is used to identify if a notice/disclaimer was
5146  * called via a link. if so, then it will NOT affect the msg_tx
5147  * value and will not show the button
5148  *
5149  * notice_device This is the type of device that is being used to request the data
5150  * {M, R, C, P}
5151  * (M)obile Device
5152  * (R)esponsive Mobile Design
5153  * (C)lassic Desktop
5154  * HomeBanking Iphone Ap(P)
5155  * notice_response This is an ARRAY of the values posted from a Marketing Message / SURVEY
5156  * [INDEX] => [VALUE]
5157  * KEY -
5158  * -- BOTH TYPES - This is a UNIQUE index for the array to keep the values unique. [0...99]
5159  * VALUE -
5160  * -- SURVEY TYPES - This will be the answerid from cusurveydetail
5161  * -- MARKETING TYPES - This will be the noticeid (survey_id) from cusurveymaster
5162  *
5163  * notice_msg_show This is the field posted when a 'do not show link again' message has
5164  * been selected. The option when notice_donotshowtext was set with a value
5165  *
5166  * ** NOTE:
5167  * The expected value for when the chooses not to show a notice, the fieldname is
5168  *
5169  *
5170  *
5171 */
5172 Function Update_NoticeInfo($p_dbh, $p_hb_env, $p_mc ) {
5173  $retStatus_ary = Array('status' => Array('code'=>'000', 'severity'=>'SUCCESS', 'errors' => Array()));
5174 
5175  $retResp_ary = Array('notice_action' => '', 'notice_results' => Array());
5176 
5177  /* TEMPORARY FLAG BIT CONSTANT */
5178  // * The set the current constant for all temporary flags added together.
5179  $tempflags = 49464;
5180 
5181  /* NOTICE ACTIONS */
5182 
5183  switch ($p_hb_env['HCUPOST']['notice_type']) {
5184  case 'N':
5185  // ** LOOKUP the Notice being referenced
5186  // ** For the purpose of Updating, I do NOT want FULL Detail
5187  $HB_Notices_ary = Get_NoticeInfo($p_dbh, $p_hb_env, $p_mc, $p_hb_env['HCUPOST']['notice_device'], $p_hb_env['HCUPOST']['notice_id'], 0);
5188 
5189  // ** I EXPECT ONLY ONE RECORD TO BE RETURNED -- THE RECORD I ASKED FOR
5190  if ($HB_Notices_ary['status']['code'] == '000' && count($HB_Notices_ary['notice']) > 0) {
5191  // SUCCESSFULLY found the notice -- Now fulfill why we are here
5192 
5193  // ** We are posting information here --
5194  // * the only reason is to set the cookie and NOT SHOW AGAIN
5195  // ** Check to see if the member is allowed to make a change
5196 
5197  if (intval($HB_Notices_ary['notice'][0]['notice_msg_tx_show']) > 0 && intval($p_hb_env['HCUPOST']['notice_msg_show']) == 1) {
5198  // ** Member is allowed to make the change TO NOT SHOW AGAIN
5199 
5200  // ** SET msg_tx constant for this feature
5201  $nflag = intval($HB_Notices_ary['notice'][0]['notice_msg_tx']);
5202 
5203  $oflag = intval($p_hb_env['Fmsg_tx']);
5204  // * subtract the NEW flag constant from the OLD flag constant
5205  $nflag = $oflag | $nflag;
5206 
5207  // * Create a Flag constant with ALL temporary flags turned off
5208  $dflag = ~(~$nflag | $tempflags);
5209 
5210  // ** Check to see if the change is permamenent
5211  if (intval($HB_Notices_ary['notice'][0]['notice_msg_tx_perm']) > 0) {
5212  if (hcu_checkOffline($p_dbh, $p_hb_env)) {
5213  // ** Update the cuusers table
5214  $upd_list_array = Array("msg_tx" => "$dflag");
5215  $UpdTable_ary = Update_MemberInfo($p_dbh, $p_hb_env, $p_mc, serialize($upd_list_array), serialize(Array()));
5216  // * CHECK THE RESULTS
5217  if ($UpdTable_ary['status']['code'] != '000') {
5218  // ** We somehow failed, set the failed information here
5219  $retStatus_ary['status']['code'] = '999';
5220  $retStatus_ary['status']['severity'] = 'ERROR';
5221  $retStatus_ary['status']['errors'] = array_merge($retStatus_ary['status']['errors'], $UpdTable_ary['status']['errors']);
5222  }
5223  }
5224  }
5225 
5226  // FINALLY -- SAVE THE NEW COOKIE VALUE FOR THE MEMBER
5227  // ** ONLY SET THE TICKET for the proper device types
5228  if ($p_hb_env['HCUPOST']['notice_device'] == 'M' ||
5229  $p_hb_env['HCUPOST']['notice_device'] == 'R' ||
5230  $p_hb_env['HCUPOST']['notice_device'] == 'C') {
5231  SetTicket($p_hb_env, $_COOKIE['Ticket'],"Fmsg_tx=$nflag");
5232  }
5233  }
5234  } // ** STATUS GOOD
5235 
5236  break;
5237  case 'M':
5238  case 'S':
5239  case 'T': // ** Add Terms of Use type for this update procedure.
5240  // ** FIRST
5241  // ** We are looking up a specific notice -- no need to send the p_noticefor option
5242  // ** FOR the purposes of updating, we do NOT want fulldetail
5243  $HB_Notices_ary = Get_NoticeInfo($p_dbh, $p_hb_env, $p_mc, $p_hb_env['HCUPOST']['notice_device'], 'B', 0, $p_hb_env['HCUPOST']['notice_id']);
5244  // ** I EXPECT ONLY ONE RECORD TO BE RETURNED -- THE RECORD I ASKED FOR
5245  if ($HB_Notices_ary['status']['code'] == '000' && count($HB_Notices_ary['notice']) > 0) {
5246  // SUCCESSFULLY found the notice -- Now fulfill why we are here
5247 
5248 
5249  // ** WORRY ABOUT POSTING SAVED VALUES TO THE cusurveysays table
5250  // ** FROM THE ['HCUPOST']['notice_response'] ARRAY
5251  $noticeRespCount = (HCU_array_key_exists('notice_response', $p_hb_env['HCUPOST']) ? count($p_hb_env['HCUPOST']['notice_response']) : 0);
5252  //if (count($p_hb_env['HCUPOST']['notice_response']) > 0 && $p_hb_env['HCUPOST']['notice_cancel'] != 1) {
5253  if ($noticeRespCount > 0 && $p_hb_env['HCUPOST']['notice_cancel'] != 1) {
5254  $upd_sql = "";
5255  foreach ($p_hb_env['HCUPOST']['notice_response'] as $response_key => $response_value) {
5256 
5257  $upd_sql .= " INSERT INTO cusurveysays (cu, surveyid, user_id, accountnumber, language, answerid)
5258 
5259  (SELECT '" . prep_save($p_hb_env['Cu']) ."', " . intval($p_hb_env['HCUPOST']['notice_id']) . ",
5260  " . prep_save($p_hb_env['Uid']) . ", '',
5261  '" . prep_save($p_hb_env['Flang']) . "', " . intval($response_value) . "
5262  WHERE NOT EXISTS (SELECT (cu, surveyid, accountnumber)
5263  FROM cusurveysays as cus
5264  WHERE cus.cu = '" . prep_save($p_hb_env['Cu']) ."'
5265  AND cus.surveyid = " . intval($p_hb_env['HCUPOST']['notice_id']) . "
5266  AND cus.user_id = '" . prep_save($p_hb_env['Uid']) . "')
5267  ) ";
5268  }
5269 
5270  if ($upd_sql != '') {
5271  if (!$upd_rs = db_query ($upd_sql, $p_dbh)) {
5272  // ** ERROR updating the datatable
5273  $retStatus_ary['status']['errors'][] = $p_mc->msg('Error udpating');
5274  }
5275  }
5276  }
5277  // ** SECOND
5278  // ** IF NEEDED -- SET THE TICKET APPROPRIATELY SO WE don't see message again
5279  // ** Survey/Marketing message are TEMPORARY msg_tx values ONLY - They do not get saved back to cuusers
5280 
5281  if (in_array($p_hb_env['HCUPOST']['notice_device'], array('M', 'R', 'C', 'D')) && intval($HB_Notices_ary['notice'][0]['notice_msg_tx']) > 0) {
5282  $oflag = $p_hb_env['Fmsg_tx'];
5283  $nflag = $p_hb_env['Fmsg_tx'] | intval($HB_Notices_ary['notice'][0]['notice_msg_tx']);
5284  SetTicket($p_hb_env,$_COOKIE['Ticket'],"Fmsg_tx=$nflag");
5285  }
5286  // * AFTER POSTING -- I WANT to retrieve the results for the SURVEY(ONLY) posted
5287  if ($p_hb_env['HCUPOST']['notice_type'] == 'S' && count($p_hb_env['HCUPOST']['notice_response']) > 0 && $p_hb_env['HCUPOST']['notice_cancel'] != 1) {
5288  // ** SURVEY -- RETRIEVE THE RESULTS
5289 
5290  // ** CALL SurveyMsg directly
5291  $HB_Results_ary = Get_HBSurveyMsg($p_dbh, $p_hb_env, $p_mc, $p_hb_env['HCUPOST']['notice_device'], '', 1, $p_hb_env['HCUPOST']['notice_id'], "RESULTS");
5292  if ($HB_Results_ary['status']['code'] == '000') {
5293  // ** SUCCESSFUL
5294  // ** IF the survey is NOT set to suppress results then SHOW the information
5295  if ($HB_Results_ary['notice'][0]['notice_suppressresponse'] != 'Y') {
5296  // ** I WANT TO RETURN THE ['notice'] element in the current ['response']['notice_results'] element
5297  $retResp_ary['notice_action'] = 'DISPLAY';
5298  $retResp_ary['notice_results'] = $HB_Results_ary['notice'];
5299  } else {
5300  // ** CLOSE if Suppress Response is set to Y
5301  $retResp_ary['notice_action'] = 'CLOSE';
5302  }
5303 
5304  } else {
5305  // ** FAILED -- DO NOT SHOW ANYTHING
5306  $retResp_ary['notice_action'] = 'CLOSE';
5307  }
5308 
5309 
5310  }
5311  } // ** STATUS GOOD
5312 
5313  break;
5314  case 'C':
5315  // ** CU CMS TABLE NOTICES/FRAGMENTS
5316  // ** FIRST
5317  // ** We are looking up a specific notice -- no need to send the p_noticefor option
5318  // ** FOR the purposes of updating, we do NOT want fulldetail
5319  $HB_Notices_ary = Get_NoticeInfo($p_dbh, $p_hb_env, $p_mc, $p_hb_env['HCUPOST']['notice_device'], 'updatecms', 0, $p_hb_env['HCUPOST']['notice_id']);
5320 
5321  // ** I EXPECT ONLY ONE RECORD TO BE RETURNED -- THE RECORD I ASKED FOR
5322  if ($HB_Notices_ary['status']['code'] == '000' && count($HB_Notices_ary['notice']) > 0) {
5323  // SUCCESSFULLY found the notice -- Now fulfill why we are here
5324 
5325 
5326  // ** WORRY ABOUT POSTING SAVED VALUES TO THE cusurveysays table
5327  // ** FROM THE ['HCUPOST']['notice_response'] ARRAY
5328  $noticeRespCount = (HCU_array_key_exists('notice_response', $p_hb_env['HCUPOST']) ? count($p_hb_env['HCUPOST']['notice_response']) : 0);
5329 
5330  $responseexists = HCU_array_key_value("notice_responseexists", $p_hb_env["HCUPOST"]);
5331  $accountnumber = HCU_array_key_value("notice_accountnumber", $p_hb_env["HCUPOST"]);
5332  $accountnumber = $accountnumber === false ? "" : trim($accountnumber); // Keep the current functionality of inserting empty string in nearly all cases.
5333  if ($noticeRespCount > 0) {
5334  $upd_sql = "";
5335  // ** This type of notice will only have ONE answer..
5336  // ** An INSERT OR UPDATE may need to be executed.
5337  // ** INSERT
5338 
5339  foreach ($p_hb_env['HCUPOST']['notice_response'] as $response_key => $response_value) {
5340  if (intval($response_value) > 0) {
5341 
5342  $updateRs = false;
5343  if ($responseexists != "Y") {
5344  // ** NO RECORD exists in cucmsresponse
5345  $upd_sql = "INSERT INTO cucmsresponse (docsid, cu, accountnumber, user_id, responseon)
5346  (SELECT " . intval($p_hb_env['HCUPOST']['notice_id']) . ", '" . prep_save($p_hb_env['Cu']) . "',
5347  '$accountnumber', {$p_hb_env['Uid']}, current_date
5348  WHERE NOT EXISTS (SELECT 'FOUND'
5349  FROM cucmsresponse as cur
5350  WHERE cur.docsid = " . intval($p_hb_env['HCUPOST']['notice_id']) . "
5351  AND cur.cu = '" . prep_save($p_hb_env['Cu']) . "'
5352  AND cur.user_id = {$p_hb_env['Uid']}
5353  " . ($accountnumber == "" ? "" : "AND cur.accountnumber = '$accountnumber'") . "
5354  )
5355  ); ";
5356 
5357  $updateRs = db_query($upd_sql, $p_dbh);
5358  }
5359 
5360  if ($responseexists == "Y" || ($updateRs && db_affected_rows($updateRs) === 0)) {
5361  // ** NO Rows affected -- NO INSERT -- SO UPDATE INSTEAD
5362  // ** UPDATE
5363  // ** If the cucmsresponse record exist, but the responsedate is NULL, then I need
5364  $upd_sql = "UPDATE cucmsresponse
5365  SET responseon = current_date
5366  WHERE docsid = " . intval($p_hb_env['HCUPOST']['notice_id']) . "
5367  AND cu = '" . prep_save($p_hb_env['Cu']) . "'
5368  AND user_id = {$p_hb_env['Uid']}
5369  " . ($accountnumber == "" ? "" : "AND accountnumber = '$accountnumber'") . "
5370  ";
5371 
5372  $updateRs = db_query($upd_sql, $p_dbh);
5373  }
5374 
5375  if (!$updateRs) {
5376  $retStatus_ary['status']['errors'][] = $p_mc->msg('Error udpating');
5377  }
5378  }
5379  }
5380  }
5381  // ** SECOND
5382  // ** IF NEEDED -- SET THE TICKET APPROPRIATELY SO WE don't see message again
5383  // ** Session flags are stored in the Cookie value of Fmsg_tx.
5384  if (in_array($p_hb_env['HCUPOST']['notice_device'], array('M', 'R', 'C', 'D')) && intval($HB_Notices_ary['notice'][0]['notice_msg_tx']) > 0) {
5385  $oflag = $p_hb_env['Fmsg_tx'];
5386  $nflag = $p_hb_env['Fmsg_tx'] | intval($HB_Notices_ary['notice'][0]['notice_msg_tx']);
5387  SetTicket($p_hb_env,$_COOKIE['Ticket'],"Fmsg_tx=$nflag");
5388  }
5389 
5390 
5391  /* At this There is no equivalent to the flag for not showing again in
5392  * the cookie.
5393  */
5394 
5395  } // ** STATUS GOOD
5396 
5397  break;
5398  default:
5399  $retStatus_ary['status']['errors'][] = $p_mc->msg('Error') . " (Invalid notice_type)";
5400 
5401  } // ** SWITCH NOTICE TYPE
5402 
5403  if (count($retStatus_ary['status']['errors']) > 0) {
5404  $retStatus_ary['status']['code'] = '999';
5405  $retStatus_ary['status']['severity'] = 'ERROR';
5406  } else {
5407  // ** FOR SUCCESSFUL NOTICES -- ALWAYS APPEND THE 'response' array to the status
5408  $retStatus_ary['response'] = $retResp_ary;
5409  }
5410  return $retStatus_ary;
5411 }
5412 /**
5413  * Update_MemberInfo
5414  * @param integer $p_dbh - Current Database handle
5415  * @param array $p_hb_env - Current HB_ENV
5416  * @param object $p_mc -- This points to the current MC value for the language class
5417  * @param string $p_values -- This array contains the values I want to save,
5418  * the values should be in php serialize string format {"field":"value"...}
5419  * @param string $p_primaryKeys -- This array contains the primary key values necessary to update the query
5420  * the values should be in php serialize string format {"field":"value"...}
5421  * @param boolean $p_BuildOnly -- {True, false}
5422  * true - The function will NOT execute any sql, instead
5423  * it will return the sql in the 'data' element of the returned
5424  * status array
5425  * false - function executes the sql, does NOT return data element
5426  *
5427  */
5428 Function Update_MemberInfo($p_dbh, $p_hb_env, $p_mc, $p_values, $p_primaryKeys, $p_BuildOnly = false) {
5429  $retStatus_ary = Array('status' => Array('code'=>'000', 'severity'=>'', 'errors' => Array()));
5430 
5431  try {
5432  /* LIST OF APPROVED CUUSERS FIELDS */
5433  /* Types are
5434  * I - Integer
5435  * C?? - Character, followed by length, if there is one
5436  * S - String (case insensitive)
5437  * N - Numeric Standard 12,2
5438  *
5439  */
5440  $HB_CUUSERS_FIELDS_ary = Array( "passwd" => "C34",
5441  "email" => "C50",
5442  "confidence" => "C20",
5443  "user_name" => "S50",
5444  "estmt_flag" => "C1",
5445  "egenl_flag" => "C1",
5446  "failedremain" => "I",
5447  "employee" => "C1",
5448  "mfaquest" => "C0",
5449  "msg_tx" => "I");
5450  /*
5451  * LIST OF PRIMARY KEYS FOR UPDATE
5452  * ** THE difference is these fields should be REQUIRED ** rather than optional
5453  */
5454  $HB_CUUSERS_PRIMARY_KEYS_ary = Array( "user_name" => 'S50');
5455 
5456  // ** Get the cuusers field/value sets
5457  //$requested_fields_ary = json_decode($p_values);
5458  $requested_fields_ary = unserialize($p_values);
5459  if (is_array($requested_fields_ary)) {
5460 
5461  // * Get the update string from the passed in array
5462  $sql_field_update = PrepareExpressionList($HB_CUUSERS_FIELDS_ary, $requested_fields_ary);
5463 
5464  $requested_keys_ary = unserialize($p_primaryKeys);
5465  $sql_keys_list = PrepareExpressionList($HB_CUUSERS_PRIMARY_KEYS_ary, $requested_keys_ary, true);
5466 
5467  if ($sql_field_update != '' && $sql_keys_list != '') {
5468  // ** We have a list to update
5469  $sql = "UPDATE {$p_hb_env['Cu']}user
5470  SET
5471  {$sql_field_update}
5472  WHERE {$sql_keys_list};
5473  ";
5474 
5475  if (!$p_BuildOnly) {
5476  // Execute the query
5477  if (!$trans_rs = db_query($sql, $p_dbh)) {
5478  // ** ERROR NOT AN ARRAY --
5479  throw new exception ($p_mc->msg('Error udpating'), '999');
5480  }
5481  } else {
5482  // ** BUILD ONLY
5483  $retStatus_ary['data']['sql'] = $sql;
5484  }
5485  } else {
5486  throw new exception ($p_mc->msg('Error'), '999');
5487  }
5488  // Create an array of the fields and their datatypes?
5489 
5490  } else {
5491  // ** ERROR NOT AN ARRAY --
5492  throw new exception ($p_mc->msg('Error'), '999');
5493  }
5494  } catch (exception $e) {
5495 
5496  $retStatus_ary['status']['code']= '999';
5497  $retStatus_ary['status']['severity'] = 'ERROR';
5498  $retStatus_ary['status']['errors'][] = $e->getMessage();
5499 
5500  }
5501  return $retStatus_ary;
5502 }
5503 /**
5504  *
5505  * Get_TxCodes
5506  * Get the Transaction codes and return them in an array
5507  *
5508  * @param integer $p_dbh - Current database handle
5509  * @param array $p_hb_env - Array for the current HB_ENV variable
5510  * @param object $p_mc - This is the current instance for the language class
5511  * @return array This will return a status/data array that should contain the data
5512  */
5513 function Get_TxCodes($p_dbh, $p_hb_env, $p_mc) {
5514  $retStatus_ary = Array('status' => Array('code'=>'000', 'severity'=>'SUCCESS', 'errors' => Array()), 'data' => Array());
5515 
5516  $codelist = Array();
5517  $sql= "SELECT t.trancode, trim(t.trandesc) as trandesc,
5518  trim(ht.cudesc) as cudesc, t.specialproc
5519  FROM cutrans as t
5520  LEFT JOIN cuhavetrans as ht on ht.trancode = t.trancode AND ht.cu = '{$p_hb_env['Cu']}' ";
5521 
5522 
5523  $sth = db_query($sql, $p_dbh);
5524 
5525  // Return a line for each allowed transaction type.
5526 
5527  $row = 0;
5528  while (list($code, $desc, $cudesc, $spec) = db_fetch_array($sth,$row)) {
5529  $row++;
5530  $desc = ($code == 'AT' ? "Transfer" : $desc );
5531  $desc = ($code == 'CW' ? "Check Withdrawal" : $desc );
5532 
5533  if ($spec > 0) {
5534  $desc = ($cudesc > '' ? $cudesc : $p_mc->msg($desc) );
5535  }
5536 
5537  $codelist[$code] = $desc;
5538  }
5539 
5540  // ** SET THE DATA
5541  $retStatus_ary['data'] = $codelist;
5542 
5543  return $retStatus_ary;
5544 }
5545 
5546 /**
5547  * Get_MemberChallengeResponses
5548  * This will retrieve the current challenge responses for the passed in user
5549  *
5550  *
5551  * @param integer $p_dbh - Current database handle
5552  * @param array $p_hb_env - Array of the HB_ENV -- may or may NOT be complete
5553  * @param string $p_user - This is the user to retrieve questions, it is separate because
5554  * the login screen may call this and the Cu value has NOT been set
5555  * @param integer $p_questid OPTIONAL - This is to look up a specific question from cu_questselect
5556  * @return array
5557  */
5558 function Get_MemberChallengeResponses($p_dbh, $p_hb_env, $p_user, $p_questid = -1) {
5559  $retVal_ary = Array();
5560 
5561 /**
5562  * FUNCTION DEPRECATED -- USE THE GetChallegeQuestions function
5563  */
5564  return $retVal_ary;
5565 
5566 }
5567 /**
5568  * GetUserInfo
5569  *
5570  * Similar to GetUserbyName
5571  *
5572  * This will make a request for the current members saved password hash,
5573  * email, confidence word, -- and possibly more information later
5574  *
5575  *
5576  * @param integer $p_dbh - Current Database handle
5577  * @param array $p_hb_env - Current HB_ENV
5578  * @param object $p_mc -- This points to the current MC value for the language class
5579  * @param array $p_values -- This array contains the values I want to look up
5580  * Expected values are:
5581  * [user_id] -- This is always the user_id value for the current authenticated OLB user
5582  * [cu] -- This is the credit union to lookup
5583  *
5584  * @return string This will return the value from the database for the password.
5585  * It is the hashed value
5586  *
5587  * [status][code] - '000' OR '999'
5588  * [status][severity] - SUCCESS / ERROR
5589  * [status][errors] - Array of errors
5590  *
5591  * [data][cuusers_passwd] - This is the password hash from the member record
5592  * [data][cuusers_email] - This is the email for this member
5593  * [data][cuusers_confidence] - This is the confidence word
5594  */
5595 function GetUserInfo($p_dbh, $p_hb_env, $p_mc, $p_values) {
5596  $retStatus_ary = Array('status' => Array('code'=>'', 'errors' => Array()));
5597 
5598  $sql = "SELECT passwd, email, confidence, egenl_flag, user_name,
5599  failedremain, userflags & " . intval(GetUserFlagsValue('MEM_FORCE_RESET')) . "::int4 as forcereset,
5600  employee, userflags, mfaquest, priorlogin, lastlogin
5601  FROM {$p_values['cu']}user
5602  WHERE user_id = '{$p_values['user_id']}' ";
5603 
5604  $mbr_rs = db_query($sql, $p_dbh);
5605 
5606  if ($mbr_row = db_fetch_assoc($mbr_rs)) {
5607  // * Get the password from the row
5608  $retStatus_ary['status']['code']= '000';
5609  $retStatus_ary['data']['cuusers_name'] = trim($mbr_row['user_name']);
5610  $retStatus_ary['data']['cuusers_passwd'] = trim($mbr_row['passwd']);
5611  $retStatus_ary['data']['cuusers_email'] = trim($mbr_row['email']);
5612  $retStatus_ary['data']['cuusers_confidence'] = trim($mbr_row['confidence']);
5613  $retStatus_ary['data']['cuusers_egenl_flag'] = trim($mbr_row['egenl_flag']);
5614  $retStatus_ary['data']['cuusers_user_name'] = trim($mbr_row['user_name']);
5615  $retStatus_ary['data']['cuusers_failedremain'] = trim($mbr_row['failedremain']);
5616  $retStatus_ary['data']['cuusers_forcereset'] = trim($mbr_row['forcereset']);
5617  $retStatus_ary['data']['cuusers_employee'] = trim($mbr_row['employee']);
5618  $retStatus_ary['data']['cuusers_userflags'] = trim($mbr_row['userflags']);
5619  $retStatus_ary['data']['cuusers_lastlogin'] = trim($mbr_row['lastlogin']);
5620  $retStatus_ary['data']['cuusers_priorlogin'] = trim($mbr_row['priorlogin']);
5621 
5622  $mbrMfaQuest = HCU_MFADecode(HCU_JsonDecode($mbr_row['mfaquest']));
5623  $retStatus_ary['data']['savecqid'] = $mbrMfaQuest['challenge'];
5624  $retStatus_ary['data']['chcount'] = $mbrMfaQuest['mfacount'];
5625  $retStatus_ary['data']['authcode'] = $mbrMfaQuest['authcode'];
5626  $retStatus_ary['data']['authexpires'] = $mbrMfaQuest['authexpires'];
5627  $retStatus_ary['data']['mfadate'] = $mbrMfaQuest['mfadate'];
5628 
5629 
5630  } else {
5631  // ** ERROR
5632  $retStatus_ary['status']['code']= '999';
5633  $retStatus_ary['status']['errors'][] = $p_mc->msg('Not Found');
5634  // ** Return an empty 'data' array in case of error. This may prevent PHP array reference errors
5635  $retStatus_ary['data'] = Array();
5636  }
5637  return $retStatus_ary;
5638 }
5639 
5640 /**
5641  * GetChallengeQuestions
5642  *
5643  * This function will get the challenge questions for the member based
5644  * on the current settings for the credit union/member/purpose
5645  *
5646  * @param string $p_mode {DISPLAY, CHALLENGE, CURRENT}
5647  * DISPLAY - Will return master list of all questions in the current Flang
5648  * CHALLENGE - Set/retrieve the current challengeq questions for a member
5649  * @param integer $p_dbh - current database handle
5650  * @param array $p_hb_env REFERENCE -- The CHALLENGE QUEST ID may be set
5651  * @param class $p_mc - This is the reference to the MC class that describes the currently selected language
5652  * @param string $p_username - The username that is being challenged
5653  *
5654  * @return mixed
5655  * Array of Arrays (CHALLENGE)
5656  * [display] - Challenge question in display form
5657  * [cqid] - Challenge question id
5658  * [cqanswer] - Challenge Question Answer
5659  * Array of Arrays (CURRENT)
5660  * [mfacount] => "Number of answers in the mfaquest array" (ALWAYS RETURNED)
5661  * [answers] => "array of key(questid)->value(text) pairs "
5662  * [challenge] => "the active quest id for mfa challenge"
5663  */
5664 function GetChallengeQuestions($p_mode, $p_dbh, &$p_hb_env, $p_mc, $p_username = '') {
5665 
5666  $retVal = Array(); // DEFAULT TO EMPTY ARRAY
5667 
5668  $mfaKeyAnswers = "answers"; // ** the answers array from the member's mfa quest array
5669  $mfaKeyChallenge = "challenge";
5670  $mfaKeyCount = "mfacount";
5671 
5672  try {
5673  // ** BASED
5674  switch ($p_mode) {
5675  case "CURRENT":
5676  /*
5677  * **********************
5678  * GET mfaquest (selected mfa answers) from [cucode]user table
5679  * **********************
5680  */
5681  $sql = "SELECT mfaquest
5682  FROM {$p_hb_env['cu']}user as cuuser
5683  WHERE lower(cuuser.user_name) = '" . strtolower(prep_save($p_username)) . "' ";
5684 
5685  $rsMfa = db_query($sql, $p_dbh);
5686  $mfaquest = '';
5687  if (db_num_rows($rsMfa) > 0) {
5688  // * retrieve the mfaquest field
5689  $recMfa = db_fetch_assoc($rsMfa);
5690  $mfaquest = $recMfa['mfaquest'];
5691  /*
5692  * SET the mfa quest array
5693  */
5694  }
5695  $retVal = HCU_MFADecode(HCU_JsonDecode($mfaquest));
5696  break;
5697  case "CHALLENGE":
5698  /*
5699  * **********************
5700  * GET mfaquest (selected mfa answers) from [cucode]user table
5701  * **********************
5702  */
5703  $sql = "SELECT mfaquest
5704  FROM {$p_hb_env['cu']}user as cuuser
5705  WHERE lower(cuuser.user_name) = '" . strtolower(prep_save($p_username)) . "' ";
5706 
5707  $rsMfa = db_query($sql, $p_dbh);
5708  if (db_num_rows($rsMfa) > 0) {
5709  // * retrieve the mfaquest field
5710  $recMfa = db_fetch_assoc($rsMfa);
5711  /*
5712  * SET the mfa quest array
5713  */
5714  $mbrMfaQuest = HCU_MFADecode(HCU_JsonDecode($recMfa['mfaquest']));
5715 
5716  $countMbrMfa = $mbrMfaQuest[$mfaKeyCount];
5717  if ($countMbrMfa > 0) {
5718  /*
5719  * **********************
5720  * IF THERE ARE ANSWERS, GET THE APPROPRIATE QUESTIONS
5721  * **********************
5722  */
5723  $sql = "SELECT quest_id, quest_text, example_text
5724  FROM cuquestmaster as m
5725  WHERE quest_lang = '{$p_mc->get_lang()}'
5726  ORDER BY quest_id, quest_lang ";
5727 
5728  // ** Before this was always ordered by the SELECTED questions oid, but I don't have that table anymore
5729  // ** the quest master will be consistent order overall. I may want to change this in the future to be the order of the array in the
5730  // ** mfaquest, however, I will try this first mws 1/29/16
5731  $rsQstMaster = db_query($sql, $p_dbh);
5732  $recQstMaster = db_fetch_all($rsQstMaster);
5733 
5734  /*
5735  * **********************
5736  * USE ONLY ONE QUESTION ??
5737  * **********************
5738  */
5739  if (($p_hb_env['flagset2'] & $GLOBALS['CU2_RANDOM_CHAL']) == $GLOBALS['CU2_RANDOM_CHAL']) {
5740  if (intval($mbrMfaQuest[$mfaKeyChallenge]) == 0 ) {
5741  /*
5742  * **********************
5743  * RANDOM CHALLENGE
5744  * NEED TO SET THE RANDOM QUESTION?
5745  * **********************
5746  */
5747  $mbrMfaQuest[$mfaKeyChallenge] = array_rand($mbrMfaQuest[$mfaKeyAnswers]);
5748  /*
5749  * **********************
5750  * UPDATE [cucode]user TABLE WITH QUEST ID
5751  * **********************
5752  */
5753  $mbrSaveMfaQuest = PrepareMfaQuestString($mbrMfaQuest);
5754  // ** update the user table
5755  $upd_list_array = serialize(Array("mfaquest" => $mbrSaveMfaQuest));
5756  $upd_keys_array = serialize(Array("user_name" => $p_username));
5757  $updateResponse = Update_MemberInfo($p_dbh, $p_hb_env, $p_mc, $upd_list_array, $upd_keys_array);
5758 
5759  if ($updateResponse['status']['code'] != '000') {
5760  // ** Unable to process for some reason...
5761  // ** What to do next
5762  throw new Exception('User Record Not Updated', '905');
5763  }
5764 
5765  } else {
5766 
5767  /*
5768  * **********************
5769  * QUESTION ALREADY SET?
5770  * Then return ONLY that array element
5771  * **********************
5772  */
5773  }
5774  /*
5775  * Challenge ID should now be set in the 'challenge'
5776  */
5777  if ($mbrMfaQuest[$mfaKeyChallenge] > 0) {
5778  // ** Get the question text by searching through the question master array where quest_id is the key being sought
5779  $masterQstIdx = array_search($mbrMfaQuest[$mfaKeyChallenge], array_column($recQstMaster, 'quest_id'));
5780  if ($masterQstIdx !== false) {
5781  // SINGLE Response -- Challenge Found -- Return the Array
5782  $retVal[] = Array("display" => $recQstMaster[$masterQstIdx]['quest_text'], "cqid" => $mbrMfaQuest[$mfaKeyChallenge], "cqanswer" => $mbrMfaQuest[$mfaKeyAnswers][$mbrMfaQuest[$mfaKeyChallenge]]);
5783  }
5784  }
5785  } else {
5786  /*
5787  * ***************************
5788  * SEND BACK ALL QUESTIONS :: SET BY USER
5789  *
5790  * ***************************
5791  */
5792  if ($mbrMfaQuest[$mfaKeyCount] > 0 and is_array($mbrMfaQuest[$mfaKeyAnswers])) {
5793  // ** Need to loop through each option and set the retVal array
5794  foreach ($mbrMfaQuest[$mfaKeyAnswers] as $questIdx => $questAnswer) {
5795  $masterQstIdx = array_search($questIdx, array_column($recQstMaster, 'quest_id'));
5796  if ($masterQstIdx !== false) {
5797  $retVal[] = Array("display" => $recQstMaster[$masterQstIdx]['quest_text'], "cqid" => $questIdx, "cqanswer" => $questAnswer);
5798  }
5799  }
5800  }
5801  }
5802  }
5803  }
5804  // ** UPDATE THE CHALLENGE QUEST ID HERE
5805  break;
5806  case "DISPLAY":
5807  // * DISPLAY */
5808  // ** RETURN the array for display purposes
5809  $sql = "SELECT quest_id as \"cqid\", trim(quest_text) as \"display\"
5810  FROM cuquestmaster
5811  WHERE quest_lang='{$p_mc->get_lang()}'
5812  ORDER BY quest_text ";
5813  $rsQstMaster = db_query($sql, $p_dbh);
5814  $retVal = db_fetch_all($rsQstMaster);
5815  if ($retVal == FALSE) {
5816  throw new Exception('No Master Records', '910');
5817  }
5818 
5819  break;
5820  default:
5821  throw new Exception('Invalid Option', '999');
5822  }
5823  } catch (Exception $e) {
5824  // ** ERROR OCCURRED return empty array
5825  $retVal = Array();
5826  }
5827  return $retVal;
5828 }
5829 
5830 
5831 
5832 /**
5833  * Update_AuditMember
5834  * Create a record in the cuauditusers table to take a snapshot of the current cuusers record
5835  *
5836  * @param integer $p_dbh -- current dB handle
5837  * @param array $p_hb_env -- Read-Only of HB_ENV array
5838  * @param string $p_action -- The audit action to be taken {0-From, 1-To, 2-RESET}
5839  * @param string $p_time -- * Optional date to be saved, if empty, now() will be used
5840  * @param string $p_post_build -- The value can be {True, false} and will determine if the
5841  * function will execute the query or append the query
5842  * {true} - POST NOW
5843  * {false} - build sql
5844  * @param string $p_build_sql -- REFERENCE -- this is a reference to the query that is
5845  * being appended
5846  */
5847 function Update_AuditMember($p_dbh, $p_hb_env, $p_action, $p_time = "", $p_post_build, &$p_build_sql) {
5848 
5849  $retFuncFailed = false; // **Did the query execute as expected
5850 
5851  if ($p_hb_env['live']) {
5852  $cutx = "culivetx";
5853  $showtx = ", show_livetx('{$p_hb_env['Cu']}','{$p_hb_env['Cn']}') ";
5854  } else {
5855  $cutx = "cubatchtx";
5856  $showtx = ", show_txacct('{$p_hb_env['Cu']}','{$p_hb_env['Cn']}') ";
5857  }
5858 
5859 
5860  $p_time = ($p_time == '' ? " now()" : $p_time);
5861  switch ($p_action) {
5862  case 1:
5863  $audit_action = "UPD_T";
5864  break;
5865  case 2:
5866  $audit_action = "RESET";
5867  break;
5868  default:
5869  $audit_action = "UPD_F";
5870  }
5871 
5872  $sql = "insert into cuauditusers
5873  (chdate, admuser, action,
5874  cu, user_name, user_alias, passwd, pktdate, pktstamp, email,
5875  estmt_flag, egenl_flag, failedremain, forcechange,
5876  forceremain, lastlogin, priorlogin, failedlogin,
5877  pwchange, msg_tx, billpayid, employee, txlist,
5878  depositlimit,userflags)
5879  select '{$p_time}', 'HomeCU_Member', '{$audit_action}',
5880  cuusers.cu, cuusers.user_name, cuusers.user_alias,
5881  cuusers.passwd, cuusers.pktdate, cuusers.pktstamp,
5882  cuusers.email, cuusers.estmt_flag, cuusers.egenl_flag,
5883  cuusers.failedremain, cuusers.forcechange,
5884  cuusers.forceremain, cuusers.lastlogin,
5885  cuusers.priorlogin, cuusers.failedlogin,
5886  cuusers.pwchange, cuusers.msg_tx, cuusers.billpayid,
5887  cuusers.employee $showtx,
5888  cuusers.depositlimit,userflags
5889  from cuusers where cu='{$p_hb_env['Cu']}' and user_name = '{$p_hb_env['Cn']}'; ";
5890 
5891 
5892  if ($p_post_build) {
5893  // * TRANSACTION -- IMMEDIATELY POST
5894  if (!$trans_rs = db_query($sql, $p_dbh)) {
5895  $retFuncFailed = true;
5896  }
5897  } else {
5898  $p_build_sql .= $sql;
5899  }
5900 
5901 }
5902 /**
5903  *
5904  * Update_ResetPassword
5905  *
5906  * Create the sql queries to update the RESET password
5907  * This function WILL do the update itself, NO DATA TRANSACTION OPTION
5908  * The array p_values will contain the following items.
5909  *
5910  * This setting will be used to save a NEW password that has been
5911  * reset
5912  * [username] - This is the username being updated
5913  * [newpasswd_hash] - This is the new HASHED password
5914  * [failedremain]- Retry value to set the cuusers record
5915  * [forceremain] - The value for the forceremain field
5916  *
5917  * @param type $p_dbh
5918  * @param type $p_hb_env
5919  * @param type $p_values
5920  */
5921 function Update_ResetPassword($p_dbh, $p_hb_env, $p_values) {
5922 
5923  $retAry = Array("status" => Array ("code" => "", "severity" => "", "errors" => Array()));
5924 
5925  $trans_failed = false;
5926  $retFuncFailed = false; // **Did the query execute as expected
5927  $sBuildSql = "";
5928 
5929  // * GET THE CURRENT dB time
5930  if ($time_rs = db_query("select now();", $p_dbh)) {
5931  list($chnow) = db_fetch_array($time_rs, 0);
5932  } else {
5933  // ** For some reason unable to get the current time
5934  $trans_failed = true;
5935  }
5936 
5937  $p_values['forceremain'] = intval($p_values['forceremain']);
5938  $p_values['failedremain'] = intval($p_values['failedremain']);
5939 
5940  // ** ONLY UPDATE IF newpasswd is defined in the p_values array
5941  // ** That way I may be able to use the current password as part of valiation and NO updated will occur
5942  if (array_key_exists('newpasswd_hash', $p_values)) {
5943  // ** Create the password hash
5944  $hash = crypt($p_values['newpasswd']);
5945 
5946  $sBuildSql = "UPDATE cuusers
5947  SET passwd = '{$p_values['newpasswd_hash']}',
5948  forcechange = 'Y',
5949  pwchange = now(),
5950  failedremain = '{$p_values['failedremain']}',
5951  forceremain = '{$p_values['forceremain']}'
5952  WHERE lower(user_name) = '" . strtolower($p_hb_env['Cn']) . "' and cu = '{$p_hb_env['Cu']}'; ";
5953 
5954 
5955  $trans_failed = Update_AuditMember($p_dbh, $p_hb_env, 2, $chnow, false, $sBuildSql);
5956  // END THE PROCESS
5957 
5958  // * WE NOW POST THE ACCUMULATED SQL
5959  if ($upd_rs = db_query($sBuildSql, $p_dbh)) {
5960  $retAry['status']['code'] = '000';
5961  $retAry['status']['severity'] = "SUCCESS";
5962  } else {
5963  // ** RECORD ERROR HERE
5964  $retAry['status']['code'] = '999';
5965  $retAry['status']['severity'] = 'ERROR';
5966  $retAry['status']['errors'][] = $p_mc->msg("Error Occurred updating settings");
5967  }
5968  } else {
5969  // ** RECORD ERROR HERE
5970  $retAry['status']['code'] = '999';
5971  $retAry['status']['severity'] = 'ERROR';
5972  $retAry['status']['errors'][] = $p_mc->msg("Error Occurred updating settings");
5973  }
5974 
5975 
5976  // ** RETURN THE status array
5977  return $retAry;
5978 }
5979 function Get_Billpayid($dbh, $HB_ENV, $TrustID='billpay', $pAcct) {
5980 # returns array of bill pay override settings for member for specified Trustid vendor
5981  $Cu = $HB_ENV['Cu'];
5982  $Cn = $HB_ENV['Cn'];
5983  $billpay = array();
5984 
5985  $sql = "select trim(billpayid) from {$Cu}memberacct
5986  where accountnumber = '{$pAcct}'";
5987 
5988  $sth = db_query($sql, $dbh);
5989  if (db_num_rows($sth) == 0) {
5990  # return error -- account not found
5991  $billpay['status']['code'] = '999';
5992  $billpay['status']['severity'] = 'ERROR';
5993  $billpay['status']['errors'][] = "Account not found";
5994  $billpay['billpayid'] = "";
5995  } else {
5996 
5997  list($billpayid) = db_fetch_array($sth, 0);
5998 
5999  # GECU converted from Midatlantic to Ipay -- ignore stale billpayid settings
6000  if (trim($billpayid) == '' || "$Cu" == 'GECU') {
6001  $billpayid = $pAcct;
6002  }
6003  switch ($TrustID) {
6004  case 'IPAY':
6005  case 'MidIPAY':
6006  case 'IPAY_V3':
6007  case 'IPAYAPP':
6008  case 'IPAYTEST':
6009  case 'IPAYADA':
6010  case 'IPAYMBL':
6011  // no longer using
6012  case 'IPAYBPS':
6013  // if billpayid is less than 2 chars, left pad w/zero
6014  if (strlen($billpayid) < 2) {
6015  $billpayid=substr("00$billpayid",-2,2);
6016  }
6017  break;
6018  default:
6019  break;
6020  }
6021  $billpay['status']['code']='000';
6022  $billpay['status']['severity']='SUCCESS';
6023  $billpay['billpayid'] = "$billpayid";
6024  }
6025 
6026  return ($billpay);
6027 }
6028 
6029 /**
6030  * Read_AllAlerts( $dbh, $pHBEnv )
6031  * Read all the current alerts.
6032  *
6033  * @param integer $pDbh -- Current database handle
6034  * @param string $pCU -- Current credit union
6035  * @param integer $pUid -- Current user
6036  *
6037  * @returns $retAlert
6038  * ["code"] -- "000" success or "999" failure
6039  * ["errors"] -- Array of errors (if any)
6040  * ["data"] -- List of current alerts.
6041  */
6042 function Read_AllAlerts( $pDbh, $pCu, $pUid ) {
6043 
6044  // initialize the return array
6045  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6046 
6047  // set up the alert types
6048  $alertTypes= array("B" => array("type" => "bal", "name" => "Balance"),
6049  "T" => array("type" => "trans", "name" => "Transaction"),
6050  "C" => array("type" => "check", "name" => "Check"),
6051  "L" => array("type" => "loan", "name" => "Loan"));
6052 
6053  // loan
6054  $sql = "SELECT alerttype, id, alert.accountnumber, emailtype, description,
6055  notifymsg, inctransdesc, notifydesc, lastalert, alert.accounttype,
6056  alert.alertstatus
6057  FROM cu_alerts alert
6058  INNER JOIN {$pCu}loanbalance lb ON lb.accountnumber = alert.accountnumber
6059  AND lb.loannumber = alert.accounttype
6060  WHERE alert.cu = '{$pCu}'
6061  AND alert.user_id = '{$pUid}' ";
6062 
6063  $sql .= " UNION ";
6064 
6065  /*
6066  * For 'trans' types, I need to also retrieve the column for inctransdesc.
6067  */
6068  $sql .= "SELECT alerttype, id, alert.accountnumber, emailtype, description,
6069  notifymsg, inctransdesc, notifydesc, lastalert, alert.accounttype,
6070  alert.alertstatus
6071  FROM cu_alerts alert
6072  INNER JOIN {$pCu}accountbalance ab ON ab.accountnumber = alert.accountnumber
6073  AND ab.accounttype = alert.accounttype
6074  AND ab.certnumber = alert.certnumber
6075  WHERE alert.cu = '{$pCu}'
6076  AND alert.user_id = '{$pUid}' ";
6077 
6078  // consistent sort order
6079  $sql .= " ORDER BY accountnumber, alerttype, description, id";
6080 
6081  $alertRS = db_query($sql, $pDbh);
6082  $iRow = 0;
6083  while ( $alertRow = db_fetch_assoc($alertRS, $iRow++) ) {
6084 
6085  // clean up the returned data
6086  foreach( $alertRow as $key => $value ) {
6087  $alertRow[$key] = trim($value);
6088  }
6089 
6090  // get the type names to return
6091  $typeRecord= $alertTypes[$alertRow["alerttype"]];
6092 
6093  $alertRow["type"] = $typeRecord["type"];
6094  $alertRow["type_name"] = $typeRecord["name"];
6095 
6096  // Don't print the last alert date if it is 1/1/2000
6097  $lastAlert = trim( $alertRow["lastalert"] );
6098  if ( $lastAlert == "01/01/2000" ) {
6099  $alertRow["lastalert"] = "";
6100  } else if ( strlen( $lastAlert ) ) {
6101  $lastAlertTime = strtotime($lastAlert);
6102  if ( date( "m/d/Y", $lastAlertTime ) == "01/01/2000" ) {
6103  $alertRow["lastalert"] = "";
6104  } else {
6105  $alertRow["lastalert"] = $lastAlert; // presentation level will need to format it
6106  }
6107  } else {
6108  $alertRow["lastalert"] = "";
6109  }
6110 
6111  $alertRow["description"] = trim( $alertRow["description"] ) . " - " . trim( $alertRow["accounttype"] );
6112 
6113  // * Build the notifydesc for trans type alerts
6114  /*
6115  * notifydesc for trans type will be different based on the value of
6116  * inctransdesc
6117  * 0 - USE the notifymsg as the descriptive text for THIS record
6118  * 1 - BUILD a message to display
6119  * 'Description Contains "notifydesc value"'
6120  *
6121  */
6122  if ($alertRow["alerttype"] == 'trans') {
6123  $alertRow["notifymsg"] = (intval($alertRow['inctransdesc']) == 1 ?
6124  'Description Contains' . ' "' . $alertRow['notifydesc'] . '" ' :
6125  $alertRow['notifymsg']);
6126  }
6127 
6128  $retAlert["data"][] = $alertRow;
6129  }
6130 
6131  db_free_result($alertRS);
6132 
6133  return $retAlert;
6134 } // end Read_AllAlerts
6135 
6136 /**
6137  * Read_OneAlert( $dbh, $pHBEnv )
6138  * Read a single alert.
6139  *
6140  * @param integer $dbh -- Current database handle
6141  * @param array $pHBEnv -- Current HB_ENV values
6142  *
6143  * Expected inputs:
6144  * $pHBEnv["Cu"] -- Current credit union
6145  * $pHBEnv["Uid"] -- Current user's user id
6146  * $pHBEnv["HCUPOST"]["id"] -- Id of alert in database table
6147  *
6148  * @returns $retAlert
6149  * ["code"] -- "000" success or "999" failure
6150  * ["errors"] -- Array of errors (if any)
6151  * ["data"] -- Detailed information about the specified alert (row in respective table).
6152  */
6153 function Read_OneAlert( $dbh, $pHBEnv ) {
6154  // initialize the return array
6155  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6156 
6157  $alertId = $pHBEnv["HCUPOST"]["id"];
6158  $Cu = $pHBEnv["Cu"];
6159  // really for another level of validation that reading correct alert
6160  $Uid = $pHBEnv["Uid"];
6161 
6162  // return the necessary data
6163  $sql = "SELECT *
6164  FROM cu_alerts
6165  WHERE id = '{$alertId}'
6166  AND cu = '{$Cu}'
6167  AND user_id = '{$Uid}' ";
6168  $alertRS = db_query( $sql, $dbh );
6169  $alertRow = db_fetch_assoc( $alertRS, 0 );
6170 
6171  // trim the data, if it exists
6172  if ( isset( $alertRow["id"] ) && $alertRow["id"] > 0 ) {
6173  foreach( $alertRow as $key => $value ) {
6174  $alertRow[$key] = trim($value);
6175  }
6176  }
6177 
6178  // loan accounts are refered to a different way
6179  if ( $alertRow["type"] == "l" ) {
6180  $selAcct = trim( $alertRow["loannumber"] );
6181  } else {
6182  $selAcct = trim( $alertRow["accounttype"] ) . "_" . trim( $alertRow["certnumber"] );
6183  }
6184 
6185  $alertRow["selacct"] = trim( $alertRow["accountnumber"] ) . "_" . $selAcct;
6186 
6187  $retAlert["data"] = $alertRow;
6188 
6189  return $retAlert;
6190 }
6191 
6192 /**
6193  * Delete_Alert( $dbh, $pHBEnv, $MC )
6194  * Delete a single alert.
6195  *
6196  * @param integer $dbh -- Current database handle
6197  * @param array $pHBEnv -- Current HB_ENV values
6198  * @param object $MC -- Language specific dictionary strings
6199  *
6200  * Expected inputs:
6201  * $pHBEnv["Cu"] -- Current credit union
6202  * $pHBEnv["Uid"] -- Current user's user id
6203  * $pHBEnv["HCUPOST"]["id"] -- Id of alert in respective database table
6204  *
6205  * @returns $retAlert
6206  * ["code"] -- "000" success or "999" failure
6207  * ["errors"] -- List of errors (if any)
6208  */
6209 function Delete_Alert( $dbh, $pHBEnv, $MC ) {
6210  // initialize the return array
6211  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6212 
6213  $alertId = $pHBEnv["HCUPOST"]["id"];
6214  $Cu = $pHBEnv["Cu"];
6215  // just this user
6216  $Uid = $pHBEnv["Uid"];
6217 
6218  $sql = "DELETE
6219  FROM cu_alerts
6220  WHERE id = {$alertId}
6221  AND cu = '{$Cu}'
6222  AND user_id = '{$Uid}'";
6223  $delRS = db_query( $sql, $dbh );
6224 
6225  $aryReturnErrors = array();
6226  if ( !$delRS ) {
6227  $aryReturnErrors[] = $MC->msg('Alert Delete Fail');
6228  } else {
6229  $affectedRows = db_affected_rows( $delRS );
6230 
6231  if ( $affectedRows != 1 ) {
6232  $aryReturnErrors[] = $MC->msg('Alert Delete Fail');
6233  }
6234  }
6235 
6236  if ( count( $aryReturnErrors ) > 0 ) {
6237  // * validation errors occurred
6238  $retAlert['code'] = '999';
6239  $retAlert["errors"] = $aryReturnErrors;
6240  }
6241 
6242  return $retAlert;
6243 }
6244 
6245 /**
6246  * Validate_Alert( $dbh, $pHBEnv, $MC )
6247  * Verify the alert update inputs.
6248  *
6249  * @param integer $dbh -- Current database handle
6250  * @param array $pHBEnv -- Current HB_ENV values
6251  * @param object $MC -- Language specific dictionary strings
6252  *
6253  * Expected inputs:
6254  * $pHBEnv["Cu"] -- Current credit union
6255  * $pHBEnv["Cn"] -- Current account number
6256  * $pHBEnv["HCUPOST"]["type"] -- Type of alert (bal, trans, check, loan)
6257  * For balance alert:
6258  * $pHBEnv["HCUPOST"]["notifyamt"] -- amount to trigger the alert
6259  * For transaction alert:
6260  * $pHBEnv["HCUPOST"]["notifydesc"] -- exact description to trigger alert (at least three characters)
6261  * $pHBEnv["HCUPOST"]["userange"] -- Y/N flag to also use a range
6262  * $pHBEnv["HCUPOST"]["desc_amtmin"] -- minimum of range
6263  * $pHBEnv["HCUPOST"]["desc_amtmax"] -- maximum of range
6264  * For check number alert:
6265  * $pHBEnv["HCUPOST"]["chknum"] -- check number to trigger alert
6266  * For all alerts:
6267  * $pHBEnv["HCUPOST"]["notifymsg"] -- message to send to member
6268  * $pHBEnv["HCUPOST"]["emailtype"] -- "E" = email, "W" = wireless
6269  * $pHBEnv["HCUPOST"]["provider_id"] -- wireless provider id
6270  * $pHBEnv["HCUPOST"]["notifyto"] -- email or cell number
6271  *
6272  * @returns $retAlert
6273  * ["code"] -- "000" success or "999" failure
6274  * ["errors"] -- List of errors (if any)
6275  */
6276 function Validate_Alert( $dbh, $pHBEnv, $MC ) {
6277  // all the information that was needed has been entered.
6278  // This is done differently depending on which options were selected
6279  // different options require different fields
6280 
6281  // initialize the return array
6282  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6283 
6284  $alertType = $pHBEnv["HCUPOST"]["type"];
6285 
6286  $aryReturnErrors = array();
6287 
6288  if ( trim( $pHBEnv["HCUPOST"]["mbr_account"] ) == "" ) {
6289  $aryReturnErrors[] = $MC->msg('Account Number Missing');
6290  }
6291 
6292  // An alert type MUST be selected
6293  $inctransdesc = 0;
6294  switch ( $alertType ) {
6295  case "bal": // ** BALANCE ALERT
6296  // Balance alert
6297  // Validate an amount was selected for less than
6298  if (trim($pHBEnv["HCUPOST"]["notifyamt"]) == "" || !is_numeric($pHBEnv["HCUPOST"]["notifyamt"])) {
6299  $aryReturnErrors[] = $MC->msg('Amount Missing');
6300  }
6301  break;
6302  case "trans": // ** TRANSACTION ALERT
6303  // Transaction Alert
6304  // Validate the range is correct if they selected to use an amount range
6305  if ( $pHBEnv["HCUPOST"]["userange"] == "1" ) {
6306  // validate the range values are entered
6307  if ( trim($pHBEnv["HCUPOST"]["desc_amtmin"]) == "" || !is_numeric($pHBEnv["HCUPOST"]["desc_amtmin"]) ) {
6308  $aryReturnErrors[] = $MC->msg('Amount Minimum');
6309  }
6310  if ( trim($pHBEnv["HCUPOST"]["desc_amtmax"]) == "" || !is_numeric($pHBEnv["HCUPOST"]["desc_amtmax"]) ) {
6311  $aryReturnErrors[] = $MC->msg('Amount Maximum');
6312  }
6313  }
6314  if ( strlen(trim($pHBEnv["HCUPOST"]["notifydesc"])) == 0 ) {
6315  $aryReturnErrors[] = $MC->msg('Description Missing');
6316  } elseif ( strlen(trim($pHBEnv["HCUPOST"]["notifydesc"])) < 3 ) {
6317  $aryReturnErrors[] = $MC->msg('Description Short');
6318  }
6319  // * For trans types, get the SUBMITTED user value for the include trans desc value
6320  $inctransdesc = intval($pHBEnv['HCUPOST']['inctransdesc']);
6321  break;
6322  case "check": // ** CHECK NUMBER ALERT
6323  // Check Number Alert
6324  if ( strlen(trim($pHBEnv["HCUPOST"]["chknum"])) == 0 ) {
6325  $aryReturnErrors[] = $MC->msg('Check Number Missing');
6326  }
6327  break;
6328  case "loan": // ** MISSED PAYMENT DATE
6329  // nothing to check
6330  break;
6331  default:
6332  $aryReturnErrors[] = $MC->msg('Invalid Alert Type');
6333  }
6334 
6335  // Require a message
6336  $notifyMsg = isset( $pHBEnv["HCUPOST"]["notifymsg"] ) && strlen( trim($pHBEnv["HCUPOST"]["notifymsg"]) ) > 0 ? trim($pHBEnv["HCUPOST"]["notifymsg"]) : "";
6337  if ( $notifyMsg == "" && (($alertType != 'trans') || ($alertType == 'trans' && $inctransdesc == 0))) {
6338  $aryReturnErrors[] = $MC->msg('Message Missing');
6339  }
6340 
6341  // Cell Phone/Email option
6342  $weType = isset( $pHBEnv["HCUPOST"]["emailtype"] ) && strlen( $pHBEnv["HCUPOST"]["emailtype"] ) ? $pHBEnv["HCUPOST"]["emailtype"] : "";
6343  $weType = substr(strtoupper($weType), 0, 1);
6344  $cellProvider = isset( $pHBEnv["HCUPOST"]["provider_id"] ) && strlen( $pHBEnv["HCUPOST"]["provider_id"] ) ? $pHBEnv["HCUPOST"]["provider_id"] : "";
6345  $notifyTo = isset( $pHBEnv["HCUPOST"]["notifyto"] ) && strlen( $pHBEnv["HCUPOST"]["notifyto"] ) ? trim( $pHBEnv["HCUPOST"]["notifyto"] ) : "";
6346  if ($weType == "E") {
6347  // Email -- be sure the value is selected
6348  if ( strlen( $notifyTo ) == 0 ) {
6349  $aryReturnErrors[] = $MC->msg('EMail Missing');
6350  } else {
6351  if ( !validateEmail( $notifyTo ) ) {
6352  $aryReturnErrors[] = $MC->msg('Email appears invalid');
6353  }
6354  }
6355  } else if ( $weType == "W" ) {
6356  // Cell Phone -- make sure a number is entered and just verify the provider
6357  if (strlen( $notifyTo ) == 0) {
6358  $aryReturnErrors[] = $MC->msg('Cell Number Missing');
6359  } elseif (strlen( $notifyTo ) != 10) {
6360  // ** Wrong number of digits entered
6361  $aryReturnErrors[] = $MC->msg('Cell Number Length');
6362  } elseif (!is_numeric( $notifyTo ) ) {
6363  // ** Be sure all are numeric digits
6364  $aryReturn['status']['errors'][] = $MC->msg('Cell Number Digits');
6365  }
6366  if (strlen( $cellProvider ) == '') {
6367  $aryReturn['status']['errors'][] = $MC->msg('Provider Missing');
6368  }
6369  } else {
6370  $aryReturn['status']['errors'][] = $MC->msg('Send Option Missing');
6371  }
6372 
6373  if ( count( $aryReturnErrors ) > 0 ) {
6374  // * validation errors occurred
6375  $retAlert['code'] = '999';
6376  $retAlert["errors"] = $aryReturnErrors;
6377  }
6378 
6379  return $retAlert;
6380 }
6381 
6382 /**
6383  * Update_Alert( $dbh, $pHBEnv, $MC )
6384  * Create/Update the alert.
6385  * NOTE: Verify_Alert should already have been called.
6386  *
6387  * @param integer $dbh -- Current database handle
6388  * @param array $pHBEnv -- Current HB_ENV values
6389  * @param object $MC -- Language specific dictionary strings
6390  *
6391  * Expected inputs:
6392  * $pHBEnv["Cu"] -- Current credit union
6393  * $pHBEnv["Cn"] -- Current account number
6394  * $pHBEnv["HCUPOST"]["type"] -- Type of alert (bal, trans, check, loan)
6395  * $pHBEnv["HCUPOST"]["id"] -- Id of alert in respective database table (0 if creating one)
6396  * $pHBEnv["HCUPOST"]["mbr_account"] -- Member account for alert
6397  * $pHBEnv["HCUPOST"]["selacct"] -- selected account_account-type_cert# or _loan#
6398  * For balance alert:
6399  * $pHBEnv["HCUPOST"]["notifyamt"] -- amount to trigger the alert
6400  * $pHBEnv["HCUPOST"]["incbal"] -- 1/0 flag to include the balance in the alert
6401  * $pHBEnv["HCUPOST"]["useavailbal"] -- use available balance (versus total balance)
6402  * $pHBEnv['HCUPOST']['inctransdesc'] -- 1/0 flag to use Transaction Desc (1) or custom message (0) *default
6403  * For transaction alert:
6404  * $pHBEnv["HCUPOST"]["notifydesc"] -- exact description to trigger alert (at least three characters)
6405  * $pHBEnv["HCUPOST"]["userange"] -- Y/N flag to also use a range
6406  * $pHBEnv["HCUPOST"]["desc_amtmin"] -- minimum of range
6407  * $pHBEnv["HCUPOST"]["desc_amtmax"] -- maximum of range
6408  * $pHBEnv["HCUPOST"]["incbal"] -- 1/0 flag to include the balance in the alert
6409  * $pHBEnv["HCUPOST"]["incamt"] -- 1/0 flag to include the amount in the description
6410  * $pHBEnv["HCUPOST"]["transtype"] -- flag for both (B), deposit (D), withdrawl (W)
6411  * For check number alert:
6412  * $pHBEnv["HCUPOST"]["chknum"] -- check number to trigger alert
6413  * $pHBEnv["HCUPOST"]["incamt"] -- 1/0 flag to include the amount in the description
6414  * For loan alerts
6415  * $pHBEnv["HCUPOST"]["days_prior"] -- number of days prior to due date
6416  * For all alerts:
6417  * $pHBEnv["HCUPOST"]["notifymsg"] -- message to send to member
6418  * $pHBEnv["HCUPOST"]["emailtype"] -- "E" = email, "W" = wireless
6419  * $pHBEnv["HCUPOST"]["provider_id"] -- wireless provider id
6420  * $pHBEnv["HCUPOST"]["notifyto"] -- email or cell number
6421  *
6422  * @returns $retAlert
6423  * ["code"] -- "000" success or "999" failure
6424  * ["errors"] -- List of errors (if any)
6425  */
6426 function Update_Alert( $dbh, $pHBEnv, $MC ) {
6427 
6428  // initialize the return array
6429  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6430 
6431  $Cu = $pHBEnv["Cu"];
6432  $alertType = $pHBEnv["HCUPOST"]["type"];
6433  $alertId = $pHBEnv["HCUPOST"]["id"];
6434 
6435  $acctType = "";
6436  $certNumber = "";
6437  $loanNumber = "";
6438  if (isset($pHBEnv["HCUPOST"]["selacct"])) {
6439  if ( $alertType == "loan" ) {
6440  list( $mbrAccount, $loanNumber) = explode( "_", $pHBEnv["HCUPOST"]["selacct"] );
6441  } else {
6442  list( $mbrAccount, $acctType, $certNumber) = explode( "_", $pHBEnv["HCUPOST"]["selacct"] );
6443  $certNumber = intval($certNumber); // need to be an integer
6444  }
6445  } else {
6446  $mbrAccount = isset( $pHBEnv["HCUPOST"]["mbr_account"] ) && strlen( trim($pHBEnv["HCUPOST"]["mbr_account"]) ) > 0 ? trim($pHBEnv["HCUPOST"]["mbr_account"]) : '';
6447  }
6448 
6449  // which account
6450  // the message
6451  $notifyMsg = isset( $pHBEnv["HCUPOST"]["notifymsg"] ) && strlen( trim($pHBEnv["HCUPOST"]["notifymsg"]) ) > 0 ? trim($pHBEnv["HCUPOST"]["notifymsg"]) : "";
6452 
6453  // Cell Phone/Email option
6454  $weType = isset( $pHBEnv["HCUPOST"]["emailtype"] ) && strlen( $pHBEnv["HCUPOST"]["emailtype"] ) ? $pHBEnv["HCUPOST"]["emailtype"] : "";
6455  $weType = substr(strtoupper($weType), 0, 1);
6456  $cellProvider = isset( $pHBEnv["HCUPOST"]["provider_id"] ) && strlen( $pHBEnv["HCUPOST"]["provider_id"] ) ? $pHBEnv["HCUPOST"]["provider_id"] : "";
6457  $notifyTo = isset( $pHBEnv["HCUPOST"]["notifyto"] ) && strlen( $pHBEnv["HCUPOST"]["notifyto"] ) ? trim( $pHBEnv["HCUPOST"]["notifyto"] ) : "";
6458 
6459  // Now Prepare to save the alert, may be UPDATE or INSERT, but first we must prepare the data
6460  $save_n_desc = "NULL"; // Notification Message
6461  $save_n_chk = "NULL"; // Check Number save Null Unless that alert is specified
6462  $save_n_trans = ""; // Transaction type for tranasction alert
6463  $save_wire_emailtype = $weType; // already formatted correctly
6464  $save_notifyto = prep_save( $notifyTo, 50 );
6465  $save_msg = prep_save( str_replace("\\", "", $notifyMsg), 255 );
6466 
6467  // SETUP THE DEFAULTS
6468  $save_n_min = "NULL";
6469  $save_n_max = "NULL";
6470 
6471  $save_loannumber = prep_save($loanNumber);
6472  $acctType = prep_save($acctType);
6473  $certNumber = prep_save($certNumber);
6474  $incBal = isset( $pHBEnv["HCUPOST"]["incbal"] ) && $pHBEnv["HCUPOST"]["incbal"] == 1 ? 1 : 0;
6475  $incAmt = isset( $pHBEnv["HCUPOST"]["incamt"] ) && $pHBEnv["HCUPOST"]["incamt"] == 1 ? 1 : 0;
6476  $incTransDesc = isset( $pHBEnv["HCUPOST"]["inctransdesc"] ) && $pHBEnv["HCUPOST"]["inctransdesc"] == 1 ? 1 : 0;
6477  $useAvailBal = isset( $pHBEnv["HCUPOST"]["useavailbal"] ) && $pHBEnv["HCUPOST"]["useavailbal"] == 1 ? 1 : 0;
6478  switch ( $alertType ) {
6479  case "bal": // ** BALANCE ALERT
6480  $save_n_min = 0; // For this type always save 0 as the minimum
6481  $save_n_max = $pHBEnv["HCUPOST"]["notifyamt"];
6482  break;
6483  case "trans": // ** TRANSACTION ALERT
6484  $save_n_desc = prep_save($pHBEnv["HCUPOST"]["notifydesc"], 90);
6485  $save_n_trans = prep_save($pHBEnv["HCUPOST"]["transtype"]);
6486  if ($pHBEnv["HCUPOST"]["userange"] == "1") {
6487  $save_n_min = $pHBEnv["HCUPOST"]["desc_amtmin"];
6488  $save_n_max = $pHBEnv["HCUPOST"]["desc_amtmax"];
6489  }
6490  $save_notifyrange = prep_save($pHBEnv["HCUPOST"]["userange"]);
6491  break;
6492  case "check": // ** CHECK NUMBER ALERT
6493  $save_n_chk = "'" . prep_save($pHBEnv["HCUPOST"]["chknum"], 8) . "'";
6494  break;
6495  case "loan": // ** MISSED PAYMENT DATE ALERT
6496  switch (intval($pHBEnv["HCUPOST"]["days_prior"])) {
6497  case 5:
6498  case 10:
6499  $save_days_prior = intval($pHBEnv["HCUPOST"]["days_prior"]);
6500  break;
6501  default:
6502  $save_days_prior = 0;
6503  }
6504  break;
6505  }
6506 
6507  // Separate out the bank account information
6508  if ( $alertId > 0 ) {
6509  // UPDATE the correct fields in the cu_alerts table for the specific type of alert
6510  switch ( $alertType ) {
6511  case "bal": // Balance Alert
6512  $field_value = "accounttype = '$acctType',
6513  certnumber = '$certNumber',
6514  incbal = '$incBal',
6515  useavailbal = '$useAvailBal',
6516  notifyamt = $save_n_max, ";
6517 
6518  break;
6519  case "trans": // Transaction Alert
6520  $field_value = "accounttype = '$acctType',
6521  certnumber = '$certNumber',
6522  incbal = '$incBal',
6523  incamt = '" . intval($incAmt) . "',
6524  inctransdesc = '$incTransDesc',
6525  notifyamtmin = $save_n_min,
6526  notifyamtmax = $save_n_max,
6527  notifyrange = '" . intval($save_notifyrange) . "',
6528  notifydesc = '$save_n_desc',
6529  notifytranstype = '$save_n_trans', ";
6530  break;
6531  case "check": // Check Number Alert
6532  $field_value = "accounttype = '$acctType',
6533  certnumber = '$certNumber',
6534  incamt = '" . intval($incAmt) . "',
6535  notifychknum = $save_n_chk, ";
6536  break;
6537  case "loan": // Missed Payment Alert
6538  $field_value = "accounttype = '$save_loannumber',
6539  notifyloandaysprior = $save_days_prior, ";
6540 
6541  break;
6542  }
6543 
6544  $sql = "UPDATE cu_alerts
6545  SET
6546  accountnumber = '$mbrAccount',
6547  $field_value
6548  emailtype = '$save_wire_emailtype',
6549  notifyto = '$save_notifyto',
6550  provider_id = '" . prep_save($cellProvider, 35) . "',
6551  notifymsg = '$save_msg'
6552  WHERE id = {$alertId} ";
6553 
6554  } else {
6555  // new entry
6556  switch ( $alertType ) {
6557  case "bal": // Balance Alert
6558  // On Insert also set the lastalert date to be 1/1/2000
6559  $field_list = "alerttype, accounttype, certnumber,
6560  incbal, useavailbal, notifyamt, lastalert ";
6561  $value_list = "'B', '$acctType', '$certNumber',
6562  $incBal, $useAvailBal, $save_n_max, NULL ";
6563  break;
6564  case "trans": // Transaction Alert
6565  // For a Transaction Alert -- I need to get the max tracenumber
6566  $sql = "SELECT max(tracenumber) as maxtrace
6567  FROM {$Cu}accounthistory
6568  WHERE accountnumber = '$mbrAccount'
6569  AND accounttype = '$acctType'
6570  AND certnumber = '$certNumber'
6571  AND tracenumber is not null ";
6572  $traceRS = db_query( $sql, $dbh );
6573  $traceRow = db_fetch_array($traceRS, 0);
6574 
6575  db_free_result($traceRS);
6576 
6577  $field_list = "alerttype, accounttype, certnumber,
6578  incbal, incamt, inctransdesc, notifyrange, notifyamtmin,
6579  notifyamtmax, notifydesc, notifytranstype, lasttrace, lastalert ";
6580  $value_list = "'T', '$acctType', '$certNumber',
6581  '$incBal',
6582  '" . intval($incAmt) . "', $incTransDesc,
6583  '" . intval($save_notifyrange) . "', $save_n_min,
6584  $save_n_max, '$save_n_desc', '$save_n_trans', '{$traceRow['maxtrace']}', NULL ";
6585  break;
6586  case "check": // Check Number Alert
6587  $field_list = "alerttype, accounttype, certnumber,
6588  incamt, notifychknum, lastalert ";
6589  $value_list = "'C', '$acctType', '$certNumber',
6590  '" . intval($incAmt) . "',
6591  $save_n_chk, NULL ";
6592  break;
6593  case "loan": // Missing Payment Alert
6594  // On Insert also set the lastalert date to be 1/1/2000
6595  $field_list = "alerttype, accounttype, lastalert, notifyloandaysprior ";
6596  $value_list = "'L', '$save_loannumber', NULL, $save_days_prior ";
6597  break;
6598  }
6599 
6600  $userId = $pHBEnv["Uid"];
6601 
6602  // get the next alert id since need to use it to return it and other info
6603  $sql = "SELECT nextval('cualerts_id_seq'::text) as alertid";
6604  $alertRS = db_query( $sql, $dbh );
6605  $alertRow = db_fetch_assoc( $alertRS );
6606  $alertId = $alertRow["alertid"];
6607 
6608  // INSERT into the cu_alerts table for the specific type of alert
6609  $sql = "INSERT INTO cu_alerts
6610  (id, cu, accountnumber, user_id, emailtype,
6611  notifyto, provider_id, notifymsg, alertstatus, $field_list )
6612  VALUES
6613  ($alertId, '{$Cu}', '$mbrAccount', $userId, '$save_wire_emailtype',
6614  '$save_notifyto', '" . prep_save($cellProvider, 35) . "',
6615  '$save_msg', 1, $value_list
6616  );";
6617 
6618  }
6619 
6620  if ((!$save_rs = db_query($sql, $dbh))) {
6621  // Error INSERTING The data
6622  $retAlert['errors'][] = $MC->msg('Error Saving Alert');
6623 
6624  }
6625  if ( count( $retAlert['errors'] ) > 0 ) {
6626  // * validation errors occurred
6627  $retAlert['code'] = '999';
6628  }
6629 
6630  return $retAlert;
6631 }
6632 
6633 /**
6634  * Check_AlertsEnabled( $dbh, $pHBEnv )
6635  * Check to see if the alert feature is enabled.
6636  *
6637  * @param integer $dbh -- Current database handle
6638  * @param array $pHBEnv -- Current HB_ENV values
6639  *
6640  * Expected inputs:
6641  * $pHBEnv["Cu"] -- Current credit union
6642  * $pHBEnv["Cn"] -- Current account number
6643  *
6644  * @returns false if not enabled OR $retAlert
6645  * ["code"] -- "000" success
6646  * ["errors"] -- List of errors (if any)
6647  */
6648 function Check_AlertsEnabled( $dbh, $pHBEnv ) {
6649  // initialize the return array
6650  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6651 
6652  // make sure they have an alert e-mail set up
6653  $sql = "SELECT email FROM cuadmnotify
6654  WHERE cu = '{$pHBEnv["Cu"]}' AND role = 'alert'";
6655  $emRS = db_query($sql, $dbh);
6656  $emRow = db_fetch_array($emRS, 0);
6657  $notifyEmail = $emRow["email"];
6658  db_free_result($emRS);
6659 
6660  if ( !strlen( trim( $notifyEmail ) ) ) {
6661  $retAlert = false;
6662  }
6663 
6664  return $retAlert;
6665 } // end Check_AlertsEnabled
6666 
6667 /**
6668  * Get_AlertLimits( )
6669  * Get the limits of totaly alerts and account-type limit for all alert types.
6670  *
6671  * @returns $retAlert
6672  * ["code"] -- "000" success
6673  * ["errors"] -- List of errors (if any)
6674  * ["data"] -- the alert limit data
6675  */
6676 function Get_AlertLimits( ) {
6677  // initialize the return array
6678  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6679 
6680  // use hard coded values
6681  define( "TRANS_LIMIT", 20 ); // This is the self-imposed limit for the number of transaction type alerts that may be created...
6682  // To change the maximum number of allowed alerts for transaction type, do it here...
6683 
6684  define( "CHECK_LIMIT", 4 ); // This is the self-imposed limit for the number of transaction type alerts that may be created...
6685  // To change the maximum number of allowed alerts for transaction type, do it here...
6686 
6687  $alertLimits = array();
6688  $alertLimits["bal"] = array( "total_limit" => 0, "acct_type" => 2 );
6689  $alertLimits["trans"] = array( "total_limit" => TRANS_LIMIT, "acct_type" => 0 );
6690  $alertLimits["check"] = array( "total_limit" => CHECK_LIMIT, "acct_type" => 0 );
6691  $alertLimits["loan"] = array( "total_limit" => 0, "acct_type" => 1 );
6692 
6693  $retAlert["data"] = $alertLimits;
6694 
6695  return $retAlert;
6696 } // end Get_AlertLimits
6697 
6698 /**
6699  * Get_AlerTypes( )
6700  * Get the names for all alert types.
6701  *
6702  * @param object $MC -- Language specific dictionary strings
6703  *
6704  * @returns $retAlert
6705  * ["code"] -- "000" success
6706  * ["errors"] -- List of errors (if any)
6707  * ["data"] -- the alert limit data
6708  */
6709 function Get_AlertTypes( $pMC ) {
6710  // initialize the return array
6711  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6712 
6713  // use hard coded values
6714  $alertTypes = array();
6715  $alertTypes[] = array( "name" => $pMC->msg('Balance'), "value" => "bal" );
6716  $alertTypes[] = array( "name" => $pMC->msg('Transaction'), "value" => "trans" );
6717  $alertTypes[] = array( "name" => $pMC->msg('Check Number'), "value" => "check" );
6718  $alertTypes[] = array( "name" => $pMC->msg('Missed Payment Date'), "value" => "loan" );
6719 
6720  $retAlert["data"] = $alertTypes;
6721 
6722  return $retAlert;
6723 } // end Get_AlertTypes
6724 
6725 /**
6726  * Get_AlertProviders( $dbh )
6727  * Get the alert cell phone provider names / ids.
6728  *
6729  * @param integer $dbh -- Current database handle
6730  *
6731  * Expected inputs:
6732  * None
6733  *
6734  * @returns $retAlert
6735  * ["code"] -- HB Standard codes 000 success, 999 error
6736  * ["errors"] -- List of errors (if any)
6737  * ["data"] -- Array of provider_id, provider_name pairs
6738  */
6739 function Get_AlertProviders( $dbh, $showSQL= false) {
6740  // initialize the return array
6741  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6742 
6743  $providers = array();
6744 
6745  $sql = "SELECT *
6746  FROM cualertproviders
6747  ORDER BY provider_name ";
6748  $provRS = db_query($sql, $dbh);
6749  $dbRow = 0;
6750  while ($provRow = db_fetch_assoc($provRS, $dbRow++)) {
6751  $provRow["provider_id"] = trim( $provRow["provider_id"] );
6752  $provRow["provider_name"] = trim( $provRow["provider_name"] );
6753  $providers[] = $provRow;
6754  }
6755 
6756  $retAlert["data"] = $providers;
6757  if ($showSQL)
6758  $retAlert["sqls"]= array($sql);
6759 
6760  return $retAlert;
6761 } // end Get_AlertProviders
6762 
6763 /**
6764  * Get_AlertDesc( $alertType, $pMC )
6765  * Get the display name of the alert type.
6766  *
6767  * @param string $alertType -- bal, trans, check, loan
6768  * @param object $MC -- Language specific dictionary strings
6769  *
6770  * Expected inputs:
6771  * None
6772  *
6773  * @returns $retAlert
6774  * ["code"] -- HB Standard codes 000 success, 999 error
6775  * ["errors"] -- List of errors (if any)
6776  * ["data"] -- Alert display name
6777  */
6778 function Get_AlertDesc( $alertType, $pMC ) {
6779  // initialize the return array
6780  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6781 
6782  $alertName = "";
6783  switch ($alertType) {
6784  case "bal":
6785  $alertName = $pMC->msg('Balance');
6786  break;
6787  case "trans":
6788  $alertName = $pMC->msg('Transaction');
6789  break;
6790  case "check":
6791  $alertName = $pMC->msg('Check Number');
6792  break;
6793  case "loan":
6794  $alertName = $pMC->msg('Missed Payment Date');
6795  break;
6796  }
6797 
6798  $retAlert["data"] = $alertName;
6799 
6800  return $retAlert;
6801 } // Get_AlertDesc
6802 
6803 /**
6804  * Get_AlertAccounts( $pDbh, $pCu, $pUid )
6805  * Get a list of accounts for all types of alerts.
6806  *
6807  * @param integer $pDbh -- Current database handle
6808  * @param string $pCu -- Current credit union
6809  * @param string $pAcct -- Current account number
6810  * @param string $pUid -- Current user
6811  *
6812  * Expected inputs:
6813  * $pHBEnv["Cu"] -- Current credit union
6814  * $pHBEnv["Cn"] -- Current account number
6815  *
6816  * @returns $retAlert
6817  * ["code"] -- HB Standard codes 000 success, 999 error
6818  * ["errors"] -- List of errors (if any)
6819  * ["data"] -- List of accounts, current count of each account in use
6820  */
6821 function Get_AlertAccounts( $pDbh, $pHBEnv ) {
6822  // initialize the return array
6823  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6824 
6825  $cu = $pHBEnv["Cu"];
6826  $uId = $pHBEnv["Uid"];
6827  $Fset = $pHBEnv["Fset"];
6828  $Fset2 = $pHBEnv["Fset2"];
6829  $Fset3 = $pHBEnv["Fset3"];
6830 
6831  // must setup an order by to match the TX_list function
6832  // this way the list will match the profile descriptions
6833  // screen and any other screens on banking.
6834 
6835  // since this is a union, loannumber and accounttype are
6836  // displayed in the accounttype column. we will use a case
6837  // statement in the sql to determine which way to trim accounttype.
6838  $orderBy = "";
6839  $orderBy .= "display_order,";
6840  $orderBy .= " CASE recordtype";
6841  $tempOid = '0';
6842  if (($Fset & GetFlagsetValue("CU_SORTORDER4")) == GetFlagsetValue("CU_SORTORDER4")) {
6843  //$orderBy .= " WHEN 'D' THEN btrim(accounttype, 'DIS')";
6844  $orderBy .= " WHEN 'D' THEN btrim(accounttype,'DIS')";
6845  } else if (($Fset2 & GetFlagsetValue("CU2_SORTORDER6")) == GetFlagsetValue("CU2_SORTORDER6")) {
6846  $orderBy .= " WHEN 'D' THEN acctoid";
6847  //" order by ua.display_order, btrim(ab.accounttype,'DIS'),ab.certnumber";
6848  //$orderBy .= " WHEN 'D' THEN "
6849 
6850  /**
6851  * This is NOT ideal, but there are some tables that do NOT have oid specified. So they can not have the 'oid' column referenced.
6852  *
6853  * If oid is NOT set then use the default value 0 as the column won't be used for ordering anyways.
6854  *
6855  * The 'oid' can not be referenced as it will break the query.
6856  *
6857  */
6858  $tempOid = "acct.oid";
6859  } else {
6860  $orderBy .= " WHEN 'D' THEN btrim(accounttype, 'DIS')";
6861  //$orderBy .= " WHEN 'D' THEN accounttype";
6862  }
6863 
6864  if ($Fset & GetFlagsetValue('CU_LNSORT2')) {
6865  $orderBy .= " WHEN 'L' THEN btrim(accounttype,'LC')";
6866  //$orderBy .= " WHEN 'L' THEN btrim(accounttype, 'LC')";
6867  } else {
6868  $orderBy .= " WHEN 'L' THEN accounttype";
6869  //$orderBy .= " WHEN 'L' THEN accounttype";
6870  }
6871 
6872  $orderBy .= " END,";
6873  $orderBy .= " accountnumber, certnumber";
6874 
6875  // bal and trans are the same accounts; checking accounts are bal/tran but with deposittype = Y
6876  $sql = "
6877  SELECT * FROM (
6878  SELECT acct.accountnumber, useracct.display_name, useracct.display_order, description, useracct.accounttype, useracct.certnumber,
6879  useracct.recordtype, useracct.view_balances, useracct.view_transactions, acct.deposittype, ma.restrictions, 1 as alertgroup, lpad({$tempOid}::varchar, 10, '0') as acctoid
6880  FROM {$cu}useraccounts as useracct
6881  INNER JOIN {$cu}accountbalance as acct ON acct.accountnumber = useracct.accountnumber
6882  AND acct.accounttype = useracct.accounttype
6883  AND acct.certnumber = useracct.certnumber
6884  INNER JOIN {$cu}memberacct ma ON ma.accountnumber = useracct.accountnumber
6885  WHERE useracct.user_id = $uId
6886  AND useracct.recordtype = 'D'
6887 
6888  UNION
6889 
6890  SELECT acct.accountnumber, useracct.display_name, useracct.display_order, description, useracct.accounttype, useracct.certnumber,
6891  useracct.recordtype, useracct.view_balances, useracct.view_transactions, 'N' as deposittype, ma.restrictions, 2 as alertgroup, lpad({$tempOid}::varchar, 10, '0') as acctoid
6892  FROM {$cu}useraccounts as useracct
6893  INNER JOIN {$cu}loanbalance as acct ON acct.accountnumber = useracct.accountnumber
6894  AND acct.loannumber = useracct.accounttype
6895  INNER JOIN {$cu}memberacct ma ON ma.accountnumber = useracct.accountnumber
6896  WHERE useracct.user_id ='$uId'
6897  AND useracct.recordtype = 'L'
6898  ) accts ORDER BY $orderBy";
6899 
6900  $acctRS = db_query( $sql, $pDbh );
6901  $rowCnt = 0;
6902  $acctListHolder = array();
6903  while ($acctRow = db_fetch_array( $acctRS, $rowCnt++ )) {
6904  // don't allow locked accounts
6905  if ( $acctRow["restrictions"] == "L" ) {
6906  continue;
6907  }
6908 
6909  $recordType = $acctRow["recordtype"];
6910  if ( $recordType == "L" ) {
6911  $ident = trim( $acctRow["accounttype"] );
6912  } else {
6913  $ident = trim( $acctRow["accounttype"] ) . "_" . trim( $acctRow["certnumber"] );
6914  }
6915 
6916  $account= trim($acctRow["accountnumber"]);
6917 
6918  // need to prepend the account number in case of multiple accounts
6919  $ident = $account . "_" . $ident;
6920 
6921  $acctListHolder[] = array( "type" => $recordType,
6922  "account" => $account,
6923  "description" => getAccountDescription($pDbh, $cu, $account, $acctRow['description'], $acctRow["accounttype"], $acctRow['display_name'], $Fset3,
6924  $acctRow["certnumber"], false),
6925  "deposit_acct" => strtoupper($acctRow["deposittype"]),
6926  "view_balances" => $acctRow['view_balances'],
6927  "view_transactions" => $acctRow['view_transactions'],
6928  "identifier" => $ident );
6929  }
6930 
6931  $retAlert["data"] = $acctListHolder;
6932  return $retAlert;
6933 } // end Get_AlertAccounts
6934 
6935 /**
6936  * Get_AlertAccountList( $dbh, $pHBEnv )
6937  * Get a list of sub-accounts that can handle the different alert types for the given user.
6938  *
6939  * @param integer $pDbh -- Current database handle
6940  * @param string $pCu -- Current credit union
6941  * @param string $pAcct -- Current account number
6942  * @param integer $pUid -- Current user id
6943  *
6944  * @returns $retAlert
6945  * ["code"] -- HB Standard codes 000 success, 999 error
6946  * ["errors"] -- List of errors (if any)
6947  * ["data"] -- List of accounts, flagged for each type of alert it can be used.
6948  */
6949 function Get_AlertAccountList( $pDbh, $pHbEnv ) {
6950  // initialize the return array
6951  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
6952 
6953  $accountList = array();
6954 
6955  $return = Get_AlertAccounts( $pDbh, $pHbEnv );
6956  $alertAccounts = $return["data"];
6957 
6958  for ( $t = 0; $t < count( $alertAccounts ); $t++ ) {
6959  // see if already have this sub_account for the member account
6960  $found = false;
6961  for ( $i = 0; $i < count( $accountList ); $i++ ) {
6962  if ( ($alertAccounts[$t]["account"] == $accountList[$i]["accountnumber"]) &&
6963  ($alertAccounts[$t]["identifier"] == $accountList[$i]["acct_ident"]) ) {
6964  $found = true;
6965  break;
6966  }
6967  }
6968 
6969  if ( !$found ) {
6970  // create new entry
6971  $accountList[] = array (
6972  "acct_ident" => $alertAccounts[$t]["identifier"],
6973  "accountnumber" => $alertAccounts[$t]["account"],
6974  "description" => $alertAccounts[$t]["description"],
6975  "bal_allowed" => false,
6976  "trans_allowed" => false,
6977  "check_allowed" => false,
6978  "loan_allowed" => false );
6979  }
6980 
6981  // mark this type as allowed if the permission allows it as can be used by this type based on permissions
6982  // RULES: If type "B" (balances):
6983  if ( $alertAccounts[$t]["type"] == "D" ) {
6984  if ( $alertAccounts[$t]["view_balances"] == "t" ) {
6985  $accountList[$i]["bal_allowed"] = true;
6986  }
6987  if ( $alertAccounts[$t]["view_transactions"] == "t" ) {
6988  $accountList[$i]["trans_allowed"] = true;
6989 
6990  if ( $alertAccounts[$t]["deposit_acct"] == "Y" ) {
6991  $accountList[$i]["check_allowed"] = true;
6992  }
6993  }
6994  } else if ( $alertAccounts[$t]["type"] == "L" ) {
6995  if ( $alertAccounts[$t]["view_balances"] == "t" ) {
6996  $accountList[$i]["loan_allowed"] = true;
6997  }
6998  }
6999 
7000  }
7001 
7002  // count limits are checked via the permissions module
7003 
7004  $retAlert["data"] = $accountList;
7005 
7006  return $retAlert;
7007 } // end Get_AlertAccountList
7008 
7009 /**
7010  * Get_AlertsDetailed( $dbh, $pHBEnv)
7011  * Read all the current alerts with any extended data for each.
7012  * NOTE: The returned information will be a flat array of all possible alert information but with
7013  * only that alert-specific information filled in.
7014  * NOTE: The "lastalert" value is returned unformatted. It is left to the presentation layer to format as necessary.
7015  *
7016  * @param integer $pDbh -- Current database handle
7017  * @param string $pCu -- Credit union code
7018  * @param integer $pUid -- Current user id
7019  * @param boolean $showSQL -- If true, then SQL will be returned. (Only the first two parameters need to be defined. If this isn't defined, then it is false.)
7020  *
7021  * @returns $retAlert
7022  * ["code"] -- HB Standard codes 000 success, 999 error
7023  * ["errors"] -- List of errors (if any)
7024  * ["sqls"] -- List of sqls (if $showSQL is defined and set to true)
7025  * ["data"] -- List of current alerts - all possible info for all alert types.
7026  */
7027 function Get_AlertsDetailed( $pDbh, $pCu, $pUid, $Fset3, $MC= null)
7028 {
7029  // initialize the return array
7030  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
7031 
7032  // initialize the return array
7033  $currAlerts = array();
7034  $sqls= array();
7035 
7036  // set up the alert types
7037  $alertTypes= array("B" => array("type" => "bal", "name" => isset($MC) ? $MC->msg("Balance", HCU_DISPLAY_AS_JS) : "Balance"),
7038  "T" => array("type" => "trans", "name" => isset($MC) ? $MC->msg("Transaction", HCU_DISPLAY_AS_JS) : "Transaction"),
7039  "C" => array("type" => "check", "name" => isset($MC) ? $MC->msg("Check", HCU_DISPLAY_AS_JS) : "Check"),
7040  "L" => array("type" => "loan", "name" => isset($MC) ? $MC->msg("Loan", HCU_DISPLAY_AS_JS) : "Loan"));
7041 
7042  // this one for loans
7043  $sql = "SELECT alert.alerttype, alert.accountnumber, coalesce(nullif(trim(ua.display_name), ''), description) as descSort, ua.certnumber, ua.accounttype, alert.*, description,
7044  ua.display_name, ma.restrictions
7045  FROM cu_alerts alert
7046  INNER JOIN {$pCu}loanbalance lb ON lb.accountnumber = alert.accountnumber
7047  AND lb.loannumber = alert.accounttype
7048  INNER JOIN {$pCu}useraccounts ua ON ua.accountnumber = alert.accountnumber
7049  AND ua.accounttype = alert.accounttype
7050  AND ua.user_id = alert.user_id
7051  INNER JOIN {$pCu}memberacct ma ON ma.accountnumber = alert.accountnumber
7052  WHERE alert.cu = '{$pCu}'
7053  AND alert.alerttype = 'L'
7054  AND alert.user_id = '{$pUid}' ";
7055 
7056  // combine into a single query
7057  $sql .= " UNION ";
7058 
7059  // this one for non-loans
7060  $sql .= "SELECT alert.alerttype, alert.accountnumber, coalesce(nullif(trim(ua.display_name), ''), description) as descSort, ua.certnumber, ua.accounttype, alert.*, description,
7061  ua.display_name, ma.restrictions
7062  FROM cu_alerts alert
7063  INNER JOIN {$pCu}accountbalance ab ON ab.accountnumber = alert.accountnumber
7064  AND ab.accounttype = alert.accounttype
7065  AND ab.certnumber = alert.certnumber
7066  INNER JOIN {$pCu}useraccounts ua ON ua.accountnumber = alert.accountnumber
7067  AND ua.accounttype = alert.accounttype
7068  AND ua.certnumber = alert.certnumber
7069  AND ua.user_id = alert.user_id
7070  INNER JOIN {$pCu}memberacct ma ON ma.accountnumber = alert.accountnumber
7071  WHERE alert.cu = '{$pCu}'
7072  AND alert.alerttype IN ('B', 'T', 'C')
7073  AND alert.user_id = '{$pUid}' ";
7074 
7075  // consistent ordering
7076  $sql .= "ORDER BY 1, 2, 3";
7077 
7078  $sqls[]= $sql;
7079 
7080  $alertRS = db_query($sql, $pDbh);
7081  $iRow = 0;
7082  while ( $alertRow = db_fetch_assoc($alertRS, $iRow++) ) {
7083 
7084  // clean up the returned data
7085  foreach( $alertRow as $key => $value ) {
7086  $alertRow[$key] = trim($value);
7087  }
7088 
7089  // Don't print the last alert date if it is 1/1/2000
7090  $lastAlert= trim($alertRow["lastalert"]);
7091  if ( $lastAlert == "01/01/2000" ) {
7092  $alertRow["lastalert"] = "";
7093  } else if ( strlen( $lastAlert ) ) {
7094  $lastAlertTime = strtotime($lastAlert);
7095  if ( date( "m/d/Y", $lastAlertTime ) == "01/01/2000" ) {
7096  $alertRow["lastalert"] = "";
7097  } else {
7098  $alertRow["lastalert"] = $lastAlert;
7099  }
7100  } else {
7101  $alertRow["lastalert"] = "";
7102  }
7103 
7104  /*
7105  * notifymsg for trans type will be different based on the value of
7106  * inctransdesc
7107  * 0 - USE the notifymsg as the descriptive text for THIS record
7108  * 1 - BUILD a message to display
7109  * 'Description Contains "notifydesc value"'
7110  *
7111  */
7112  $lNotifyMsg = (intval($alertRow['inctransdesc']) == 1 ?
7113  'Description Contains' . ' ' . $alertRow['notifydesc'] :
7114  $alertRow['notifymsg']);
7115 
7116  // get the type names to return
7117  $type= $alertRow["alerttype"];
7118  $typeRecord= $alertTypes[$type];
7119 
7120  $accountnumber= trim($alertRow["accountnumber"]);
7121 
7122  // loan accounts are referred to a different way than non-loans
7123  $selAcct = $type == "L" ? trim( $alertRow["accounttype"] ) : trim( $alertRow["accounttype"] ) . "_" . trim( $alertRow["certnumber"] );
7124  $selAcct = trim( $alertRow["accountnumber"] ) . "_" . $selAcct;
7125 
7126  // return consistent information even if this alert type doesn't use that information
7127  $currAlerts[] = array(
7128  "type" => $typeRecord["type"],
7129  "type_name" => $typeRecord["name"],
7130  "id" => $alertRow["id"],
7131  "description" => getAccountDescription($pDbh, $pCu, $accountnumber, $alertRow["description"], $alertRow["accounttype"], $alertRow['display_name'], $Fset3, $alertRow["certnumber"]),
7132  "accountnumber" => $accountnumber,
7133  "emailtype" => $alertRow["emailtype"],
7134  "notifyto" => $alertRow["notifyto"],
7135  "provider_id" => $alertRow["provider_id"],
7136  "provider_name" => isset( $alertRow["provider_name"] ) ? $alertRow["provider_name"] : "",
7137  "notifymsg" => $alertRow["notifymsg"],
7138  "notifydisplaymsg" => $lNotifyMsg,
7139  "lastalert" => $alertRow["lastalert"],
7140  "alertstatus" => $alertRow["alertstatus"],
7141  "restrictions" => $alertRow["restrictions"],
7142  "selacct" => $selAcct,
7143  "incbal" => $type == "B" || $type == "T" ? $alertRow["incbal"] : "", // bal, trans
7144  "inctransdesc" => $type == "T" ? $alertRow["inctransdesc"] : "0", // trans
7145  "notifyamt" => $type == "B" ? $alertRow["notifyamt"] : "", // bal
7146  "useavailbal" => $type == "B" ? $alertRow["useavailbal"] : "", // bal
7147  "incamt" => $type == "T" || $type == "C" ? $alertRow["incamt"] : "", // check, trans
7148  "notifychknum" => $type == "C" ? $alertRow["notifychknum"] : "", // check
7149  "alert_days_prior" => $type == "L" ? $alertRow["notifyloandaysprior"] : "", // loan
7150  "notifyrange" => $type == "T" ? $alertRow["notifyrange"] : "", // trans
7151  "notifyamtmin" => $type == "T" ? $alertRow["notifyamtmin"] : "", // trans
7152  "notifyamtmax" => $type == "T" ? $alertRow["notifyamtmax"] : "", // trans
7153  "notifydesc" => $type == "T" ? $alertRow["notifydesc"] : "", // trans
7154  "notifytranstype" => $type == "T" ? $alertRow["notifytranstype"] : "" // trans
7155  );
7156  }
7157 
7158  db_free_result($alertRS);
7159 
7160  $retAlert["data"] = $currAlerts;
7161 
7162  return $retAlert;
7163 } // end Get_AlertsDetailed
7164 
7165 /**
7166  * Get_UserAccounts( $dbh, $pHBEnv, $alertType )
7167  * Get the accounts the user can work with.
7168  *
7169  * @param integer $pDbh -- Current database handle
7170  * @param string $pCu -- Current HB_ENV values
7171  * @param integer $pUid -- Current HB_ENV values
7172  *
7173  * @returns $retAlert
7174  * ["code"] -- HB Standard codes 000 success, 999 error
7175  * ["errors"] -- List of errors (if any)
7176  * ["data"] -- Default email if any.
7177  */
7178 function Get_UserAccounts( $pDbh, $pCu, $pUid ) {
7179  // initialize the return array
7180  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
7181 
7182  $cu = strtolower( $pCu );
7183 
7184  $sql = "SELECT DISTINCT accountnumber
7185  FROM {$cu}useraccounts
7186  WHERE user_id = $pUid ";
7187  $accountRS = db_query( $sql, $pDbh );
7188 
7189  $accountList = array();
7190  $iRow = 0;
7191  while ( $alertRow = db_fetch_assoc($accountRS, $iRow++) ) {
7192  $accountList[] = trim( $alertRow["accountnumber"] );
7193  }
7194 
7195  db_free_result( $accountRS );
7196 
7197  $retAlert["data"] = $accountList;
7198  $retAlert["sql"] = $sql;
7199 
7200  return $retAlert;
7201 } // end Get_UserAccounts
7202 
7203 
7204 /**
7205  * Get_AlertDefaultEmail( $dbh, $pHBEnv )
7206  * Get the default email for the given user.
7207  *
7208  * @param integer $dbh -- Current database handle
7209  * @param array $pHBEnv -- Current HB_ENV values
7210  *
7211  * Expected inputs:
7212  * $pHBEnv["Cu"] -- Current credit union
7213  * $pHBEnv["Uid"] -- Current user id
7214  *
7215  * @returns $retAlert
7216  * ["code"] -- HB Standard codes 000 success, 999 error
7217  * ["errors"] -- List of errors (if any)
7218  * ["data"] -- Default email if any.
7219  */
7220 function Get_AlertDefaultEmail( $dbh, $pHBEnv ) {
7221  // initialize the return array
7222  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
7223 
7224  $Cu = $pHBEnv["Cu"];
7225  $Uid = $pHBEnv["Uid"];
7226 
7227  $cu = strtolower( $Cu );
7228  $sql = "SELECT email
7229  FROM {$cu}user
7230  WHERE user_id = $Uid ";
7231  $emailRS = db_query( $sql, $dbh );
7232  $emailRow = db_fetch_array( $emailRS, 0 );
7233  db_free_result( $emailRS );
7234 
7235  $defaultEmail = "";
7236  if ( strlen( trim( $emailRow['email'] ) ) ) {
7237  if (function_exists('hcu_displayHtml')) {
7238  $defaultEmail = hcu_displayHtml( $emailRow['email'], ENT_QUOTES, true );
7239  } else {
7240  $defaultEmail = disp_i18n( $emailRow['email'], ENT_QUOTES );
7241  }
7242  }
7243 
7244  $retAlert["data"] = $defaultEmail;
7245 
7246  return $retAlert;
7247 } // end Get_AlertDefaultEmail
7248 
7249 /**
7250  * Get_AlertDefaultCell( $dbh, $pHBEnv )
7251  * Get the default cell for the given user by looking through previously set up alerts.
7252  * - get this regardless of which account the alert was set up for
7253  *
7254  * @param integer $dbh -- Current database handle
7255  * @param array $pHBEnv -- Current HB_ENV values
7256  * @param string &$cellProvider -- Return value of cell provider
7257  * @param string &$cellProviderId -- Return value of cell provider id
7258  *
7259  * Expected inputs:
7260  * $pHBEnv["Cu"] -- Current credit union
7261  * $pHBEnv["Uid"] -- Current user's user id
7262  *
7263  * @returns $retAlert
7264  * ["code"] -- HB Standard codes 000 success, 999 error
7265  * ["errors"] -- List of errors (if any)
7266  * ["data"] -- Default cell: name of provider, provider id
7267  */
7268 function Get_AlertDefaultCell( $dbh, $pHBEnv ) {
7269  // initialize the return array
7270  $retAlert = array( "code" => "000", "errors" => array(), "data" => array() );
7271 
7272  $Cu = $pHBEnv["Cu"];
7273  // just this user
7274  $Uid = $pHBEnv["Uid"];
7275 
7276  $sql = "
7277  SELECT notifyto, provider_id
7278  FROM cu_alerts
7279  WHERE cu = '$Cu'
7280  AND user_id = '{$Uid}'
7281  AND emailtype = 'W'
7282  GROUP BY notifyto, provider_id
7283  ORDER BY notifyto, provider_id
7284  ";
7285 
7286  $cellRS = db_query( $sql, $dbh );
7287  $cellRow = db_fetch_array( $cellRS, 0 );
7288  db_free_result($cellRS);
7289 
7290  if ( $cellRow ) {
7291  if (function_exists('hcu_displayHtml')) {
7292  $cellProvider["cell_number"] = hcu_displayHtml( $cellRow['notifyto'], ENT_QUOTES, true );
7293  } else {
7294  $cellProvider["cell_number"] = disp_i18n( $cellRow['notifyto'], ENT_QUOTES );
7295  }
7296  $cellProvider["provider_id"] = trim( $cellRow['provider_id'] ); // Set the cellular provider selected
7297  } else {
7298  $cellProvider["cell_number"] = "";
7299  $cellProvider["provider_id"] = "";
7300  }
7301 
7302  $retAlert["data"] = $cellProvider;
7303 
7304  return $retAlert;
7305 } // end Get_AlertDefaultCell
7306 
7307 /**
7308  * Update_AlertStatuses($dbh, $cuCode, $userId, $alerts, $loggedInUser, $showSQL=false)
7309  *
7310  * @param integer $dbh the database connection
7311  * @param string $cuCode the Credit Union
7312  * @param string $userId the user Id
7313  * @param boolean $alerts Alert list
7314  * @param string $loggedInUser the logged in user
7315  *
7316  * @return $returnArray["code" => code, "errors" => errors, "sqls" => sqls]
7317  * If there is a syntax error on the SQL, then code= 1 and errors = array(error). Otherwise code=0 and errors= array().
7318  * If $showSQL is true, then $returnArray["sqls"] is also available: the list of sqls.
7319  */
7320 function Update_AlertStatuses($dbh, $cuCode, $userId, $alerts, $loggedInUser) {
7321  $code = 0;
7322  $errors = array();
7323 
7324  try {
7325  if (trim($alerts) != "") {
7326  $alerts = HCU_JsonDecode($alerts, false);
7327  if (!is_array($alerts)) {
7328  throw new Exception("Alerts are not encoded correctly.", 2);
7329  }
7330  } else {
7331  $alerts = array();
7332  }
7333 
7334  $updateArray = array();
7335  foreach($alerts as $alert) {
7336  if (!(isset($alert["id"]) && isset($alert["alertstatus"]))) {
7337  throw new Exception("Alert is not formatted correctly.", 3);
7338  }
7339  $updateArray[] = array("_action" => "update", "id" => $alert["id"], "alertstatus" => $alert["alertstatus"]);
7340  }
7341 
7342  $updateArray= array("alert" => $updateArray);
7343 
7344  // TODO: this is in a function in userSupport.data. If it is used elsewhere, need to change variables.
7345  $context = "admin";
7346  $script = "userSupport.prg";
7347  $email = "";
7348 
7349  $sql = "select email from cuadminusers where user_name = '$loggedInUser' and cu= '$cuCode'";
7350  if (($sth = db_query($sql, $dbh)) !== false) {
7351  $email = db_fetch_row($sth)[0];
7352  } else {
7353  throw new Exception("Email query failed.", 7);
7354  }
7355 
7356  if (count($updateArray["alert"]) > 0 && DataUserTableUpdate($dbh, array("cu" => $cuCode), null, $updateArray, $userId, "ALT_STATUS", $context, $script, "A", "Alert Status Update",
7357  $loggedInUser, $email, trim($_SERVER["REMOTE_ADDR"])) === false) {
7358  throw new Exception("Alert status update failed.", 6);
7359  }
7360  } catch(Exception $e) {
7361  $errors = array($e->getMessage());
7362  $code = $e->getCode();
7363  }
7364 
7365  $returnArray = array("code" => $code, "errors" => $errors);
7366  return $returnArray;
7367 }
7368 
7369 /**
7370  *
7371  * Get_BannerText($dbh, $HB_ENV, $MC, $device)
7372  * Get the stored banner text, if any, for the cu / device in use
7373  *
7374  * @param integer $dbh - Current database handle
7375  * @param array $HB_ENV - Current HB_ENV values
7376  * @param class $p_mc - Current object for MC Language class
7377  * @param string $p_device - {M,R,C,D,P}Pass in the device type
7378  * M - Mobile Device
7379  * P - Iphone App Device
7380  * C - Classic device
7381  * D - Desktop (NEW) Presentation *
7382  * Expected inputs:
7383  * $HB_ENV["Cu"] -- Current credit union
7384  * $HB_ENV["Cn"] -- Current account number
7385  *
7386  * Returns:
7387  * [status]
7388  * [code] HB Standard codes 000 success, 999 error
7389  * [errors] List of errors if any exist
7390  * [banner]
7391  * [bannertext] banner content text
7392  * [startdate] defined start date for banner YYYY-MM-DD
7393  * [stopdate] defined stop date for banner YYYY-MM-DD
7394  */
7395 
7396 function Get_BannerText($dbh, $HB_ENV, $MC, $device) {
7397  # look for embedded banner info
7398  $aryReturn = Array("status" => Array("code", "errors" => Array()));
7399 
7400  switch ($device) {
7401  case "M":
7402  case "P":
7403  $stype=3;
7404  break;
7405  case "C":
7406  case "D":
7407  default:
7408  $stype=2;
7409  break;
7410  }
7411  $Cu = $HB_ENV['Cu'];
7412 
7413  $bannertext="";
7414  $bnrSql = "select trim(question) as question,
7415  to_char(startdate,'YYYY-MM-DD') as startdate,
7416  to_char(stopdate,'YYYY-MM-DD') as stopdate
7417  from cusurveymaster
7418  where cu = '$Cu' and surveytype = $stype
7419  and startdate <= CURRENT_DATE
7420  and stopdate >= CURRENT_DATE";
7421 
7422  if (!$sbh = db_query($bnrSql, $dbh)) {
7423  $aryReturn['status']['errors'][] = $MC->msg('Error Finding Form');
7424  } else {
7425  $bnrRow = db_fetch_array( $sbh, 0 );
7426  $bannertext=stripslashes($bnrRow['question']);
7427  }
7428 
7429  if ( count( $aryReturn['status']['errors'] ) > 0 ) {
7430  // * validation errors occurred
7431  $aryReturn['status']['code'] = '999';
7432  $aryReturn['banner']=array();
7433  } else {
7434  // * SUCCESS
7435  $aryReturn['status']['code'] = '000';
7436  $aryReturn['banner']['bannertext'] = $bannertext;
7437  $aryReturn['banner']['startdate'] = $bnrRow['startdate'];
7438  $aryReturn['banner']['stopdate'] = $bnrRow['startdate'];
7439  $aryReturn['banner']['bnrRow'] = $bnrRow;
7440  $aryReturn['banner']['bnrSql'] = $bnrSql;
7441  }
7442 
7443  return $aryReturn;
7444 
7445 }
7446 
7447 function Translate_BannerText($HB_ENV, $btext) {
7448  $Cu = $HB_ENV['Cu'];
7449  $Cn = $HB_ENV['Cn'];
7450 
7451  $aryfind = array('$Cn','$Cu');
7452  $aryreplace = array("$Cn","$Cu");
7453 
7454  $bannertext = str_replace($aryfind, $aryreplace,$btext);
7455 
7456  if ( empty($bannertext) ) {
7457  $aryReturn['status']['code'] = '999';
7458  $aryReturn['banner']['bannertext'] = '';
7459  } else {
7460 
7461  $aryReturn['status']['code'] = '000';
7462  $aryReturn['banner']['bannertext'] = $bannertext;
7463  }
7464 
7465  return $aryReturn;
7466 
7467  }
7468 
7469  /**
7470  * Post_CUEStmt
7471  *
7472  * Purpose: This function will post the necessary pieces for the estatement
7473  * enrollment.
7474  *
7475  * Options are:
7476  * Post packet to CU Core
7477  * Set the ES flag on cuusers table
7478  * Create the CU sslform
7479  *
7480  * @param integer $pDbh - Current Database handle
7481  * @param array $pHBEnv - Current HB_ENV
7482  * esProcessMode - {start, stop} - determines the processing type
7483  *
7484  * ['HCUPOST']['stop_reason'] - esProcessMode = 'stop' ONLY This is the reason
7485  * member is stopping. It is required for 'stop'
7486  *
7487  * @param object $pMC -- This points to the current MC value for the language class
7488  * @param string $pAcct -- account number
7489  *
7490  * @return array Return status array
7491  * 'status' : '000' - Success
7492  * '999' - Error found
7493  *
7494  */
7495  function Post_CUEStmt($pDbh, $pHBEnv, $pMC, $pAcct) {
7496 
7497  $retStatus_ary = Array('status' => Array('code'=>'000', 'errors' => Array()));
7498 
7499  try {
7500  /*
7501  * Verify Credit Union has EStatements setup
7502  * Validate the information is ready to post
7503  * ** PROCESS **
7504  * Post Packet to CU Core if Applicable
7505  * Write the CU secure form
7506  * Update the Member ES Flag
7507  * Send email to the CU Admin Notify
7508  */
7509 
7510  /*
7511  * ** VERIFY CU IS SET UP**
7512  */
7513  $retCUStatus = Get_EstmtEnrollStatus($pDbh, $pHBEnv, $pMC, $pAcct);
7514  if ($retCUStatus['status']['code'] == '999') {
7515  if ($retCUStatus['status']['errors'][0] != '') {
7516  $errMsg = $retCUStatus['status']['errors'][0];
7517  } else {
7518  $errMsg = $pMC->msg('Contact CU');
7519  }
7520  throw new Exception($errMsg);
7521  }
7522 
7523  /*
7524  * ** VALIDATE ANY DATA HERE**
7525  */
7526  $esFormNotes = Array();
7527  if (strtoupper($pHBEnv['esProcessMode']) == 'STOP') {
7528  // * Stop Mode
7529  $esFormMode = 'N';
7530  $esFormNotes[] = 'This is a STOP request.';
7531  } else {
7532  // * Start Mode
7533  $esFormMode = 'Y';
7534  }
7535  if ($pHBEnv['Ml'] == '') {
7536  // ** THERE is NO email,
7537  $esFormNotes[] = 'No valid email set.';
7538  }
7539 
7540  // ** Validate the stop_reason is entered for stop mode
7541  if ($esFormMode == 'N') {
7542  if (trim($pHBEnv['HCUPOST']['stop_reason']) == '') {
7543  $errMsg = 'Please provide the reason for stopping e-statements.';
7544  throw new Exception($errMsg);
7545  }
7546  }
7547 
7548  $secureFormTitle = $pMC->msg('E-STATEMENT ' . strtoupper($pHBEnv['esProcessMode']) . ' REQUEST');
7549 
7550  /*
7551  * ** POST TO CU CORE??
7552  * 09/19: we need to know if the ES flag is enabled in CU Home Banking in order to add the
7553  * online transaction message to the response for admin secure forms. Previously this
7554  * was done with an SQL query in Post_CUESPacket(), after it is needed here. Use
7555  * Get_HaveTrans() for this purpose, moving the logic here and only call
7556  * Post_CUESPacket() if we need to, making Post_CUESPacket()follow
7557  * SRP. We can also eliminate the DB param sent to Post_CUESPacket().
7558  */
7559  $trans_array = Get_HaveTrans($pDbh, $pHBEnv);
7560 
7561  // ** This is a LIVE system and the ES feature is ENABLED
7562  if (isset($pHBEnv['live']) && array_key_exists('ES', $trans_array)) {
7563 
7564  $packetValues = Array(
7565  'Tc' => 'ES',
7566  'R1' => ' ',
7567  'R2' => ' ',
7568  'R3' => $pHBEnv['Ml'],
7569  'R4' => ' ',
7570  'R5' => $esFormMode,
7571  "selectedAccount" => $pAcct
7572  );
7573  $postEntryPacketAry = Post_CUESPacket($pHBEnv, $pMC, $packetValues);
7574 
7575  if ($postEntryPacketAry['status']['error'] != '') {
7576  if ($postEntryPacketAry['status']['code'] == '000') {
7577  // ** Packet was posted.. Capture the string returned from the core
7578  $esFormNotes[] = 'This request was processed as an online transaction';
7579  } else {
7580  throw new Exception($postEntryPacketAry['status']['error']);
7581  }
7582  }
7583  }
7584 
7585  /*
7586  * ** WRITE SECURE FORM
7587  */
7588  $entryFields = Array (
7589  "Cn" => Array('required' => false, 'dataKey' => '', 'dataLabel' => 'CU Account Number'),
7590  "Ml" => Array('required' => true, 'dataKey' => '', 'dataLabel' => 'E-mail Address')
7591  );
7592  if ($esFormMode == 'N') {
7593  $entryFields["stop_reason"] = Array('required' => true, 'dataKey' => 'HCUPOST', 'dataLabel' => $pMC->msg('Why Stop'));
7594  }
7595  foreach ($entryFields as $fieldKey => $fieldAttr) {
7596  // ** loop through each field add to the form data array
7597  $secureFormDataAry[] = Array('type' => 'field',
7598  'label' => $fieldAttr['dataLabel'],
7599  'value' => ($fieldAttr['dataKey'] != '' ? $pHBEnv[$fieldAttr['dataKey']][$fieldKey] : $pHBEnv[$fieldKey]));
7600  }
7601 
7602  $secureFormData = <<< printblock
7603 <?xml version="1.0"?><!doctype html>
7604 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7605  <head>
7606  <title>$secureFormTitle</title>
7607  <link href="https://{$pHBEnv['cloudfrontDomainName']}/homecu/css/KendoUI/{$pHBEnv['homecuKendoVersion']}/kendo.common.min.css" rel="stylesheet">
7608  <link href="https://{$pHBEnv['cloudfrontDomainName']}/homecu/css/KendoUI/{$pHBEnv['homecuKendoVersion']}/kendo.default.min.css" rel="stylesheet">
7609 
7610  <script type="text/javascript" src="https://{$pHBEnv['cloudfrontDomainName']}/jquery/js/jquery-1.9.1.min.js.gz"></script>
7611  <script src="https://{$pHBEnv['cloudfrontDomainName']}/homecu/js/KendoUI/{$pHBEnv['homecuKendoVersion']}/kendo.web.min.js"></script>
7612  </head>
7613  <style>
7614  .k-block {width: 500px}
7615  .field-label-wrapper { margin: 0px 5px 5px 5px; padding: 0px 5px 5px 20px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; }
7616  .field-label-wrapper label { display: block; padding: 10px 0 6px 4px; color: #333333; font-size:1.2em; margin-left: -10px; width: 100%; }
7617  .field-label-wrapper label.note {color: red;font-weight: bold;}
7618  .field-label-wrapper label.note:before {content: "NOTE: "}
7619  .field-label-wrapper label.field:after {content: ":"}
7620  .field-label-wrapper label hr { z-index: 0; display:inline-block; width: 100%; position:relative; top:-24px;background-color:#000000; }
7621  </style>
7622  <body>
7623  <div class='k-content'>
7624  <div class="k-block"><div class="k-header k-shadow">$secureFormTitle</div>
7625 printblock;
7626 
7627  // ** First Print any NOTES AT the top of the form
7628  foreach ($esFormNotes as $printNote) {
7629  $printLabel = "<label class='note'>{$printNote}</label>";
7630  $secureFormData .= <<< printblock
7631  <div class='field-label-wrapper'>
7632  {$printLabel}
7633  </div>
7634 printblock;
7635  }
7636  // ** Loop through the fields and print
7637  foreach ($secureFormDataAry as $dataIdx => $dataAttr) {
7638 
7639  $printLabel = ($dataAttr['label'] != '' ? "<label class='{$dataAttr['type']}'>{$dataAttr['label']}</label>" : '');
7640  $secureFormData .= <<< printblock
7641  <div class='field-label-wrapper'>
7642  {$printLabel}
7643  <div class='field-value'>{$dataAttr['value']}</div>
7644  </div>
7645 printblock;
7646  }
7647  // ** Set the ending of the file
7648  $secureFormData .= <<< printblock
7649  </div>
7650  </div>
7651  </body>
7652 </html>
7653 printblock;
7654 
7655  /*
7656  * File name should be
7657  * estmt[YYYYMMDDHHNNSS{PID}].html
7658  */
7659  $sslFormsFileName = 'estmt' . date('YmdHis') . posix_getpid() . '.html';
7660 
7661  /*
7662  * Open and Write the data to the secure form
7663  */
7664  $secureFormFileHdl = fopen($retCUStatus['estmt']['sslformsdir'] . $sslFormsFileName, 'w');
7665  if ($secureFormFileHdl) {
7666  fwrite($secureFormFileHdl, $secureFormData);
7667  fclose($secureFormFileHdl);
7668  } else {
7669  // ** ERROR -- Was it caught automatically by the try..catch?
7670  throw new Exception($pMC->msg('Errors found'));
7671  }
7672 
7673  /*
7674  * ** UPDATE the cuusers table
7675  */
7676  $validateEntryAry['estmnt'] = $esFormMode;
7677  $updateMbrAry = Update_CUMbrEs($pDbh, $pHBEnv, $pMC, $validateEntryAry, $pAcct);
7678 
7679  if ($updateMbrAry['status']['code'] == '999') {
7680  $retStatus_ary['homecuErrors'] = $updateMbrAry['status']['errors'];
7681  throw new Exception($pMC->msg('Errors found'));
7682  }
7683  /*
7684  * ** SEND EMAIL
7685  */
7686  $notify = new ErrorMail;
7687  $notify->mailto = $retCUStatus['estmt']['notifyemail'];
7688  $notify->replyto = ($pHBEnv['Ml'] != '' ? $pHBEnv['Ml'] : $retCUStatus['estmt']['notifyemail']);
7689  $notify->subject = "SECURE FORM NOTIFICATION (estmt)";
7690  $notify->msgbody = "\tSECURE FORM NOTIFICATION (estmt)\n\n";
7691  $notify->msgbody .= "{$pHBEnv['Cn']} has left a secure document at your site. ";
7692  $notify->msgbody .= "\nYou can retrieve it in the password protected ";
7693  $notify->msgbody .= "admin directory.\n\n";
7694 
7695  $notify->msgbody .= "Member Email: " . ($pHBEnv['Ml'] != '' ? $pHBEnv['Ml'] : 'Member needs to validate e-mail') . "\n";
7696  $notify->callingfunction = __FUNCTION__;
7697  $notify->file = __FILE__;
7698  $notify->cu = $pHbEnv['Cu'];
7699  $notify->SendMail();
7700 
7701  /*
7702  * Prepare for returning the data
7703  */
7704  $retStatus_ary['homecuInfo'] = $pMC->msg('Thank you your request will be sent');
7705 
7706 
7707  } catch (Exception $ex) {
7708  // ** Errors processed here
7709  $retStatus_ary['status']['errors'][] = $ex->getMessage();
7710  $retStatus_ary['status']['code'] = '999';
7711  }
7712 
7713 
7714  return $retStatus_ary;
7715  }
7716  /**
7717  *
7718  * Post_CUESPacket
7719  *
7720  * 09/19 This function should only be called if we are posting the ES packet, removed the
7721  * logic deciding whether it has to post to core or not. That logic should precede call.
7722  * Must be ENV['live'] and array key exists 'ES' fromGet_HaveTrans() call.
7723  *
7724  * @param array $PHbEnv - Current HB Environment array
7725  * @param object $pMc - The current language class
7726  * @param array $pValues - Current values being passed in to validate
7727  * ARRAY SHOULD CONSIST OF
7728  * [Tc] - Transaction code to post
7729  * [R1] - Reference field 1 for packet post
7730  * [R2] - Reference field 2 for packet post
7731  * [R3] - Email
7732  * [R4] - Reference field 4 for packet post
7733  * [R5] - Value to post to core for e-Statement setting
7734  *
7735  * @return array
7736  * HomeCU [status]
7737  * [code] {000, 999}
7738  * [error] [string]
7739  * [data]
7740  * Data returned is a string value from the core if the
7741  * value was posted. EMPTY if not posted
7742  *
7743  */
7744  function Post_CUESPacket($pHbEnv, $pMC, $pValues) {
7745 
7746  $retStatus_ary = Array(
7747  'status' => Array('code'=>'000', 'error' =>''),
7748  'data' => ''
7749  );
7750  /**
7751  * STOP E-STATEMENT REQUESTS *
7752  * 7/22/19 - Reactivating Stop requests
7753  * --------------------------------------------
7754  * Skip stop requests being sent to core *
7755  * Prodigy has not added this to their core yet and will result in an error
7756  * By skipping this part the credit union will get a secure form
7757  */
7758  $stopRequest = (HCU_array_key_value("R5", $pValues) == "N");
7759 
7760  /* ** NEW SYNTAX ** */
7761  $txnValues = array(
7762  "member" => $pValues['selectedAccount'],
7763  "type" => "T",
7764  "tran_code" => $pValues['Tc'],
7765  "ref1" => $pValues['R1'],
7766  "ref2" => $pValues['R2'],
7767  "ref3" => $pValues['R3'],
7768  "ref4" => $pValues['R4'],
7769  "ref5" => $pValues['R5']
7770  );
7771 
7772  $esAction = $stopRequest ? 'ESTMTSTOP' : 'ESTMTACTIVATE';
7773  $sendResp = SendTransaction( $pHbEnv, $esAction, $txnValues );
7774 
7775  $statcode = $sendResp['status']['code'];
7776  if ($statcode == '000') {
7777  // ** SUCCESS
7778  $retDataMsg = $pMC->msg('E-Statement Request OK', HCU_DISPLAY_AS_RAW);
7779 
7780  } else {
7781  $statreason = HCU_array_key_value("desc", $sendResp['data']);
7782  $retStatus_ary['status']['code'] = '999';
7783  $retStatus_ary['status']['error'] = $pMC->msg('E-Statement Request Error', HCU_DISPLAY_AS_RAW)
7784  . $pMC->msg('Contact CU', HCU_DISPLAY_AS_RAW);
7785 
7786  // Undefined variables . . .
7787  //$retDataMsg = $pMC->msg('E-Statement Request Error', HCU_DISPLAY_AS_RAW) . " [$Cn $R3 $R5] $statcode $statreason";
7788  // 11/19 We are storing two errors in this condition. ['status']['error'] is what will
7789  // display in the Exception. the one stored below does not display anywhere as it
7790  // contains sensitive information. It also doesn't currently log anywhere, so
7791  // it can be considered strictly a debugging hook.
7792  $retDataMsg = $pMC->msg('E-Statement Request Error', HCU_DISPLAY_AS_RAW)
7793  . " [{$pHbEnv['Cn']} {$pValues['R3']} {$pValues['R5']}] $statcode $statreason";
7794  }
7795 
7796  $retStatus_ary['data'] = $retDataMsg;
7797 
7798  return $retStatus_ary;
7799 
7800  }
7801 
7802 /**
7803  *
7804  * Update the member record for the e-statement flag and possibly the email
7805  * Take a snapshot of the record before and after and insert into cuauditusers
7806  *
7807  * @param integer $pDbh - Current integer pointer to the database handle
7808  * @param array $pHbEnv - Current HB Environment array
7809  * @param class $pMc - The current lanaguage class
7810  * @param array $pValues - Current values being passed in to validate
7811  * ARRAY SHOULD CONSIST OF
7812  * [estmt] - Transaction code to post
7813  * @param string-ish $pSelectedAccount - The selected account.
7814  *
7815  * @return array
7816  * HomeCU [status]
7817  * [code] {000, 999}
7818  * [errors] {array of strings}
7819  * [data]
7820  * No Data returned
7821  */
7822  function Update_CUMbrEs($pDbh, $pHbEnv, $pMC, $pValues, $pSelectedAccount) {
7823 
7824  $retStatus_ary = Array(
7825  'status' => Array('code'=>'000', 'errors' => Array()),
7826  'data' => ''
7827  );
7828 
7829 
7830  $updateTrans = false;
7831  $sBuildSql = '';
7832 
7833  try {
7834 
7835  if ($time_rs = db_query("select now();", $pDbh)) {
7836  list($chnow) = db_fetch_array($time_rs, 0);
7837  } else {
7838  // ** For some reason unable to get the current time
7839  throw new Exception($pMC->msg("Error Occurred updating settings"));
7840  }
7841 
7842  # update the usermember entry
7843  $updateTableArray = array(
7844  'memberacct' => array(
7845  array(
7846  '_action' => 'update',
7847  'accountnumber' => $pSelectedAccount,
7848  'estmnt_flag' => $pValues['estmnt'])
7849  )
7850  );
7851  # SEND DATA TO UPDATE USER
7852  $result = DataUserTableUpdate($pDbh, $pHbEnv, $pMC, $updateTableArray, $pHbEnv["Uid"], 'U_UPD', $pHbEnv['platform'], $pHbEnv['currentscript'], 'U', 'E-Statement Update',
7853  $pHbEnv['Cn'], $pHbEnv['Ml'], $pHbEnv['remoteIp'], false, $pSelectedAccount);
7854  if ( $result === false ) {
7855  $retStatus_ary['status']['errors'][] = $pMC->msg("Error Occurred updating settings");
7856  }
7857 
7858  } catch (Exception $ex) {
7859  $retStatus_ary['status']['errors'][] = $ex->getMessage();
7860  }
7861  // ** Evaluate and see if any errors were found
7862  if (count($retStatus_ary['status']['errors']) > 0) {
7863  $retStatus_ary['status']['code'] = '999';
7864  }
7865 
7866  return $retStatus_ary;
7867  }
7868 
7869 
7870 
7871 /**
7872  * getMask($dbh, $Cu, $showSQL=false)
7873  * Gets the mask from a TODO UNDEFINED column, currently maskconfig.
7874  * @param integer $dbh the database connection
7875  * @param string $Cu the Credit Union
7876  * @param boolean $showSQL if defined and true, sqls will show up in the array.
7877  *
7878  * @return $returnArray["code" => code, "errors" => errors, "sqls" => sqls]
7879  * Code is 0, 1, 2, or 3 depending on the errors shown (3 is errors 1+2)
7880  * If $showSQL is true, then $returnArray["sqls"] is also available: the list of sqls.
7881  */
7882 function GetMask($dbh, $Cu, $showSQL=false)
7883 {
7884  $code= 0;
7885  $errors= array();
7886 
7887  // TODO: For #695, "use" this function. When working on #111 later, I will need to rework this logic.
7888  // ----------------------------------------------
7889  // $sql= "select maskconfig from cuadmin where cu= '$Cu'";
7890  // $sth= db_query($sql, $dbh);
7891  // $lastError= trim(db_last_error());
7892 
7893  // if ($lastError != "")
7894  // {
7895  // $errors[]= $lastError;
7896  // $code+= 1;
7897  // }
7898 
7899  // $row= db_fetch_array($sth, 0);
7900  // db_free_result($sth);
7901  // $mask= trim($row[0]);
7902 
7903 
7904  // if ($mask == "")
7905  // $mask= array();
7906  // else
7907  // {
7908  // $mask= json_decode($mask, true);
7909  // if (!is_array($mask))
7910  // {
7911  // $errors[]= "Mask is not valid.";
7912  // $code+= 2;
7913  // $mask= array();
7914  // }
7915  // }
7916  // $returnArray= array("errors" => $errors, "code" => "$code", "data" => $mask);
7917  // if ($showSQL)
7918  // $returnArray["sqls"]= array($sql);
7919 
7920  // Temp for #695
7921  $returnArray= array("error" => array(), "code" => 0, "data" => array("start" => -2));
7922  return $returnArray;
7923 }
7924 
7925 /**
7926  * applyMask($stringInput, $maskArray)
7927  *
7928  * @param string $stringInput String to mask
7929  * @param array $maskArray Contains "start" and "length" (but doesn't have to contain either)
7930  */
7931 function ApplyMask($stringInput, $maskArray)
7932 {
7933  $stringInput= trim($stringInput);
7934  $mask= preg_replace("/\S/", "*", $stringInput);
7935  $start= HCU_array_key_exists("start", $maskArray) ? intval($maskArray["start"]) : 0;
7936  $stringLength= strlen($stringInput);
7937  $maskLength= HCU_array_key_exists("length", $maskArray) ? intval($maskArray["length"]) : null;
7938 
7939  $returnString= $start > 0 ? substr($mask, 0, $start) : ($start < 0 ? substr($mask, 0, $stringLength+$start) : "");
7940  $returnString.= isset($maskLength) ? substr($stringInput, $start, $maskLength) : substr($stringInput, $start);
7941  $returnString.= substr($mask, strlen($returnString)); // Add the remainder of the mask.
7942 
7943  if (strpos($returnString, "*") === false)
7944  $returnString= "****" . $returnString;
7945 
7946  return $returnString;
7947 }
7948 
7949 /**
7950  * function getAccountDescription($dbh, $Cu, $acct, $desc, $type, $display, $Fset3, $cert=0, $doEncode=true)
7951  * This gets a consistent account description for the many places in banking.
7952  *
7953  * @param $dbh -- the database connection. This will be needed to get the mask.
7954  * @param $Cu -- the credit union. This will be needed to get the mask.
7955  * @param $acct -- the member account number.
7956  * @param $desc -- the description from the core-ish.
7957  * @param $type -- the accounttype.
7958  * @param $display -- the display name.
7959  * @param $Fset3 -- the third flagset.
7960  * @param $cert -- the certificate number.
7961  * @param $doEncode -- if true, encode the description. Needs to be false if it is going into a Kendo component because Kendo automatically encodes it.
7962  *
7963  * @return the full description according to if the flags are set.
7964  */
7965 function getAccountDescription($dbh, $Cu, $acct, $desc, $type, $display, $Fset3, $cert=0, $doEncode=true, $isM2M=false) {
7966 
7967  $display= trim($display);
7968  if ($display != "") // Use custom description instead
7969  return $display;
7970 
7971  $desc= trim($desc);
7972  $type= trim($type);
7973  $cert= trim($cert);
7974  $acct= trim($acct);
7975 
7976  if ($doEncode) // If going through a kendo widget, then Kendo does this automatically.
7977  {
7978  // ** BEFORE it's used, encode the description with UTF-8 Encoding.
7979  // * setting it here eliminates the need to set it each time it's called in this loop
7980  $desc = utf8_encode($desc);
7981  $desc = htmlspecialchars($desc, ENT_QUOTES);
7982 
7983  }
7984 
7985  // If member to member, always show masked account. Decision made 10/18/2017.
7986  $doPrepend= $isM2M || ($Fset3 & GetFlagsetValue('CU3_PREPEND_MBR_DESC')) != 0;
7987  $doMask= $isM2M || ($Fset3 & GetFlagsetValue('CU3_MASK_MBR_DESC')) != 0;
7988 
7989  $acct= $doPrepend ? $acct : "";
7990  if ($doPrepend && $doMask)
7991  {
7992  $mask= GetMask($dbh, $Cu);
7993  $mask= $mask["code"] != 0 ? array("start" => -2) : $mask["data"]; // Just return the default mask in this case.
7994  $acct= ApplyMask($acct, $mask);
7995  }
7996 
7997  if ($isM2M)
7998  $desc= "$acct / $type";
7999  else
8000  {
8001  $desc= $acct == "" ? $desc : "$acct / $desc";
8002  $desc= $cert == 0 ? "$desc - $type" : "$desc # $cert - $type";
8003  }
8004 
8005  return $desc;
8006 }
8007 
8008 /**
8009  * Get_FeatureAccounts( $pHBEnv, $pFeature, $pPlatform )
8010  * Use the {cu}memberacctrights table to determine the accounts that can access the given feature for the given platform.
8011  * If there is any error or anything wrong, just return an empty list.
8012  * NOTE: Locked accounts are not returned (read-only are just for E-Statements).
8013  *
8014  * @param object $pHBEnv Banking environment object
8015  * @param string $pFeature String such as: BP, RDC, ES
8016  * @param string $pPlatform Character: D(esktop), M(obiile), A(pp)
8017  *
8018  * @return array with list of accounts that can be accessed.
8019  */
8020 function Get_FeatureAccounts( $pHBEnv, $pFeature, $pPlatform ) {
8021  $resultAccounts = array();
8022 
8023  try {
8024  // some error checking
8025  if ( !( $pPlatform == "D" ||
8026  $pPlatform == "A" ) ) {
8027  throw new Exception( "Get_FeatureAccounts: Invalid platform parameter" );
8028  }
8029 
8030  $restrictedList = array( "L", "R" );
8031  switch ( $pFeature ) {
8032  case "BP":
8033  // no read-only or locked
8034  $restrictedList = array( "L", "R" );
8035  break;
8036  case "ES":
8037  // no locked
8038  $restrictedList = array( "L" );
8039  break;
8040  case "RDC":
8041  // no read-only or locked
8042  $restrictedList = array( "L", "R" );
8043  break;
8044  case "LOAN":
8045  // no read-only or locked
8046  $restrictedList = array( "L", "R" );
8047  // ** LOAN is not an access rigfht at this time.. Use the right of ACCESS
8048  // * to determine if the user has access for the purposes of adding a loan
8049  $pFeature = 'BP';
8050  break;
8051  default:
8052  throw new Exception( "Get_FeatureAccounts: Invalid feature parameter" );
8053  break;
8054  }
8055 
8056  // get some parameters
8057  $Cu = $pHBEnv["Cu"];
8058  $Uid = $pHBEnv["Uid"];
8059  $dbh = $pHBEnv["dbh"];
8060 
8061  // check the access
8062  $sql = "SELECT DISTINCT mar.accountnumber, mar.platform, ma.restrictions
8063  FROM {$Cu}memberacctrights mar
8064  INNER JOIN {$Cu}memberacct ma ON ma.accountnumber = mar.accountnumber
8065  WHERE mar.user_id = {$Uid}
8066  AND mar.whichright = '{$pFeature}'
8067  AND mar.allowed = TRUE";
8068  $rs = db_query( $sql, $dbh );
8069 
8070  $row = 0;
8071  while ( $aRow = db_fetch_array( $rs, $row++ ) ) {
8072  if ( in_array( $aRow["restrictions"], $restrictedList )) {
8073  continue;
8074  }
8075  $platforms = HCU_JsonDecode( $aRow["platform"] );
8076  if ( in_array( $pPlatform, $platforms )) {
8077  // found one, add to array
8078  $resultAccounts[] = trim( $aRow["accountnumber"] );
8079  }
8080  }
8081 
8082  // return the list of accounts found
8083  } catch (Exception $e) {
8084  // log an error
8085  $pHBEnv["SYSENV"]["logger"]->error( $e->getMessage() );
8086 
8087  $resultAccounts = array();
8088  }
8089 
8090  return $resultAccounts;
8091 } // end Get_FeatureAccounts
8092 
8093 /**
8094  *
8095  * Get the Member's Description from the 'accountbalance' or 'loanbalance' record.
8096  * ** NOTE: 11/2/17 Later this will also apply to Cross Account records
8097  *
8098  * @param integer $pDbh - Current Database handle
8099  * @param string $pCu - Credit Union
8100  * @param integer $pUid - Authenticted User's id from <client>user
8101  * @param arrray $pAcctKey - This variable contains the elements that make up the Account we are looking for
8102  * [recordtype] - {D, L} Which type of account are we looking up?
8103  * D - Deposit
8104  * L - Loan
8105  * [accountnumber] - Accountnumber field we will be looking up
8106  * [accounttype] - Sub-Account identifier
8107  * [certnumber] - Cert number if applicable
8108  *
8109  * @return array
8110  * [description]
8111  * Returns the specified account's account description from either
8112  * <client>accountbalance
8113  * <client>loanbalance
8114  * [display_name]
8115  * Returns the custom description for this account from
8116  * <client>useraccount for this user/account combination
8117  *
8118  */
8119 function GetMemberDescription ($pDbh, $pCu, $pUid, $pAcctKey) {
8120  $retDesc = Array("description" => '', "display_name" => ""); // Returned array
8121  $sql = ''; // Balance Description SQL
8122  $userSql = ''; // User Custom Description SQL
8123 
8124  $acctTypeorLoan = (in_array(HCU_array_key_value('recordtype', $pAcctKey), array("L", "C")) ? "loannumber" : "accounttype");
8125  $isCrossAccount = strpos(HCU_array_key_value($acctTypeorLoan, $pAcctKey), '#');
8126 
8127  switch ($pAcctKey['recordtype']) {
8128  case "D":
8129  if ($isCrossAccount) {
8130  // ** CROSS-ACCOUNT LOOKUP
8131  /*
8132  * Separate the Cross Account member suffix from Key
8133  */
8134  list ($localXASfx, $localXAMbr) = explode('#', $pAcctKey['accounttype']);
8135  $sql = "SELECT trim(description) as description, useraccount.display_name
8136  FROM " . prep_save($pCu, 10) . "crossaccounts as crossaccounts
8137  LEFT JOIN " . prep_save($pCu, 10) . "useraccounts as useraccount ON
8138  useraccount.accountnumber = crossaccounts.accountnumber
8139  AND useraccount.recordtype = 'T'
8140  AND useraccount.accounttype = trim(crossaccounts.accounttype) || '#' || trim(crossaccounts.tomember)
8141  AND useraccount.certnumber = 0
8142  AND useraccount.user_id = " . intval($pUid) . "
8143  WHERE crossaccounts.accountnumber = '" . prep_save($pAcctKey['accountnumber'], 12) . "'
8144  AND crossaccounts.tomember = '" . prep_save($localXAMbr, 12) . "'
8145  AND crossaccounts.accounttype = '" . prep_save($localXASfx, 12) . "'
8146  AND crossaccounts.deposittype in ('Y', 'N'); ";
8147 
8148  } else {
8149  // ** DEPOSIT
8150  $sql = "SELECT trim(description) as description,
8151  useraccount.display_name
8152  FROM " . prep_save($pCu, 10) . "accountbalance as accountbalance
8153  LEFT JOIN " . prep_save($pCu, 10) . "useraccounts as useraccount ON
8154  useraccount.accountnumber = accountbalance.accountnumber
8155  AND useraccount.recordtype = 'D'
8156  AND useraccount.accounttype = accountbalance.accounttype
8157  AND useraccount.certnumber = accountbalance.certnumber
8158  AND useraccount.user_id = " . intval($pUid) . "
8159  WHERE accountbalance.accountnumber = '" . prep_save($pAcctKey['accountnumber'], 12) . "'
8160  AND accountbalance.accounttype = '" . prep_save($pAcctKey['accounttype'], 25) . "'
8161  AND accountbalance.certnumber = " . intval($pAcctKey['certnumber']) . "; ";
8162  }
8163  break;
8164  case "L":
8165  case "C":
8166  if ($isCrossAccount) {
8167  // ** CROSS-ACCOUNT LOOKUP
8168  /*
8169  * Separate the Cross Account member suffix from Key
8170  */
8171  list ($localXASfx, $localXAMbr) = explode('#', $pAcctKey['loannumber']);
8172  $sql = "SELECT trim(description) as description, useraccount.display_name
8173  FROM " . prep_save($pCu, 10) . "crossaccounts as crossaccounts
8174  LEFT JOIN " . prep_save($pCu, 10) . "useraccounts as useraccount ON
8175  useraccount.accountnumber = crossaccounts.accountnumber
8176  AND useraccount.recordtype = 'P'
8177  AND useraccount.accounttype = trim(crossaccounts.accounttype) || '#' || trim(crossaccounts.tomember)
8178  AND useraccount.certnumber = 0
8179  AND useraccount.user_id = " . intval($pUid) . "
8180  WHERE crossaccounts.accountnumber = '" . prep_save($pAcctKey['accountnumber'], 12) . "'
8181  AND crossaccounts.tomember = '" . prep_save($localXAMbr, 12) . "'
8182  AND crossaccounts.accounttype = '" . prep_save($localXASfx, 12) . "'
8183  AND crossaccounts.deposittype = 'L'; ";
8184 
8185 
8186  } else {
8187  // ** LOAN
8188  $sql = "SELECT trim(description) as description,
8189  useraccount.display_name
8190  FROM " . prep_save($pCu, 10) . "loanbalance as loanbalance
8191  LEFT JOIN " . prep_save($pCu, 10) . "useraccounts as useraccount ON
8192  useraccount.accountnumber = loanbalance.accountnumber
8193  AND useraccount.recordtype = 'L'
8194  AND useraccount.accounttype = loanbalance.loannumber
8195  AND useraccount.user_id = " . intval($pUid) . "
8196  WHERE loanbalance.accountnumber = '" . prep_save($pAcctKey['accountnumber'], 12) . "'
8197  AND loanbalance.loannumber = '" . prep_save($pAcctKey['loannumber'], 25) . "'; ";
8198  }
8199  break;
8200  // ** default -- leave empty return nothing
8201  }
8202 
8203  if ($sql != '' && db_connection_status($pDbh) === PGSQL_CONNECTION_OK) {
8204  // ** Execute SQL -- Get the description
8205  $descRs = db_query($sql, $pDbh);
8206  $descRow = db_fetch_assoc($descRs);
8207  if ($descRow) {
8208  // ** Row was found -- return the description
8209  $retDesc['description'] = trim($descRow['description']);
8210  $retDesc['display_name'] = trim($descRow['display_name']);
8211  }
8212  }
8213  return $retDesc;
8214 }
8215 
8216 /**
8217  *
8218  * Search for a specific account/accounttype combo from the <client>useraccount
8219  * table for a user
8220  *
8221  * @param integer $pDbh - Current Database handle
8222  * @param string $pCu - Credit Union
8223  * @param integer $pUid - Authenticted User's id from <client>user
8224  * @param string $pAcctType - {D, L, X} Which type of account are we looking up?
8225  * D - Deposit
8226  * L - Loan
8227  * X - Cross Account
8228  * @param string $pAcctNbr - Account Number
8229  * @param string $pAcctSfx - Suffix (sub-account) related to the specified account
8230  * @param string $pCertNo - The Related Cert no (for Deposit types only)
8231  *
8232  * @return mixed
8233  * false -- IF NOT FOUND
8234  * array -- Returns the array of information if found
8235  *
8236  */
8237 function FindUserAccountExists ($pDbh, $pCu, $pUid, $pAcctType, $pAcctNbr, $pAcctSfx, $pCertNo='') {
8238  $retVal = false;
8239  $sql = ''; // Balance Description SQL
8240 
8241  switch ($pAcctType) {
8242  case "D":
8243  case "T":
8244  // ** DEPOSIT
8245  $sql = "SELECT useraccount.*
8246  FROM " . prep_save($pCu, 10) . "useraccounts as useraccount
8247  WHERE
8248  useraccount.recordtype = '" . prep_save($pAcctType, 1) . "'
8249  AND useraccount.accountnumber = '" . prep_save($pAcctNbr, 12) . "'
8250  AND useraccount.accounttype = '" . prep_save($pAcctSfx, 25) . "'
8251  AND useraccount.certnumber = " . intval($pCertNo) . "
8252  AND useraccount.user_id = " . intval($pUid) . "; ";
8253 
8254  break;
8255  case "L":
8256  case "P":
8257  // ** LOAN
8258  $sql = "SELECT useraccount.*
8259  FROM " . prep_save($pCu, 10) . "useraccounts as useraccount
8260  WHERE
8261  useraccount.recordtype = '" . prep_save($pAcctType, 1) . "'
8262  AND useraccount.accountnumber = '" . prep_save($pAcctNbr, 12) . "'
8263  AND useraccount.accounttype = '" . prep_save($pAcctSfx, 25) . "'
8264  AND useraccount.user_id = " . intval($pUid) . "; ";
8265  break;
8266  // ** default -- leave empty return nothing
8267  }
8268 
8269  if ($sql != '' && db_connection_status($pDbh) === PGSQL_CONNECTION_OK) {
8270  // ** Execute SQL -- Get the description
8271  $descRs = db_query($sql, $pDbh);
8272  $descRow = db_fetch_assoc($descRs);
8273  if ($descRow) {
8274  $retVal = Array("data" => $descRow);
8275  }
8276  }
8277 
8278  return $retVal;
8279 }
8280 
8281 
8282 /**
8283  *
8284  * Search for a specific account in the <client>memberacct table
8285  *
8286  * @param integer $pDbh - Current Database handle
8287  * @param string $pCu - Credit Union
8288  * @param string $pAcctNbr - Account Number
8289  *
8290  * @return mixed
8291  * false -- IF NOT FOUND
8292  * array -- Returns the array of information if found
8293  *
8294  */
8295 function FindMemberAccountExists ($pDbh, $pCu, $pAcctNbr) {
8296  $retVal = false;
8297  $sql = ''; // Balance Description SQL
8298 
8299  $sql = "SELECT *
8300  FROM " . prep_save($pCu, 10) . "memberacct as memberacct
8301  WHERE
8302  accountnumber = '" . prep_save($pAcctNbr, 12) . "'; ";
8303 
8304  if ($sql != '' && db_connection_status($pDbh) === PGSQL_CONNECTION_OK) {
8305  // ** Execute SQL -- Get the description
8306  $descRs = db_query($sql, $pDbh);
8307  $descRow = db_fetch_assoc($descRs);
8308  if ($descRow) {
8309  $retVal = Array("data" => $descRow);
8310  }
8311  }
8312 
8313  return $retVal;
8314 }
8315 
8316 
8317 /**
8318  * Get the list of users that have ACCESS rights to a member account
8319  *
8320  * @param integer $pDbh -- Database handle
8321  * @param array $pHBEnv -- The current environment array
8322  * @param string $pMbrAcct -- the member account we are querying
8323  *
8324  * @return array -- Empty array if no values found, otherwise it is an array of (user_id)
8325  *
8326  */
8327 function GetMemberAccessList($pDbh, $pHBEnv, $pMbrAcct) {
8328  $retList = Array();
8329 
8330  try {
8331  $sql = "SELECT user_id, allowed
8332  FROM " . prep_save($pHBEnv['Cu'], 10) . "memberacctrights as mar
8333  WHERE accountnumber = '" . prep_save($pMbrAcct, 12) . "'
8334  AND whichright = 'ACCESS'
8335  AND allowed = true";
8336 
8337  $accessRS = db_query($sql, $pDbh);
8338  $accessRows = db_fetch_all( $accessRS);
8339 
8340  if (is_array($accessRows)) {
8341  // ** ALL rows are returned -- Loop through them and create the returned data array
8342  for ($idx = 0; $idx < count($accessRows); $idx++) {
8343  $retList[] = intval($accessRows[$idx]['user_id']);
8344  }
8345  }
8346  } catch (Exception $ex) {
8347  $retList = Array();
8348  }
8349  return $retList;
8350 }
8351 
8352 /**
8353  * function CanActivateUser($pHBEnv, $pMbrAcct)
8354  * See if the user can be activated for the account number.
8355  *
8356  * @param $pHBEnv -- the environment variables
8357  * @param $pMbrAcct -- the member account to check
8358  *
8359  * @return array --
8360  * exists -- true if the user exists, false otherwise.
8361  * isNullPassword -- true if the password is set to the special "NULL PASSWORD" string.
8362  * isFailed -- true if the failedremain is less than or equal to zero. (Needed for the special locked out error.)
8363  */
8364 function CanActivateUser($pHBEnv, $pMbrAcct) {
8365  try {
8366  $Cu = $pHBEnv["Cu"];
8367  $dbh = $pHBEnv["dbh"];
8368 
8369  $returnArray = array("memberExists" => false, "userExists" => false, "isNullPassword" => false, "isFailed" => false, "allowEnroll" => false);
8370 
8371  // Needs to be broken up. Once checks for account existence and one for user existence. In the case of failed checks, a record is only created in user.
8372  $sql = "select ma.accountnumber, ma.allowenroll from ${Cu}memberacct ma where ma.accountnumber = '$pMbrAcct'";
8373 
8374  $sth = db_query ($sql, $dbh);
8375  if (!$sth) {
8376  throw new exception("Member query failed.", 4);
8377  }
8378 
8379  if (db_num_rows($sth) > 0) { // Found user so return isnull and isfailed
8380  $row = db_fetch_assoc($sth, 0);
8381  $returnArray ["memberExists"] = true;
8382  $returnArray ["allowEnroll"] = isset($row["allowenroll"]) && trim($row["allowenroll"]) == "t";
8383  }
8384 
8385  $sql = "select u.user_id, u.passwd, u.failedremain from ${Cu}user u
8386  left join ${Cu}memberacct ma on u.user_id = ma.primary_user and u.user_name = '$pMbrAcct'
8387  where u.user_name = '$pMbrAcct' or ma.primary_user is not null";
8388 
8389  $sth = db_query ($sql, $dbh);
8390  if (!$sth) {
8391  throw new exception("User account query failed.", 3);
8392  }
8393 
8394  if (db_num_rows($sth) > 0) { // Found user so return isnull and isfailed
8395  $row = db_fetch_assoc($sth, 0);
8396  $returnArray ["userExists"] = true;
8397  $returnArray ["isNullPassword"] = trim($row["passwd"]) == 'NULL PASSWORD';
8398  $returnArray ["isFailed"] = $row["failedremain"] <= 0;
8399  }
8400 
8401  } catch (exception $e) {
8402  $pHBEnv["SYSENV"]["logger"]->error($e->getMessage());
8403  }
8404 
8405  return $returnArray;
8406 }
8407 
8408 function FindAccountDisplay($pEnv, $pDbh, $pCu, $pMember, $pSuffix, $pType, $pCert = 0) {
8409 
8410  $acctKey = array(
8411  "accountnumber" => $pMember,
8412  "recordtype" => $pType
8413  );
8414 
8415  if ($acctKey['recordtype'] == "D" ) {
8416  $acctKey['accounttype'] = $pSuffix;
8417  $acctKey['certnumber'] = $pCert;
8418  } else if ($acctKey['recordtype'] == "L" || $acctKey['recordtype'] == "C") {
8419  $acctKey['loannumber'] = $pSuffix;
8420  }
8421 
8422  $acctDisp = GetMemberDescription($pDbh, $pCu, $pEnv['Uid'], $acctKey);
8423  if ($acctKey['recordtype'] == "D") {
8424  $acctDesc = getAccountDescription($pDbh, $pCu, $acctKey['accountnumber'], $acctDisp['description'], $acctKey['accounttype'], $acctDisp['display_name'], $pEnv["Fset3"], $acctKey['certnumber'], false);
8425  } else if ($acctKey['recordtype'] == "L" || $acctKey['recordtype'] == "C") {
8426  $acctDesc = getAccountDescription($pDbh, $pCu, $acctKey['accountnumber'], $acctDisp['description'], $acctKey['loannumber'], $acctDisp['display_name'], $pEnv["Fset3"], 0, false);
8427  } else {
8428  $acctDesc = $pEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
8429  }
8430 
8431  return $acctDesc;
8432 
8433 }
SendMail()
Definition: errormail.i:111