Odyssey
sAPIAppl.i
1 <?php
2 
3  /** **
4  * ** GLOBAL CONSTANTS
5  * **
6  */
7 
8  define ("PACKET_FULL", 1); // ** Packet requests should contain all account information
9  define ("PACKET_PER_ACCOUNT", 2); // ** Packet requests are PER Account/suffix . Except the initial. It is BALANCES ONLY
10 
11  define ("PACKET_REQUEST_VERIFY_PIN", "PIN"); // This is the "CLASSIC" version of getting data for NEW member
12  define ("PACKET_REQUEST_INQUIRY", "INQ"); // This is the "CLASSIC" version of getting data for a regular Inquiry
13  define ("PACKET_REQUEST_BAL", "BAL");
14  define ("PACKET_REQUEST_HIS", "HISTORY");
15  define ("PACKET_REQUEST_XAC", "XAC");
16  define ("PACKET_REQUEST_TRN", "TRN");
17  define ("PACKET_REQUEST_NEWAPP", "NEWAPP");
18  define ("PACKET_REQUEST_INQAPP", "INQAPP");
19  define ("PACKET_REQUEST_MIR", "MIR");
20  define ("PACKET_REQUEST_MA", "MA");
21  define ("PACKET_REQUEST_ES", "ES");
22  define ("PACKET_REQUEST_ES_TOC", "TOC");
23 
24 
25  define ("PACKET_DEFAULT_CUTOFF_DAYS", 366);
26  define ("PACKET_DEFAULT_INQ_CUTOFF", '20000101');
27  define ("PACKET_DEFAULT_NEW_CUTOFF", '20060101');
28  define ("PACKET_MIN_FETCH_DAYS", 7);
29  define ("PACKET_SECONDS_DAY", 86400);
30 
31 // CORE request connection constants:
32 // # of times to retry getting data from core if connection timed out
33 define ("CURL_CONN_TO_CORE_DEFAULT_RETRIES", 2);
34 // Number of seconds to wait/sleep between each try
35 define ("CURL_CONN_TO_CORE_RETRY_DELAY", 2);
36 
37  // imports
38  require_once (dirname(__FILE__) . '/../../shared/library/xml_processing.i');
39 
40  /**
41  *
42  * Functions for retrieving data from a HomeCU Appliance
43  *
44  ** ** PUBLIC FUNCTIONS **
45  *
46  * GetMemberInfo -- Gets the MIR request for a member number
47  *
48  * GetMemberES -- Get the member eStatement from the core
49  *
50  * FindMemberAccounts -- This will return the member accounts / mir for a given member number
51  *
52  * LoadUserData -- This will get the member INQ packet from the core and populate the database tables
53  *
54  * LoadCrossAcctData -- This will get the XAC packet from the core and populate the database tables
55  *
56  * VerifyMemberPin -- Verify the member pin from the core
57  *
58  * PostTransactionRequest -- This handles all types of transactions requests
59  * TRN / MA / NEWAPP / ES
60  *
61  ** ** PRIVATE FUNCTIONS **
62  *
63  * _ProcessAPIResponse -- Parses the response from the api and breaks into the components
64  *
65  * _SendDataRequest -- Sends the request to the homecu api server
66  *
67  * _CreateAPIUrl -- This will create the API URL from the connection settings
68  *
69  * _ReturnCurlDefaults -- Return the default CURL parameters for the request
70  *
71  * _RetrieveMemberCrossAccount -- Retrieve the Member Cross Account packet
72  * from the CORE (XAC)
73  *
74  * _RetrieveMemberES -- Retrieve Membe Estatement from the core
75  *
76  * _RetrieveMemberInfo -- Retrieve the Member Information Packet from
77  * the core (MIR) and process results.
78  *
79  * _RetrieveMemberInquiry -- Retrieve the Member Inquiry packet from
80  * the CORE (INQ)
81  *
82  * _ReturnCUSettings -- Get the Credit Union settings. This included the information to connect with the appliance as well as the data settings
83  *
84  * _ReturnCutoffDate -- Return the cutoff based on the request and current data
85  *
86  ** ** PRIVATE FUNCTIONS Related to Core Requst Log Table (cucorerequests)**
87  *
88  * _PopulateCUCoreRequestsTable -- Insert or Update cucorerequset record
89  *
90  * _SkipCucorerequestsEntry -- Return a skip flag for db operations
91  *
92  * _UpdateRequestStatus -- Prepare status json object and update
93  * AFTER curl request
94  * Being called from _RetrieveMemberInquiry,
95  * _RetrieveMemberInfo, _RetrieveMemberES,
96  * _RetrieveMemberCrossAccount, and
97  * PostTransactionRequest
98  *
99  * _GetAdditionalQueryStr -- Add additional query string
100  * for book-keeping
101  *
102  * _HideSensitiveContent -- Hide sensitive information from live
103  * url and query string
104  *
105  * _PopulateApplianceId -- Extract appliance_ip (ip or dns name)
106  * from live url
107  *
108  * _GetNextCucorerequestsSeqId -- get next cucorerequests.id value from db
109  *
110  * _PrepareCucoreInfoBeforeRequest -- Insert cucorerequest record with initial
111  * information BEFORE curl request (being
112  * called from _SendDataRequest)
113  *
114  */
115 /**
116  * ****
117  * **** ERROR CODES *****
118  * 50000 - 55000
119  * _ParsePacketData
120  * 50010 - _ProcessAPIResponse returned an error
121  * 50020 - _GetPacketStatus retruend an unknown status
122  * 50030 - Member Number Out of Sync
123  * ****
124  * _RetrieveMemberInfo
125  * 50050 - Member Number not set
126  * 50060 - _ParsePacketData error
127  * 50070 - Deprecated Status Codes
128  * ****
129  * FindMemberAccounts
130  * 50101 - Invalid Member Account (MIR)
131  * 50102 - Invalid Member Account (INQ)
132  * ****
133  * LoadUserData
134  * 50111 - Too soon to ask again
135  * 50115 - Failed getting last packet status
136  * 50120 - Failed updating packet status
137  * LoadCrossAccountData
138  * 50211 - Already requested this session
139  * 50220 - Failed updating cross account data
140  */
141 /**
142  * *** **
143  * *** ** PUBLIC FUNCTIONS **
144  * *** **
145  */
146 
147 
148 /**
149  * Request the MIR packet for a member from the core
150  *
151  * @param array $pHbEnv -- The current HB_ENV environment array
152  * @param array $pMbrData -- Array of data for retrieving a packet
153  * type - PACKET_REQUEST_MIR
154  * member - member number of the MIR packet we want to request
155  * email - Send email if supplied
156  *
157  *
158  * @return array -- This will return a status array
159  * [code]
160  * {000} -- Good member
161  * [data] array populated with mir packet information
162  * {001} -- Invalid Account Number,
163  * [data] array empty,
164  * [error] set to 'Invalid Account Number'
165  * {999} -- Invalid Account Number,
166  * [data] array empty
167  * [error] -- Error Message
168  *
169  */
170 function GetMemberInfo($pHbEnv, $pMbrData) {
171 
172  $retVal = Array("code" => '000', "data" => Array());
173 
174  try {
175 
176  /**
177  * ** GET CREDIT UNION SETTINGS **
178  */
179  $cuConnResp = _ReturnCUSettings($pHbEnv);
180  if ($cuConnResp['code'] != '000') {
181  throw new Exception ("Unable to Load CU Settings");
182  }
183  $cuConnSet = HCU_array_key_value('data', $cuConnResp);
184 
185  // ** Set the Member Number to retrieve
186  $mbrRequest = HCU_array_key_value('member', $pMbrData);
187 
188  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n** Get Member Info **\n");
189 
190 
191  /*
192  * MIR PACKET REQUEST
193  */
194  // $mirMbrData = array_combine($pMbrData, array("type" => PACKET_REQUEST_MIR));
195  $mirResp = _RetrieveMemberInfo($pHbEnv, $cuConnSet, HCU_array_key_value('member', $pMbrData));
196 
197  if ($mirResp['code'] != '000') {
198  throw new Exception ("Unable to retrieve MIR Packet - " . $mirResp['error']);
199  }
200 
201  $retVal['code'] = '000';
202  $retVal['data'] = $mirResp['data'];
203 
204  } catch (Exception $e) {
205  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n** Mbr Info Error Caught ** \n" . "({$e->getCode()})" . $e->getMessage() );
206  $retVal['code'] = '999';
207  $retVal['error'] = "Unable to retrieve data";
208  }
209 
210  return $retVal;
211 
212 }
213 
214 /**
215  * Request E-Statement from the core
216  * This includes the Table of Contents and the E-Statement
217  *
218  * @param array $pHbEnv -- The current HB_ENV environment array
219  * @param array $pMbrData -- Array of data for retrieving a packet
220  * member - member number of the EStatement we are retrieving
221  * email - Send email if supplied
222  * statement-id - If supplied this statement is retrieved (ESTM), otherwise it will retrieve the Table of Contents (ETOC)
223  *
224  *
225  * @return array -- This will return a status array
226  * [code]
227  * {000} -- Good member
228  * [data] array populated with mir packet information
229  * {001} -- Invalid Account Number,
230  * [data] array empty,
231  * [error] set to 'Invalid Account Number'
232  * {999} -- Invalid Account Number,
233  * [data] array empty
234  * [error] -- Error Message
235  *
236  */
237 function GetMemberES($pHbEnv, $pMbrData) {
238  $retVal = Array("code" => '000', "data" => Array());
239 
240  try {
241 
242  /**
243  * ** GET CREDIT UNION SETTINGS **
244  */
245  $cuConnResp = _ReturnCUSettings($pHbEnv);
246  if ($cuConnResp['code'] != '000') {
247  throw new Exception ("Unable to Load CU Settings");
248  }
249  $cuConnSet = HCU_array_key_value('data', $cuConnResp);
250 
251  // ** Set the Member Number to retrieve
252  $mbrRequest = HCU_array_key_value('member', $pMbrData);
253 
254  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n** Get Estatement **\n");
255 
256 
257  /*
258  * EStatement REQUEST
259  */
260  if (HCU_array_key_value('statement-id', $pMbrData) != '') {
261  $esType = PACKET_REQUEST_ES;
262  $eStatementId = HCU_array_key_value('statement-id', $pMbrData);
263  } else {
264  $esType = PACKET_REQUEST_ES_TOC;
265  $eStatementId = '';
266  }
267 
268  $esResp = _RetrieveMemberES($pHbEnv, $cuConnSet, HCU_array_key_value('member', $pMbrData), HCU_array_key_value('email', $pMbrData), $esType, $eStatementId);
269 
270  if ($esResp['code'] != '000') {
271  $retVal['code'] = '999';
272  $retVal['error'] = $esResp['error'];
273  } else {
274  $retVal['code'] = '000';
275  $retVal['data'] = $esResp['data'];
276  }
277  } catch (Exception $e) {
278  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n** ES Request Error Caught ** \n" . "({$e->getCode()})" . $e->getMessage() );
279  $retVal['code'] = '999';
280  $retVal['error'] = "Unable to retrieve data";
281  }
282 
283  return $retVal;
284 
285 }
286 
287 /**
288  * Request Cross Account (XAC) packets from the core for all the user's member account
289  * This is a standard api request. This will retrieve the XAC packet and update the
290  * useraccounts table. Cross Account information does not get saved to the accountbalance record
291  *
292  * @param array $pHbEnv -- Current HB_ENV setting
293  * @param integer $pUserId -- User ID for data that is being requested
294  * @param array $pUserData -- Array of data for the user
295  * email - The email to send to core that goes with the member
296  * lastlogin - The lasttime the user logged in.. This is questionable.. at this time it will be the last time this USER logged in.
297  * @return array
298  * [code]
299  * {000, 900, 999}
300  * 000 - Success - This can be set if the response from the core was successful and was not one of the known error codes.
301  * 900 - NO ACTION - This can be returned for "too soon to ask again"
302  * 999 - Failure - This happens when the routine fails for any reason. From communication to core error.
303  * [error]
304  * [data]
305  * 'requestDate' => packet stamp formatted to 'D M j Y H:i:s T'
306  * 'requestDesc' => Message from Core
307 */
308 function LoadCrossAcctData($pHbEnv, $pUserId, $pUserData) {
309  $retVal = Array("code" => "000", "data" => Array());
310 
311  $mbrReqType = PACKET_REQUEST_XAC;
312  try {
313 
314  $pktDateStamp = date("U");
315 
316  /**
317  * Before calling this function it is the responsibility of the programmer to determine
318  * If the XAC packet should be loaded. This is an attempt to encapsulate this function and limit
319  * its dependencies
320  */
321  if (false) {
322  throw new Exception("Already requested this session", 50211);
323  }
324 
325 
326  /*
327  * Get CU Connection Settings
328  */
329  $cuConnResp = _ReturnCUSettings($pHbEnv);
330  if ($cuConnResp['code'] != '000') {
331  throw new Exception ("Unable to Load CU Settings");
332  }
333  $cuConnSet = HCU_array_key_value('data', $cuConnResp);
334 
335  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n** Load User Data **\n");
336 
337  /*
338  * 7/30/2018 - MWS
339  * Implementing the new flag for creating Access Control entries from XAC
340  * I don't want to hit the core for the new "xac" entries, so I am adding a new
341  * flag to ONLY get member accounts the use has set to "Auto-Add". This will
342  * limit the number of calls to the core as they wouldn't be adding any of the
343  * subsequent entries.
344  * Trying to keep the calls to a minimum.
345  * -- At this time, ONLY changing when CU3_CREATE_ACCESS_CONTROL_FROM_XAC is set
346  */
347  $showAutoAddOnly = (($pHbEnv['flagset3'] & GetFlagsetValue("CU3_CREATE_ACCESS_CONTROL_FROM_XAC")) > 0);
348 
349  $mbrAcctList = _ReturnMemberAcctList($pHbEnv, $pUserId, $showAutoAddOnly);
350  if ($mbrAcctList['code'] != '000') {
351  throw new Exception ("No Accounts Found");
352  }
353 
354  /*
355  * Loop through Member List
356  */
357 
358  /*
359  * Retrieve Member Data
360  */
361  foreach ($mbrAcctList['data'] as $idx => $subAcctItem) {
362  /**
363  * @var string Account number
364  */
365  $reqMemberAcctNbr = $subAcctItem['accountnumber'];
366 
367  /**
368  * mbrEmail
369  */
370  // ** Using the email from the user isn't always the right answer
371  // ** we may want
372  $paramEmail = HCU_array_key_value('email', $pUserData);
373  $mbrEmail = (($paramEmail == '' || $paramEmail == 'no@email.com') ? "NULL" : trim($paramEmail));
374 
375 
376  /**
377  * ** START THE PROCESS OF REQUESTING DATA FROM THE CORE
378  */
379 
380  /**
381  * ** Build Data Request
382  */
383 
384  $dataArray = Array(
385  "member" => $reqMemberAcctNbr,
386  "type" => 'X',
387  "ref3" => $mbrEmail
388  );
389  _ApplPrintLogger($pHbEnv, $cuConnSet, print_r($dataArray, true));
390  /*
391  * Inquiry Packet Request
392  */
393  $acctResp = _RetrieveMemberCrossAccount($pHbEnv, $cuConnSet, $dataArray);
394 
395  if ($acctResp['code'] != '000') {
396  if (in_array($acctResp['code'], array('001', '002', '003'))) {
397  throw new Exception ($acctResp['error'], 50102);
398  }
399  throw new Exception ("Unable to retrieve list of accounts - " . $acctResp['error']);
400  }
401  $xmlPacket = $acctResp['data']['packet-xml'];
402 
403  /*
404  * UPDATE DATABASE (useraccounts)
405  */
406 
407  $mbrData = Array(
408  'type' => PACKET_REQUEST_XAC,
409  'user_id' => $pUserId,
410  'member' => $reqMemberAcctNbr
411  );
412  $dataResp = _SaveMemberXAData($pHbEnv, $cuConnSet, $mbrData, $xmlPacket);
413  if ($dataResp['code'] !== '000') {
414  // ** Error Updating the tables
415  _ApplPrintLogger($pHbEnv, $cuConnSet, " *** **** ***** ERROR UPDATING TABLES ");
416  throw new Exception ("Update Failure", 999);
417  } else {
418  if (($pHbEnv['flagset3'] & GetFlagsetValue("CU3_CREATE_ACCESS_CONTROL_FROM_XAC")) != 0 && intval(HCU_array_key_value('memberacct-added', $dataResp['data'])) > 0) {
419  // ** SUCCESS -- IF ANY MemberAcct was added then just call LoadUserData to force packet fetch
420  $userData = Array (
421  'email' => '',
422  'lastlogin' => ''
423  );
424 
425  /*
426  * FOR Live CU Load all the member account related to the current user
427  */
428  $localDataResp = LoadUserData($pHbEnv, $pUserId, $userData);
429  // ** Not sure if we care about a packet failure here -- If data is not loaded they simply will not see the newly added cross accounts
430  }
431  }
432 
433  }
434  $retVal = Array('code' => '000', 'data' => array('requestDate' => $pktDateStamp, 'requestDesc' => 'Success'));
435  } catch (Exception $e) {
436  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n Load Cross Account Data -- Catch Error :: ({$e->getCode()}) {$e->getMessage()}");
437  // ** Not sure how to handle here
438  if ($e->getCode() == 50211) {
439  // ** Already requested this session
440  // ** The last packet date is passed as the message in the thrown error
441  $retVal = Array('code' => '900', 'data' => array('requestDate' => $e->getMessage(), 'requestDesc' => 'Too soon to ask again'));
442  } else {
443  // ** Unknown Error
444  $retVal = Array('code' => '999', 'data' => array('requestDate' => 1, 'requestDesc' => 'Unable to retrieve data'));
445  }
446  }
447 
448  return $retVal;
449 }
450 
451 
452 /**
453  * Post transaction request to the core
454  * This function should handle all types of transactions requests
455  * TRN / MA / NEWAPP / ES
456  *
457  * @param array $pHbEnv -- The current HB_ENV array
458  * @param array $pData -- Array of data for retrieving a packet
459  * pkt-type - one of the PACKET_REQUEST_{CONSTANTS} -- Used for parsing the data packet
460  * ** Refer to specific transaction type below for additional parameters
461  * @param boolean $pSendAsPost -- (false default), (true - send the transaction request as a post to the core)
462  *
463  * * Different transaction types have different values for the transaction *
464  * * TRN: (Normal Transaction {AT, LP, etc})
465  * * member - From Member Number
466  * * type - T (always)
467  * * tran_code - {AT, LP, etc}
468  * * ref1 - the "FROM" Suffix (sub-account)
469  * * ref2 - the "TO" Suffix (sub-account)
470  * * ref3 - email associated with the transaction 'member'
471  * * ref4 - misc1 value (used for LP)
472  * * ref5 - the "TO" member number
473  * * amount - amount of transaction
474  * * tauth - The "AUTHORIZING" member number (used for core defined joint transfers)
475  * * tmemo - The custom description to send to the core for this transfer
476  * *
477  * * MA: (Member Activation)
478  * * member - Member Number being activated
479  * * type - T
480  * * tran_code - MA
481  * * ref1 - Last 4 digits of SSN
482  * * ref2 - DOB MM/DD/YYYY
483  * * ref3 - Email Address
484  * * ref4 - Custom Field 1 (Number portion of street address)
485  * * ref5 - E-Statement activiation answer {Y/N}
486  * *
487  * * ES: (E-Statement Signup Enroll/Decline)
488  * * member - Member Number associated with E-Statement change
489  * * type - T (always)
490  * * tran_code - ES
491  * * ref3 - email for the member to be updated on the core (if core allows)
492  * * ref5 - {Y/N} - determines enroll or decline
493  * *
494  * * NEWAPP: (Submit a new Loan application to the core)
495  * * member - Member Number associated with E-Statement change
496  * * type - NEWAPP (always)
497  * * ref1 - Loan data to POST to the core
498  * * ref3 - email for the member to be updated on the core (if core allows)
499  * *
500  * * INQAPP: (Inquire status of a previously submitted loan application)
501  * * member - Member Number associated with E-Statement change
502  * * type - INQAPP (always)
503  * * ref1 - Loan App Id that is being queried
504  * * ref3 - email for the member to be updated on the core (if core allows)
505  * *
506  *
507  *
508 
509  *
510  * @return array
511  * [code] - {000 -- Success
512 
513  * 999 -- General error returned}
514  * [error] - ** ONLY code != 000
515  * [data]
516  */
517 function PostTransactionRequest($pHbEnv, $pData, $pSendAsPost=false) {
518  $retVal = array("code" => "000", "data" => array());
519 
520  $packetsize = 0;
521  $origPktStatCode = "";
522  $origPktStatDesc = "";
523  $origPktStatExtra = "";
524 
525  $transTempl = Array(
526  "member" => "NULL",
527  "type" => "NULL",
528  "tran_code" => "NULL",
529  "ref1" => "NULL",
530  "ref2" => "NULL",
531  "ref3" => "NULL",
532  "ref4" => "NULL",
533  "ref5" => "NULL",
534  "amount" => "NA",
535  "tauth" => "NULL",
536  "tmemo" => "NULL"
537  );
538 
539  try {
540 
541  /**
542  * ** GET CREDIT UNION SETTINGS **
543  */
544  $cuConnResp = _ReturnCUSettings($pHbEnv);
545  if ($cuConnResp['code'] != '000') {
546  throw new Exception ("Unable to Load CU Settings");
547  }
548  $cuConnSet = HCU_array_key_value('data', $cuConnResp);
549 
550  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n** Make Transaction Request **\n");
551 
552 
553  if (!is_array($pData)) {
554  throw new Exception ("Invalid data");
555  }
556 
557  /**
558  * Determine the transaction values from the KNOWN transaction options
559  */
560  $setTransValues = array_intersect_key($pData, $transTempl);
561  // ** Now append the values that did were NOT referenced
562  $setTransValues = array_merge($setTransValues, array_diff_key($transTempl, $setTransValues));
563 
564  // ** setTransValues should be all known values to be posted to the core
565  // _ApplPrintLogger($pHbEnv, $cuConnSet, print_r($setTransValues, true));
566 
567  // ** Make the request **
568  // * build the request string
569  $packetQuery = http_build_query($setTransValues);
570 
571  // ** send the request as a GET or POST??
572  if ($pSendAsPost) {
573  $sendPost = $packetQuery;
574  $sendGet = '';
575  } else {
576  $sendGet = $packetQuery;
577  $sendPost = '';
578  }
579 
580 
581  $sendDataResp = _SendDataRequest($pHbEnv, $cuConnSet, $sendGet, $sendPost);
582  $cucorereqAfter = HCU_array_key_value("cucorereq_after", $sendDataResp);
583 
584  // ** ONLY bail out for 999, preserve the transaction posting error
585  // ** this identifies an error in the 'process' of getting the packet
586  if ($sendDataResp['code'] == '999') {
587  // ** Error -- Getting data from core... Does the detailed error matter??
588  // ** Or can I just respond 999 -- Errors here will be communication or incomplete packet
589  throw new Exception ('Data Request Error');
590  }
591  /*
592  * Each transaction request type has potential different response options
593  */
594  $mbrData = Array(
595  "type" => HCU_array_key_value("pkt-type", $pData),
596  "member" => (HCU_array_key_exists("tauth", $pData) ? HCU_array_key_value("tauth", $pData) : HCU_array_key_value("member", $pData))
597  );
598  //_ApplPrintLogger($pHbEnv, $cuConnSet, print_r($mbrData, true));
599  $packetContent = HCU_array_key_value('packet', $sendDataResp);
600  $packetsize = strlen($packetContent);
601  $xmlParse = _ParsePacketData($pHbEnv, $cuConnSet, $mbrData, $packetContent);
602  //_ApplPrintLogger($pHbEnv, $cuConnSet, print_r($xmlParse, true));
603  if ($xmlParse['code'] != '000') {
604  // ** General Error
605  throw new Exception ("General Error");
606  }
607 
608  // ** Check for actual error being returned
609  /**
610  * THE REQUEST WAS SUCCESSFUL -- RETURN THE RESPONSE TO THE CALLER
611  * This function will still return 000 for the code...
612  *
613  if (HCU_array_key_value("pktStatCode", $xmlParse['data']['packet-status']) == '999') {
614  // ** Error Parsing -- throw error
615  throw new Exception (HCU_array_key_value("pktStatDesc", $xmlParse['data']['packet-status']));
616  }
617  *
618  *
619  **/
620 
621  $origPktStatCode = HCU_array_key_value("pktStatCode", $xmlParse['data']['packet-status']);
622  $origPktStatDesc = HCU_array_key_value("pktStatDesc", $xmlParse['data']['packet-status']);
623  $origPktStatExtra = HCU_array_key_value("pktStatExtra", $xmlParse['data']['packet-status']);
624 
625  $retVal['data']['seg1'] = HCU_array_key_value("pktStatMember", $xmlParse['data']['packet-status']);
626  $retVal['data']['code'] = $origPktStatCode;
627  $retVal['data']['desc'] = $origPktStatDesc;
628 
629  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n* Packet Resp Status *\n" . print_r($xmlParse['data']['packet-status'], true) . "\n");
630 
631 
632  } catch (Exception $e) {
633  /// * reset data array - prevent data from being returned
634  $retVal['data'] = Array();
635  $retVal['code'] = '999';
636  $retVal['error'] = ($e->getMessage() != '' ? $e->getMessage() : "General Error");
637  $cucorereqAfter["errors"][] = $e->getMessage();
638  }
639  _UpdateRequestStatus($pHbEnv, $cuConnSet, $cucorereqAfter, $packetsize, $origPktStatCode, $origPktStatDesc, $origPktStatExtra);
640  return $retVal;
641 }
642 
643 
644 /**
645  * This function is used to return a member info packet (MIR) and the
646  * sub accounts associated with the account number (member) requested
647  *
648  * @param array $pHbEnv -- The current HB_ENV array
649  * @param array $pMbrData -- Array of data for retrieving a packet
650  * member - member number for request
651  * email - Send email if supplied
652  *
653  * @return array
654  * [code] - {000 -- Success
655  * 001 -- Invalid Account number
656  * 999 -- General error returned}
657  * [error] - ** ONLY code != 000
658  * [data]
659  * [mir]
660  * [accounts]
661  * [deposit]
662  * [loan]
663  */
664 function FindMemberAccounts($pHbEnv, $pMbrData) {
665  $retVal = array("code" => "000", "data" => array());
666 
667  /**
668  * array of Sub Accounts
669  */
670  $subAcctListAry = Array("deposit" => Array(), "loan" => Array());
671  $balTemplates = GetBalanceTemplates();
672 
673  try {
674 
675 
676  /**
677  * ** GET CREDIT UNION SETTINGS **
678  */
679  $cuConnResp = _ReturnCUSettings($pHbEnv);
680  if ($cuConnResp['code'] != '000') {
681  throw new Exception ("Unable to Load CU Settings");
682  }
683  $cuConnSet = HCU_array_key_value('data', $cuConnResp);
684 
685  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n** Find Member Accounts **\n");
686 
687  if (($pHbEnv["flagset3"] & GetFlagsetValue("CU3_MIR_PACKET_NOT_SUPPORTED")) === 0) {
688  /*
689  * MIR PACKET REQUEST
690  */
691  // $mirMbrData = array_combine($pMbrData, array("type" => PACKET_REQUEST_MIR));
692  $mirResp = _RetrieveMemberInfo($pHbEnv, $cuConnSet, HCU_array_key_value('member', $pMbrData));
693 
694  if ($mirResp['code'] != '000') {
695  if ($mirResp['code'] == '001') {
696  throw new Exception ($mirResp['error'], 50101);
697  }
698  throw new Exception ("Unable to retrieve MIR Packet - " . $mirResp['error']);
699  }
700  // ** CONTINUE
701  // ** Add Mir Data to data to be returned
702  $retVal['data']['mir'] = $mirResp['data'];
703  }
704 
705  /*
706  * MEMBER SUB ACCOUNT REQUEST
707  */
708  /**
709  * mbrEmail -- I don't want to risk the core email being overwritten by passing an email here --
710  */
711  // $mbrEmail = (in_array(HCU_array_key_value('email', $pMbrData), array('', 'no@email.com')) ? "NULL" : HCU_array_key_value('email', $pMbrData));
712  $mbrEmail = 'NULL';
713  /**
714  * Last Login
715  */
716  $mbrLastLogin = 'NULL';
717 
718  /**
719  * ** GET CUTOFF DATE **
720  * ** USE TOMORROW AS THE CUTOFF -- THIS WILL LIMIT HISTORY THAT IS RETURNED
721  */
722  $packetCutoff = date('Ymd', time() + 86400);
723 
724  $lastPktStamp = 'NULL';
725  /**
726  * ** Build Data Request
727  */
728  $dataArray = Array(
729  "member" => HCU_array_key_value('member', $pMbrData),
730  "if_mod_since" => $lastPktStamp,
731  "ref3" => $mbrEmail,
732  "cutoff" => $packetCutoff
733  );
734 
735  /*
736  * Inquiry Packet Request
737  */
738  $acctResp = _RetrieveMemberInquiry($pHbEnv, $cuConnSet, $dataArray);
739 
740  if ($acctResp['code'] != '000') {
741  if (in_array($acctResp['code'], array('001', '002', '003'))) {
742  throw new Exception ($acctResp['error'], 50102);
743  }
744  throw new Exception ("Unable to retrieve list of accounts - " . $acctResp['error']);
745  }
746 
747  /**
748  * Loop through the returned accounts and format into the desired structure
749  */
750  foreach ($balTemplates as $tmplKey => $tmplValue) {
751  // ** Loop through each type of expected table and modify to only return the expected columns
752  if (HCU_array_key_exists($tmplValue['inquiry-key'], $acctResp['data']['packet-data'])) {
753  // ** Their IS data for this type -- Loop through array and get the information we want
754  $inqAcctList = $acctResp['data']['packet-data'][$tmplValue['inquiry-key']];
755  if (is_array($inqAcctList)) {
756  foreach ($inqAcctList as $listIdx => $listArray) {
757  $subAcctListAry[$tmplKey][] = array_intersect_key($listArray, array_flip($tmplValue['field-list']));
758  }
759  }
760 
761  }
762 
763  }
764 
765  /*
766  * Cross Account Transfer List
767  */
768 
769  if (($pHbEnv['flagset3'] & GetFlagsetValue('CU3_API_XAC'))) {
770  // * Retrieve Packet
771  $dataArray = Array(
772  "member" => HCU_array_key_value('member', $pMbrData),
773  "type" => 'X',
774  "ref3" => $mbrEmail
775  );
776 
777  /*
778  * Inquiry Packet Request
779  */
780  $acctResp = _RetrieveMemberCrossAccount($pHbEnv, $cuConnSet, $dataArray);
781  // * Parse Packet
782  if ($acctResp['code'] != '000') {
783  if (in_array($acctResp['code'], array('001', '002', '003'))) {
784  throw new Exception ($acctResp['error'], 50102);
785  }
786  throw new Exception ("Unable to retrieve list of accounts - " . $acctResp['error']);
787  }
788 
789 
790  $crossAcctFieldList = Array(
791  "accountnumber",
792  "tomember",
793  "accounttype",
794  "deposittype",
795  "description",
796  "may_deposit",
797  "may_withdraw"
798  );
799 
800  // ** Loop through the crossaccounts list
801  if (HCU_array_key_exists("crossaccounts", $acctResp['data']['packet-data'])) {
802  // ** Their IS data for this type -- Loop through array and get the information we want
803  $inqAcctList = $acctResp['data']['packet-data']['crossaccounts'];
804  if (is_array($inqAcctList)) {
805  foreach ($inqAcctList as $listIdx => $listArray) {
806  $subAcctListAry['xa'][] = array_intersect_key($listArray, array_flip($crossAcctFieldList));
807  }
808  }
809 
810  }
811 
812 
813  }
814 
815 
816  $retVal['data']['accounts'] = $subAcctListAry;
817 
818  } catch (Exception $e) {
819  /// * reset data array - prevent data from being returned
820  $retVal['data'] = Array();
821  switch ($e->getCode()) {
822  case 50101:
823  case 50102:
824  $retVal['code'] = '001';
825  // ** always return 'Invalid Account Number' with 001
826  $retVal['error'] = "Invalid Account Number";
827  break;
828  default:
829  $retVal['code'] = '999';
830  $retVal['error'] = "Unable to retrieve data";
831  }
832  }
833  return $retVal;
834 }
835 
836 /**
837  * Verify a member PIN with the core for a member number.
838  * This process will make an INQ request to the core but includes the PIN
839  * for validation.
840  * On error this will return the status code from the core to identify the
841  * failed reason.
842  * On success this will return the list of accounts this user has access to
843  * so they can be added to their useraccounts list.
844  *
845  * This is used for authenticating a member for the first time.
846  * For normal balance / history queries we do NOT request data with the PIN
847  *
848  * @param array $pHbEnv -- The current HB_ENV array
849  * [dbh] - database handle
850  *
851  * @param array $pMbrData -- Array of data for retrieving a packet
852  * member - member number for request
853  * pin - pin code to verify on the core
854  * email - (optional) future use
855  *
856  * @return array
857  * [code] - {000 -- Success
858  * 001 -- Invalid Account number
859  * 002 -- Invalid PIN
860  * 003 -- Closed Account
861  * 004 -- Member already in system?
862  * 999 -- General error returned}
863  * [error] - ** ONLY code != 000
864  * [data]
865  * [accounts]
866  * [deposit]
867  * [loan]
868  * [xa]
869  *
870  */
871 function VerifyMemberPin($pHbEnv, $pMbrData) {
872  $retVal = array("code" => "000", "data" => array());
873 
874  $subAcctListAry = Array("deposit" => Array(), "loan" => Array());
875  $balTemplates = GetBalanceTemplates();
876 
877  try {
878 
879  /**
880  * ** GET CREDIT UNION SETTINGS **
881  */
882  $cuConnResp = _ReturnCUSettings($pHbEnv);
883  if ($cuConnResp['code'] != '000') {
884  throw new Exception ("Unable to Load CU Settings");
885  }
886  $cuConnSet = HCU_array_key_value('data', $cuConnResp);
887 
888  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n** Verify Member PIN **\n");
889 
890 
891  /*
892  * MEMBER SUB ACCOUNT REQUEST WITH PIN
893  */
894  /**
895  * mbrEmail -- do NOT pass the email to the core when verifying the email.. This could possibly have the side effect of modifying the member email unintentionally
896  *
897  */
898  $mbrEmail = "NULL";
899  // $mbrEmail = (in_array(HCU_array_key_value('email', $pMbrData), array('', 'no@email.com')) ? "NULL" : HCU_array_key_value('email', $pMbrData));
900 
901  /**
902  * Last Login
903  */
904  $mbrLastLogin = 'NULL';
905 
906  /**
907  * ** GET CUTOFF DATE **
908  * ** USE TOMORROW AS THE CUTOFF -- THIS WILL LIMIT HISTORY THAT IS RETURNED
909  */
910  $packetCutoff = date('Ymd', time() + 86400);
911 
912  $lastPktStamp = '1';
913  /**
914  * ** Build Data Request
915  */
916  $dataArray = Array(
917  "member" => HCU_array_key_value('member', $pMbrData),
918  "if_mod_since" => $lastPktStamp,
919  "ref3" => $mbrEmail,
920  "cutoff" => $packetCutoff,
921  "pass" => HCU_array_key_value('pin', $pMbrData)
922  );
923 
924  /*
925  * Inquiry Packet Request
926  */
927  $acctResp = _RetrieveMemberInquiry($pHbEnv, $cuConnSet, $dataArray);
928 
929  if ($acctResp['code'] != '000') {
930  /**
931  * Member Inquiry failed -- need to return the message to the calling function
932  */
933  if (in_array($acctResp['code'], array('001', '002', '003'))) {
934  throw new Exception ($acctResp['code'], 50102);
935  }
936  throw new Exception ("Unable to retrieve list of accounts - " . $acctResp['error']);
937  }
938 
939  /**
940  * Loop through the returned accounts and format into the desired structure
941  */
942  foreach ($balTemplates as $tmplKey => $tmplValue) {
943  // ** Loop through each type of expected table and modify to only return the expected columns
944  if (HCU_array_key_exists($tmplValue['inquiry-key'], $acctResp['data']['packet-data'])) {
945  // ** Their IS data for this type -- Loop through array and get the information we want
946  $inqAcctList = $acctResp['data']['packet-data'][$tmplValue['inquiry-key']];
947  if (is_array($inqAcctList)) {
948  foreach ($inqAcctList as $listIdx => $listArray) {
949  $subAcctListAry[$tmplKey][] = array_intersect_key($listArray, array_flip($tmplValue['field-list']));
950  }
951  }
952 
953  }
954 
955  }
956 
957 
958  /*
959  * Cross Account Transfer List
960  */
961 
962  if (($pHbEnv['flagset3'] & GetFlagsetValue('CU3_API_XAC'))) {
963  // * Retrieve Packet
964  $dataArray = Array(
965  "member" => HCU_array_key_value('member', $pMbrData),
966  "type" => 'X',
967  "ref3" => $mbrEmail
968  );
969 
970  /*
971  * Inquiry Packet Request
972  */
973  $acctResp = _RetrieveMemberCrossAccount($pHbEnv, $cuConnSet, $dataArray);
974  // * Parse Packet
975  if ($acctResp['code'] != '000') {
976  if (in_array($acctResp['code'], array('001', '002', '003'))) {
977  throw new Exception ($acctResp['error'], 50102);
978  }
979  throw new Exception ("Unable to retrieve list of accounts - " . $acctResp['error']);
980  }
981 
982 
983  $crossAcctFieldList = Array(
984  "accountnumber",
985  "tomember",
986  "accounttype",
987  "deposittype",
988  "description",
989  "may_deposit",
990  "may_withdraw"
991  );
992 
993  // ** Loop through the crossaccounts list
994  if (HCU_array_key_exists("crossaccounts", $acctResp['data']['packet-data'])) {
995  // ** Their IS data for this type -- Loop through array and get the information we want
996  $inqAcctList = $acctResp['data']['packet-data']['crossaccounts'];
997  if (is_array($inqAcctList)) {
998  foreach ($inqAcctList as $listIdx => $listArray) {
999  $subAcctListAry['xa'][] = array_intersect_key($listArray, array_flip($crossAcctFieldList));
1000  }
1001  }
1002 
1003  }
1004 
1005 
1006  }
1007 
1008 
1009  $retVal['data']['accounts'] = $subAcctListAry;
1010 
1011 
1012 
1013  } catch (Exception $e) {
1014 
1015  switch ($e->getCode()) {
1016  case 50101:
1017  case 50102:
1018  $retVal['code'] = $e->getMessage();
1019  switch ($e->getMessage()) {
1020  case '001':
1021  $retVal['error'] = "Invalid Account Number";
1022  break;
1023  case '002':
1024  $retVal['error'] = "Invalid Password";
1025  break;
1026  case '003':
1027  $retVal['error'] = "Closed Account";
1028  break;
1029  }
1030  break;
1031  default:
1032  $retVal['code'] = '999';
1033  $retVal['error'] = "Unable to retrieve data";
1034  }
1035 
1036 
1037  }
1038 
1039  return $retVal;
1040 }
1041 
1042 /**
1043  * This function is used by the background process to look at data
1044  * for scheduled transactions and alerts. Obtain the balances and
1045  * data back to the given cutoff date. Put the resultant information into
1046  * the cutronXX so it doesn't affect regular banking information.
1047  *
1048  * TRON means "Temporary Resource Over Network".
1049  *
1050  * This function ignores cutoff times and last login and gaps in the history
1051  * because it isreally testing for background processing.
1052  *
1053  * This function is still member account-based.
1054  *
1055  * Tables affected:
1056  * cu_alertab (account balances), cu_alertah (account history),
1057  * cu_alertlb (loan balances), cu_alertlh (loan history),
1058  *
1059  *
1060  * @param array $pEnv -- The current Environment array (not complete)
1061  * @param array $pMbrData -- Array of data for retrieving a packet
1062  * account - member account number for request
1063  * cutoff - date to which history is desired (could be future date if just want balances)
1064  * packetstamp - timestamp for packets???
1065  * email - email for member account (can be "NULL" )
1066  *
1067  * @return array
1068  * [code]
1069  * {000, 900, 999}
1070  * 000 - Success - This can be set if the response from the core was successful and was not one of the known error codes.
1071  * 900 - NO ACTION - This can be returned for "too soon to ask again"
1072  * 999 - Failure - This happens when the routine fails for any reason. From communication to core error.
1073  * [error]
1074  * [data]
1075  * 'requestDate' => packet stamp formatted to 'D M j Y H:i:s T'
1076  * 'requestDesc' => Message from Core
1077  */
1078 function FetchMemberDataTRON( $pHbEnv, $pMbrData ) {
1079  $packetStatus = -1;
1080 
1081  $mbrReqType = PACKET_REQUEST_INQUIRY;
1082  try {
1083  /*
1084  * Get CU Connection Settings
1085  */
1086  $cuConnResp = _ReturnCUSettings( $pHbEnv );
1087  if ( $cuConnResp['code'] != '000' ) {
1088  throw new Exception ("Unable to Load CU Settings");
1089  }
1090  $cuConnSet = HCU_array_key_value( 'data', $cuConnResp );
1091 
1092  $Cu = $pHbEnv["Cu"];
1093 
1094  _ApplPrintLogger( $pHbEnv, $cuConnSet, "\n** Load User Data **\n" );
1095 
1096  $reqMemberAcctNbr = HCU_array_key_value( 'account', $pMbrData );
1097 
1098  // cutoff date
1099  $paramStamp = HCU_array_key_value( 'packetstamp', $pMbrData );
1100  $dataStamp = (($paramStamp == '') ? date( "Ymd" ) : trim($paramStamp));
1101 
1102  // cutoff date
1103  $paramCutoff = HCU_array_key_value( 'cutoff', $pMbrData );
1104  $dataCutoff = (($paramCutoff == '') ? date( "Ymd" ) : trim($paramCutoff));
1105 
1106  // email
1107  // ** NOTE: Using the email from the user isn't always the right answer as the user might not be the member.
1108  $paramEmail = HCU_array_key_value( 'email', $pMbrData );
1109  $dataEmail = (($paramEmail == '') ? "NULL" : trim($paramEmail));
1110 
1111  /**
1112  * ** START THE PROCESS OF REQUESTING DATA FROM THE CORE
1113  */
1114  $dataArray = Array(
1115  "member" => $reqMemberAcctNbr,
1116  "type" => 'I',
1117  "if_mod_since" => $dataStamp,
1118  "ref3" => $dataEmail,
1119  "cutoff" => $dataCutoff
1120  );
1121  _ApplPrintLogger($pHbEnv, $cuConnSet, print_r($dataArray, true));
1122  /*
1123  * Inquiry Packet Request
1124  */
1125  $acctResp = _RetrieveMemberInquiry( $pHbEnv, $cuConnSet, $dataArray );
1126 
1127  // get the packet status from the core
1128  $packetStatus = HCU_array_key_value("packet-status", $acctResp['data']);
1129  $statusCode = HCU_array_key_value('pktStatCode', $packetStatus);
1130 
1131  if ($acctResp['code'] != '000') {
1132  if (in_array($acctResp['code'], array('001', '002', '003'))) {
1133  throw new Exception ( $acctResp['error'], $acctResp['code'] );
1134  }
1135  throw new Exception ("Unable to retrieve list of accounts - " . $acctResp['error']);
1136  }
1137 
1138  // get the packet data
1139  $xmlPacket = $acctResp['data']['packet-xml'];
1140 
1141  // Validate DataPacket is valid xml
1142  if ( !is_a($xmlPacket, "SimpleXMLElement") ) {
1143  // *NOT VALID XML OBJECT
1144  throw new Exception ("Data Packet Error");
1145  }
1146 
1147  /* FINISHED */
1148  $retVal = array('code' => '000', "status" => $statusCode, 'data' => array('requestData' => $xmlPacket, 'requestDesc' => 'Success'));
1149  } catch (Exception $e) {
1150  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n Load User Data -- Catch Error :: ({$e->getCode()}) {$e->getMessage()}");
1151  // return the error code we are given as a three character string or a default error code
1152  $errorCodeTest = $e->getCode();
1153  $errorMessage = $e->getMessage();
1154 
1155  if ( $errorCodeTest > 0 ) {
1156  $errorCode = ( strlen( $errorCodeTest ) > 3 ) ? $errorCodeTest : substr( "000" . $errorCodeTest, -3 );
1157  } else {
1158  $errorCode = "999";
1159  }
1160 
1161  $retVal = array( 'code' => $errorCode, "status" => $statusCode, 'data' => array( 'requestData' => "", 'requestDesc' => $errorMessage ) );
1162  }
1163 
1164  return $retVal;
1165 } // FetchMemberDataTRON
1166 
1167 /**
1168  * Load the plugin that will be used for this connection
1169  * For the Standard HomeCU API load sAPIAppl.std.i
1170  * For the new PLUS API load sAPIAppl.plus.i
1171  *
1172  * @param array $pHbEnv -- The current HB_ENV array
1173  *
1174  * @return NULL
1175  */
1176 function IncludeApplPlugin($pHbEnv) {
1177 
1178  /**
1179  * ** LOAD PLUGIN **
1180  */
1181 
1182  if (true) {
1183  /** STANDARD API **/
1184  require_once (dirname(__FILE__) . '/../../shared/library/sAPIAppl.std.i');
1185  } else {
1186  /** HOMECU API PLUS **/
1187  require_once (dirname(__FILE__) . '/../../shared/library/sAPIAppl.plus.i');
1188  }
1189 
1190 }
1191 /**
1192  * *** **
1193  * *** ** PRIVATE FUNCTIONS **
1194  * *** **
1195  */
1196 
1197 /**
1198  * Process the XML Packet
1199  *
1200  * This will take the packet received and parse into the different pieces.
1201  * This function does NOT care about what the data means. It's only job is to
1202  * ensure the data is a well formed xml and can be parsed.
1203  * Returns an error if a problem arises from decoding the data
1204  *
1205  * @param string $pDataPacket -- the data packet to parse
1206  *
1207  * @return array
1208  * This should return the parsed data
1209  * code - {000, 999}
1210  * data - N/A
1211  * homecu-packet - simple xml object of the data returned
1212  *
1213  */
1214 function _ProcessAPIResponse($pDataPacket) {
1215 
1216  $retVal = array("code"=>"000", "data"=>Array());
1217  $isXmlParseError = False;
1218  try {
1219 
1220  if ($pDataPacket != '') {
1221 
1222  // ** This will SUPPRESS libxml errors from being sent to STDERR
1223  // ** instead the errors will be added to the libxml_get_errors function
1224  libxml_use_internal_errors(true);
1225 
1226  // ** Let's try and parse
1227  $xml = simplexml_load_string($pDataPacket);
1228 
1229 
1230  if ($xml === false) {
1231  $libXmlErrors = libxml_get_errors();
1232  list($libXmlErrors,
1233  $isXmlParseError) = modifyXmlErrorsForLogging($libXmlErrors, $pDataPacket);
1234 
1235  $xmlErrors = HCU_JsonEncode($libXmlErrors);
1236  throw new Exception ($xmlErrors, -712);
1237  }
1238 
1239  $retVal['homecu-packet'] = $xml;
1240  } else {
1241  // ** EMPTY -- WRONG
1242  throw new Exception('Empty Data Packet', -710);
1243  }
1244 
1245  } catch (Exception $e ) {
1246  /*
1247  * SHOULD I RECORD THE ERROR
1248  */
1249  $retVal['code'] = '999';
1250  $retVal['error'] = "Unable to retrieve data " . $e->getMessage();
1251  }
1252 
1253  return array($retVal, $isXmlParseError);
1254 }
1255 
1256 /**
1257  * Parse a homecu xml packet from the core. This function will ensure the packet is well formed
1258  * and perform additional test.
1259  * It will return an array with the xml object and status
1260  *
1261  * @param array $pHbEnv - The current HB_ENV environment settings
1262  * @param array $pConnSet - The current connection settings
1263  * [debugMode] - Is debug mode enabled
1264  * @param array $pMbrData - The member information for the request
1265  * [type] - one of the PACKET_REQUEST_{CONSTANTS}
1266  * [member] - member number for request
1267  * @param string $pPktData - The packet data that was returned from the core
1268  *
1269  * @return array
1270  * [code]
1271  * {000, 999}
1272  * [data]
1273  * [packet-status]
1274  * [packet-xml]
1275  */
1276 function _ParsePacketData($pHbEnv, $pConnSet, $pMbrData, $pPktData) {
1277  $retVal = array("code" => "000", "data" => array());
1278 
1279  try {
1280 
1281  /*
1282  * Process API Response
1283  */
1284  list($xmlParse, $isXmlParseError) = _ProcessAPIResponse($pPktData);
1285  if ($xmlParse['code'] != '000') {
1286  if ($isXmlParseError) {
1287  _ApplPrintLogger($pHbEnv,
1288  $pConnSet,
1289  "_ParsePacketData Error (" . __FILE__ . ":" . __LINE__ . ") :: ". $xmlParse["error"],
1290  True);
1291  }
1292  // ** Error Parsing -- throw error
1293  throw new Exception ("XML Parse " . $xmlParse['error'], 50010);
1294  }
1295 
1296  /**
1297  * **** Set the XML Packet ****
1298  */
1299  $xmlPacket = $xmlParse['homecu-packet'];
1300  /*
1301  * Get Packet Status
1302  */
1303  $statResp = _GetPacketStatus(HCU_array_key_value('type', $pMbrData), $xmlPacket);
1304  if ($statResp['code'] != '000') {
1305  throw new Exception ("Unknown Status Returned", 50020);
1306  }
1307  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Packet Resp Status *\n" . print_r($statResp, true) . "\n");
1308 
1309  /*
1310  * Check Sync Member
1311  */
1312  if (_CheckSyncMember(HCU_array_key_value("type", $pMbrData), HCU_array_key_value('pktStatCode', $statResp['data']))) {
1313  // Explode MIR - RETURN DATA
1314  // ** Location is different based on the Packet type
1315  // * Default the value to the pktMember value returned from _GetPacketStatus
1316  // * BUT if that did not return a value for pktMember, then fallback to the original method
1317  // for finding the node
1318  if (HCU_array_key_exists("pktMember", $statResp['data'])) {
1319  $syncMember = HCU_array_key_value("pktMember", $statResp['data']);
1320  } else {
1321  $syncMember = trim($xmlPacket->{_GetRequestNodeName(HCU_array_key_value("type", $pMbrData))}->Member);
1322  }
1323 
1324  // ** Use the Member value from <Member if it was set.. Otherwise use the value in the <status
1325  if ($syncMember != $pMbrData['member']) {
1326  _ApplPrintLogger($pHbEnv, $pConnSet, "\n ** out of sync * requested ({$pMbrData['member']}) received ($syncMember)");
1327 
1328  // ** OUT OF SYNC
1329  throw new Exception ('Data Request Out of Sync', 50030);
1330  }
1331  }
1332  /**
1333  * **** SUCCESS ****
1334  */
1335  $retVal['data']['packet-status'] = $statResp['data'];
1336  $retVal['data']['packet-xml'] = $xmlPacket;
1337 
1338 
1339  } catch (Exception $e) {
1340  $retVal['code'] = '999';
1341  switch ($e->getCode()) {
1342  case 50010:
1343  case 50020:
1344  case 50030:
1345  $retVal['error'] = $e->getMessage();
1346  break;
1347  default:
1348  $retVal['error'] = "Unable to retrieve data";
1349  }
1350  }
1351 
1352  return $retVal;
1353 }
1354 /**
1355  * Get the status from the XML Packet
1356  * The problem is the status can be organized in different sections depending on the type of request.
1357  *
1358  * @param const $pReqType - This is one of the PACKET_REQUEST contants
1359  * @param object $pXMLPacket - This is the XML Object
1360  *
1361  * @return array
1362  * [code] = {000, 999}
1363  * [data]
1364  * [pktStatMember] -- Member number from the status section
1365  * [pktStatCode] -- The status code that was returned from the request
1366  * [pktStatDesc] -- The associated Status description
1367  * [pktStatExtra] -- Any Extra meta data on end of the response
1368  * [pktMember] -- Member Number from the <Member> section
1369  * [pktTime] -- Packet Time Returned by the request
1370  * [pktDate] -- Packet Date (formatted date of packet time)
1371  *
1372  */
1373 function _GetPacketStatus($pReqType, $pXMLPacket) {
1374  $retVal = Array('code' => '000', 'data' => array());
1375  $xpathLoc = '';
1376 
1377  $statKeyAry = Array('pktStatMember', 'pktStatCode', 'pktStatDesc', 'pktStatExtra');
1378  try {
1379 
1380 
1381  if (!($pXMLPacket instanceof SimpleXMLElement)) {
1382  // ** Not a simple xml object
1383  throw new Exception ('XML Packet Not an xml object');
1384  }
1385  /*
1386  * SWITCH statement to specify the xpath query for finding the status
1387  * The status may not always be in the same location for all types
1388  * // allows for a wildcard search
1389  */
1390  switch ($pReqType) {
1391  case PACKET_REQUEST_INQUIRY:
1392  case PACKET_REQUEST_VERIFY_PIN:
1393  case PACKET_REQUEST_TRN:
1394  case PACKET_REQUEST_MIR:
1395  case PACKET_REQUEST_MA:
1396  case PACKET_REQUEST_XAC:
1397  case PACKET_REQUEST_ES:
1398  case PACKET_REQUEST_ES_TOC:
1399  $xpathLoc = '//status';
1400  break;
1401  case PACKET_REQUEST_NEWAPP:
1402  case PACKET_REQUEST_INQAPP:
1403  $xpathLoc = '//Status';
1404  break;
1405  default:
1406  throw new Exception ('Packet Response Type Not Found');
1407  }
1408 
1409  $nodeSearch = $pXMLPacket->xpath($xpathLoc);
1410  if (count($nodeSearch)) {
1411  // At least one value found -- use the first
1412  // Use trim to remove the beginning/end new line
1413  $statValAry = explode ("\t", trim($nodeSearch[0][0], "\n"));
1414 
1415  // * If there aren't enough items returned, then add empty strings for each that is missing
1416  if (count($statValAry) < count($statKeyAry)) {
1417  $newItemCount = (count($statKeyAry) - count($statValAry));
1418  for ($idx = 0; $idx < $newItemCount; $idx++) {
1419  $statValAry[] = '';
1420  }
1421  }
1422  $retVal['data'] = array_combine($statKeyAry, $statValAry);
1423  }
1424 
1425  // ** MEMBER SECTION
1426  $xpathLoc = '//Member';
1427 
1428  $nodeSearch = $pXMLPacket->xpath($xpathLoc);
1429  if (count($nodeSearch) > 0) {
1430 
1431  // ** The Member tag section may include the PIN in the returned response
1432  // In this instance the Member number will not match correctly. Remove PIN
1433  $tmpMember = trim($nodeSearch[0][0]);
1434 
1435  if (strpos($tmpMember, "\t")) {
1436  // * Split on Tab and take first section
1437  $tmpMember = trim(substr($tmpMember, 0, strpos($tmpMember, "\t")));
1438  }
1439 
1440  // * Some information was found --- Add to the response
1441  $retVal['data']['pktMember'] = $tmpMember;
1442  }
1443 
1444  // ** TIME SECTION ** USE STANDARD XML Packet Lookup
1445  $xpathLoc = '//time';
1446  if ($pXMLPacket->time) {
1447  $timeNode = trim($pXMLPacket->time->__toString());
1448  if ($timeNode != '') {
1449  // ** Time Node was found -- Save the values to retVal
1450  list ($retVal['data']['pktTime'], $retVal['data']['pktDate']) = explode ("\t", $timeNode);
1451  }
1452  }
1453 
1454 
1455  } catch (Exception $e) {
1456  $retVal['code'] = '999';
1457  $retVal['error'] = 'Packet Status Not Found';
1458  }
1459 
1460  return $retVal;
1461 }
1462 
1463 /**
1464  *
1465  * Inserts (before_request) OR Updates (after_request) the cucorerequests
1466  * record associated with respect to $cucoreRequestRec["id"] value.
1467  *
1468  * @param array $pHbEnv -- The current HB_ENV array. Used mostly for the
1469  * logger if need be.
1470  * @param array $pConnSet -- This is the Connection information
1471  * from _ReturnCUSettings
1472  * @param str $when -- before_request or after_request
1473  * @param array $cucoreRequestRec -- Associative array of cucorequests
1474  * record values
1475  *
1476  */
1477 function _PopulateCUCoreRequestsTable($pHbEnv, $pConnSet, $when, $cucoreRequestRec) {
1478  try {
1479  if (array_key_exists('id', $cucoreRequestRec)) {
1480  if($cucoreRequestRec["id"] == NULL) {
1481  throw new Exception("cucorerequests.id value not set -- possibly preceding next_val('cucorerequests_id_seq') call failed!.");
1482  } else {
1483  $dbh = HCU_array_key_value('dbh', $pHbEnv);
1484  $lMc = HCU_array_key_value('MC', $pHbEnv);
1485  $pTableName = "cucorerequests";
1486 
1487  if ($when == "before_request") {
1488  $cucoreRequestRec["appliance_ip"] = array_key_exists('appliance_ip', $cucoreRequestRec) ? $cucoreRequestRec["appliance_ip"] : "NULL";
1489  $cucoreRequestRec["request_url"] = array_key_exists('request_url', $cucoreRequestRec) ? $cucoreRequestRec["request_url"] : "NULL";
1490  $cucoreRequestRec["request_type"] = array_key_exists('request_type', $cucoreRequestRec) ? $cucoreRequestRec["request_type"] : "NULL";
1491  $cucoreRequestRec["remote_ip"] = array_key_exists('remote_ip', $cucoreRequestRec) ? $cucoreRequestRec["remote_ip"] : "NULL";
1492  $cucoreRequestRec["cu"] = array_key_exists('cu', $cucoreRequestRec) ? $cucoreRequestRec["cu"] : "NULL";
1493  $cucoreRequestRec["accountnumber"] = array_key_exists('accountnumber', $cucoreRequestRec) ? $cucoreRequestRec["accountnumber"] : "NULL";
1494  $cucoreRequestRec["request_start"] = DBTIMESTAMP_USETS;
1495 
1496  # Insert record to cucorerequests table
1497  $cucoreRequestRec['_action'] = "insert";
1498  $insTableResp = SetDataTableUpdate($dbh, $pHbEnv, $lMc, $pTableName, $cucoreRequestRec, false);
1499 
1500  if ($insTableResp['code'] != '000') {
1501  throw new exception ('Data Insert Error', '901');
1502  }
1503  }
1504  # $when = after_request
1505  else {
1506  $updateArr = Array();
1507  $updateArr["request_status"] = $cucoreRequestRec["request_status"];
1508  $updateArr["id"] = $cucoreRequestRec["id"];
1509  $updateArr["request_end"] = DBTIMESTAMP_USETS;
1510  # custom expression
1511  $updateArr["request_elapsed"] = "EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - request_start))::int";
1512 
1513  # Update record to cucorerequests table for a specific id with
1514  # additional information after the completion of request
1515  # to the appliance
1516  $updateArr['_action'] = "update";
1517  $updTableResp = SetDataTableUpdate($dbh, $pHbEnv, $lMc, $pTableName, $updateArr, false);
1518 
1519  if ($updTableResp['code'] != '000') {
1520  throw new exception ('Data Update Error', '902');
1521  }
1522 
1523  }
1524  }
1525  }
1526  }
1527  catch (Exception $e) {
1528  _ApplPrintLogger($pHbEnv, $pConnSet, "\n Error :: {$e->getMessage()} ({$e->getCode()})");
1529  }
1530 }
1531 
1532 
1533 /**
1534  * Utility function where extra logic can be implemented to return a flag
1535  * that will enable/disable inserting entries in the cucorerequests table
1536  *
1537  * @param str $activeCu -- CU code of active CU
1538  *
1539  * @return boolean $skip
1540  * $skip --
1541  * true: skip db operation,
1542  * false: ok, populate request information to database
1543  *
1544  */
1545 function _SkipCucorerequestsEntry($activeCu) {
1546  $skip = False;
1547 
1548  // Add a logic here to set $skip True or False
1549  // Example:
1550  // if (strtolower(trim($activeCu)) != "unofcu" && strtolower(trim($activeCu)) != "brown" ) {
1551  // $skip = True;
1552  // }
1553  return $skip;
1554 }
1555 
1556 
1557 /**
1558  *
1559  * Inserts (before_request) OR Updates (after_request) the cucorerequests
1560  * record associated with respect to $cucoreRequestRec["id"] value.
1561  *
1562  * @param array $pHbEnv -- The current HB_ENV array. Used mostly for the
1563  * logger if need be.
1564  * @param array $pConnSet -- This is the Connection information
1565  * from _ReturnCUSettings
1566  * @param array $cucorereqAfter -- includes:
1567  * - record - cucorerequests record values
1568  * - curl_http - includes curl errno and http response code
1569  * - errors - any preceding error(s) being catched in
1570  * try/catch blocks
1571  * @param int $packetsize -- size (strlen) of the packet response from
1572  * curl request
1573  * @param str $origStatCode -- status code
1574  * @param str $origStatDesc -- status description
1575  * @param str $origStatExtra -- status extra value
1576  *
1577  *
1578  */
1579 function _UpdateRequestStatus($pHbEnv, $pConnSet, $cucorereqAfter, $packetsize, $origStatCode, $origStatDesc, $origStatExtra) {
1580 
1581  $activeCu = HCU_array_key_value("cu", $pHbEnv);
1582  if (!_SkipCucorerequestsEntry($activeCu)) {
1583 
1584  $recordAssoc = $cucorereqAfter["record"];
1585  $curlHttpMsgs = $cucorereqAfter["curl_http"];
1586  $errorMsgs = $cucorereqAfter["errors"];
1587 
1588  $requestStatus = Array();
1589 
1590  # populate status code and description returned by appliance
1591  $status = Array();
1592  $status["packetsize"] = $packetsize;
1593  if (is_null($origStatCode)) {$origStatCode = "";}
1594  if (is_null($origStatDesc)) {$origStatDesc = "";}
1595  if (is_null($origStatExtra)) {$origStatExtra = "";}
1596  $status["code"] = $origStatCode;
1597  $status["desc"] = $origStatDesc;
1598  $status["extra"] = $origStatExtra;
1599  # add curl_errno and http_code to status array
1600  $status["curl_errno"] = HCU_array_key_value("curl_errno", $curlHttpMsgs);
1601  $status["http_code"] = HCU_array_key_value("http_code", $curlHttpMsgs);
1602  $status["attempted_core_conns"] = $cucorereqAfter["attempted_core_conns"];
1603 
1604  $requestStatus["status"] = $status;
1605 
1606  # populate error messages
1607  $error = Array();
1608  $error["messages"] = join(" -> ", $errorMsgs);
1609  $requestStatus["error"] = $error;
1610 
1611  # populate note: db_error
1612  $note = Array();
1613  $note["dberror"] = db_last_error();
1614  if (is_null($note["dberror"])) {$note["dberror"] = "";}
1615  $requestStatus["note"] = $note;
1616 
1617  # prepare a final json object to be stored in `cucorerequests.request_status`
1618  $recordAssoc["request_status"] = json_encode($requestStatus);
1619  _PopulateCUCoreRequestsTable($pHbEnv, $pConnSet, "after_request", $recordAssoc);
1620 
1621  }
1622 }
1623 
1624 /**
1625  *
1626  * Retrieves $_SERVER['REMOTE_ADDR'], if exists
1627  *
1628  * @return $remoteAddr: $_SERVER['REMOTE_ADDR'], if exists, otherwise ''
1629  *
1630  */
1631 function _GetRemoteIp() {
1632  if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
1633  $remoteAddr = trim($_SERVER['REMOTE_ADDR']);
1634  } else {
1635  $remoteAddr = '';
1636  }
1637  return $remoteAddr;
1638 }
1639 
1640  /**
1641  * Prepare additional query string to append to curl url for book-keeping
1642  * purposes
1643  *
1644  * @param int $cucorerequestsSeqId -- associated cucorerequests.id
1645  *
1646  * @return str $extraQueryStr
1647  * $extraQueryStr -- extra query string. eg. corerespid=12my
1648  *
1649  */
1650 function _GetAdditionalQueryStr($cucorerequestsSeqId) {
1651  if (array_key_exists('HTTP_HOST', $_SERVER)) {
1652  # eg. www4.homecu.net
1653  $serverHost = trim(explode(".", trim($_SERVER['HTTP_HOST']))[0]);
1654  } else {
1655  $serverHost = 'localhost';
1656  }
1657  return "corerespid=$cucorerequestsSeqId$serverHost";
1658 }
1659 
1660 /**
1661  * Hide/mask sensitive information like password, form data, etc from
1662  * query string (get or post data)
1663  *
1664  * @param str $urlPortion -- live server url
1665  * @param array $queryStrArray -- post or get data (in query string format)
1666  * @param str $extraQueryStr -- extra query str eg. coreresp=xxSERVERHOST
1667  *
1668  * @return str $returnUrl
1669  -- full safe url to be stored in cucorerequests table
1670  *
1671  */
1672 function _HideSensitiveContent($urlPortion, $queryStrArray, $extraQueryStr) {
1673  $replace_str = "HIDDEN";
1674  $type = trim($queryStrArray["type"]);
1675 
1676  switch ($type) {
1677  case "I":
1678  if (array_key_exists("pass", $queryStrArray)) {
1679  $queryStrArray["pass"] = $replace_str;
1680  }
1681  break;
1682  case "T":
1683  break;
1684  case "X":
1685  break;
1686  case "NEWAPP":
1687  if (array_key_exists("ref1", $queryStrArray)) {
1688  $queryStrArray["ref1"] = $replace_str;
1689  }
1690  if (array_key_exists("ref3", $queryStrArray)) {
1691  $queryStrArray["ref3"] = $replace_str;
1692  }
1693  break;
1694  case "ESTMT":
1695  break;
1696  case "ETOC":
1697  break;
1698  }
1699 
1700  $querySep = (strstr($urlPortion, '?') ? '&' : '?');
1701  $returnUrl = $urlPortion . $querySep . http_build_query($queryStrArray);
1702 
1703  $querySep = (strstr($returnUrl, '?') ? '&' : '?');
1704  $returnUrl .= $querySep . $extraQueryStr;
1705 
1706  return $returnUrl;
1707 }
1708 
1709  /**
1710  * Populate appliance_ip information in for cucorerequests table record
1711  *
1712  * @param array $pHbEnv -- The current HB_ENV array. Used mostly for the
1713  * logger if need be.
1714  * @param array $pConnSet -- This is the Connection information
1715  * from _ReturnCUSettings
1716  * @param str $hculiveURL -- HCU Live server url
1717  * @param array $cucorerequestsRec -- Associative array of cucorequests
1718  * record values
1719  *
1720  * @return array $cucorerequestsRec
1721  * -- Associative array of cucorequests
1722  * record values with appliance_ip=value
1723  *
1724  */
1725 function _PopulateApplianceId($pHbEnv, $cuConnSet, $hculiveURL, $cucorerequestsRec) {
1726  $appliance_id = NULL;
1727  try{
1728  $split_res = parse_url($hculiveURL, PHP_URL_HOST);
1729  if(!$split_res) {
1730  throw new Exception("Something went wrong while extracting appliance ip/dns for fetcher: $hculiveURL");
1731  }
1732  $appliance_id = $split_res;
1733  } catch (Exception $e) {
1734  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n Error :: {$e->getMessage()}");
1735  }
1736 
1737  if ($appliance_id == NULL) {
1738  $cucorerequestsRec["appliance_ip"] = "Couldn't be extracted";
1739  } else {
1740  $cucorerequestsRec["appliance_ip"] = $appliance_id;
1741  }
1742  return $cucorerequestsRec;
1743 }
1744 
1745  /**
1746  * Obtains the nextval from cucorerequests_id_seq object
1747  *
1748  * @param array $pHbEnv -- The current HB_ENV array. Used mostly for the
1749  * logger if need be.
1750  * @param array $pConnSet -- This is the Connection information
1751  * from _ReturnCUSettings
1752  *
1753  * @return int $nextSeqId or NULL
1754  -- next integer value of cucorerequests.id
1755  * serial in normal case, otherwise, returns NULL
1756  *
1757  */
1758 function _GetNextCucorerequestsSeqId($pHbEnv, $cuConnSet){
1759  $nextSeqId = NULL;
1760  try {
1761  $dbh = HCU_array_key_value('dbh', $pHbEnv);
1762 
1763  $cucorerequestsSql = "select nextval('cucorerequests_id_seq'::regclass);";
1764  $cucorerequestsSth = db_query($cucorerequestsSql, $dbh);
1765 
1766  if (!$cucorerequestsSth) {
1767  throw new Exception("cucorerequests_id_seq query failed ($cucorerequestsSql). DB error: " . db_last_error());
1768  }
1769  # get the next sequence number from `cucorerequests_id_seq` object
1770  $nextSeqId = intval(db_fetch_row($cucorerequestsSth,0)[0]);
1771  } catch (Exception $e) {
1772  _ApplPrintLogger($pHbEnv, $cuConnSet, "\n Error :: {$e->getMessage()}");
1773  }
1774  return $nextSeqId;
1775 }
1776 
1777  /**
1778  * Prepare cucorerequests record before making a curl request
1779  *
1780  * @param array $pHbEnv -- The current HB_ENV array. Used mostly for the
1781  * logger if need be.
1782  * @param array $pConnSet -- This is the Connection information
1783  * from _ReturnCUSettings
1784  *
1785  * @return array {$cucorerequestsRecord, $extraQueryStr}
1786  * $cucorerequestsRecord -- Associative array of cucorerequest
1787  * record values
1788  * $extraQueryStr -- extra query string. eg. corerespid=12my
1789  *
1790  */
1791 function _PrepareCucoreInfoBeforeRequest($pHbEnv, $pConnSet, $hculiveURL, $queryStr) {
1792  $cucorerequestsRecord = Array();
1793  $extraQueryStr = "";
1794  $activeCu = HCU_array_key_value("cu", $pHbEnv);
1795 
1796  try {
1797  if (!_SkipCucorerequestsEntry($activeCu)){
1798  $cucorerequestsId = _GetNextCucorerequestsSeqId($pHbEnv, $pConnSet);
1799  $cucorerequestsRecord["id"] = $cucorerequestsId;
1800 
1801  if($cucorerequestsRecord["id"] != NULL) {
1802 
1803  $extraQueryStr = _GetAdditionalQueryStr($cucorerequestsRecord["id"]);
1804 
1805  parse_str($queryStr, $queryStrArray);
1806  $cucorerequestsRecord["request_url"] = _HideSensitiveContent($hculiveURL, $queryStrArray, $extraQueryStr);
1807 
1808  $cucorerequestsRecord["accountnumber"] = HCU_array_key_value("member", $queryStrArray);
1809  $cucorerequestsRecord["request_type"] = HCU_array_key_value("type", $queryStrArray);
1810  $cucorerequestsRecord["remote_ip"] = _GetRemoteIp();
1811  $cucorerequestsRecord["cu"] = $activeCu;
1812  $cucorerequestsRecord = _PopulateApplianceId($pHbEnv, $pConnSet, $hculiveURL, $cucorerequestsRecord);
1813 
1814  # populate request information to cucorerequests table before getting the packets
1815  _PopulateCUCoreRequestsTable($pHbEnv, $pConnSet, "before_request", $cucorerequestsRecord);
1816  }
1817  }
1818 
1819  } catch (Exception $e) {
1820  _ApplPrintLogger($pHbEnv, $pConnSet, "\n** Send Data Error Caught ** \n" . "({$e->getCode()})" . $e->getMessage() );
1821  }
1822  return Array($cucorerequestsRecord, $extraQueryStr);
1823 }
1824 
1825 /**
1826  *
1827  * Send the Packet Request
1828  *
1829  * This will send the packet to the core
1830  *
1831  * @param array $pHbEnv -- The current HB_ENV array. Used mostly for the logger if need be.
1832  * @param array $pConnSet -- This is the Connection information from _ReturnCUSettings
1833  * @param string $pGetData --- URL Encoded string of key/value pairs
1834  * field1=val1&field2=val2field3=val%203
1835  * @param string $pPostData -- URL Encodeed string of key/value pairs to be
1836  * sent as POST data
1837  *
1838  * @return array {code, packet}
1839  *
1840  *
1841  * mws tested 3/31/17
1842  * * fail if no url
1843  * * fail if curl handle empty
1844  * * fail if request times out
1845  * * fail if script not found (404)
1846  *
1847  *
1848  */
1849 function _SendDataRequest($pHbEnv, $pConnSet, $pGetData, $pPostData=null) {
1850 
1851  $cucorerequestsErrors = Array();
1852  $reqStatCurlHttpInfo = Array("curl_errno" => "", "http_code" => "");
1853  $queryDataStr = "";
1854 
1855  $retVal = array("code" => "000", "packet" => "");
1856 
1857  try {
1858 
1859  $startTime = time(); // * Start time of request
1860 
1861  $envLogger = HCU_array_key_value('logger', $pHbEnv['SYSENV']);
1862  /*
1863  * Get the hculive API URL
1864  */
1865  $hculiveURL = _CreateAPIUrl($pConnSet);
1866  if ($hculiveURL == '') {
1867  throw new exception ('Unable to retrieve data', -700);
1868  }
1869  /*
1870  * OPEN CURL HANDLE
1871  */
1872  $curlHndl = curl_init($hculiveURL);
1873 
1874  if (!$curlHndl) {
1875  throw new Exception ('Unable to retrieve data', -701);
1876  }
1877  /* *** CONFIGURE *** */
1878  /* Configure the stream for transport */
1879  $curlOptions = _ReturnCurlDefaults();
1880 
1881  /* *** ASSIGN URL W/ GET QUERY *** */
1882  $querySep = (strstr($hculiveURL, '?') ? '&' : '?');
1883  $curlOptions[CURLOPT_URL] = $hculiveURL . $querySep . $pGetData;
1884  $queryDataStr = $pGetData;
1885 
1886  if (HCU_array_key_exists('platform', $pHbEnv)) {
1887  // ** Append the 'src=ABC' to the end of the URL
1888  $querySep = (strstr($curlOptions[CURLOPT_URL], '?') ? '&' : '?');
1889  $curlOptions[CURLOPT_URL] .= $querySep . 'src=' . $pHbEnv['platform'];
1890  }
1891 
1892  /* *** ASSIGN POST DATA *** */
1893  if ($pPostData !== null && $pPostData !== '') {
1894  $curlOptions[CURLOPT_POST] = 1;
1895  $curlOptions[CURLOPT_POSTFIELDS] = $pPostData;
1896  $queryDataStr = $pPostData;
1897  }
1898 
1899  # php passes arguments with pass by value, no need to worry about
1900  # accidental changes in hculiveURL and $queryDataStr
1901  list($cucorerequestsRecord, $extraQueryStr) = _PrepareCucoreInfoBeforeRequest($pHbEnv, $pConnSet, $hculiveURL, $queryDataStr);
1902  # if applicable, append extra query string to the actual url for book-keeping
1903  if ($extraQueryStr != "") {
1904  if ($pPostData !== null && $pPostData !== '') {
1905  $curlOptions[CURLOPT_POSTFIELDS] .= "&$extraQueryStr";
1906  } else {
1907  $querySep = (strstr($curlOptions[CURLOPT_URL], '?') ? '&' : '?');
1908  $curlOptions[CURLOPT_URL] .= $querySep . $extraQueryStr;
1909  }
1910  }
1911 
1912  _ApplPrintLogger($pHbEnv, $pConnSet, "\n** CURL OPTIONS **\n" . print_r($curlOptions, true));
1913  /*
1914  * CONNECTION TIMEOUT
1915  */
1916  curl_setopt_array ($curlHndl, $curlOptions);
1917 
1918  /* *** EXEC THE REQUEST *** */
1919  $coreConnAttempts = 0;
1920  $curlErrs = array();
1921 
1922  // Retry curl_exec for CURL_CONN_TO_CORE_DEFAULT_RETRIES number of
1923  // times when the curl error code for the request is 28
1924  // (CURLE_OPERATION_TIMEDOUT) More on curl error codes:
1925  // https://www.php.net/manual/en/function.curl-errno.php
1926  do {
1927 
1928  // pause before a retry
1929  if ($coreConnAttempts > 0 && CURL_CONN_TO_CORE_RETRY_DELAY > 0) {
1930  sleep(CURL_CONN_TO_CORE_RETRY_DELAY);
1931  }
1932 
1933  // execute curl request
1934  $applResponse = Array(
1935  'content' => curl_exec($curlHndl),
1936  'errno' => curl_errno($curlHndl),
1937  'errmsg' => curl_error($curlHndl),
1938  'header' => curl_getinfo($curlHndl)
1939  );
1940  $curlErrNo = HCU_array_key_value("errno", $applResponse);
1941  ++$coreConnAttempts;
1942 
1943  // accumulate curl error codes for all attempts for
1944  // cucorerequests report
1945  $curlErrs[] = "Attempt#" . $coreConnAttempts . " : " . $curlErrNo;
1946 
1947  } while ($curlErrNo == CURLE_OPERATION_TIMEDOUT &&
1948  $coreConnAttempts < CURL_CONN_TO_CORE_DEFAULT_RETRIES);
1949 
1950  if ($coreConnAttempts == 1) {
1951  $reqStatCurlHttpInfo["curl_errno"] = $curlErrNo;
1952  } else {
1953  $reqStatCurlHttpInfo["curl_errno"] = implode(', ', $curlErrs);
1954  }
1955 
1956  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Appliance Response *\n" . print_r($curlOptions, true));
1957 
1958  /* ** CLOSE CONNECTION ** */
1959  curl_close($curlHndl);
1960 
1961  /* ** WAS THERE A CURL ERROR ** */
1962  if ($applResponse['errno'] != 0) {
1963  throw new Exception ($applResponse['errmsg'], -703);
1964  }
1965 
1966  /* ** WAS THERE AN HTML ERROR ** */
1967  // this html code is for the last core curl request connection (if
1968  // there were retries)
1969  if (HCU_array_key_exists('http_code', $applResponse['header'])) {
1970  $httpCode = HCU_array_key_value('http_code', $applResponse['header']);
1971  $reqStatCurlHttpInfo["http_code"] = $httpCode;
1972  // ** Validate http_code is 200
1973  if ($httpCode != '200') {
1974  // A script error was returned. It could be a range of things.
1975  /** common are
1976  * ** 400 Bad Request
1977  * ** 403 Forbidden
1978  * ** 404 Not Found
1979  * ** 500 Internal Server Error
1980  * ** 503 Service Unavailable
1981  */
1982  throw new Exception ("HTTP Request Failure", -704);
1983  }
1984  }
1985 
1986  /* *** RESPONSE META *** */
1987  /* Evaluate the response meta data and determine if all data is there */
1988  $retVal['packet'] = $applResponse['content'];
1989 //print_r($applResponse['content']);
1990  } catch (Exception $e) {
1991  _ApplPrintLogger($pHbEnv, $pConnSet, "\n** Send Data Error Caught ** \n" . "({$e->getCode()})" . $e->getMessage() );
1992 
1993  // ** Error out
1994  $retVal['code'] = '999';
1995  // ** $e->getCode();
1996  $retVal['error'] = Array($e->getMessage());
1997  /* ** Create default packet for parsing **/
1998  $retVal['packet'] = '<?xml version="1.0" encoding="UTF-8"?><homecu-packet></homecu-packet>';
1999  // capture caught error to be updated to a record corresponding to
2000  // $cucorerequestsId
2001  $cucorerequestsErrors[] = $e->getMessage() . " ({$e->getCode()})";
2002  }
2003 
2004  $retVal["cucorereq_after"] = Array();
2005  $retVal["cucorereq_after"]["attempted_core_conns"] = $coreConnAttempts;
2006  $retVal["cucorereq_after"]["curl_http"] = $reqStatCurlHttpInfo;
2007  $retVal["cucorereq_after"]["record"] = $cucorerequestsRecord;
2008  $retVal["cucorereq_after"]["errors"] = $cucorerequestsErrors;
2009 
2010  $endTime = time(); // End of request function
2011 
2012  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Return From _SendDataRequest ** time :: " . ($endTime - $startTime) . " *\n" . print_r($retVal, true));
2013 
2014  return $retVal;
2015 }
2016 
2017 /**
2018  *
2019  * Return the Live API Url for this credit union
2020  *
2021  * @param array $pConnSet -- The connection settings for the hculive API server
2022  *
2023  * @return string -- "" empty string on failure
2024  *
2025  * tested mws 3/31/17
2026  * ** return empty string '' if liveserver is blank or #
2027  */
2028 function _CreateAPIUrl ($pConnSet) {
2029  $retVal = '';
2030 
2031  try {
2032  $liveserver = trim(HCU_array_key_value('liveserver', $pConnSet));
2033  if ($liveserver == '' || $liveserver == '#') {
2034  throw new exception ('Server Configuration Empty');
2035  } else {
2036  $retVal = $liveserver;
2037  }
2038 
2039 
2040  } catch (Exception $e) {
2041  $retVal = '';
2042  }
2043 
2044  return $retVal;
2045 }
2046 
2047 /**
2048  * Retrieve the Member Information Packet from the core (MIR)
2049  * and process results.
2050  * If successful, this will return the mir information in the data element
2051  * If failed, an error will be returned
2052  *
2053  * @param array $pHbEnv -- The current HB_ENV setting
2054  * @param array $pConnSet -- The connection settings for the hculive API server
2055  * @param array $pMbrRequest -- The member number being sent to core for MIR packet
2056  *
2057  * @return array
2058  * [code]
2059  * {000, 999}
2060  * [data]
2061  */
2062 function _RetrieveMemberInfo($pHbEnv, $pConnSet, $pMbrRequest) {
2063 
2064  $retVal = Array("code" => '000', "data" => Array());
2065 
2066  $mirFields = Array(
2067  "accountnumber",
2068  "firstname",
2069  "middlename",
2070  "lastname",
2071  "email",
2072  "homephone",
2073  "workphone",
2074  "cellphone",
2075  "fax",
2076  "ssn",
2077  "address1",
2078  "address2",
2079  "city",
2080  "state",
2081  "zip",
2082  "cc",
2083  "dob",
2084  "class"
2085  );
2086 
2087  $origPktStatCode = "";
2088  $origPktStatDesc = "";
2089  $origPktStatExtra = "";
2090  $packetsize = 0;
2091 
2092  // ** cc - country code
2093  /**
2094  * EXAMPLE Packet Response
2095  <MemberInfo>
2096  <Member>
2097  1234567
2098  </Member>
2099  <Info> Member[TAB]FirstName[TAB]MiddleName[TAB]LastName[TAB]Email[TAB]HomePhone[TAB]WorkPhone[TAB]CellPhone[TAB]Fax[TAB]SSN [TAB]Address1[TAB]Address2[TAB]City[TAB]State[TAB]Zip[TAB]CC[TAB]DateOfBirth\n
2100  </Info> </MemberInfo>
2101  **/
2102  try {
2103  _ApplPrintLogger($pHbEnv, $pConnSet, "\n** Get Member Info **\n");
2104 
2105  /* ** VALIDATION ** */
2106  if ($pMbrRequest == '') {
2107  throw new Exception ("Unknown Account Number", 50050);
2108  }
2109 
2110  $dataArray = Array(
2111  "member" => $pMbrRequest,
2112  "type" => 'MIR'
2113  );
2114  $packetQuery = http_build_query($dataArray);
2115 
2116  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Packet Query *\n$packetQuery\n");
2117  $sendDataResp = _SendDataRequest($pHbEnv, $pConnSet, $packetQuery);
2118  $cucorereqAfter = HCU_array_key_value("cucorereq_after", $sendDataResp);
2119 
2120  if ($sendDataResp['code'] != '000') {
2121  // ** Error -- Getting data from core... Does the detailed error matter??
2122  // ** Or can I just respond 999 -- Errors here will be communication or incomplete packet
2123  throw new Exception ('Data Request Error');
2124  }
2125  /*
2126  * EXAMPLE Return Value
2127  $sendDataResp = Array(
2128  'code' => '000',
2129  'packet' => '<?xml version="1.0" encoding="UTF-8"?><homecu-packet>
2130  <status>958777 101 New Data</status>
2131 
2132  <MemberInfo>
2133  <Member>
2134  958777
2135  </Member>
2136  <Info>
2137  958777 Erna Rollins erna.rollins@gmail.com 303-979-7550 303-597-5241 303-895-9429 ***-**-1275 PO BOX 1456 LITTLETON CO 80127 19620530
2138  </Info>
2139  </MemberInfo></homecu-packet>
2140  '
2141  );
2142  */
2143  $mbrData = Array(
2144  "type" => PACKET_REQUEST_MIR,
2145  "member" => $pMbrRequest
2146  );
2147 
2148  $packetContent = HCU_array_key_value('packet', $sendDataResp);
2149  $packetsize = strlen($packetContent);
2150  $xmlParse = _ParsePacketData($pHbEnv, $pConnSet, $mbrData, $packetContent);
2151  if ($xmlParse['code'] != '000') {
2152  // ** Error Parsing -- throw error
2153  throw new Exception ("XML Parse " . $xmlParse['error'], 50060);
2154  }
2155 
2156  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Packet Resp Status *\n" . print_r($xmlParse['data']['packet-status'], true) . "\n");
2157  /* ******* *
2158  *
2159  * ** PROCESS PACKET RESPONSE **
2160  *
2161  * 101 New Data -- process packet
2162  *
2163  * 001 Invalid Account Number -- return immediately -- invalid account number
2164  * 002 Invalid Password -- change to 001 Invalid Account and return
2165  * 003 Closed Account -- change to 001 Invalid Account and return
2166  *
2167  * 002 Invalid Password -- Password not used -- general error
2168  * 100 No New Data -- return immediately -- general error
2169  *
2170  * DEPRECATED -- 2XX codes imply we can communicate with appliance but NOT the core
2171  * -- Returning any type of success is a false positive -- RETURN ERROR
2172  * 200 System Unavailable, No New Data -- return immediately
2173  * 201 System Unavailable, New Data -- can't use stale for MIR
2174  * 202 System Unavailable, No Data -- return immediately
2175  *
2176  * 999 Calling error or Invalid Parms -- return immediately
2177  *
2178  *
2179  * ******* */
2180 
2181  $origPktStatCode = HCU_array_key_value("pktStatCode", $xmlParse['data']['packet-status']);
2182  $origPktStatDesc = HCU_array_key_value("pktStatDesc", $xmlParse['data']['packet-status']);
2183  $origPktStatExtra = HCU_array_key_value("pktStatExtra", $xmlParse['data']['packet-status']);
2184 
2185  switch ($xmlParse['data']['packet-status']['pktStatCode']) {
2186  case '101':
2187 
2188  // Explode MIR - RETURN DATA
2189  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Parse API Response *\n$packetQuery\n" . print_r($xmlParse, true));
2190 
2191  $xmlPacket = $xmlParse['data']['packet-xml'];
2192 
2193  $mirInfo = trim($xmlPacket->MemberInfo->Info, "\n");
2194 
2195  $recordValues = explode("\t", $mirInfo);
2196 
2197  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Response Values *\n" . print_r($recordValues, true));
2198  // /* Combine column / values */
2199  // ** Validate the number of columns match before doing this.. Throw an error if they are mismatched
2200  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Column Count : tblCol " . count($mirFields) . " :: pktRec " . count($recordValues) . " *\n");
2201 
2202  // make sure there is a "class" value; use default if not there
2203  if ( count($mirFields) != count($recordValues) ) {
2204  $recordValues[count( $mirFields ) - 1] = "";
2205  }
2206 
2207  if (count($mirFields) != count($recordValues)) {
2208  throw new Exception ("Column Count Mismatch");
2209  }
2210  $mirInfoData = array_combine($mirFields, $recordValues);
2211 
2212  if ( isset( $pHbEnv['SYSENV']['devmode'] ) && $pHbEnv['SYSENV']['devmode']) {
2213  // ** We are in development mode -- It's possible the core is masking ssn -- Replace all * with 0
2214  $mirInfoData['ssn'] = str_replace('*', '0', $mirInfoData['ssn']);
2215  }
2216 
2217  // * Standardize the date of birth to MM/DD/YYYY
2218  // * Different cores are sending different format
2219  if (trim($mirInfoData['dob']) != '') {
2220  /**
2221  * Preferred format is MM/DD/YYYY
2222  * Others are YYYY-MM-DD MM-DD-YYYY YYYYMMDD
2223  * * PRODIGY - YYYYMMDD
2224  * Use php strtotime to evaluate string and create a new date value
2225  * it will recognize the primary format first
2226  */
2227  $mirInfoData['dob'] = date('m/d/Y', strtotime($mirInfoData['dob']));
2228 
2229  }
2230 
2231  $retVal['code'] = '000';
2232  $retVal['data'] = $mirInfoData;
2233  break;
2234 
2235  case '002':
2236  case '003':
2237  $retVal['code'] = '001';
2238  $retVal['error'] = 'INVALID ACCOUNT NUMBER';
2239  break;
2240 
2241  case '001':
2242  case '999':
2243  $retVal['code'] = $xmlParse['data']['packet-status']['pktStatCode'];
2244  $retVal['error'] = $xmlParse['data']['packet-status']['pktStatDesc'];
2245  break;
2246 
2247  case '100':
2248  case '200':
2249  case '201':
2250  case '202':
2251  default:
2252  throw new Exception("Packet Request Failed" . $xmlParse['data']['packet-status']['pktStatCode'], 50070);
2253  }
2254  } catch (Exception $e) {
2255  _ApplPrintLogger($pHbEnv, $pConnSet, "\n** Mbr Info Error Caught ** \n" . "({$e->getCode()})" . $e->getMessage() );
2256  $retVal['code'] = '999';
2257  $retVal['error'] = "Unable to retrieve data";
2258  $cucorereqAfter["errors"][] = $e->getMessage();
2259  }
2260 
2261  _UpdateRequestStatus($pHbEnv, $pConnSet, $cucorereqAfter, $packetsize, $origPktStatCode, $origPktStatDesc, $origPktStatExtra);
2262  return $retVal;
2263 
2264 }
2265 
2266 /**
2267  * Retrieve the Member Information Packet from the core (MIR)
2268  * and process results.
2269  * If successful, this will return the mir information in the data element
2270  * If failed, an error will be returned
2271  *
2272  * @param array $pHbEnv -- The current HB_ENV setting
2273  * @param array $pConnSet -- The connection settings for the hculive API server
2274  * @param string $pMbrRequest -- Member number requesting e-statments
2275  * @param string $pMbrEmail -- Email of the member we are requesting
2276  * @param string $pMbrCmd -- This is one of the constants {PACKET_REQUEST_ES, PACKET_REQUEST_ES_TOC}
2277  * @param string $pMbrStmtId -- ESTM ONLY -- STATEMENT ID we are requesting
2278  *
2279  * @return array
2280  * [code]
2281  * {000, 999, 001}
2282  * [error]
2283  * [data]
2284  * [TOC]
2285  * [statement]
2286  */
2287 function _RetrieveMemberES($pHbEnv, $pConnSet, $pMbrRequest, $pMbrEmail, $pMbrCmd, $pMbrStmtId='') {
2288 
2289  $retVal = Array("code" => '000', "data" => Array());
2290 
2291  $tocFields = Array(
2292  "Member",
2293  "ID",
2294  "Type",
2295  "PeriodEnd",
2296  "Description",
2297  "Format"
2298  );
2299 
2300  $dataToc = Array();
2301 
2302  $origPktStatCode = "";
2303  $origPktStatDesc = "";
2304  $origPktStatExtra = "";
2305  $packetsize = 0;
2306 
2307  try {
2308  _ApplPrintLogger($pHbEnv, $pConnSet, "\n** Get E-Statement [$pMbrCmd] **\n");
2309 
2310  /* ** VALIDATION ** */
2311  if ($pMbrRequest == '') {
2312  throw new Exception ("Unknown Account Number", 50150);
2313  }
2314 
2315  /* STATEMENT ID MUST BE ENTERED FOR ESTM */
2316  if ($pMbrCmd == PACKET_REQUEST_ES && $pMbrStmtId == '') {
2317  throw new Exception ("Unknown Statement ID" , 50170);
2318  }
2319 
2320  $dataArray = Array(
2321  "member" => $pMbrRequest,
2322  "type" => ($pMbrCmd == PACKET_REQUEST_ES ? "ESTM" : "ETOC")
2323  );
2324  if ($pMbrEmail != '') {
2325  $dataArray['ref3'] = $pMbrEmail;
2326  }
2327  if ($pMbrCmd == PACKET_REQUEST_ES) {
2328  $dataArray['ref1'] = $pMbrStmtId;
2329  }
2330  $packetQuery = http_build_query($dataArray);
2331 
2332  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Packet Query *\n$packetQuery\n");
2333  $sendDataResp = _SendDataRequest($pHbEnv, $pConnSet, $packetQuery);
2334  $cucorereqAfter = HCU_array_key_value("cucorereq_after", $sendDataResp);
2335 
2336  if ($sendDataResp['code'] != '000') {
2337  // ** Error -- Getting data from core... Does the detailed error matter??
2338  // ** Or can I just respond 999 -- Errors here will be communication or incomplete packet
2339  throw new Exception ('Data Request Error');
2340  }
2341  /*
2342  * EXAMPLE Return Value
2343  */
2344 
2345  /*
2346  *ETOC REQUEST
2347 <?xml version="1.0" encoding="UTF-8"?><homecu-packet>
2348 <status>85902 101 New Data</status>
2349 <EStatementTOC>
2350 <Member>
2351 85902
2352 </Member>
2353 <TOC>
2354 85902 2017-10 M 2017-10-31 2017-10-Statement (may not actually exist) PDF
2355 85902 2017-09 M 2017-09-30 2017-09-Statement (may not actually exist) PDF
2356 85902 2017-08 M 2017-08-31 2017-08-Statement (may not actually exist) PDF
2357 85902 2017-07 M 2017-07-31 2017-07-Statement (may not actually exist) PDF
2358 85902 2017-06 M 2017-06-30 2017-06-Statement (may not actually exist) PDF
2359 85902 2017-05 M 2017-05-31 2017-05-Statement (may not actually exist) PDF
2360 85902 2017-04 M 2017-04-30 2017-04-Statement (may not actually exist) PDF
2361 </TOC>
2362 </EStatementTOC></homecu-packet>
2363 
2364  */
2365 
2366  /*
2367  * ESTM REQUEST for STATEMENT
2368 <?xml version="1.0" encoding="UTF-8"?><homecu-packet>
2369 <status>85920 101 New Data</status>
2370 <EStatement>
2371 <Member>
2372 85920 2017-11 M 2017-11-30 2017-11-Statement PDF
2373 </Member>
2374 <Data>
2375 JVBERi0x...data...g==
2376 </Data>
2377 </EStatement></homecu-packet>
2378  */
2379 
2380 
2381  $mbrData = Array(
2382  "type" => $pMbrCmd,
2383  "member" => $pMbrRequest
2384  );
2385  $packetContent = HCU_array_key_value('packet', $sendDataResp);
2386  $packetsize = strlen($packetContent);
2387  $xmlParse = _ParsePacketData($pHbEnv, $pConnSet, $mbrData, $packetContent);
2388  if ($xmlParse['code'] != '000') {
2389  // ** Error Parsing -- throw error
2390  throw new Exception ("XML Parse " . $xmlParse['error'], 50160);
2391  }
2392 
2393  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Packet Resp Status *\n" . print_r($xmlParse['data']['packet-status'], true) . "\n");
2394  /* ******* *
2395  *
2396  * ** PROCESS PACKET RESPONSE **
2397  *
2398  * 101 New Data -- process packet
2399  *
2400  * 001 Invalid Account Number -- return immediately -- invalid account number
2401  * 002 Invalid Password -- change to 001 Invalid Account and return
2402  * 003 Closed Account -- change to 001 Invalid Account and return
2403  *
2404  * 002 Invalid Password -- Password not used -- general error
2405  * 100 No New Data -- return immediately -- general error
2406  *
2407  * DEPRECATED -- 2XX codes imply we can communicate with appliance but NOT the core
2408  * -- Returning any type of success is a false positive -- RETURN ERROR
2409  * 200 System Unavailable, No New Data -- return immediately
2410  * 201 System Unavailable, New Data -- can't use stale for MIR
2411  * 202 System Unavailable, No Data -- return immediately
2412  *
2413  * 999 Calling error or Invalid Parms -- return immediately
2414  *
2415  *
2416  * ******* */
2417  $origPktStatCode = HCU_array_key_value("pktStatCode", $xmlParse['data']['packet-status']);
2418  $origPktStatDesc = HCU_array_key_value("pktStatDesc", $xmlParse['data']['packet-status']);
2419  $origPktStatExtra = HCU_array_key_value("pktStatExtra", $xmlParse['data']['packet-status']);
2420 
2421  switch ($xmlParse['data']['packet-status']['pktStatCode']) {
2422  case '101':
2423  // Explode MIR - RETURN DATA
2424  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* Parse API Response *\n$packetQuery\n" . print_r($xmlParse, true));
2425 
2426  $xmlPacket = $xmlParse['data']['packet-xml'];
2427 
2428  if ($pMbrCmd == PACKET_REQUEST_ES_TOC) {
2429  // ** Get Table of Contents -- Returned for both types, but different xml tags
2430  $mbrToc = trim($xmlPacket->EStatementTOC->TOC);
2431  } else {
2432  $mbrToc = trim($xmlPacket->EStatement->Member);
2433  }
2434 
2435  $dataRow = strtok($mbrToc, "\n");
2436  while ($dataRow !== false) {
2437  //** Validate we have a line
2438  if ($dataRow != '') {
2439  // Parse each line -- Combine the 'columns' list with data line exploded on \t
2440  // ** Current interface (2017/11/22) is adding an extra <tab> at the end.
2441  // ** Perform a strip on the right side. This will leave the type column as the last field
2442  $dataRow = rtrim($dataRow);
2443  $recordValues = explode("\t", $dataRow);
2444  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* TOC Response Values *\n" . print_r($recordValues, true));
2445 
2446  /* Combine column / values */
2447  // ** Validate the number of columns match before doing this.. Throw an error if they are mismatched
2448  // ** If the tab count doesn't match then ignore this entry
2449 
2450  if (count($tocFields) == count($recordValues)) {
2451  $updateRow = array_combine($tocFields, $recordValues);
2452  // ** Add row to information being returned
2453  if (count($updateRow) > 0) {
2454  $dataToc[] = $updateRow;
2455  }
2456  }
2457  }
2458  $dataRow = strtok("\n");
2459  }
2460 
2461  /* GET ACTUAL ESTATEMENT DATA */
2462  $esData = '';
2463  if ($pMbrCmd == PACKET_REQUEST_ES) {
2464  $esData = trim($xmlPacket->EStatement->Data);
2465  }
2466 
2467  $retVal['code'] = '000';
2468  $retVal['data']['TOC'] = $dataToc;
2469  $retVal['data']['statement'] = $esData;
2470  break;
2471 
2472  case '002':
2473  case '003':
2474  $retVal['code'] = '001';
2475  $retVal['error'] = 'INVALID ACCOUNT NUMBER';
2476  break;
2477 
2478  case '001':
2479  case '012':
2480  case '999':
2481  $retVal['code'] = $xmlParse['data']['packet-status']['pktStatCode'];
2482  $retVal['error'] = $xmlParse['data']['packet-status']['pktStatDesc'];
2483  break;
2484 
2485  case '100':
2486  case '200':
2487  case '201':
2488  case '202':
2489  default:
2490  throw new Exception("Packet Request Failed" . $xmlParse['data']['packet-status']['pktStatCode'], 50170);
2491  }
2492  } catch (Exception $e) {
2493  _ApplPrintLogger($pHbEnv, $pConnSet, "\n** ES Request Error Caught ** \n" . "({$e->getCode()})" . $e->getMessage() );
2494  $retVal['code'] = '999';
2495  $retVal['error'] = "Unable to retrieve data";
2496  $cucorereqAfter["errors"][] = $e->getMessage();
2497  }
2498 
2499  _UpdateRequestStatus($pHbEnv, $pConnSet, $cucorereqAfter, $packetsize, $origPktStatCode, $origPktStatDesc, $origPktStatExtra);
2500  return $retVal;
2501 }
2502 
2503 
2504 /**
2505  * Retrieve the Member Cross Account packet from the CORE (XAC)
2506  * This is the classic Cross Account request.
2507  *
2508  * @param array $pHbEnv -- The current HB_ENV setting
2509  * @param array $pConnSet -- The connection settings for the hculive API server
2510  * @param array $pReqData -- The request data to be sent to the core --
2511  * member -- Member number for
2512  * if_mod_since -- last packet stamp
2513  * ref3 -- email for inquiry request
2514  * cutoff -- cutoff date for request
2515  * pass -- **optional password
2516  *
2517  * @return array
2518  * [code]
2519  * {000, 999}
2520  * [data]
2521  * [packet-status]
2522  * [packet-xml]
2523  * [packet-data]
2524 */
2525 function _RetrieveMemberCrossAccount ($pHbEnv, $pConnSet, $pReqData) {
2526 
2527  $retVal = Array("code" => '000', "data" => Array());
2528  $packetData = Array();
2529 
2530  $origPktStatCode = "";
2531  $origPktStatDesc = "";
2532  $origPktStatExtra = "";
2533  $packetsize = 0;
2534 
2535  try {
2536  $dataArray = array_merge ($pReqData, array("type" => "X"));
2537  $packetQuery = http_build_query($dataArray);
2538 
2539  _ApplPrintLogger($pHbEnv, $pConnSet, "\n** Packet XAC Query ** \n$packetQuery\n");
2540 
2541  // * * XAC member=99999&type=X&ref3=email@email.com
2542 
2543  $sendDataResp = _SendDataRequest($pHbEnv, $pConnSet, $packetQuery);
2544  $cucorereqAfter = HCU_array_key_value("cucorereq_after", $sendDataResp);
2545 
2546  if ($sendDataResp['code'] != '000') {
2547  // ** Error -- Getting data from core... Does the detailed error matter??
2548  // ** Or can I just respond 999 -- Errors here will be communication or incomplete packet
2549  throw new Exception ('Data Request Error');
2550  }
2551 
2552  $mbrData = Array(
2553  "type" => PACKET_REQUEST_XAC,
2554  "member" => $pReqData['member']
2555  );
2556  $packetContent = HCU_array_key_value('packet', $sendDataResp);
2557  $packetsize = strlen($packetContent);
2558  $xmlParse = _ParsePacketData($pHbEnv, $pConnSet, $mbrData, HCU_array_key_value('packet', $sendDataResp));
2559  if ($xmlParse['code'] != '000') {
2560  // ** Error Parsing -- throw error
2561  throw new Exception ("XML Parse " . $xmlParse['error'], 50060);
2562  }
2563  $dataPacket = $xmlParse['data']['packet-xml'];
2564 
2565  $origPktStatCode = HCU_array_key_value("pktStatCode", $xmlParse['data']['packet-status']);
2566  $origPktStatDesc = HCU_array_key_value("pktStatDesc", $xmlParse['data']['packet-status']);
2567  $origPktStatExtra = HCU_array_key_value("pktStatExtra", $xmlParse['data']['packet-status']);
2568 
2569  switch ($xmlParse['data']['packet-status']['pktStatCode']) {
2570  case '101':
2571  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 101 *\n");
2572  /* ** NEW DATA ** */
2573 
2574 
2575 
2576  // ** Traverse to the Inquiry Node
2577  $tableName = 'crossaccounts';
2578  $tableDef = _GetPacketColumnList($pHbEnv, $tableName);
2579  $pktInquiryNode = $dataPacket->CrossAccount;
2580  // ** set the expected node string
2581 
2582  // ** Search for the expected <node> in the packet
2583  $tblPktData = $pktInquiryNode->{HCU_array_key_value('node', $tableDef)};
2584  $convResp = _ConvertPacketLineToArray($pHbEnv, $pConnSet, $tableName, $tblPktData);
2585 
2586  if ($convResp['code'] == '000') {
2587  if (count($convResp['data']) > 0) {
2588  $packetData[$tableName] = $convResp['data'];
2589  }
2590  }
2591  $retVal['data'] = $xmlParse['data'];
2592  $retVal['data']['packet-data'] = $packetData;
2593 
2594  break;
2595  case '100':
2596  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 100 *\n");
2597  $retVal['data'] = $xmlParse['data'];
2598  break;
2599 
2600  /**
2601  * ERROR CASES
2602  *
2603  **/
2604  case '003':
2605  /* ** CLOSED ACCOUNT ** */
2606  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 003 *\n");
2607  $retVal['code'] = '003';
2608  $retVal['error'] = 'Closed Account';
2609  break;
2610  case '001':
2611  /* ** INVALID ACCOUNT NUMBER ** */
2612  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 001 *\n");
2613  $retVal['code'] = '001';
2614  $retVal['error'] = 'Invalid Account Number';
2615  break;
2616  case '999':
2617  /* ** CORE RETURN ERROR ** */
2618  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 999 *\n");
2619 
2620  $retVal['code'] = '999';
2621  $retVal['error'] = $xmlParse['data']['packet-status']['pktStatDesc'];
2622  break;
2623  case '200':
2624  case '201':
2625  case '202':
2626  default:
2627  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* DEPRECATED STATCODE *\n");
2628  /* ** DEPRECATED ** */
2629  /* ** UNKNOWN STATUS CODE ** */
2630  throw new Exception ('Unexpected Result');
2631  break;
2632  }
2633  } catch (Exception $e) {
2634  _ApplPrintLogger($pHbEnv, $pConnSet, "\n_RetrieveMemberInquiry Catch Error ({$e->getCode()}) :: {$e->getMessage()}");
2635  $retVal['code'] = '999';
2636  $retVal['error'] = "Unable to retrieve data";
2637  $cucorereqAfter["errors"][] = $e->getMessage();
2638  }
2639 
2640  _UpdateRequestStatus($pHbEnv, $pConnSet, $cucorereqAfter, $packetsize, $origPktStatCode, $origPktStatDesc, $origPktStatExtra);
2641  return $retVal;
2642 }
2643 
2644 /**
2645  * Retrieve the Member Inquiry packet from the CORE (INQ)
2646  * This is the classic standard request. I am thinking this will NOT be called by
2647  * the PLUS interface. If it is, then it should be moved to sAPIAppl.i
2648  *
2649  * @param array $pHbEnv -- The current HB_ENV setting
2650  * @param array $pConnSet -- The connection settings for the hculive API server
2651  * @param array $pReqData -- The request data to be sent to the core --
2652  * member -- Member number for
2653  * if_mod_since -- last packet stamp
2654  * ref3 -- email for inquiry request
2655  * cutoff -- cutoff date for request
2656  * pass -- **optional password
2657  *
2658  * @return array
2659  * [code]
2660  * {000, 001, 002, 003, 999}
2661  * [data]
2662  * [packet-status]
2663  * [packet-xml]
2664  * [packet-data]
2665 */
2666 function _RetrieveMemberInquiry ($pHbEnv, $pConnSet, $pReqData) {
2667 
2668  $retVal = Array("code" => '000', "data" => Array());
2669  $packetData = Array();
2670 
2671  $origPktStatCode = "";
2672  $origPktStatDesc = "";
2673  $origPktStatExtra = "";
2674  $packetsize = 0;
2675 
2676  try {
2677 
2678  $dataArray = array_merge ($pReqData, array("type" => "I"));
2679  $packetQuery = http_build_query($dataArray);
2680 
2681  _ApplPrintLogger($pHbEnv, $pConnSet, "\n** Packet Query ** \n$packetQuery\n");
2682 
2683  // ** packetQuery should look something like
2684  // * * INQUIRY member=$Cn&type=I&if_mod_since=$pktstamp&cutoff=$cutoff&ref3=$R3&lastlogin=$lastlogin
2685  // * * NEW MBR member=$Cn&type=I&if_mod_since=1&cutoff=20060101&pass=" . urlencode($pwd) . "&ref3=$R3";
2686 /*
2687  *REMOVE FOR TESTING
2688  */
2689 
2690  $sendDataResp = _SendDataRequest($pHbEnv, $pConnSet, $packetQuery);
2691  $cucorereqAfter = HCU_array_key_value("cucorereq_after", $sendDataResp);
2692 
2693 
2694  if ($sendDataResp['code'] != '000') {
2695  // ** Error -- Getting data from core... Does the detailed error matter??
2696  // ** Or can I just respond 999 -- Errors here will be communication or incomplete packet
2697  throw new Exception ('Data Request Error');
2698  }
2699 
2700 /*
2701  * end
2702 */
2703 /* TEST ONLY */
2704 /*
2705 require_once ('../../banking/scripts/hcuSamplePacket.INQ.958777.sm.txt');
2706 $sendDataResp = $testResp;
2707 print "Data test";
2708 */
2709 /* END TEST ONLY */
2710 
2711 
2712  $mbrData = Array(
2713  "type" => PACKET_REQUEST_INQUIRY,
2714  "member" => $pReqData['member']
2715  );
2716 
2717  $packetContent = HCU_array_key_value('packet', $sendDataResp);
2718  $packetsize = strlen($packetContent);
2719  $xmlParse = _ParsePacketData($pHbEnv, $pConnSet, $mbrData, $packetContent);
2720  if ($xmlParse['code'] != '000') {
2721  // ** Error Parsing -- throw error
2722  throw new Exception ("XML Parse " . $xmlParse['error'], 50060);
2723  }
2724  $dataPacket = $xmlParse['data']['packet-xml'];
2725 
2726  $origPktStatCode = HCU_array_key_value("pktStatCode", $xmlParse['data']['packet-status']);
2727  $origPktStatDesc = HCU_array_key_value("pktStatDesc", $xmlParse['data']['packet-status']);
2728  $origPktStatExtra = HCU_array_key_value("pktStatExtra", $xmlParse['data']['packet-status']);
2729 
2730 
2731  switch ($xmlParse['data']['packet-status']['pktStatCode']) {
2732  case '101':
2733  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 101 *\n");
2734  /* ** NEW DATA ** */
2735 
2736  // ** Traverse to the Inquiry Node
2737  $pktInquiryNode = $dataPacket->Inquiry;
2738  $tableList = Array("accountbalance", "loanbalance");
2739 
2740  foreach ($tableList as $tableName) {
2741  $tableDef = _GetPacketColumnList($pHbEnv, $tableName);
2742  // ** Search for the expected <node> in the packet
2743  $tblPktData = $pktInquiryNode->{HCU_array_key_value('node', $tableDef)};
2744 
2745  $convResp = _ConvertPacketLineToArray($pHbEnv, $pConnSet, $tableName, $tblPktData);
2746 
2747  if ($convResp['code'] == '000') {
2748  if (count($convResp['data']) > 0) {
2749  $packetData[$tableName] = $convResp['data'];
2750  }
2751  }
2752  }
2753  $retVal['data'] = $xmlParse['data'];
2754  $retVal['data']['packet-data'] = $packetData;
2755 
2756  break;
2757  case '100':
2758  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 100 *\n");
2759  $retVal['data'] = $xmlParse['data'];
2760  break;
2761 
2762  /**
2763  * ERROR CASES
2764  *
2765  **/
2766  case '002':
2767  /* ** INVALID PASSWORD ** */
2768  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 002 *\n");
2769  $retVal['data'] = $xmlParse['data'];
2770  $retVal['code'] = '002';
2771  $retVal['error'] = 'Invalid Password';
2772  break;
2773  case '003':
2774  /* ** CLOSED ACCOUNT ** */
2775  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 003 *\n");
2776  $retVal['data'] = $xmlParse['data'];
2777  $retVal['code'] = '003';
2778  $retVal['error'] = 'Closed Account';
2779  break;
2780  case '001':
2781  /* ** INVALID ACCOUNT NUMBER ** */
2782  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 001 *\n");
2783  $retVal['data'] = $xmlParse['data'];
2784  $retVal['code'] = '001';
2785  $retVal['error'] = 'Invalid Account Number';
2786  break;
2787  case '999':
2788  /* ** CORE RETURN ERROR ** */
2789  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* STATCODE 999 *\n");
2790 
2791  $retVal['code'] = '999';
2792  $retVal['error'] = $xmlParse['data']['packet-status']['pktStatDesc'];
2793  break;
2794  case '200':
2795  case '201':
2796  case '202':
2797  default:
2798  _ApplPrintLogger($pHbEnv, $pConnSet, "\n* DEPRECATED STATCODE *\n");
2799  /* ** DEPRECATED ** */
2800  /* ** UNKNOWN STATUS CODE ** */
2801  throw new Exception ('Unexpected Result');
2802  break;
2803  }
2804  } catch (Exception $e) {
2805  _ApplPrintLogger($pHbEnv, $pConnSet, "\n_RetrieveMemberInquiry Catch Error ({$e->getCode()}) :: {$e->getMessage()}");
2806  $retVal['code'] = '999';
2807  $retVal['error'] = "Unable to retrieve data";
2808  $cucorereqAfter["errors"][] = $e->getMessage();
2809  }
2810 
2811  _UpdateRequestStatus($pHbEnv, $pConnSet, $cucorereqAfter, $packetsize, $origPktStatCode, $origPktStatDesc, $origPktStatExtra);
2812  return $retVal;
2813 }
2814 
2815 /**
2816  *
2817  * Return the CURL default options
2818  *
2819  * tested mws 3/31/17
2820  *
2821  */
2822 function _ReturnCurlDefaults() {
2823  $retVal = Array("code" => '000', "data" => Array());
2824 
2825  try {
2826 
2827 
2828  /* Some possible options are
2829  *
2830  * CURLOPT_SSLVERSION
2831  * CURL_SSLVERSION_DEFAULT (0),
2832  * CURL_SSLVERSION_TLSv1 (1),
2833  * CURL_SSLVERSION_SSLv2 (2),
2834  * CURL_SSLVERSION_SSLv3 (3),
2835  * CURL_SSLVERSION_TLSv1_0 (4),
2836  * CURL_SSLVERSION_TLSv1_1 (5) or
2837  * CURL_SSLVERSION_TLSv1_2 (6).
2838  *
2839  *
2840  */
2841 
2842  $retVal = Array(
2843  CURLOPT_RETURNTRANSFER => 1, // The returned content will be returned by curl_exec, otherwise it goes to STDOUT
2844  CURLOPT_SSL_VERIFYHOST => 0, // Do NOT verify the Hostname.. Appliance ssl certs hostname will not match
2845  CURLOPT_SSL_VERIFYPEER => false, // This will allow self signed certficates
2846  CURLOPT_CONNECTTIMEOUT => 5, // Connection Timeout set to 5
2847  CURLOPT_TIMEOUT => 180 // Max number of seconds to allow curl func to execute
2848  );
2849 
2850  } catch (Exception $e) {
2851  // * ON ERROR -- RETURN EMPTY ARRAY
2852  $retVal = Array();
2853  }
2854 
2855  return $retVal;
2856 }
2857 
2858 
2859 
2860 /**
2861  * Get the HomeCU Appliance Settings
2862  *
2863  * This will return the settings needed to create a packet and to parse the data
2864  *
2865  */
2866 
2867 /**
2868  * Get the connection settings for the credit union specified
2869  *
2870  * @param array $pHbEnv -- This is the current HB_ENV array. values needed are
2871  * dbh - database handle
2872  * Cu - Credit union code
2873  *
2874  * @return array {code, data}
2875  * data => array (
2876  * 'liveserver'
2877  * 'liveport'
2878  * 'livewait'
2879  * 'retrylimit'
2880  * 'gracelimit'
2881  * 'flagset'
2882  * 'flagset2'
2883  * 'flagset3'
2884  * 'offlinestat'
2885  * 'offlineblurb'
2886  *
2887  * mws tested 3/31/2017
2888  * ** Fail if no dbh
2889  * ** Fail if no record
2890  * ** Fail if no cu passed
2891  */
2892 function _ReturnCUSettings ($pHbEnv) {
2893 
2894  $retVal = array("code"=>"000", "data"=>Array());
2895 
2896  $lDbh = HCU_array_key_value('dbh', $pHbEnv);
2897  try {
2898 
2899  /* Verify CU Set */
2900  $lCu = HCU_array_key_value('Cu', $pHbEnv);
2901  if ($lCu == '') {
2902  throw new Exception ('Credit Union Not Set');
2903  }
2904  if (db_connection_status($lDbh) === PGSQL_CONNECTION_OK) {
2905  $sql = "SELECT liveserver, liveport, livewait, retrylimit,
2906  gracelimit, flagset, flagset2, flagset3, histdays,
2907  offlinestat, offlineblurb, ahdropdays, lhdropdays
2908  FROM cuadmin
2909  WHERE cu = '" . prep_save($lCu, 10) . "'; ";
2910  $settingsRs = db_query($sql, $lDbh);
2911  if ($settingsRs && db_num_rows($settingsRs) > 0) {
2912  $settingsRow = db_fetch_assoc($settingsRs);
2913 
2914  /*
2915  * * SET MINIMUMS *
2916  */
2917  $settingsRow['retrylimit'] = (intval($settingsRow['retrylimit']) <= 0 ? 5 : $settingsRow['retrylimit']);
2918  $settingsRow['gracelimit'] = (intval($settingsRow['gracelimit']) <= 0 ? 5 : $settingsRow['gracelimit']);
2919  $settingsRow['livewait'] = (intval($settingsRow['livewait']) <= 0 ? 300 : $settingsRow['livewait']);
2920  $settingsRow['histdays'] = (intval($settingsRow['histdays']) <= 0 ? 33 : $settingsRow['histdays']);
2921 
2922  $debugMode = false;
2923 
2924  if (HCU_array_key_exists("SYSENV", $pHbEnv)) {
2925  $debugMode = HCU_array_key_value("devmode", $pHbEnv['SYSENV']);
2926  }
2927  $settingsRow['debugMode'] = $debugMode;
2928 
2929 
2930  $retVal['data'] = $settingsRow;
2931 
2932 
2933  } else {
2934  throw new Exception ('Database Request Error');
2935  }
2936 
2937  } else {
2938  throw new Exception ('Database Not Connected');
2939  }
2940  } catch (Exception $e ) {
2941  $retVal['code'] = '999';
2942  $retVal['error'] = Array($e->getMessage());
2943  }
2944 
2945  return $retVal;
2946 
2947 }
2948 
2949 /**
2950  * Get the cutoff date for the packet
2951  * As of 4/6/17 this will return
2952  * 20060101 for fetching data for a new member
2953  * 20000101 for fetching data normally
2954  * @param array $pCuSet - Credit Union Settings
2955  * uses:
2956  * ahdropdays - Account History Drop days
2957  * lhdropdays - Loan History drop days
2958  * livewait - The wait time for fetching a packet from the core
2959  * histdays - settings for history days to fetch for a packet
2960  * @param array $pPktStamps - This is an array for the packet stamp information
2961  * {laststamp} - This is the last packet stamp for the data
2962  * {lastattempt} - this is the last attempt we tried to make to the core
2963  * @param string - $pPktType - This is the packet type One of "PACKET_REQUEST" Constants
2964  *
2965  * @return string
2966  *
2967  */
2968 function _ReturnCutoffDate($pCuSet, $pPktStamps, $pPktType) {
2969  $cuAcctDropDays = HCU_array_key_value('ahdropdays', $pCuSet);
2970  $cuLoanDropDays = HCU_array_key_value('lhdropdays', $pCuSet);
2971  $cuPktHistDays = intval(HCU_array_key_value('histdays', $pCuSet));
2972  $cuWaitSeconds = intval(HCU_array_key_value('livewait', $pCuSet));
2973 
2974  /*
2975  * Determine the DEFAULT MAX number of days for retrieving data -- 4/7/17 -- used later when we get granular requests
2976  * Odyssey -- use the Max of accounthistory / loanhistory drop days.
2977  * -- If both are 0 then use 366 -- going back too far can take an exceptional amount of time
2978  * -- These fields can also accept the value 'HOLD' as of this coding 4/4/17. No Cu's make use
2979  * -- of this option
2980  */
2981  $cutoffHistDays = max(($cuAcctDropDays == 'HOLD' ? 0 : $cuAcctDropDays), ($cuLoanDropDays == 'HOLD' ? 0 : $cuLoanDropDays), PACKET_DEFAULT_CUTOFF_DAYS);
2982  // Epoch in seconds - (days * seconds in day)
2983  $cutoffHist = date('Ymd', date('U') - ($cutoffHistDays * PACKET_SECONDS_DAY));
2984  /*
2985  * SET THE RETURN DEFAULT PACKET DAYS -- DEPENDS on pPktType
2986  *
2987  * For PACKET_REQUEST_INQUIRY - This will be 20000101
2988  * For PACKET_REQUEST_VERIFY_PIN - This will be 20060101
2989  * For Others -- ONLY go back the max number of days for History Drop Off
2990  *
2991  */
2992  $retCutoffDate = ($pPktType == PACKET_REQUEST_VERIFY_PIN ? PACKET_DEFAULT_NEW_CUTOFF : ($pPktType == PACKET_REQUEST_INQUIRY ? PACKET_DEFAULT_INQ_CUTOFF : $cutoffHist));
2993  $lastPacketStamp = intval(HCU_array_key_value('laststamp', $pPktStamps));
2994  $lastPacketAttempt = intval(HCU_array_key_value('lastattempt', $pPktStamps));
2995  /*
2996  * if the last packet is newer than Default Cutoff data and history days is set
2997  * calculate a newer cutoff to reduce the packet size
2998  */
2999  if ($lastPacketStamp > date('U', strtotime($retCutoffDate)) && $cuPktHistDays > 0 ) {
3000 
3001  /*
3002  * If the last packet was fairly recent, only fetch 7 days (PACKET_SECONDS_DAY)
3003  * "recent" defined as 3 times the packet "livewait" setting
3004  */
3005 
3006  $calcMinTime = time() - (3 * $cuWaitSeconds);
3007  if ($lastPacketStamp > $calcMinTime) {
3008  $retCutoffDate = date("Ymd", time() - (PACKET_SECONDS_DAY * PACKET_MIN_FETCH_DAYS));
3009  } else {
3010  $retCutoffDate = date("Ymd",$lastPacketStamp - (PACKET_SECONDS_DAY * $cuPktHistDays));
3011  }
3012  }
3013 
3014  return $retCutoffDate;
3015 }
3016 
3017 /**
3018  * Function to print information to the logger if debugMode is enabled
3019  *
3020  * @param array $pHbEnv -- This is the current HB_ENV settings
3021  * [SYSENV][logger]
3022  * @param array $pConnSet -- This is the current connection settings
3023  * [debugMode]
3024  * @param string $pText -- The value to print to the logger screen
3025  *
3026  * @return null
3027  */
3028 function _ApplPrintLogger($pHbEnv, $pConnSet, $pText, $error=False) {
3029 
3030  // error messages that needs to be logged to Kibana
3031  if ($error) {
3032  if (HCU_array_key_value('logger', $pHbEnv['SYSENV'])) {
3033  $logger = HCU_array_key_value('logger', $pHbEnv['SYSENV']);
3034  $logger->error($pText);
3035  }
3036  } else { // only debugging messages
3037  //Remove any new lines from the text
3038  $pText = "<appl-logger><line>" . str_replace("\n" , " </line><line> ", $pText) . "</line></appl-logger>";
3039  if (HCU_array_key_value('debugMode', $pConnSet)) {
3040  if (HCU_array_key_value('logger', $pHbEnv['SYSENV'])) {
3041  // ** Print information to the logger -- info
3042  $logger = HCU_array_key_value('logger', $pHbEnv['SYSENV']);
3043  $logger->debug($pText);
3044  }
3045  }
3046  }
3047 }
3048 
3049 /**
3050  * Function to determine if we should check out-of-sync for packet
3051  * This will check the status code for the particular request type
3052  * sync member will only be done for successful status codes
3053  * It's possible some types may not do this
3054  *
3055  * @param integer $pPacketType -- One of the PACKET_REQUEST_{CONSTANTS}
3056  * @param string $pPacketStatusCode -- The status code returned from the core
3057  *
3058  * @return boolean {true, false}
3059  *
3060  */
3061 function _CheckSyncMember($pPacketType, $pPacketStatusCode) {
3062  $retVal = false;
3063 
3064  switch ($pPacketType) {
3065  case PACKET_REQUEST_VERIFY_PIN:
3066  case PACKET_REQUEST_INQUIRY:
3067  case PACKET_REQUEST_BAL:
3068  case PACKET_REQUEST_HIS:
3069  case PACKET_REQUEST_XAC:
3070  case PACKET_REQUEST_TRN:
3071  case PACKET_REQUEST_MIR:
3072  if (in_array($pPacketStatusCode, array('101'))) {
3073  $retVal = true;
3074  }
3075  break;
3076  }
3077 
3078  return $retVal;
3079 }
3080 
3081 /**
3082  * Function to return the name of the primary node that is determined by the request
3083  *
3084  * @param integer $pPacketType -- One of the PACKET_REQUEST_{CONSTANTS}
3085  *
3086  * @return boolean {true, false}
3087  */
3088 function _GetRequestNodeName($pPacketType) {
3089  $retVal = '';
3090 
3091  switch ($pPacketType) {
3092  case PACKET_REQUEST_VERIFY_PIN:
3093  case PACKET_REQUEST_INQUIRY:
3094  $retVal = "Inquiry";
3095  break;
3096  case PACKET_REQUEST_BAL:
3097  case PACKET_REQUEST_HIS:
3098  break;
3099  case PACKET_REQUEST_XAC:
3100  $retVal = "CrossAccount";
3101  break;
3102  case PACKET_REQUEST_TRN:
3103  case PACKET_REQUEST_MIR:
3104  $retVal = "MemberInfo";
3105  break;
3106  case PACKET_REQUEST_ES:
3107  $retVal = "EStatement";
3108  break;
3109  case PACKET_REQUEST_ES_TOC:
3110  $retVal = "EStatementTOC";
3111  break;
3112  }
3113 
3114  return $retVal;
3115 }
3116 
3117 
3118 /**
3119  * Return the deposit / loan balance array templates.
3120  * These templates are used for returning columns for VerifyMemberPin and FindMemberAccounts
3121  *
3122  * @return array
3123  *
3124  */
3125 function GetBalanceTemplates() {
3126  return Array(
3127  "deposit" => Array(
3128  "inquiry-key" => "accountbalance",
3129  "field-list" => Array(
3130  "accountnumber",
3131  "accounttype",
3132  "certnumber",
3133  "deposittype",
3134  "description",
3135  "may_deposit",
3136  "may_withdraw",
3137  "available"
3138  )
3139  ),
3140  "loan" => Array(
3141  "inquiry-key" => "loanbalance",
3142  "field-list" => Array(
3143  "accountnumber",
3144  "loannumber",
3145  "description",
3146  "may_payment",
3147  "may_addon"
3148  )
3149  )
3150  );
3151 }