Odyssey
hcuUserActivity.i
1 <?php
2 /**
3  * @package hcuUserActivity.data
4  *
5  * Packages functions needed for both hcuUserActivity.data and hcuUserActivity.prg plus the ones that would sort of be considered utility in this locale.
6  */
7 
8 // Drop Down List data
9 // *******************************
10 
11 /**
12  * function getActiveStatuses
13  * Gets the statuses for setting the Active status filtering.
14  *
15  * @param $MC -- the dictionary object.
16  * @return the DDL of statuses.
17  */
18 function getActiveStatuses($MC) {
19  return array(array("value" => "", "text" => $MC->msg("Any", HCU_DISPLAY_AS_HTML)),
20  array("value" => "A", "text" => $MC->msg("Active", HCU_DISPLAY_AS_HTML)),
21  array("value" => "I", "text" => $MC->msg("Inactive", HCU_DISPLAY_AS_HTML)));
22 }
23 
24 /**
25  * function getApprovalStatuses($MC)
26  * Gets the statuses for setting the Approval status filtering.
27  *
28  * @param $MC -- the dictionary object.
29  * @return the DDL of statuses.
30  */
31 function getApprovalStatuses($MC)
32 {
33  return array(array("value" => "", "text" => $MC->msg("Any", HCU_DISPLAY_AS_HTML)),
34  array("value" => 10, "text" => $MC->msg("Approved", HCU_DISPLAY_AS_HTML)),
35  array("value" => 99, "text" => $MC->msg("Cancelled", HCU_DISPLAY_AS_HTML)),
36  array("value" => 90, "text" => $MC->msg("Declined", HCU_DISPLAY_AS_HTML)));
37 }
38 
39 /**
40  * function getActions($MC)
41  * Gets the actions with filters and whatnot.
42  *
43  * @param $MC -- the dictionary object.
44  * @return the DDL of actions.
45  */
46 function getActions($MC) {
47  return array(
48  array("value" => "action", "text" => $MC->msg("Action", HCU_DISPLAY_AS_HTML)),
49  array("value" => "viewDetails", "text" => $MC->msg("View Details", HCU_DISPLAY_AS_HTML)),
50  array("value" => "approve", "text" => $MC->msg("Approve", HCU_DISPLAY_AS_HTML), "grids" => array("pendingApprovalGrid"), "uid" => array("without")),
51  array("value" => "decline", "text" => $MC->msg("Decline", HCU_DISPLAY_AS_HTML), "grids" => array("pendingApprovalGrid"), "uid" => array("without")),
52  array("value" => "cancel", "text" => $MC->msg("Cancel", HCU_DISPLAY_AS_HTML), "grids" => array("pendingApprovalGrid", "scheduledTransactionsGrid"), "uid" => array("with")),
53  array("value" => "skip", "text" => $MC->msg("Skip", HCU_DISPLAY_AS_HTML), "grids" => array("scheduledTransactionsGrid"), "uid" => array("with")));
54 }
55 
56 /**
57  * function getApprovalList()
58  * Gets the approved features for approval and whatnot.
59  *
60  * @return the list of approved features for approval.
61  */
62 function getApprovalList() {
63  return array("TRN", "ACHPMT", "ACHCOL", "TRNEXT", "TRNM2M");
64 }
65 
66 // Helper functions
67 // *******************************
68 
69 /**
70  * function parseWhere($where, $whereBase, $whereBase)
71  * This helps with the where clauses in the filter.
72  *
73  * @param $where -- the list of to/from pairs or singles.
74  * @param $whereBase -- the list of feature/statuses.
75  * @return string of the full where clause.
76  */
77 function parseWhere($where, $whereBase) {
78  foreach($where as $whereCode => $whereRecord) {
79  $where[$whereCode] = implode(" and ", $whereRecord);
80  }
81 
82  $where = (count($where) > 0 ? "((" . implode(") or (", $where) . ")) " : "");
83  $whereBase = (count($whereBase) > 0 ? implode(" and ", $whereBase) : "");
84  $whereAll = $where != "" ? ($whereBase != "" ? "$where and $whereBase" : $where) : ($whereBase != "" ? $whereBase : "");
85  return $whereAll;
86 }
87 
88 /**
89  * function addCustomData($key, &$row)
90  * Adds the custom data to the row.
91  *
92  * @param $key -- the key to append.
93  * @param $row -- the row to append the key to.
94  */
95 function addCustomData($key, &$row) {
96  if ($row[$key] == null) {
97  $customData = array("string" => "");
98  } else {
99  $customData = HCU_JsonDecode($row[$key]);
100  if (!is_array($customData)) {
101  $customData = array("string" => trim($row[$key]));
102  } else if (count($customData) == 0) {
103  $customData = array("string" => "");
104  }
105  }
106 
107  unset($row[$key]);
108  return $customData;
109 }
110 
111 /**
112  * function gridModify(&$grid)
113  * Modifies the grid to add kendoId to the recordset. This is done after the sort so it is the real order.
114  *
115  * @param $grid -- the grid data to modify.
116  */
117 function gridModify(&$grid) {
118  for($i = 0, $count = count($grid); $i != $count; $i++) {
119  unset($grid[$i]["dateSortObj"]);
120  unset($grid[$i]["isscheduled"]);
121 
122  foreach($grid[$i] as $key => $value) {
123  $grid[$i][$key] = isset($value) ? (!is_array($value) ? trim($value) : $value) : "";
124  }
125 
126  $grid[$i]["kendoId"] = $i + 1;
127  $grid[$i]["amount"] = isset($grid[$i]["amount"]) ? floatval($grid[$i]["amount"]) : 0; // Set to zero. Use this value in the template which throws an exception if it is null.
128  }
129 }
130 
131 /**
132  * function getIntervalLookup($MC)
133  * Converts the TxIntervalList in an format for usage in a DDL.
134  *
135  * @param $MC -- the dictionary for translation.
136  * @return array(array("text" => $text, "value" => $value), ...)
137  */
138 function getIntervalLookup($MC) {
139  $intervalList = TxIntervalList($MC);
140  foreach($intervalList as $interval) {
141  $value = trim($interval["value"]);
142  $intervalLookup[$value] = trim($interval["text"]);
143  }
144  return $intervalLookup;
145 }
146 
147 
148 /**
149  * getFeatures($dbh, $Cu, &$sqls, $MC)
150  * Gets the enabled features for the credit union.
151  *
152  * @param $dbh -- the database connection
153  * @param $Cu -- the credit union
154  * @param $sqls -- the list of SQLs
155  * @param $MC -- the dictionary object
156  *
157  * @return a DDL of all the relevant features.
158  */
159 function getFeatures($dbh, $Cu, &$sqls, $MC, $Uid) {
160  // Get a list of features that currently used by the Credit Union.
161  $sql = "
162  SELECT DISTINCT f.feature_code AS value, f.description AS text
163  FROM cu_feature f
164  RIGHT JOIN cu_featuremenu fm ON f.feature_code = fm.feature_code
165  INNER JOIN cu_profilerights pr ON fm.feature_code = pr.feature_code
166  INNER JOIN {$Cu}group g ON pr.profile_id = g.profile_id
167  INNER JOIN {$Cu}user u ON g.group_id = u.group_id
168  WHERE u.user_id = $Uid
169  AND fm.feature_code IN ('TRN', 'TRNEXT', 'TRNM2M', 'ACHPMT', 'ACHCOL', 'TRNWIRE')
170  ORDER BY f.description";
171  $sqls[] = $sql;
172  $sth = db_query($sql, $dbh);
173  if (!$sth) {
174  throw new exception("feature query failed.", 504);
175  }
176  $featureDDL = array(array("value" => "", "text" => $MC->msg("All", HCU_DISPLAY_AS_HTML)));
177  for($i = 0; $row = db_fetch_assoc($sth, $i); $i++) {
178  // Translate the "Funds Transfer", "External Accounts", etc.
179  $feature = $MC->msg("CU feature " . $row["value"], HCU_DISPLAY_AS_RAW);
180  $row["text"] = isset($feature) ? $feature : $row["text"]; // If the dictionary exists, use it. Otherwise, use the value in the database.
181 
182  $featureDDL[] = $row;
183  }
184  return $featureDDL;
185 }
186 
187 /**
188  * function getValidUserIds($dbh, $Cu, $Cn, &$sqls)
189  * Gets the valid user ids (from the group of the current user.)
190  *
191  * @param $dbh -- the database connection
192  * @param $Cu -- the credit union
193  * @param $Cn -- the logged in user
194  * @param $sqls -- the SQLs used
195  *
196  * @return the list of all valid users.
197  */
198 function getValidUserIds($dbh, $Cu, $Cn, &$sqls) {
199  // Query to see the users in a particular group. Other queries will be limited to these users.
200  $sql = "select b.user_id from ${Cu}user a inner join ${Cu}user b on a.user_name = '" . prep_save($Cn, 50) . "' and a.group_id = b.group_id";
201  $sqls[] = $sql;
202  $sth = db_query($sql, $dbh);
203  if (!$sth) {
204  throw new exception("group query failed.", 602);
205  }
206  $validUserIds = array();
207 
208  for($i = 0; $row = db_fetch_row($sth, $i); $i++) {
209  $validUserIds[] = intval($row[0]);
210  }
211  $showPendingApprovalGrid = count($validUserIds) > 1;
212  return array("showPendingApprovalGrid" => $showPendingApprovalGrid, "validUserIds" => "(" . implode(",", $validUserIds) . ")");
213 }
214 
215 /**
216  * function getDateTime($datestring)
217  * Gets the dateTime object for a date string. This is needed to sort on the PHP side.
218  *
219  * @param $datestring -- the date in string format
220  * @return DateTime $dateTime -- the dateTime object
221  */
222 function getDateTime($datestring) {
223  // Date may appear without the microseconds or without the timepart.
224  $dateTime = DateTime::createFromFormat("Y-m-d h:i:s.u+", $datestring);
225  $dateTime = !$dateTime ? DateTime::createFromFormat("Y-m-d h:i:s+", $datestring) : $dateTime;
226  $dateTime = !$dateTime ? DateTime::createFromFormat("Y-m-d+", $datestring) : $dateTime;
227 
228  // If it doesn't fit that, set it to 1970 for comparison.
229  $dateTime = !$dateTime ? new DateTime("@1") : $dateTime;
230  return $dateTime;
231 }
232 
233 function getValidDate($datestring, $tz, $setTimezone = true) {
234  $dateTime = isset($datestring) && trim($datestring) != "" ? new DateTime($datestring) : null;
235  // If it is a type of "date" in the database, timezone is set to zero so display shows as the previous day.
236  // If it is a type of "timestamp" in the database, then we do need to adjust.
237  if ($setTimezone && isset($dateTime)) {
238  $dateTime->setTimezone($tz);
239  }
240  return $dateTime;
241 }
242 
243 // Sort functions
244 // ********************************
245 
246 /**
247  * function cmp($a, $b)
248  * compares two dates and puts the oldest first
249  * @param $a -- the first object to compare
250  * @param $b -- the second object to compare
251  * @return 1, 0, -1
252  */
253 function cmp($a, $b) {
254  $aCmp = $a["dateSortObj"];
255  $bCmp = $b["dateSortObj"];
256 
257  return $aCmp > $bCmp ? 1 : ($aCmp < $bCmp ? -1 : 0);
258 }
259 
260 /**
261  * function revCmp($a, $b)
262  * compares two dates and puts the newest first
263  * @param $a -- the first object to compare
264  * @param $b -- the second object to compare
265  * @return 1, 0, -1
266  */
267 function revCmp($a, $b) {
268  $aCmp = $a["dateSortObj"];
269  $bCmp = $b["dateSortObj"];
270 
271  return $aCmp > $bCmp ? -1 : ($aCmp < $bCmp ? 1 : 0);
272 }
273 
274 /**
275  * function getGFormat($dateString)
276  * This function gets a string version of the date that looks like "kendo.toString(date, 'g')."
277  *
278  * @param $dateString -- the string of the date coming from the database.
279  * @return formatted date string.
280  */
281 function getGFormat() {
282  return "n/j/Y g:i A";
283 }
284 
285 /**
286  * function getDFormat($dateString)
287  * This function gets a string version of the date that looks like "kendo.toString(date, 'd')."
288  *
289  * @param $dateString -- the string of the date coming from the database.
290  * @return formatted date string.
291  */
292 function getDFormat() {
293  return "n/j/Y";
294 }
295 
296 /************* New Entrypoints **************/
297 
298 /**
299  * function GetUserActivity
300  * After checking permissions, figure out what the user wants and get that information. This
301  * function does not get details.
302  *
303  * @param $pHBEnv -- the current environment
304  * @param $pWhichActivity -- the requested operation (e.g. scheduled, details, prior, pending)
305  * @param $pParams -- paramters for the operation
306  *
307  * filter info:
308  * $pParams["filter"]["start"] - date start (needed if not detail) - this is the earlier date
309  * $pParams["filter"]["end"] - date ended (needed if not detail) - this is the later date
310  * $pParams["filter"]["type"] - type of transaction (feature_code: eg TRNEXT)
311  *
312  * @return The requested information
313  */
314 function GetUserActivity( $pHBEnv, $pWhichActivity, $pParams ) {
315  $returnData = array( "code" => "000", "error" => "", "data" => array() );
316 
317  try {
318  // Check the confirm permissions for the features that we care about.
319  // If there are no confirm permissions and there are multiple users in the group, then throw an error.
320  $confirmPermissions = array();
321  $results = Perm_FeatureAccessList( $pHBEnv["dbh"], $pHBEnv );
322  if ( !intval($results["status"]["code"] ) == 0) {
323  throw new exception($results["status"]["error"] . " 1404");
324  }
325 
326  // the rights for this user will be returned
327  $permissions = $results["data"][$pHBEnv["Uid"]];
328 
329  // Prevent the page from being accessible when the user doesn't have approve access to at least one feature.
330  $approvalFeatureList = getApprovalList();
331  $confirmFound = false;
332  foreach( $permissions as $featureCode => $featureRecord ) {
333  if ( !in_array( $featureCode, $approvalFeatureList ) ) {
334  continue; // Feature is irrelevant to this script.
335  }
336 
337  $confirmFound = $confirmFound || $featureRecord["confirm"];
338  $confirmPermissions[$featureCode] = $featureRecord["confirm"]; // Save the permission for later.
339  }
340 
341  if ( !$confirmFound )
342  {
343  $sql= "SELECT 'FOUND' FROM {$pHBEnv["Cu"]}user a
344  INNER JOIN {$pHBEnv["Cu"]}user b ON a.user_id = {$pHBEnv["Uid"]}
345  AND a.group_id = b.group_id
346  AND a.user_id <> b.user_id";
347  $sth = db_query($sql, $pHBEnv["dbh"]);
348  if (!$sth) {
349  throw new exception("Error checking if multiple users found" . " 1403");
350  }
351  if (db_num_rows($sth) > 0) {
352  // We care if there are multiple users. If it is one user, then user has the permissions to view the page.
353  throw new exception("No approval permissions found" . " 1402");
354  }
355  }
356 
357  // get the requested information
358  if ( $pWhichActivity == "prior" ) {
359  $result = _GetUserActivityPrior( $pHBEnv, $pParams );
360  } else if ( $pWhichActivity == "scheduled" ) {
361  $result = _GetUserActivityScheduled( $pHBEnv, $pParams );
362  } else if ( $pWhichActivity == "pending" ) {
363  $result = _GetUserActivityPending( $pHBEnv, $pParams, $confirmPermissions );
364  } else {
365  // unexpected activity
366  throw new exception( $pHBEnv["MC"]->msg( "Feature Unavailable", HCU_DISPLAY_AS_RAW ) . " 1401");
367  }
368 
369  if ( $result["code"] != "000" ) {
370  throw new exception( $result["error"] );
371  }
372 
373  $returnData["data"] = $result["data"];
374 
375  } catch (Exception $e) {
376  // get the message
377  $message = $e->getMessage();
378 
379  $returnData["code"] = "999";
380  $returnData["error"] = $message;
381  }
382 
383  return $returnData;
384 } // end GetUserActivity
385 
386 /**
387  * function GetActivityDetail
388  * Get the detail for the given type of transaction from the cu_scheduledtxn table.
389  *
390  * @param $pHBEnv -- the current environment
391  * @param $pTxnId -- the transaction item wanting detail for
392  * @param $pIsScheduled -- flag if scheduled or not (to know which table)
393  *
394  * @return The requested information
395  */
396 function GetActivityDetail( $pHBEnv, $pTxnId, $pIsScheduled ) {
397  if ( $pIsScheduled ) {
398  $returnInfo = _GetActivityDetailScheduled( $pHBEnv, $pTxnId );
399  } else {
400  $returnInfo = _GetActivityDetailRegular( $pHBEnv, $pTxnId );
401  }
402 
403  return $returnInfo;
404 } // end GetActivityDetail
405 
406 /**
407  * function _GetActivityDetailRegular
408  * Get the detail for the given type of transaction from the {cu}transhdr/dtl tables.
409  *
410  * @param $pHBEnv -- the current environment
411  * @param $pTxnId -- the transaction item wanting detail for
412  *
413  * @return The requested information
414  */
415 function _GetActivityDetailRegular( $pHBEnv, $pTxnId ) {
416  $returnData = array( "code" => "000", "error" => "", "data" => array() );
417 
418  try {
419  // get the account number mask, in case we need it
420  $accountMask = GetMask( $pHBEnv["dbh"], $pHBEnv["Cu"] );
421 
422  // get the requested information, making sure it really is for this user
423  $sql = "SELECT h.*, u.user_name, a.user_name as approve_name, u.group_id as user_group, t.group_id as test_group
424  FROM {$pHBEnv["Cu"]}transhdr h
425  INNER JOIN {$pHBEnv["Cu"]}user u ON u.user_id = h.posted_by
426  INNER JOIN {$pHBEnv["Cu"]}user t ON t.user_id = {$pHBEnv["Uid"]}
427  LEFT JOIN {$pHBEnv["Cu"]}user a ON a.user_id = h.approved_by
428  WHERE h.id = $pTxnId";
429 
430  $sth = db_query( $sql, $pHBEnv["dbh"] );
431  if (!$sth) {
432  throw new exception($pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1412");
433  }
434 
435  $headerRow = db_fetch_assoc($sth, 0);
436 
437  if ( $headerRow["user_group"] != $headerRow["test_group"] ) {
438  throw new exception($pHBEnv["MC"]->msg( "Invalid account access", HCU_DISPLAY_AS_RAW ) . " 1413");
439  }
440 
441  $approvedStatus = intval( $headerRow["approved_status"] );
442 
443  // get all the details for this transaction
444  $sql = "SELECT d.*
445  FROM {$pHBEnv["Cu"]}transdtl d
446  WHERE transhdr_id = $pTxnId";
447 
448  $sth = db_query( $sql, $pHBEnv["dbh"] );
449  if (!$sth) {
450  throw new exception($pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1414");
451  }
452 
453  $detailRows = db_fetch_all($sth);
454 
455  // this information is common to all types
456  $transDetail = array();
457 
458  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Created On", HCU_DISPLAY_AS_RAW ),
459  "value" => date( "m/d/Y g:ia", strtotime( $headerRow["posted_date"] ) ) );
460  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Created By", HCU_DISPLAY_AS_RAW ),
461  "value" => $headerRow["user_name"] );
462  if ( $approvedStatus == 90 ) {
463  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Declined on", HCU_DISPLAY_AS_RAW ),
464  "value" => date( "m/d/Y g:ia", strtotime( $headerRow["approved_date"] ) ) );
465  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Declined by", HCU_DISPLAY_AS_RAW ),
466  "value" => $headerRow["approve_name"] );
467 
468  } else if ( $approvedStatus == 99 ) {
469  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Cancelled on", HCU_DISPLAY_AS_RAW ),
470  "value" => date( "m/d/Y g:ia", strtotime( $headerRow["approved_date"] ) ) );
471  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Cancelled by", HCU_DISPLAY_AS_RAW ),
472  "value" => $headerRow["approve_name"] );
473  } else if ( $approvedStatus > 0 ) {
474  // only show approval info if different user
475  if ( $headerRow["approved_by"] != $headerRow["posted_by"] ) {
476  $approveTime = strtotime( $headerRow["approved_date"] );
477  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Approved on", HCU_DISPLAY_AS_RAW ),
478  "value" => date( "m/d/Y", $approveTime ) );
479 
480  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Approved by", HCU_DISPLAY_AS_RAW ),
481  "value" => $headerRow["approve_name"] );
482  }
483 
484  $processTime = strtotime( $headerRow["processed_date"] );
485  if ( $processTime == 0 ) {
486  $dateString = $pHBEnv["MC"]->msg( "Not processed", HCU_DISPLAY_AS_RAW );
487  } else {
488  $dateString = date( "m/d/Y", $processTime );
489  }
490  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Processed Date", HCU_DISPLAY_AS_RAW ),
491  "value" => $dateString );
492  } else if ( $approvedStatus == 0 ) {
493  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Approved by", HCU_DISPLAY_AS_RAW ),
494  "value" => $pHBEnv["MC"]->msg( "Pending Approval", HCU_DISPLAY_AS_RAW ) );
495  }
496 
497  // this is used to hold the transcode in case there is an "other" type transaction.
498  $trans = null;
499 
500  $transactionCode = $headerRow["transactioncode"];
501 
502  // should only be one row for now
503  $txnInfo = HCU_JsonDecode( $detailRows[0]["transdata"] );
504 
505  $fromDesc = "";
506  if ( in_array( $transactionCode, array("2W","2P") ) ) {
507  // get the external account info; use the name on account since that is common for creator and approver
508  $fromDesc = $txnInfo["acct_source"]["remote_entity"]["name"];
509 
510  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "From", HCU_DISPLAY_AS_RAW ),
511  "value" => $fromDesc );
512 
513  // add routing and masked account number
514  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "ACH Routing Number", HCU_DISPLAY_AS_RAW ),
515  "value" => $txnInfo["acct_source"]["rdfi"]["rdfi_routing"] );
516 
517  $fromAcct = ApplyMask( $txnInfo["acct_source"]["rdfi"]["rdfi_account"], $accountMask["data"] );
518 
519  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Account", HCU_DISPLAY_AS_RAW ),
520  "value" => $fromAcct );
521  } else {
522  // "1W","1P","AT","LP","LA","MM","OT","CW" - source account is internal
523  $acctParts = explode( "|", $txnInfo["acct_source"] );
524  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
525  $accountType = $txnInfo['source_key']['recordtype'] == "L" ? $txnInfo['source_key']['loannumber'] : $txnInfo['source_key']['accounttype'];
526 
527  $fromDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['source_key']['accountnumber'], $accountType, $txnInfo['source_key']['recordtype'], $certNumber );
528 
529  if ( $fromDesc == "" ) {
530  $fromDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
531  }
532 
533  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "From", HCU_DISPLAY_AS_RAW ),
534  "value" => $fromDesc );
535  }
536 
537  if ( in_array( $transactionCode, array("1W","1P") ) ) {
538  // get the external account info; use the name on account since that is common for creator and approver
539  $toDesc = $txnInfo["acct_dest"]["remote_entity"]["name"];
540 
541  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "To", HCU_DISPLAY_AS_RAW ),
542  "value" => $toDesc );
543 
544  // add routing and masked account number
545  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "ACH Routing Number", HCU_DISPLAY_AS_RAW ),
546  "value" => $txnInfo["acct_dest"]["rdfi"]["rdfi_routing"] );
547 
548  $toAcct = ApplyMask( $txnInfo["acct_dest"]["rdfi"]["rdfi_account"], $accountMask["data"] );
549 
550  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Account", HCU_DISPLAY_AS_RAW ),
551  "value" => $toAcct );
552  } else if ( $transactionCode == "MM" ) {
553  // use the account number, masked
554  // NOTE: The mask logic should all be below this routine and we shouldn't have to know the data structure.
555  $toAcct = ApplyMask( $txnInfo["dest_key"]["accountnumber"], $accountMask["data"] );
556 
557  // add on the name
558  $toName = $txnInfo["dest_key"]["name"];
559 
560  $toDesc = "$toAcct ($toName)";
561 
562  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "To", HCU_DISPLAY_AS_RAW ),
563  "value" => $toDesc );
564 
565  } else if ( in_array( $transactionCode, array("OT","CW") ) ) {
566  // Need to check if destination is an other
567  $acctParts = explode( "|", $txnInfo["acct_dest"] );
568  if ( $acctParts[0] == "O" ) {
569  if ( $trans == null ) {
570  $trans = Get_HaveTrans( $pHBEnv["dbh"], $pHBEnv );
571  }
572 
573  $otherDesc = HCU_array_key_value($acctParts[2], $trans);
574 
575  $cuDesc = isset($otherDesc[2]) ? trim($otherDesc[2]) : "";
576  $nonCUDesc = isset($otherDesc[0]) ? trim($otherDesc[0]) : "";
577 
578  $toDesc = $cuDesc != "" ? $cuDesc : $nonCUDesc;
579  }
580 
581  if ( $toDesc == "" ) {
582  $toDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
583  }
584 
585  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "To", HCU_DISPLAY_AS_RAW ),
586  "value" => $toDesc );
587  } else {
588  // "2W","2P","AT","LP","LA" - destination account is internal
589  $acctParts = explode( "|", $txnInfo["acct_dest"] );
590  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
591  $accountType = $txnInfo['dest_key']['recordtype'] == "L" ? $txnInfo['dest_key']['loannumber'] : $txnInfo['dest_key']['accounttype'];
592 
593  $toDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['dest_key']['accountnumber'], $accountType, $txnInfo['dest_key']['recordtype'], $certNumber );
594 
595  if ( $toDesc == "" ) {
596  $toDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
597  }
598 
599  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "To", HCU_DISPLAY_AS_RAW ),
600  "value" => $toDesc );
601  }
602 
603  // what to return depends on the type of transaction
604  switch( $headerRow["feature_code"] ) {
605  case "TRN":
606  break;
607  case "TRNEXT":
608  break;
609  case "TRNM2M":
610  break;
611  case "ACHCOL":
612  break;
613  case "ACHPMT":
614  break;
615  default:
616  throw new exception($pHBEnv["MC"]->msg( "Unknown feature type", HCU_DISPLAY_AS_RAW ) . " 1415");
617  }
618 
619  // these go at the end
620  $amount = number_format( $detailRows[0]["amount"], 2 );
621  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Amount", HCU_DISPLAY_AS_RAW ),
622  "value" => "$" . $amount, "type" => "currency" );
623 
624  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Comment", HCU_DISPLAY_AS_RAW ),
625  "value" => $headerRow["memo"] );
626 
627 
628  // confirmation code is different depending on how far the txn has progressed
629  $confCodeBuilder["id"] = $headerRow["id"];
630  if ( $headerRow["processed_by"] != "" ) {
631  // based the confirmation code on the processed info
632  $confCodeBuilder["processed_by"] = "*immed*";
633  $confCodeBuilder["posted_by"] = $headerRow["posted_by"]; // immediate transfers need the posted by id
634  $confCodeBuilder["processed_date"] = $headerRow["processed_date"];
635  $confirmationCode = GetTransferConfirmCode( $pHBEnv, "process", $confCodeBuilder );
636  } else if ( $headerRow["approved_by"] != "" ) {
637  // based the confirmation code on the approved info
638  $confCodeBuilder["approved_by"] = $headerRow["approved_by"];
639  $confCodeBuilder["approved_date"] = $headerRow["approved_date"];
640  $confirmationCode = GetTransferConfirmCode( $pHBEnv, "approve", $confCodeBuilder );
641  } else if ( $headerRow["posted_by"] != "" ) {
642  // based the confirmation code on the posted info
643  $confCodeBuilder["posted_by"] = $headerRow["posted_by"];
644  $confCodeBuilder["posted_date"] = $headerRow["posted_date"];
645  $confirmationCode = GetTransferConfirmCode( $pHBEnv, "post", $confCodeBuilder );
646  } else {
647  $confirmationCode = "";
648  }
649 
650  if ( $confirmationCode != "" ) {
651  $transDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Confirmation", HCU_DISPLAY_AS_RAW ),
652  "value" => $confirmationCode );
653  }
654 
655  // return as ["detail"] = array( "name", "value" );
656  for ( $i = 0; $i < count( $transDetail ); $i++ ) {
657  $returnData["data"][]["detail"] = $transDetail[$i];
658  }
659 
660  } catch (Exception $e) {
661  // get the message
662  $message = $e->getMessage();
663 
664  $returnData["code"] = "999";
665  $returnData["error"] = $message;
666  }
667 
668  return $returnData;
669 } // end _GetActivityDetailRegular
670 
671 /**
672  * function _GetActivityDetailScheduled
673  * Get the detail for the given type of transaction from the cu_scheduledtxn table.
674  *
675  * @param $pHBEnv -- the current environment
676  * @param $pTxnId -- the transaction item wanting detail for
677  *
678  * @return The requested information
679  */
680 function _GetActivityDetailScheduled( $pHBEnv, $pTxnId ) {
681  $returnData = array( "code" => "000", "error" => "", "data" => array() );
682 
683  try {
684  // get the account number mask, in case we need it
685  $accountMask = GetMask( $pHBEnv["dbh"], $pHBEnv["Cu"] );
686 
687  // get the list of transfer features to get the name
688  $transferFeatureList = GetTransferFeatureList( $pHBEnv );
689 
690  // make it a lookup array
691  $transferFeatures = ConvertToLookupArray( $transferFeatureList );
692 
693  // get the list of schedule intervals for display
694  $recurringIntervals = getIntervalLookup( $pHBEnv["MC"] );
695 
696  // get the requested information, making sure it really is for this user
697  $sql = "SELECT s.*, c.user_name as created, a.user_name as approved,
698  c.group_id as user_group, t.group_id as test_group
699  FROM cu_scheduledtxn s
700  INNER JOIN {$pHBEnv["Cu"]}user c ON c.user_id = s.user_id
701  INNER JOIN {$pHBEnv["Cu"]}user t ON t.user_id = {$pHBEnv["Uid"]}
702  LEFT JOIN {$pHBEnv["Cu"]}user a ON a.user_id = s.approved_by
703  WHERE s.id = $pTxnId";
704 
705  $sth = db_query( $sql, $pHBEnv["dbh"] );
706  if (!$sth) {
707  throw new exception($pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1416");
708  }
709 
710  $schedRow = db_fetch_assoc( $sth, 0 );
711 
712  if ( $schedRow["user_group"] != $schedRow["test_group"] ) {
713  throw new exception($pHBEnv["MC"]->msg( "Invalid account access", HCU_DISPLAY_AS_RAW ) . " 1417");
714  }
715 
716  /*
717  * Need this info:
718  * Created date/time, created by (user), approved by / date /time, start date, end date,
719  * next trigger date, status, repeatingParams, scheduled transaction
720  */
721 
722  $txnInfo = HCU_JsonDecode( $schedRow["txn_data"] );
723 
724  // this is the return info
725  $schedDetail = array();
726 
727  // show the status first, if it is inactive
728  if ( $schedRow["status"] == "I" ) {
729  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Status", HCU_DISPLAY_AS_RAW ),
730  "value" => $pHBEnv["MC"]->msg( "Inactive", HCU_DISPLAY_AS_RAW ) );
731  }
732 
733  // look up the feature name
734  $featureName = $transferFeatures[$schedRow["feature_code"]];
735  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Transfer", HCU_DISPLAY_AS_RAW ),
736  "value" => $featureName );
737 
738  $createTime = date( "m/d/Y g:ia", strtotime( $schedRow["create_date"] ) );
739  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Created On", HCU_DISPLAY_AS_RAW ),
740  "value" => $createTime );
741 
742  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Created By", HCU_DISPLAY_AS_RAW ),
743  "value" => $schedRow["created"] );
744 
745  $status = $schedRow["approved_status"];
746 
747  if ( strlen( trim( $schedRow["approved"] ) ) > 0 ) {
748  // only show who approved if it was a different user
749  // only choices are approved or declined
750  if ( $schedRow["user_id"] != $schedRow["approved_by"] ) {
751  $approveTime = date( "m/d/Y g:ia", strtotime( $schedRow["approved_date"] ) );
752  if ( $status == 90 ) {
753  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Declined on", HCU_DISPLAY_AS_RAW ),
754  "value" => $approveTime );
755 
756  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Declined by", HCU_DISPLAY_AS_RAW ),
757  "value" => $schedRow["approved"] );
758  } else {
759  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Approved on", HCU_DISPLAY_AS_RAW ),
760  "value" => $approveTime );
761 
762  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Approved by", HCU_DISPLAY_AS_RAW ),
763  "value" => $schedRow["approved"] );
764  }
765 
766  }
767  } else {
768  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Approved by", HCU_DISPLAY_AS_RAW ),
769  "value" => $pHBEnv["MC"]->msg( "Pending Approval", HCU_DISPLAY_AS_RAW ) );
770  }
771 
772  $startDate = date( "m/d/Y", strtotime( $schedRow["start_date"] ) );
773  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Start Date", HCU_DISPLAY_AS_RAW ),
774  "value" => $startDate );
775 
776  $endDate = empty( trim( $schedRow["end_date"] ) ) ? $pHBEnv["MC"]->msg( "Transfer does not stop", HCU_DISPLAY_AS_RAW) : date( "m/d/Y", strtotime( $schedRow["end_date"] ) );
777  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "End Date", HCU_DISPLAY_AS_RAW ),
778  "value" => $endDate );
779 
780  $nextTriggerDate = date( "m/d/Y", strtotime( $schedRow["next_trigger_date"] ) );
781  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Next Date", HCU_DISPLAY_AS_RAW ),
782  "value" => $nextTriggerDate );
783 
784  // only show the "status" field if the approved_status is not 0 (awaiting approval)
785  if ( $status > 0 ) {
786  if ( $status == 10 ) {
787  $statusString = $pHBEnv["MC"]->msg( $schedRow["status"] == "A" ? "Active" : "Inactive", HCU_DISPLAY_AS_RAW );
788  } else {
789  $allowedStatuses = _GetAllowedStatuses( $pHBEnv["MC"] );
790 
791  $statusString = $allowedStatuses[$schedRow["approved_status"]];
792  }
793 
794  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Status", HCU_DISPLAY_AS_RAW),
795  "value" => $statusString );
796  }
797 
798  $repeatingParams = HCU_JsonDecode( $schedRow["repeating_parameters"], false, true );
799  $intervalName = $recurringIntervals[$repeatingParams["interval"]];
800  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Interval", HCU_DISPLAY_AS_RAW),
801  "value" => $intervalName );
802 
803  // determine the "from" and "to" based on the transaction code
804  $transactionCode = $txnInfo["txn"]["transactioncode"];
805 
806  if ( in_array( $transactionCode, array("2W","2P") ) ) {
807  // read the external account info
808  $extId = $txnInfo["txn"]["from"];
809  $fromInfo = _GetExternalAccount( $pHBEnv, $extId );
810 
811  $fromDesc = $fromInfo["display"];
812 
813  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "From Account", HCU_DISPLAY_AS_RAW ),
814  "value" => $fromDesc );
815 
816  // add the routing and masked account
817  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "ACH Routing Number", HCU_DISPLAY_AS_RAW ),
818  "value" => $fromInfo["routing"] );
819 
820  $fromAcct = ApplyMask( $fromInfo["account"], $accountMask["data"] );
821 
822  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Account", HCU_DISPLAY_AS_RAW ),
823  "value" => $fromAcct );
824  } else {
825  // "1W","1P","AT","LP","LA","MM" - source account is internal
826  $acctParts = explode( "|", $txnInfo["txn"]["from"] );
827  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
828  $fromDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['txn']['frommember'], $txnInfo['txn']['fromsuffix'], $txnInfo['txn']['fromtype'], $certNumber );
829 
830  if ( $fromDesc == "" ) {
831  $fromDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
832  }
833 
834  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "From Account", HCU_DISPLAY_AS_RAW ),
835  "value" => $fromDesc );
836  }
837 
838  if ( in_array( $transactionCode, array("1W","1P") ) ) {
839  // read the external account info
840  $extId = $txnInfo["txn"]["to"];
841  $toInfo = _GetExternalAccount( $pHBEnv, $extId );
842 
843  $toDesc = $toInfo["display"];
844  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "To Account", HCU_DISPLAY_AS_RAW ),
845  "value" => $toDesc );
846 
847  // add the routing number
848  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "ACH Routing Number", HCU_DISPLAY_AS_RAW ),
849  "value" => $toInfo["routing"] );
850 
851  // add masked account number
852  $toAcct = ApplyMask( $toInfo["account"], $accountMask["data"] );
853 
854  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Account", HCU_DISPLAY_AS_RAW ),
855  "value" => $toAcct );
856  } else if ( $transactionCode == "MM" ) {
857  // scheduled M2M is only for pre-defined
858  $extId = $txnInfo["txn"]["to"];
859  $toInfo = _GetExternalAccount( $pHBEnv, $extId );
860 
861  // NOTE: The mask logic should all be below this routine and we shouldn't have to know the data structure.
862  $toAcct = ApplyMask( $toInfo["account"], $accountMask["data"] );
863 
864  // add on the name
865  $toName = $toInfo["name"];
866 
867  $toDesc = "$toAcct ($toName)";
868 
869  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "To Account", HCU_DISPLAY_AS_RAW ),
870  "value" => $toDesc );
871  } else {
872  // "2W","2P","AT","LP","LA" - destination account is internal
873  $acctParts = explode( "|", $txnInfo["txn"]["to"] );
874  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
875  $toDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['txn']['tomember'], $txnInfo['txn']['tosuffix'], $txnInfo['txn']['totype'], $certNumber );
876 
877  if ( $toDesc == "" ) {
878  $toDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
879  }
880 
881  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "To Account", HCU_DISPLAY_AS_RAW ),
882  "value" => $toDesc );
883  }
884 
885  $amount = number_format( $txnInfo["txn"]["amount"], 2 );
886  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Amount", HCU_DISPLAY_AS_RAW ),
887  "value" => "$" . $amount, "type" => "currency" );
888 
889  $memo = trim( $txnInfo["txn"]["memo"] );
890  $schedDetail[] = array( "name" => $pHBEnv["MC"]->msg( "Comment", HCU_DISPLAY_AS_RAW ),
891  "value" => $memo );
892 
893  // return as ["detail"] = array( "name", "value" );
894  for ( $i = 0; $i < count( $schedDetail ); $i++ ) {
895  $returnData["data"][]["detail"] = $schedDetail[$i];
896  }
897 
898  } catch (Exception $e) {
899  // get the message
900  $message = $e->getMessage();
901 
902  $returnData["code"] = "999";
903  $returnData["error"] = $message;
904  }
905 
906  return $returnData;
907 } // end _GetActivityDetailScheduled
908 
909 /**
910  * GetTransferFeatureList will return name/value pairs of the transfer features.
911  */
912 function GetTransferFeatureList( $pHBEnv ) {
913  // get the list of transfer features that User Activity shows
914  $allowedTranfers = getApprovalList();
915  $transLimitStr = "'" . implode( "','", $allowedTranfers ) . "'";
916 
917  // Get a list of features that currently used by the Credit Union.
918  $sql = "SELECT distinct f.feature_code AS name, f.description AS value
919  FROM cu_feature f
920  INNER JOIN cu_profilerights pr ON f.feature_code = pr.feature_code
921  AND f.enabled
922  INNER JOIN cu_profile p ON pr.profile_id = p.profile_id
923  AND p.cu='{$pHBEnv["Cu"]}'
924  INNER JOIN {$pHBEnv["Cu"]}group g ON p.profile_id = g.profile_id
925  WHERE f.feature_code IN ($transLimitStr)
926  ORDER BY f.description";
927  $sth = db_query($sql, $pHBEnv["dbh"]);
928  if ( !$sth ) {
929  throw new exception($pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1405" );
930  }
931 
932  $featureList = array();
933  $row = 0;
934  while ( $featureRow = db_fetch_assoc( $sth, $row++ ) ) {
935  $featureList[] = array( "name" => $featureRow["name"], "value" => $featureRow["value"] );
936  }
937 
938  return $featureList;
939 } // end GetTransferFeatureList
940 
941 /**
942  * ConvertToLookupArray will take a key/value array and make it into a [key]=value array. All
943  * the elements of the list need the same structure.
944  * For example, $input[0] = array( "name" => "this", "value" => "thing" ) becomes $result["this"] = "thing";
945  */
946 function ConvertToLookupArray( $inputArray ) {
947  $outputArray = array();
948 
949  // get the keys
950  $keys = array_keys( $inputArray[0] );
951 
952  for ( $i = 0; $i < count( $inputArray ); $i++ ) {
953  $newKey = $inputArray[$i][$keys[0]];
954  $newValue = $inputArray[$i][$keys[1]];
955 
956  $outputArray[$newKey] = $newValue;
957  }
958 
959  return $outputArray;
960 } // end ConvertToLookupArray
961 
962 
963 /**
964  * Only show pending approval grid if there is more than one user and if a Needs Approval right is set.
965  */
966 function ShowPendingApproval( $pHBEnv ) {
967  $showPending = false;
968 
969  // Query to see the users in a particular group. Other queries will be limited to these users.
970  $sql = "SELECT b.user_id, b.group_id
971  FROM {$pHBEnv["Cu"]}user a
972  INNER JOIN {$pHBEnv["Cu"]}user b ON b.group_id = a.group_id
973  WHERE a.user_id = {$pHBEnv["Uid"]}";
974  $sth = db_query( $sql, $pHBEnv["dbh"] );
975  if (!$sth) {
976  throw new exception($pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1407");
977  }
978 
979  $groupId = 0;
980  $groupUserIds = array();
981  for( $i = 0; $row = db_fetch_row($sth, $i); $i++ ) {
982  // they are all in the same group, by definition
983  $groupId = intval( $row[1] );
984 
985  $groupUserIds[] = intval( $row[0] );
986  }
987 
988  // see if checking the "needs approval rights"
989  if ( count( $groupUserIds ) > 1 ) {
990  // check the profile rights
991  $sql = "SELECT 1
992  FROM {$pHBEnv["Cu"]}group g
993  INNER JOIN cu_profilerights p ON p.profile_id = g.profile_id
994  AND p.confirm_required
995  WHERE g.group_id = $groupId
996  LIMIT 1";
997 
998  $sth = db_query( $sql, $pHBEnv["dbh"] );
999  if (!$sth) {
1000  throw new exception($pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1409");
1001  }
1002 
1003  $row = db_fetch_row($sth, 0);
1004  $showPending = $row[0] > 0;
1005 
1006  if ( !$showPending ) {
1007  // check the group rights
1008  $sql = "SELECT 1
1009  FROM {$pHBEnv["Cu"]}grouprights g
1010  WHERE g.group_id = $groupId
1011  AND g.confirm_required
1012  LIMIT 1";
1013 
1014  $sth = db_query( $sql, $pHBEnv["dbh"] );
1015  if (!$sth) {
1016  throw new exception($pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1410");
1017  }
1018 
1019  $row = db_fetch_row($sth, 0);
1020  $showPending = $row[0] > 0;
1021  }
1022 
1023  if ( !$showPending ) {
1024  // check the user rights
1025  $userIdList = "'" . implode( "','", $groupUserIds ) . "'";
1026  $sql = "SELECT 1
1027  FROM {$pHBEnv["Cu"]}userrights u
1028  WHERE u.user_id IN ($userIdList)
1029  AND u.confirm_required
1030  LIMIT 1";
1031 
1032  $sth = db_query( $sql, $pHBEnv["dbh"] );
1033  if (!$sth) {
1034  throw new exception($pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1411");
1035  }
1036 
1037  $row = db_fetch_row($sth, 0);
1038  $showPending = $row[0] > 0;
1039  }
1040  }
1041 
1042  return $showPending;
1043 } // end ShowPendingApproval
1044 
1045 /**
1046  * function GetUserActivityMetaData
1047  * Gather and return the one-time meta data used by the user-facing screen. This would be the
1048  * actions, features, and statuses. No need to check permissions because this function should
1049  * only be called in addition to the GetUserActivity, which is checking permissions. The data
1050  * is returned in a name=value format, where the "name" is an internal code (i.e. do not present to user).
1051  *
1052  * @param $pHBEnv -- the current environment
1053  *
1054  * @return The requested information
1055  */
1056 
1057 function GetUserActivityMetaData( $pHBEnv ) {
1058  $returnData = array( "code" => "000", "error" => "", "data" => array() );
1059 
1060  try {
1061  // list all the actions that can be done to a transaction
1062  $actionList = array();
1063  $actionList[] = array("name" => "details", "value" => $pHBEnv["MC"]->msg("View Details", HCU_DISPLAY_AS_RAW));
1064  $actionList[] = array("name" => "approve", "value" => $pHBEnv["MC"]->msg("Approve", HCU_DISPLAY_AS_RAW));
1065  $actionList[] = array("name" => "decline", "value" => $pHBEnv["MC"]->msg("Decline", HCU_DISPLAY_AS_RAW));
1066  $actionList[] = array("name" => "cancel", "value" => $pHBEnv["MC"]->msg("Cancel", HCU_DISPLAY_AS_RAW));
1067 
1068  $actions = array();
1069  for ( $i = 0; $i < count( $actionList ); $i++ ) {
1070  $actions[] = array( "action" => $actionList[$i] );
1071  }
1072 
1073  $returnData["data"]["actions"] = $actions;
1074 
1075  $transferFeatures = GetTransferFeatureList( $pHBEnv );
1076 
1077  // create a feature list with the "all" choice
1078  $featureList = array();
1079  $featureList[] = array( "feature" => array("name" => "", "value" => $pHBEnv["MC"]->msg("All", HCU_DISPLAY_AS_RAW)) );
1080  for ( $i = 0; $i < count( $transferFeatures ); $i++ ) {
1081  $featureList[] = array( "feature" => $transferFeatures[$i] );
1082  }
1083 
1084  $returnData["data"]["features"] = $featureList;
1085 
1086  // get the statuses
1087  $statuses = _GetAllowedStatuses( $pHBEnv["MC"] );
1088 
1089  $statusList = array();
1090  $keys = array_keys( $statuses );
1091  foreach( $keys as $key ) {
1092  $statusList[] = array( "status" => array( "name" => $key, "value" => $statuses[$key] ) );
1093  }
1094 
1095  $returnData["data"]["statuses"] = $statusList;
1096 
1097  // see if need to show pending
1098  $settingsList = array();
1099  $showPending = ShowPendingApproval( $pHBEnv ) ? 1 : 0;
1100  $settingsList[] = array( "setting" => array( "name" => "showpending", "value" => $showPending ) );
1101 
1102  $returnData["data"]["settings"] = $settingsList;
1103 
1104  } catch( Exception $e ) {
1105  // get the message and error code
1106  $message = $e->getMessage();
1107 
1108  $returnData["code"] = "999";
1109  $returnData["error"] = $message;
1110  }
1111 
1112  return $returnData;
1113 } // end GetUserActivityMetaData
1114 
1115 /**
1116  * Get a list of the allowed statuses for activities.
1117  */
1118 function _GetAllowedStatuses( $MC ) {
1119 
1120  $statusList = array( 0 => $MC->msg("Any", HCU_DISPLAY_AS_RAW),
1121  10 => $MC->msg("Approved", HCU_DISPLAY_AS_RAW),
1122  90 => $MC->msg("Declined", HCU_DISPLAY_AS_RAW),
1123  99 => $MC->msg("Cancelled", HCU_DISPLAY_AS_RAW) );
1124 
1125  return $statusList;
1126 } // end _GetAllowedStatuses
1127 
1128 /**
1129  * Get the scheduled user activity information. Filter is passed through from GetUserActivity().
1130  */
1131 function _GetUserActivityScheduled( $pHBEnv, $pParams ) {
1132  $returnData = array( "code" => "000", "error" => "", "data" => array() );
1133 
1134  try {
1135  // get the list of transfer features to get the name
1136  $transferFeatureList = GetTransferFeatureList( $pHBEnv );
1137 
1138  // make it a lookup array
1139  $transferFeatures = ConvertToLookupArray( $transferFeatureList );
1140 
1141  // get the list of schedule intervals for display
1142  $recurringIntervals = getIntervalLookup( $pHBEnv["MC"] );
1143 
1144  // validate the filters
1145  $allowedTypes = getApprovalList();
1146 
1147  // see if there are any filters
1148  $filterTransferType = isset( $pParams["filter"]["type"] ) && in_array( $pParams["filter"]["type"], $allowedTypes ) ? $pParams["filter"]["type"] : "";
1149 
1150  // date filter is: start is included and is earlier than end which is a ceiling (start<= data < end)
1151  $filterStartDate = isset( $pParams["filter"]["start"] ) ? $pParams["filter"]["start"] : "";
1152  $filterEndDate = isset( $pParams["filter"]["end"] ) ? $pParams["filter"]["end"] : "";
1153 
1154  // see if getting all statuses and dates
1155  $getAllScheduled = ( isset( $pParams["filter"]["scheduled"] ) && $pParams["filter"]["scheduled"] == "all" );
1156 
1157  // making sure getting all dates
1158  if ( $getAllScheduled ) {
1159  $filterStartDate = "";
1160  $filterEndDate = "";
1161  }
1162 
1163  // get the allowed statuses, default is any
1164  $allowedStatuses = _GetAllowedStatuses( $pHBEnv["MC"] );
1165 
1166  $filterStatus = isset( $pParams["filter"]["status"] ) && in_array( $pParams["filter"]["status"], $allowedStatuses ) ? $pParams["filter"]["status"] : 0;
1167 
1168  // dates need to be yyyy-mm-dd
1169  if ( $filterStartDate != "" ) {
1170  $filterStartDate = date( "Y-m-d", strtotime( $filterStartDate ) );
1171  }
1172 
1173  if ( $filterEndDate != "" ) {
1174  $filterEndDate = date( "Y-m-d", strtotime( $filterEndDate ) );
1175  }
1176 
1177  // get the requested information, based on the parameters
1178  $sql = "SELECT id, user_id, feature_code, next_trigger_date as date, repeating_parameters,
1179  txn_data, approved_status
1180  FROM cu_scheduledtxn sched
1181  WHERE cu = '{$pHBEnv["Cu"]}'
1182  AND user_id = {$pHBEnv["Uid"]} ";
1183 
1184  // see if getting all
1185  if ( $getAllScheduled ) {
1186  // don't get the ones not yet approved
1187  $sql .= " AND approved_status != 0";
1188  } else {
1189  // ones that haven't completed
1190  $sql .= " AND (end_date is NULL OR current_date <= end_date OR next_trigger_date < end_date)";
1191  $sql .= " AND approved_status = 10";
1192  }
1193 
1194  // add the filters
1195  if ( $filterTransferType != "" ) {
1196  $sql .= " AND feature_code = '$filterTransferType'";
1197  } else {
1198  $sql .= " AND feature_code IN ('" . implode("','", $allowedTypes) . "')";
1199  }
1200 
1201  if ( $filterStartDate != "" ) {
1202  $sql .= " AND next_trigger_date >= '$filterStartDate'";
1203  } else {
1204  // allow older transactions that haven't triggered for some reason
1205  $sql .= "";
1206  }
1207 
1208  if ( $filterEndDate != "" ) {
1209  $sql .= " AND next_trigger_date <= '$filterEndDate'";
1210  } else {
1211  // get all newer transaction (e.g. showing all scheduled)
1212  }
1213 
1214  $sql .= " ORDER BY next_trigger_date ASC";
1215 
1216  $sth = db_query( $sql, $pHBEnv["dbh"] );
1217  if (!$sth) {
1218  throw new exception( $pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1408" );
1219  }
1220 
1221  /*
1222  * Need this info:
1223  * <actions>value,value,...,value</actions> - this depends on if the user has rights, etc
1224  * <type>feature name</type>
1225  * <status>activity status</status>
1226  * <date>date</date>
1227  * <id>id</id>
1228  * <area1_label></area1_label><area1_value></area1_value>
1229  * <area2_label></area2_label><area2_value></area2_value>
1230  * <area3_label></area3_label><area3_value></area3_value>
1231  * <area4_label></area4_label><area4_value></area4_value>
1232  */
1233  $row = 0;
1234  $schedInfo = array();
1235  while ( $schedRow = db_fetch_assoc( $sth, $row++ ) ) {
1236  $schedRow["table"] = "sched";
1237 
1238  $txnInfo = HCU_JsonDecode( $schedRow["txn_data"] );
1239 
1240  // save the type and look up the feature name
1241  $schedRow["type"] = $schedRow["feature_code"];
1242  $featureName = $transferFeatures[$schedRow["feature_code"]];
1243  $schedRow["feature"] = $featureName;
1244 
1245  // next_trigger_date is directly queried as "date"
1246 
1247  // return approved_status meaning as a string
1248  $status = $schedRow["approved_status"];
1249  $schedRow["status"] = $allowedStatuses[$status];
1250 
1251  // get the allowed actions based on rights, etc.
1252  // for scheduled transfers they are only getting their own
1253  $schedRow["actions"] = ( $status == 10 ? "cancel" : "" );
1254 
1255  // the status color depends on the state of the activity and who owns it
1256  if ( $status == 0 ) {
1257  // cannot approve own items
1258  $statusColor = ( $schedRow["user_id"] == $pHBEnv["Uid"] ) ? "info" : "warning";
1259  } else if ( $status == 10 ) {
1260  $statusColor = "success";
1261  } else if ( $status == 90 || $status == 99 ) {
1262  $statusColor = "danger";
1263  } else {
1264  $statusColor = "unknown";
1265  }
1266  $schedRow["color"] = $statusColor;
1267 
1268  $transactionCode = $txnInfo["txn"]["transactioncode"];
1269 
1270  if ( $transactionCode == "2W" ) {
1271  // read the external account info
1272  $extId = $txnInfo["txn"]["from"];
1273 
1274  $fromInfo = _GetExternalAccount( $pHBEnv, $extId );
1275 
1276  $fromDesc = $fromInfo["display"];
1277  } else {
1278  $acctParts = explode( "|", $txnInfo["txn"]["from"] );
1279  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
1280  $fromDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['txn']['frommember'], $txnInfo['txn']['fromsuffix'], $txnInfo['txn']['fromtype'], $certNumber );
1281  }
1282 
1283  if ( $transactionCode == "1W" || $transactionCode == "MM" ) {
1284  // read the external account info
1285  $extId = $txnInfo["txn"]["to"];
1286 
1287  $toInfo = _GetExternalAccount( $pHBEnv, $extId );
1288 
1289  $toDesc = $toInfo["display"];
1290  } else {
1291  $acctParts = explode( "|", $txnInfo["txn"]["to"] );
1292  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
1293  $toDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['txn']['tomember'], $txnInfo['txn']['tosuffix'], $txnInfo['txn']['totype'], $certNumber );
1294  }
1295 
1296  // area1 -> From description
1297  $schedRow["area1_label"] = $pHBEnv["MC"]->msg( "From", HCU_DISPLAY_AS_RAW );
1298  $schedRow["area1_value"] = $fromDesc;
1299 
1300  // area2 -> To description
1301  $schedRow["area2_label"] = $pHBEnv["MC"]->msg( "To", HCU_DISPLAY_AS_RAW );
1302  $schedRow["area2_value"] = $toDesc;
1303 
1304  // area3 -> amount and recurring option
1305  $repeatingParams = HCU_JsonDecode( $schedRow["repeating_parameters"], false, true );
1306  $intervalName = $recurringIntervals[$repeatingParams["interval"]];
1307  $amount = number_format( $txnInfo["txn"]["amount"], 2 );
1308  $schedRow["area3_label"] = "";
1309  $schedRow["area3_value"] = "\${$amount} {$intervalName}";
1310 
1311  // area4 -> next trigger date
1312  $nextTrigger = strtotime( $schedRow["date"] );
1313  if ( $nextTrigger == 0 ) {
1314  // this should never happen
1315  $dateString = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1316  } else {
1317  $dateString = date( "m/d/Y", $nextTrigger );
1318  }
1319  $schedRow["area4_label"] = $pHBEnv["MC"]->msg( "Next Date", HCU_DISPLAY_AS_RAW );
1320  $schedRow["area4_value"] = $dateString;
1321 
1322  // don't return these
1323  unset( $schedRow["txn_data"] );
1324  unset( $schedRow["repeating_parameters"] );
1325 
1326  $schedInfo[]["txn"] = $schedRow;
1327  }
1328 
1329  $returnData["data"] = $schedInfo;
1330 
1331  } catch( Exception $e ) {
1332  // get the message and error code
1333  $message = $e->getMessage();
1334 
1335  $returnData["code"] = "999";
1336  $returnData["error"] = $message;
1337  }
1338 
1339  return $returnData;
1340 } // end _GetUserActivityScheduled
1341 
1342 // Get the ids of all the users in the current user's group.
1343 // Returns an array of user ids, including the current user.
1344 function GetUserIdsForGroup( $pHBEnv ) {
1345 
1346  try {
1347  $sql = "SELECT u2.user_id
1348  FROM {$pHBEnv["Cu"]}user u1
1349  INNER JOIN {$pHBEnv["Cu"]}user u2 ON u2.group_id = u1.group_id
1350  WHERE u1.user_id = {$pHBEnv["Uid"]}";
1351 
1352  $sth = db_query( $sql, $pHBEnv["dbh"] );
1353  if (!$sth) {
1354  throw new exception( $pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1423" );
1355  }
1356 
1357  $row = 0;
1358  $userIdList = array();
1359  while ( $userRow = db_fetch_assoc( $sth, $row++ ) ) {
1360  $userIdList[] = $userRow["user_id"];
1361  }
1362  } catch( Exception $e ) {
1363  // return nothing
1364  $userIdList = array();
1365  }
1366 
1367  return $userIdList;
1368 } // end GetUserIdsForGroup
1369 
1370 /**
1371  * Get the "Need to be approved" pending user activity information. These are in both the
1372  * cu_scheduledtxn table and the <cu>transhdr table. The only filter is the type.
1373  * Only show other user's transactions that this user has the right to confirm.
1374  */
1375 function _GetUserActivityPending( $pHBEnv, $pParams, $pConfirmPermissions ) {
1376  $returnData = array( "code" => "000", "error" => "", "data" => array() );
1377 
1378  try {
1379  // get the list of transfer features to get the name
1380  $transferFeatureList = GetTransferFeatureList( $pHBEnv );
1381 
1382  // make it a lookup array
1383  $transferFeatures = ConvertToLookupArray( $transferFeatureList );
1384 
1385  // get the list of schedule intervals for display
1386  $recurringIntervals = getIntervalLookup( $pHBEnv["MC"] );
1387 
1388  // validate the filters
1389  $allowedTypes = getApprovalList();
1390 
1391  // get all the user ids in the group
1392  $userIdList = GetUserIdsForGroup( $pHBEnv );
1393  $userIdStr = implode( ",", $userIdList );
1394 
1395  // see if there are any filters
1396  $filterTransferType = isset( $pParams["filter"]["type"] ) && in_array( $pParams["filter"]["type"], $allowedTypes ) ? $pParams["filter"]["type"] : "";
1397 
1398  // get the requested information, based on the parameters
1399  // NOTE: right now getting the single detail with the header; may need to re-work when Batch ACH shows up.
1400  $sql = "SELECT hdr.posted_date as sortkey, 'trans' as table_type, hdr.id, hdr.feature_code,
1401  hdr.posted_date as create_date, hdr.effective_date as process_date, hdr.posted_by as create_id,
1402  hdr.approved_status, dtl.amount, '' as repeating_parameters, hdr.transactioncode,
1403  dtl.transdata as txn_data, '' as status
1404  FROM {$pHBEnv["Cu"]}transhdr hdr
1405  INNER JOIN {$pHBEnv["Cu"]}transdtl dtl ON dtl.transhdr_id = hdr.id
1406  WHERE hdr.posted_by IN ($userIdStr)
1407  AND coalesce( hdr.approved_by, 0 ) = 0";
1408 
1409  // add the filters
1410  if ( $filterTransferType != "" ) {
1411  $sql .= " AND feature_code = '$filterTransferType'";
1412  } else {
1413  $sql .= " AND feature_code IN ('" . implode("','", $allowedTypes) . "')";
1414  }
1415 
1416  // columns need to match with a union; amount is a placeholder since it is in the txn_data
1417  $sql .= " UNION
1418  SELECT sched.create_date as sortkey, 'sched' as table_type, sched.id, sched.feature_code,
1419  sched.create_date as create_date, next_trigger_date as process_date, user_id as create_id,
1420  sched.approved_status, 0 as amount, repeating_parameters, '' as transactioncode,
1421  txn_data, status
1422  FROM cu_scheduledtxn sched
1423  WHERE sched.cu = '{$pHBEnv["Cu"]}'
1424  AND sched.user_id IN ($userIdStr)
1425  AND coalesce( sched.approved_by, 0 ) = 0";
1426 
1427  // add the filters
1428  if ( $filterTransferType != "" ) {
1429  $sql .= " AND feature_code = '$filterTransferType'";
1430  } else {
1431  $sql .= " AND feature_code IN ('" . implode("','", $allowedTypes) . "')";
1432  }
1433 
1434  $sql .= " ORDER BY 1 ASC";
1435 
1436  $sth = db_query( $sql, $pHBEnv["dbh"] );
1437  if (!$sth) {
1438  throw new exception( $pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1424" );
1439  }
1440 
1441  // this is used to hold the transcode in case there is an "other" type transaction.
1442  $trans = null;
1443 
1444  /*
1445  * Need this info:
1446  * <actions>value,value,...,value</actions> - this depends on if the user has rights, etc
1447  * <type>feature name</type>
1448  * <status>activity status</status>
1449  * <date>date</date>
1450  * <id>id</id>
1451  * <area1_label></area1_label><area1_value></area1_value>
1452  * <area2_label></area2_label><area2_value></area2_value>
1453  * <area3_label></area3_label><area3_value></area3_value>
1454  * <area4_label></area4_label><area4_value></area4_value>
1455  */
1456  $row = 0;
1457  $approveInfo = array();
1458  while ( $approveRow = db_fetch_assoc( $sth, $row++ ) ) {
1459  // only keep transaction if the current user can approve it
1460  if ( $approveRow["create_id"] != $pHBEnv["Uid"] ) {
1461  if ( !$pConfirmPermissions[$approveRow["feature_code"]] ) {
1462  continue;
1463  }
1464  }
1465 
1466  $txnInfo = HCU_JsonDecode( $approveRow["txn_data"] );
1467 
1468  // get the allowed actions based on rights, etc.
1469  // for transactions needing approval, cancel your own or approve/decline someone elses
1470  $approveRow["actions"] = ( $approveRow["create_id"] == $pHBEnv["Uid"] ) ? "cancel" : "approve,decline";
1471 
1472  // save the type and look up the feature name
1473  $approveRow["type"] = $approveRow["feature_code"];
1474  $featureName = $transferFeatures[$approveRow["feature_code"]];
1475  $approveRow["feature"] = $featureName;
1476 
1477  // the status color is really either cancelled/declined, or completed
1478  if ( $approveRow["create_id"] == $pHBEnv["Uid"] ) {
1479  $statusColor = "info";
1480  } else if ( $approveRow["create_id"] != $pHBEnv["Uid"] ) {
1481  $statusColor = "warning";
1482  } else {
1483  $statusColor = "unknown";
1484  }
1485  $approveRow["color"] = $statusColor;
1486 
1487  // the scheduled transactions may be active or inactive
1488  $txnStatus = "";
1489  if ( $approveRow["status"] == "A" ) {
1490  $txnStatus = $pHBEnv["MC"]->msg( "Active" );
1491  } else if ( $approveRow["status"] == "I" ) {
1492  $txnStatus = $pHBEnv["MC"]->msg( "Inactive" );
1493  }
1494 
1495  // overwrite the field since this is what will be picked up by the client
1496  $approveRow["status"] = $txnStatus;
1497 
1498 
1499  // the below information is different for transaction history vs a scheduled txn
1500  if ( $approveRow["table_type"] == "sched" ) {
1501  $approveRow["table"] = "sched";
1502 
1503  $transactionCode = $txnInfo["txn"]["transactioncode"];
1504 
1505  // the sort key is the <date>
1506  $approveRow["date"] = date( "m/d/Y", strtotime( $approveRow["sortkey"] ) );
1507 
1508  $fromDesc = "";
1509  if ( $transactionCode == "2W" ) {
1510  // read the external account info
1511  $extId = $txnInfo["txn"]["from"];
1512 
1513  $fromInfo = _GetExternalAccount( $pHBEnv, $extId );
1514 
1515  $fromDesc = $fromInfo["display"];
1516  } else {
1517  $acctParts = explode( "|", $txnInfo["txn"]["from"] );
1518  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
1519 
1520  $fromDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['txn']['frommember'], $txnInfo['txn']['fromsuffix'], $txnInfo['txn']['fromtype'], $certNumber );
1521  }
1522 
1523  if ( $fromDesc == "" ) {
1524  $fromDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1525  }
1526 
1527  $toDesc = "";
1528  if ( $transactionCode == "1W" || $transactionCode == "MM" ) {
1529  // read the external account info
1530  $extId = $txnInfo["txn"]["to"];
1531 
1532  $toInfo = _GetExternalAccount( $pHBEnv, $extId );
1533  $toDesc = $toInfo["display"];
1534  } else {
1535  $acctParts = explode( "|", $txnInfo["txn"]["to"] );
1536 
1537  // NOTE: "Other" type transactions cannot be scheduled
1538 
1539  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
1540  $toDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['txn']['tomember'], $txnInfo['txn']['tosuffix'], $txnInfo['txn']['totype'], $certNumber );
1541  }
1542 
1543  if ( $toDesc == "" ) {
1544  $toDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1545  }
1546 
1547  $repeatingParams = HCU_JsonDecode( $approveRow["repeating_parameters"], false, true );
1548  $intervalName = $recurringIntervals[$repeatingParams["interval"]];
1549  $amount = number_format( $txnInfo["txn"]["amount"], 2 );
1550 
1551  $amountLabel = "";
1552  $amountString = "\${$amount} {$intervalName}";
1553 
1554  $dateLabel = $pHBEnv["MC"]->msg( "ACH Effective Date", HCU_DISPLAY_AS_RAW );
1555  $processTime = strtotime( $approveRow["process_date"] );
1556  if ( $processTime == 0 ) {
1557  // this should never happen
1558  $dateString = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1559  } else {
1560  $dateString = date( "m/d/Y", $processTime );
1561  }
1562  } else {
1563  // from the <cu>transdtl table
1564  $approveRow["table"] = "trans";
1565 
1566  $transactionCode = $approveRow["transactioncode"];
1567 
1568  $fromDesc = "";
1569  if ( in_array( $transactionCode, array("1W","1P","AT","LP","LA","MM","CW","OT") ) ) {
1570  $acctParts = explode( "|", $txnInfo["acct_source"] );
1571  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
1572  $accountType = $txnInfo['source_key']['recordtype'] == "L" ? $txnInfo['source_key']['loannumber'] : $txnInfo['source_key']['accounttype'];
1573 
1574  $fromDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['source_key']['accountnumber'], $accountType, $txnInfo['source_key']['recordtype'], $certNumber );
1575  } else if ( in_array( $transactionCode, array("2W","2P") ) ) {
1576  // get the external account info; use the name on account since that is common for creator and approver
1577  $fromDesc = $txnInfo["acct_source"]["remote_entity"]["name"];
1578  }
1579 
1580  if ( !$fromDesc ) {
1581  $fromDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1582  }
1583 
1584  $toDesc = "";
1585  if ( in_array( $transactionCode, array("2W","2P","AT","LP","LA") ) ) {
1586  $acctParts = explode( "|", $txnInfo["acct_dest"] );
1587  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
1588  $accountType = $txnInfo['dest_key']['recordtype'] == "L" ? $txnInfo['dest_key']['loannumber'] : $txnInfo['dest_key']['accounttype'];
1589 
1590  $toDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['dest_key']['accountnumber'], $accountType, $txnInfo['dest_key']['recordtype'], $certNumber );
1591  } else if ( in_array( $transactionCode, array("1W","1P") ) ) {
1592  // get the external account info; use the name on account since that is common for creator and approver
1593  $toDesc = $txnInfo["acct_dest"]["remote_entity"]["name"];
1594  } else if ( in_array( $transactionCode, array( "MM" ) ) ) {
1595  // get the member account info; use the name on account since that is common for creator and approver
1596  $toDesc = $txnInfo["dest_key"]["name"];
1597  } else if ( in_array( $transactionCode, array( "OT","CW" ) ) ) {
1598  $acctParts = explode( "|", $txnInfo["acct_dest"] );
1599 
1600  if ( $acctParts[0] == "O" ) {
1601  if ( $trans == null ) {
1602  $trans = Get_HaveTrans( $pHBEnv["dbh"], $pHBEnv );
1603  }
1604 
1605  $otherDesc = HCU_array_key_value($acctParts[2], $trans);
1606 
1607  $cuDesc = isset($otherDesc[2]) ? trim($otherDesc[2]) : "";
1608  $nonCUDesc = isset($otherDesc[0]) ? trim($otherDesc[0]) : "";
1609 
1610  $toDesc = $cuDesc != "" ? $cuDesc : $nonCUDesc;
1611  }
1612  }
1613 
1614  if ( !$toDesc ) {
1615  $toDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1616  }
1617 
1618  $amount = number_format( $approveRow["amount"], 2 );
1619 
1620  $amountLabel = "";
1621  $amountString = "\${$amount}";
1622 
1623  $dateLabel = $pHBEnv["MC"]->msg( "ACH Effective Date", HCU_DISPLAY_AS_RAW );
1624  $processTime = strtotime( $approveRow["process_date"] );
1625  if ( $processTime == 0 ) {
1626  // this should never happen
1627  $dateString = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1628  } else {
1629  $dateString = date( "m/d/Y", $processTime );
1630  }
1631  }
1632 
1633  // area1 -> From description
1634  $approveRow["area1_label"] = $pHBEnv["MC"]->msg( "From", HCU_DISPLAY_AS_RAW );
1635  $approveRow["area1_value"] = $fromDesc;
1636 
1637  // area2 -> To description
1638  $approveRow["area2_label"] = $pHBEnv["MC"]->msg( "To", HCU_DISPLAY_AS_RAW );
1639  $approveRow["area2_value"] = $toDesc;
1640 
1641  // area3 -> amount and possibly recurring option
1642  $approveRow["area3_label"] = $amountLabel;
1643  $approveRow["area3_value"] = $amountString;
1644 
1645  // area4 -> next trigger date
1646  $approveRow["area4_label"] = $dateLabel;
1647  $approveRow["area4_value"] = $dateString;
1648 
1649  // status for some of them
1650  $approveRow["status"] = $txnStatus;
1651 
1652  // don't return these
1653  unset( $approveRow["txn_data"] );
1654  unset( $approveRow["repeating_parameters"] );
1655  unset( $approveRow["sortkey"] );
1656  unset( $approveRow["amount"] );
1657  unset( $approveRow["transactioncode"] );
1658 
1659  $approveInfo[]["txn"] = $approveRow;
1660  }
1661 
1662  $returnData["data"] = $approveInfo;
1663 
1664  } catch( Exception $e ) {
1665  // get the message and error code
1666  $message = $e->getMessage();
1667 
1668  $returnData["code"] = "999";
1669  $returnData["error"] = $message;
1670  }
1671 
1672  return $returnData;
1673 } // end _GetUserActivityPending
1674 
1675 
1676 /**
1677  * Get the prior history user activity information.
1678  *
1679  * NOTE: Date range is required. Start date is earliest, end is latest. Start
1680  * must be before end. End date is a ceiling (i.e. less than), start date is included.
1681  */
1682 function _GetUserActivityPrior( $pHBEnv, $pParams ) {
1683  $returnData = array( "code" => "000", "error" => "", "data" => array() );
1684 
1685  try {
1686  // date filter is: start is included and is earlier than end which is a ceiling (start<= data < end)
1687  $filterStartDate = isset( $pParams["filter"]["start"] ) ? $pParams["filter"]["start"] : "";
1688  $filterEndDate = isset( $pParams["filter"]["end"] ) ? $pParams["filter"]["end"] : "";
1689 
1690  $startDate = strtotime( $filterStartDate );
1691  $endDate = strtotime( $filterEndDate );
1692 
1693  // dates need to be yyyy-mm-dd
1694  if ( $filterStartDate == "" || $startDate == 0 ) {
1695  throw new exception( $pHBEnv["MC"]->msg( "Please provide a Start Date", HCU_DISPLAY_AS_RAW ) . " 1420" );
1696  }
1697 
1698  if ( $filterEndDate == "" || $endDate == 0 ) {
1699  throw new exception( $pHBEnv["MC"]->msg( "Please provide an End Date", HCU_DISPLAY_AS_RAW ) . " 1421" );
1700  }
1701 
1702  if ( $startDate > $endDate ) {
1703  throw new exception( $pHBEnv["MC"]->msg( "Please provide an End Date", HCU_DISPLAY_AS_RAW ) . " 1422" );
1704  }
1705 
1706  $formattedStartDate = date( "Y-m-d ", $startDate );
1707  $formattedEndDate = date( "Y-m-d", $endDate );
1708 
1709  // get the list of transfer features to get the name
1710  $transferFeatureList = GetTransferFeatureList( $pHBEnv );
1711 
1712  // make it a lookup array
1713  $transferFeatures = ConvertToLookupArray( $transferFeatureList );
1714 
1715  // get the list of schedule intervals for display
1716  $recurringIntervals = getIntervalLookup( $pHBEnv["MC"] );
1717 
1718  // validate the filters
1719  $allowedTypes = getApprovalList();
1720 
1721  // see if there are any filters
1722  $filterTransferType = isset( $pParams["filter"]["type"] ) && in_array( $pParams["filter"]["type"], $allowedTypes ) ? $pParams["filter"]["type"] : "";
1723 
1724  // get the allowed statuses, default is any
1725  $allowedStatuses = _GetAllowedStatuses( $pHBEnv["MC"] );
1726 
1727  $filterStatus = isset( $pParams["filter"]["status"] ) && in_array( $pParams["filter"]["status"], $allowedStatuses ) ? $pParams["filter"]["status"] : 0;
1728 
1729  // get the requested information, based on the parameters
1730  // NOTE: right now getting the single detail with the header; may need to re-work when Batch ACH shows up.
1731  // NOTE: We don't care how far forward in time (there shouldn't be any future approvals, anyway)
1732  $sql = "SELECT hdr.posted_date as sortkey, 'trans' as table_type, hdr.id, hdr.feature_code,
1733  hdr.posted_date as create_date, hdr.approved_status, hdr.processed_date,
1734  hdr.processed_status, hdr.transactioncode,
1735  dtl.amount, '' as repeating_parameters, dtl.transdata as txn_data
1736  FROM {$pHBEnv["Cu"]}transhdr hdr
1737  INNER JOIN {$pHBEnv["Cu"]}transdtl dtl ON dtl.transhdr_id = hdr.id
1738  WHERE (hdr.posted_by = {$pHBEnv["Uid"]} OR hdr.approved_by = {$pHBEnv["Uid"]})
1739  AND hdr.posted_date > '$formattedStartDate 23:59:59'
1740  AND hdr.posted_date <= '$formattedEndDate 23:59:59'
1741  AND hdr.approved_by IS NOT NULL";
1742 
1743  // add the filters
1744  if ( $filterTransferType != "" ) {
1745  $sql .= " AND feature_code = '$filterTransferType'";
1746  } else {
1747  $sql .= " AND feature_code IN ('" . implode("','", $allowedTypes) . "')";
1748  }
1749 
1750  // columns need to match with a union; amount is a placeholder since it is in the txn_data
1751  // NOTE: We don't care how far forward in time because it would be a cancelled record, and prior is
1752  // only worried about looking back in time.
1753  // Currently (04/19/2018) only showing other users' scheduled txns
1754  $sql .= " UNION
1755  SELECT sched.approved_date as sortkey, 'sched' as table_type, sched.id, sched.feature_code,
1756  sched.create_date as create_date, sched.approved_status, sched.approved_date as processed_date,
1757  0 as processed_status, '' as transactioncode, 0 as amount, repeating_parameters, txn_data
1758  FROM cu_scheduledtxn sched
1759  WHERE sched.cu = '{$pHBEnv["Cu"]}'
1760  AND sched.user_id != {$pHBEnv["Uid"]}
1761  AND sched.approved_by = {$pHBEnv["Uid"]}
1762  AND sched.approved_date > '$formattedStartDate 23:59:59'
1763  AND sched.approved_date <= '$formattedEndDate 23:59:59'";
1764 
1765  // add the filters
1766  if ( $filterTransferType != "" ) {
1767  $sql .= " AND feature_code = '$filterTransferType'";
1768  } else {
1769  $sql .= " AND feature_code IN ('" . implode("','", $allowedTypes) . "')";
1770  }
1771 
1772  $sql .= " ORDER BY 1 DESC";
1773 
1774  $sth = db_query( $sql, $pHBEnv["dbh"] );
1775  if (!$sth) {
1776  throw new exception( $pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1419" );
1777  }
1778 
1779  // this is used to hold the transcode in case there is an "other" type transaction.
1780  $trans = null;
1781 
1782  /*
1783  * Need this info:
1784  * <actions>value,value,...,value</actions> - this depends on if the user has rights, etc
1785  * <type>feature name</type>
1786  * <status>activity status</status>
1787  * <date>date</date>
1788  * <id>id</id>
1789  * <area1_label></area1_label><area1_value></area1_value>
1790  * <area2_label></area2_label><area2_value></area2_value>
1791  * <area3_label></area3_label><area3_value></area3_value>
1792  * <area4_label></area4_label><area4_value></area4_value>
1793  */
1794 
1795  $row = 0;
1796  $priorInfo = array();
1797  while ( $priorRow = db_fetch_assoc( $sth, $row++ ) ) {
1798  // the sort key is the <date>
1799  $priorRow["date"] = date( "m/d/Y", strtotime( $priorRow["sortkey"] ) );
1800 
1801  $txnInfo = HCU_JsonDecode( $priorRow["txn_data"] );
1802 
1803  // don't show micro deposits
1804  if ( $priorRow["transactioncode"] == "1P" ||
1805  $priorRow["transactioncode"] == "2P" ) {
1806  if ( (isset( $txnInfo["acct_source"] ) && $txnInfo["acct_source"] == "micro") ||
1807  (isset( $txnInfo["acct_dest"] ) && $txnInfo["acct_dest"] == "micro") ) {
1808  continue;
1809  }
1810  }
1811 
1812  if ( $priorRow["table_type"] == "trans" &&
1813  !isset( $txnInfo["source_key"] ) && !isset( $txnInfo["dest_key"] ) ) {
1814  continue;
1815  }
1816 
1817  // get the allowed actions based on rights, etc.
1818  // for prior transactions, there are no actions currently
1819  $priorRow["actions"] = "";
1820 
1821  // save the type and look up the feature name
1822  $priorRow["type"] = $priorRow["feature_code"];
1823  $featureName = $transferFeatures[$priorRow["feature_code"]];
1824  $priorRow["feature"] = $featureName;
1825 
1826  // return approved_status meaning as a string
1827  $status = $priorRow["approved_status"];
1828  $priorRow["status"] = $allowedStatuses[$status];
1829 
1830  // the status color is really either cancelled/declined, or completed
1831  if ( $status == 10 ) {
1832  $statusColor = "success";
1833  } else if ( $status == 90 || $status == 99 ) {
1834  $statusColor = "danger";
1835  } else {
1836  $statusColor = "unknown";
1837  }
1838  $priorRow["color"] = $statusColor;
1839 
1840  // the below information is different for transaction history vs a scheduled txn
1841  if ( $priorRow["table_type"] == "sched" ) {
1842  $priorRow["table"] = "sched";
1843 
1844  $transactionCode = $txnInfo["txn"]["transactioncode"];
1845 
1846  $fromDesc = "";
1847  if ( $transactionCode == "2W" ) {
1848  // read the external account info
1849  $extId = $txnInfo["txn"]["from"];
1850 
1851  $fromInfo = _GetExternalAccount( $pHBEnv, $extId );
1852 
1853  $fromDesc = $fromInfo["display"];
1854  } else {
1855  $acctParts = explode( "|", $txnInfo["txn"]["from"] );
1856  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
1857  $fromDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['txn']['frommember'], $txnInfo['txn']['fromsuffix'], $txnInfo['txn']['fromtype'], $certNumber );
1858  }
1859 
1860  if ( !$fromDesc ) {
1861  $fromDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1862  }
1863 
1864  $toDesc = "";
1865  if ( $transactionCode == "1W" || $transactionCode == "MM" ) {
1866  // read the external account info
1867  $extId = $txnInfo["txn"]["to"];
1868 
1869  $toInfo = _GetExternalAccount( $pHBEnv, $extId );
1870 
1871  $toDesc = $toInfo["display"];
1872  } else {
1873  $acctParts = explode( "|", $txnInfo["txn"]["to"] );
1874 
1875  if ( $acctParts[0] == "O" ) {
1876  if ( $trans == null ) {
1877  $trans = Get_HaveTrans( $pHBEnv["dbh"], $pHBEnv );
1878  }
1879 
1880  $otherDesc = HCU_array_key_value($acctParts[2], $trans);
1881 
1882  $cuDesc = isset($otherDesc[2]) ? trim($otherDesc[2]) : "";
1883  $nonCUDesc = isset($otherDesc[0]) ? trim($otherDesc[0]) : "";
1884 
1885  $toDesc = $cuDesc != "" ? $cuDesc : $nonCUDesc;
1886 
1887  if ( !$toDesc ) {
1888  $toDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1889  }
1890  } else {
1891  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
1892  $toDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['txn']['tomember'], $txnInfo['txn']['tosuffix'], $txnInfo['txn']['totype'], $certNumber );
1893  }
1894  }
1895 
1896  if ( !$toDesc ) {
1897  $toDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1898  }
1899 
1900  $repeatingParams = HCU_JsonDecode( $priorRow["repeating_parameters"], false, true );
1901  $intervalName = $recurringIntervals[$repeatingParams["interval"]];
1902  $amount = number_format( $txnInfo["txn"]["amount"], 2 );
1903 
1904  $amountLabel = "";
1905  $amountString = "\${$amount} {$intervalName}";
1906 
1907  // only show if approved status is 10 (not declined or cancelled)
1908  if ( $priorRow["approved_status"] == 10 ) {
1909  $dateLabel = $pHBEnv["MC"]->msg( "Processed Date", HCU_DISPLAY_AS_RAW );
1910  $processTime = strtotime( $priorRow["processed_date"] );
1911  if ( $processTime == 0 ) {
1912  $dateString = $pHBEnv["MC"]->msg( "Not processed", HCU_DISPLAY_AS_RAW );
1913  } else {
1914  $dateString = date( "m/d/Y", $processTime );
1915  }
1916  } else {
1917  $dateLabel = "";
1918  $dateString = "";
1919  }
1920  } else {
1921  // from the <cu>transdtl table
1922  $priorRow["table"] = "trans";
1923 
1924  $transactionCode = $priorRow["transactioncode"];
1925 
1926  $fromDesc = "";
1927  if ( in_array( $transactionCode, array("1W","1P","AT","LP","LA","MM","CW","OT") ) ) {
1928  $acctParts = explode( "|", $txnInfo["acct_source"] );
1929  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
1930  $accountType = $txnInfo['source_key']['recordtype'] == "L" ? $txnInfo['source_key']['loannumber'] : $txnInfo['source_key']['accounttype'];
1931 
1932  $fromDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['source_key']['accountnumber'], $accountType, $txnInfo['source_key']['recordtype'], $certNumber );
1933  } else if ( in_array( $transactionCode, array("2W","2P") ) ) {
1934  // get the external account info; use the name on account since that is common for creator and approver
1935  $fromDesc = $txnInfo["acct_source"]["remote_entity"]["name"];
1936  }
1937 
1938  if ( !$fromDesc ) {
1939  $fromDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1940  }
1941 
1942  $toDesc = "";
1943  if ( in_array( $transactionCode, array("2W","2P","AT","LP","LA") ) ) {
1944  $acctParts = explode( "|", $txnInfo["acct_dest"] );
1945  $certNumber = isset( $acctParts[3] ) && $acctParts[3] > 0 ? $acctParts[3] : 0;
1946  $accountType = $txnInfo['dest_key']['recordtype'] == "L" ? $txnInfo['dest_key']['loannumber'] : $txnInfo['dest_key']['accounttype'];
1947 
1948  $toDesc = FindAccountDisplay( $pHBEnv, $pHBEnv["dbh"], $pHBEnv['Cu'], $txnInfo['dest_key']['accountnumber'], $accountType, $txnInfo['dest_key']['recordtype'], $certNumber );
1949  } else if ( in_array( $transactionCode, array("1W","1P") ) ) {
1950  // get the external account info; use the name on account since that is common for creator and approver
1951  $toDesc = $txnInfo["acct_dest"]["remote_entity"]["name"];
1952  } else if ( in_array( $transactionCode, array( "MM" ) ) ) {
1953  // get the member account info; use the name on account since that is common for creator and approver
1954  $toDesc = $txnInfo["dest_key"]["name"];
1955  } else if ( in_array( $transactionCode, array( "OT","CW" ) ) ) {
1956  $acctParts = explode( "|", $txnInfo["acct_dest"] );
1957 
1958  if ( $acctParts[0] == "O" ) {
1959  if ( $trans == null ) {
1960  $trans = Get_HaveTrans( $pHBEnv["dbh"], $pHBEnv );
1961  }
1962 
1963  $otherDesc = HCU_array_key_value($acctParts[2], $trans);
1964 
1965  $cuDesc = isset($otherDesc[2]) ? trim($otherDesc[2]) : "";
1966  $nonCUDesc = isset($otherDesc[0]) ? trim($otherDesc[0]) : "";
1967 
1968  $toDesc = $cuDesc != "" ? $cuDesc : $nonCUDesc;
1969  }
1970  }
1971 
1972  if ( !$toDesc ) {
1973  $toDesc = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
1974  }
1975 
1976  $amount = number_format( $priorRow["amount"], 2 );
1977 
1978  $amountLabel = "";
1979  $amountString = "\${$amount}";
1980 
1981 
1982  $dateLabel = $pHBEnv["MC"]->msg( "Processed Date", HCU_DISPLAY_AS_RAW );
1983  $processTime = strtotime( $priorRow["processed_date"] );
1984  if ( $processTime == 0 || $priorRow["processed_status"] == 90 ) {
1985  $dateString = $pHBEnv["MC"]->msg( "Not processed", HCU_DISPLAY_AS_RAW );
1986  } else {
1987  $dateString = date( "m/d/Y", $processTime );
1988  }
1989  }
1990 
1991  // area1 -> From description
1992  $priorRow["area1_label"] = $pHBEnv["MC"]->msg( "From", HCU_DISPLAY_AS_RAW );
1993  $priorRow["area1_value"] = $fromDesc;
1994 
1995  // area2 -> To description
1996  $priorRow["area2_label"] = $pHBEnv["MC"]->msg( "To", HCU_DISPLAY_AS_RAW );
1997  $priorRow["area2_value"] = $toDesc;
1998 
1999  // area3 -> amount and possibly recurring option
2000  $priorRow["area3_label"] = $amountLabel;
2001  $priorRow["area3_value"] = $amountString;
2002 
2003  // area4 -> next trigger date (scheduled) or processed date (tranhdr)
2004  $priorRow["area4_label"] = $dateLabel;
2005  $priorRow["area4_value"] = $dateString;
2006 
2007  // don't return these
2008  unset( $priorRow["txn_data"] );
2009  unset( $priorRow["repeating_parameters"] );
2010  unset( $priorRow["sortkey"] );
2011 
2012  $priorInfo[]["txn"] = $priorRow;
2013  }
2014 
2015  $returnData["data"] = $priorInfo;
2016 
2017  } catch( Exception $e ) {
2018  // get the message and error code
2019  $message = $e->getMessage();
2020 
2021  $returnData["code"] = "999";
2022  $returnData["error"] = $message;
2023  }
2024 
2025  return $returnData;
2026 } // end _GetUserActivityPrior
2027 
2028 /**
2029  * function DoActivityAction
2030  * Perform the given action on the activity. If successful, read the activity detail and return that information.
2031  * The action can be an approve or decline of a pending transfer, or the cancel of own scheduled or pending
2032  * transfer.
2033  *
2034  * @param array $pHBEnv - Home banking settings
2035  * @param int $pDetailId - The detail id to act upon
2036  * @param boolean $pIsScheduled - The type of txn acting upon is a scheduled txn
2037  * @param string $pAction - The specific action
2038  *
2039  * @return The activity detail
2040  */
2041 function DoActivityAction( $pHBEnv, $pDetailId, $pIsScheduled, $pAction ) {
2042  $returnData = array( "code" => "000", "error" => "", "data" => array() );
2043 
2044  try {
2045  // get list of userIds for group
2046  $userIdList = GetUserIdsForGroup( $pHBEnv );
2047  $userIdStr = implode( ",", $userIdList );
2048 
2049 
2050  // make sure this user has the rights to do the approval
2051  $confirmPermissions = array();
2052  $results = Perm_FeatureAccessList( $pHBEnv["dbh"], $pHBEnv );
2053  if ( !intval($results["status"]["code"] ) == 0) {
2054  throw new exception($results["status"]["error"] . " 1404");
2055  }
2056 
2057  // the rights for this user will be returned
2058  $permissions = $results["data"][$pHBEnv["Uid"]];
2059 
2060  // Prevent the page from being accessible when the user doesn't have approve access to at least one feature.
2061  $approvalFeatureList = getApprovalList();
2062  $confirmFound = false;
2063  foreach( $permissions as $featureCode => $featureRecord )
2064  {
2065  if ( !in_array( $featureCode, $approvalFeatureList ) ) {
2066  continue; // Feature is irrelevant to this script.
2067  }
2068 
2069  $confirmFound = $confirmFound || $featureRecord["confirm"];
2070  $confirmPermissions[$featureCode] = $featureRecord["confirm"]; // Save the permission for later.
2071  }
2072 
2073  // if this user is the only person in group then can confirm (but shouldn't be here, really)
2074  if ( !$confirmFound ) {
2075  if ( in_array( $pHBEnv["Uid"], $userIdList ) &&
2076  count( $userIdList ) == 1 ) {
2077  $confirmFound = true;
2078  }
2079  }
2080 
2081  if ( !$confirmFound ) {
2082  throw new exception( $pHBEnv["MC"]->msg( "Trans approval failure", HCU_DISPLAY_AS_RAW ) . " 1427");
2083  }
2084 
2085  // get the feature code to see if this user has permissions to approve
2086  $table = $pIsScheduled ? "cu_scheduledtxn" : "{$pHBEnv["Cu"]}transhdr";
2087  $postedField = $pIsScheduled ? "user_id" : "posted_by";
2088  $sql = "SELECT feature_code, $postedField as user_id, approved_status
2089  FROM $table
2090  WHERE id = $pDetailId
2091  AND $postedField IN ($userIdStr)";
2092 
2093  $sth = db_query( $sql, $pHBEnv["dbh"] );
2094  if (!$sth) {
2095  throw new exception( $pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1428" );
2096  }
2097 
2098  $txnRow = db_fetch_assoc($sth, 0);
2099  $transferFeatureCode = trim( $txnRow["feature_code"] );
2100 
2101  // can they approve this type of transaction?
2102  if ( !$confirmPermissions[$transferFeatureCode] ) {
2103  throw new exception( $pHBEnv["MC"]->msg( "Trans approval failure", HCU_DISPLAY_AS_RAW ) . " 1429");
2104  }
2105 
2106  // get the action code
2107  $actionStatus = 0;
2108  if ( $pAction == "approve" ) {
2109  $actionStatus = 10;
2110  } else if ( $pAction == "decline" ) {
2111  $actionStatus = 90;
2112  } else if ( $pAction == "cancel" ) {
2113  $actionStatus = 99;
2114  } else {
2115  throw new exception( $pHBEnv["MC"]->msg( "ACH Unknown Action", HCU_DISPLAY_AS_RAW ) . " 1425");
2116  }
2117 
2118  // are they confirming their own transaction?
2119  if ( ($actionStatus == 10 || $actionStatus == 90) &&
2120  ($txnRow["user_id"] == $pHBEnv["Uid"]) ) {
2121  throw new exception( $pHBEnv["MC"]->msg( "Trans approval failure", HCU_DISPLAY_AS_RAW ) . " 1430");
2122  }
2123 
2124  // are they cancelling someone else's transaction?
2125  if ( ($actionStatus == 99) &&
2126  ($txnRow["user_id"] != $pHBEnv["Uid"]) ) {
2127  throw new exception( $pHBEnv["MC"]->msg( "Trans approval failure", HCU_DISPLAY_AS_RAW ) . " 1436");
2128  }
2129 
2130  // is this a transaction waiting to be approved/declined?
2131  if ( ($actionStatus == 10 || $actionStatus == 90) &&
2132  $txnRow["approved_status"] != 0 ) {
2133  throw new exception( $pHBEnv["MC"]->msg( "Trans approval failure", HCU_DISPLAY_AS_RAW ) . " 1431");
2134  }
2135 
2136  if ( $pIsScheduled ) {
2137  // is this a scheduled transaction to be cancelled? (Okay if already cancelled)
2138  if ( $actionStatus == 99 &&
2139  $txnRow["approved_status"] != 0 &&
2140  $txnRow["approved_status"] != 10 &&
2141  $txnRow["approved_status"] != 99 ) {
2142  throw new exception( $pHBEnv["MC"]->msg( "Trans approval failure", HCU_DISPLAY_AS_RAW ) . " 1437");
2143  }
2144 
2145  // for scheduled transactions, just set it to the new approved_status
2146  $sql = "UPDATE cu_scheduledtxn SET approved_by = {$pHBEnv["Uid"]}, approved_date = now(), approved_status = $actionStatus WHERE id = $pDetailId AND user_id IN ($userIdStr)";
2147 
2148  $sth = db_query( $sql, $pHBEnv["dbh"] );
2149  if (!$sth) {
2150  throw new exception( $pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1426" );
2151  }
2152 
2153  $resultDetail = _GetActivityDetailScheduled( $pHBEnv, $pDetailId );
2154  } else {
2155  if ( $actionStatus == 10 ) {
2156  // need to submit as a transfer
2157  $aryApprovalResults = array();
2158  if (!ApproveTransfer($pHBEnv["dbh"], $pHBEnv, $pHBEnv["MC"], $pDetailId, $aryApprovalResults)) {
2159  throw new exception($aryApprovalResults["status"]["errors"][0] . "1432");
2160  }
2161 
2162  // save the approval confirmation code
2163  $confirmationCode = $aryApprovalResults["status"]["confirm"];
2164 
2165  // If a regular transaction is approved, try to post it to the core.
2166  if ( in_array( $transferFeatureCode, array(FEATURE_TRANSFERS, FEATURE_M2M_TRANSFERS) ) ) {
2167  $aryProcessResults = array();
2168  if (!ProcessTransfer($pHBEnv["dbh"], $pHBEnv, $pHBEnv["MC"], $pDetailId, $aryProcessResults, true)) {
2169  // since there was an error posting to the core, we revert approval
2170  // and commit only the cucorerequest record
2171  RevertMarkAsApproved($pDetailId, $pHBEnv["dbh"], $pHBEnv["Cu"], "1433");
2172  // throw exception regardless of the RevertMarkAsApproved function
2173  // would throw sql execution failure exception or not as we do not
2174  // want to execute the code logic for successful transfer below
2175  throw new exception($aryProcessResults["status"]["errors"][0] . "1433");
2176  }
2177 
2178  // use the processing confirmation code
2179  $confirmationCode = $aryProcessResults["txn"]["data_confirm"];
2180  }
2181 
2182  // return the confirmation code
2183  $returnData["data"]["confirm"] = $confirmationCode;
2184  } else {
2185  // apply the status because it is either a cancel or decline
2186  // make sure it is someone in the group
2187  $sql = "UPDATE {$pHBEnv["Cu"]}transhdr SET approved_by = {$pHBEnv["Uid"]}, approved_date = now(), approved_status = $actionStatus WHERE id = $pDetailId AND posted_by IN ($userIdStr)";
2188 
2189  $sth = db_query( $sql, $pHBEnv["dbh"] );
2190  if (!$sth) {
2191  throw new exception( $pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1426" );
2192  }
2193  }
2194 
2195  $resultDetail = _GetActivityDetailRegular( $pHBEnv, $pDetailId );
2196  }
2197 
2198  $returnData["data"]["details"] = $resultDetail["data"];
2199  } catch( Exception $e ) {
2200  // get the message and error code
2201  $message = $e->getMessage();
2202 
2203  $returnData["code"] = "999";
2204  $returnData["error"] = $message;
2205  }
2206 
2207  return $returnData;
2208 } // end DoActivityAction
2209 
2210 
2211 /**
2212  * Utility function to reset approved* attributes from ${CU}transhdr table
2213  * when the transfer process fails.
2214  *
2215  * @param $transferId - transfer id to delete
2216  * @param $dbh - database handler
2217  * @param $Cu - CU code
2218  *
2219  * @throws Exception if the transhdr record update fails
2220  *
2221  */
2222 function RevertMarkAsApproved($transferId, $dbh, $Cu, $errCode) {
2223 
2224  try {
2225  $transHdrTbl = trim(strtolower($Cu)) . "transhdr";
2226 
2227  // reset approved* attributes
2228  $sqlUpdateHdr = "UPDATE ${transHdrTbl} SET".
2229  " approved_by = NULL,".
2230  " approved_date = NULL,".
2231  " approved_status = NULL".
2232  " WHERE id = ${transferId}";
2233 
2234  $sqlUpdateHdrRs = db_query($sqlUpdateHdr, $dbh);
2235 
2236  if (!$sqlUpdateHdrRs) {
2237  if ($errCode == "1433") {
2238  throw new exception("Transfer approval reset failed.". $errCode);
2239  } else {
2240  throw new exception("Transfer approval reset failed.", $errCode);
2241  }
2242  } else {
2243  // commit the transhdr update including cucorerequests record
2244  db_work($dbh, HOMECU_WORK_COMMIT);
2245  }
2246  } catch (Exception $ex) {
2247  throw $ex;
2248  }
2249 }
2250 
2251 // Get the information from the given external account. This can be an external ACH or a m2m account.
2252 // NOTE: any error has the function just returning "unknown" as the account.
2253 function _GetExternalAccount( $pHBEnv, $pExtId ) {
2254  $returnData = array( "display" => "000", "name" => "", "routing" => "", "account" => "" );
2255 
2256  try {
2257  // get the requested information, making sure it really is for this user (or at least in this user's group)
2258  $sql = "SELECT e.*, u.group_id as user_group, t.group_id as test_group
2259  FROM {$pHBEnv["Cu"]}extaccount e
2260  INNER JOIN {$pHBEnv["Cu"]}user u ON u.user_id = e.user_id
2261  INNER JOIN {$pHBEnv["Cu"]}user t ON t.user_id = {$pHBEnv["Uid"]}
2262  WHERE e.id = $pExtId";
2263 
2264  $sth = db_query( $sql, $pHBEnv["dbh"] );
2265  if (!$sth) {
2266  throw new exception($pHBEnv["MC"]->msg( "ACH Query Error", HCU_DISPLAY_AS_RAW ) . " 1434");
2267  }
2268 
2269  $accountRow = db_fetch_assoc($sth, 0);
2270 
2271  if ( $accountRow["user_group"] != $accountRow["test_group"] ) {
2272  throw new exception($pHBEnv["MC"]->msg( "Invalid account access", HCU_DISPLAY_AS_RAW ) . " 1435");
2273  }
2274 
2275  $acctInfo = HCU_JsonDecode( $accountRow["remote_info"] );
2276 
2277  $returnData["display"] = $accountRow["display_name"];
2278 
2279  if ( $accountRow["type"] == "EXT" ) {
2280  $returnData["name"] = $acctInfo["rdfi"]["name"];
2281  $returnData["routing"] = $acctInfo["rdfi"]["routing"];
2282  $returnData["account"] = $acctInfo["rdfi"]["account"];
2283  } else {
2284  $returnData["name"] = $acctInfo["rdfi"]["name"];
2285  $returnData["account"] = $acctInfo["rdfi"]["account"];
2286  }
2287  } catch( Exception $e ) {
2288  // not worring about message and error code
2289 
2290  $returnData["display"] = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
2291  $returnData["name"] = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
2292  $returnData["routing"] = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
2293  $returnData["account"] = $pHBEnv["MC"]->msg( "Unknown", HCU_DISPLAY_AS_RAW );
2294  }
2295 
2296  return $returnData;
2297 
2298 } // end _GetExternalAccount