Odyssey
aAdminSettings.i
1 <?php
2 /**
3  * Reply:
4  * @uses return data to client view print to json
5  * @param assoc $pResult: array contining results of search
6  * @param assoc $pReply: empty array to return to client
7  * @param assoc $pOperation: requested search operation
8  */
9 function AdminSettingsReplay($pResult, $pReply, $pOperation) {
10  $pReply['operation'] = $pOperation;
11  isset($pResult['data']) && count($pResult['data']) ? $pReply['data'] = $pResult['data'] : null;
12  isset($pResult['info']) && count($pResult['info']) ? $pReply['info'] = $pResult['info'] : null;
13 
14  print HCU_JsonEncode(array("Results" => $pReply));
15 }
16 
17 /**
18  * AdminUpdateSettings
19  * @uses return updated banking settings
20  * @param assoc $pEnv: environment values
21  * @param assoc $pDbh: database access
22  * @param string $pCu: credit union code
23  * @param json $pSettings: values for update
24  *
25  * @return updated banking settings
26  */
27 function AdminUpdateSettings($pEnv, $pDbh, $pCu, $pSettings) {
28  $sqlRouting = HCU_array_key_value("routing", $pSettings);
29  $sqlSettings = HCU_array_key_value("settings", $pSettings);
30 
31 
32  $setPart = array();
33 
34  // Ensure that changing attributes in the JSON will not remove data. (In the case of changing Auto Enroll so that it doesn't remove ACH attributes.)
35  $sqlPart = "'$sqlSettings'::jsonb";
36  $sqlSettings === false ? null : $setPart[] = "settings = CASE WHEN settings IS NULL or trim(settings) = '' THEN $sqlPart ELSE settings::jsonb || $sqlPart END";
37 
38  // Routing number is not updated when updating Auto Enrollment.
39  $sqlRouting === false ? null : $setPart[] = "rt = $sqlRouting";
40 
41  if (count($setPart) == 0) {
42  throw new Exception("Failed to update credit union settings");
43  }
44  $setPart = "SET " . implode(", ", $setPart);
45 
46  $sqlReturn = array();
47  $sql = "
48  UPDATE cuadmin
49  $setPart
50  WHERE cu = '{$pCu}'
51  RETURNING
52  TRIM(rt) AS routing,
53  settings::json->>'name' AS name,
54  settings::json->>'account' AS account,
55  settings::json->>'sub_account_mask' AS sub_account_mask,
56  settings::json->>'offsetting' AS offsetting,
57  settings::json->>'cutoff' AS cutoff,
58  settings::json->>'profile' AS profile,
59  settings::json->>'achnotify' AS notify,
60  settings::json->>'type' AS type";
61 
62  $sqlRs = db_query($sql, $pDbh);
63  if (!$sqlRs) {
64  throw new Exception("Failed to update credit union settings");
65  }
66 
67  $sqlData = db_fetch_assoc($sqlRs);
68  $sqlReturn['settings'] = array(
69  "routing" => $sqlData['routing'],
70  "name" => $sqlData['name'] === "null" ? null : $sqlData['name'],
71  "account" => $sqlData['account'] === "null" ? null : $sqlData['account'],
72  "sub_account_mask" => $sqlData['sub_account_mask'] === "null" ? null : $sqlData['sub_account_mask'],
73  "offsetting" => $sqlData['offsetting'] === "null" ? 0 : $sqlData['offsetting'],
74  "cutoff" => $sqlData['cutoff'] === "null" ? null : $sqlData['cutoff'],
75  "profile" => $sqlData['profile'] === "null" ? null : $sqlData['profile'],
76  "notify" => $sqlData['notify'] === "null" ? null : $sqlData['notify'],
77  "type" => $sqlData['type'] === "null" ? null : $sqlData['type']
78  );
79  $sqlReturn['message'] = "Settings updated successfully";
80  return $sqlReturn;
81 }
82 
83 /**
84  * AdminReadSettings
85  * @uses return banking settings
86  * @param assoc $pEnv: environment values
87  * @param assoc $pDbh: database access
88  * @param string $pCu: credit union code
89  *
90  * @return current banking settings for this credit union
91  */
92 function AdminReadSettings($pEnv, $pDbh, $pCu) {
93  $sqlReturn = array();
94  $sql = "
95  SELECT
96  TRIM(a.rt) AS routing,
97  a.settings::json->>'name' AS name,
98  a.settings::json->>'account' AS account,
99  a.settings::json->>'sub_account_mask' AS sub_account_mask,
100  a.settings::json->>'offsetting' AS offsetting,
101  a.settings::json->>'cutoff' AS cutoff,
102  a.settings::json->>'profile' AS profile,
103  a.settings::json->>'achnotify' AS notify,
104  a.settings::json->>'type' AS type
105  FROM cuadmin a
106  WHERE cu = '{$pCu}'";
107  $sqlRs = db_query($sql, $pDbh);
108  if (!$sqlRs) {
109  throw new Exception("Failed to read credit union settings");
110  }
111 
112  $sqlData = db_fetch_assoc($sqlRs);
113  $sqlReturn['settings'] = array(
114  "routing" => $sqlData['routing'],
115  "name" => $sqlData['name'] === "null" ? null : $sqlData['name'],
116  "account" => $sqlData['account'] === "null" ? null : $sqlData['account'],
117  "sub_account_mask" => $sqlData['sub_account_mask'] === "null" ? null : $sqlData['sub_account_mask'],
118  "offsetting" => $sqlData['offsetting'] === "null" ? 0 : $sqlData['offsetting'],
119  "cutoff" => $sqlData['cutoff'] === "null" ? null : $sqlData['cutoff'],
120  "profile" => $sqlData['profile'] === "null" ? null : $sqlData['profile'],
121  "notify" => $sqlData['notify'] === "null" ? null : $sqlData['notify']
122  );
123 
124  // The Company ID Type should always default to 9 no matter what
125  if (isset($sqlData['type']) && $sqlData['type'] == 1) {
126  $sqlReturn['settings']['type'] = "1";
127  } else if (isset($sqlData['type']) && $sqlData['type'] == " ") {
128  $sqlReturn['settings']['type'] = " ";
129  } else {
130  $sqlReturn['settings']['type'] = "9";
131  }
132 
133  return $sqlReturn;
134 }
135 
136 /**
137  * AdminReadProfiles
138  * @uses return list of profiles configured for this cu
139  * @param assoc $pEnv: environment values
140  * @param assoc $pDbh: database access
141  * @param string $pCu: credit union code
142  *
143  * @return list of profiles configured for this cu
144  */
145 function AdminReadProfiles($pEnv, $pDbh, $pCu) {
146  $sqlReturn = array();
147  $sql = "
148  SELECT
149  TRIM(profile_code) AS code,
150  TRIM(description) AS description
151  FROM cu_profile
152  WHERE cu = '{$pCu}'";
153  $sqlRs = db_query($sql, $pDbh);
154  if (!$sqlRs) {
155  throw new Exception("Failed to read credit union profiles");
156  }
157 
158  $sqlReturn['profiles'] = db_fetch_all($sqlRs);
159  return $sqlReturn;
160 }
161 
162 /**
163  * ValidateACHSettings
164  * @uses return data valid for input into the database
165  * @param assoc $pEnv: environment values
166  * @param json $pSettings: values for update
167  *
168  * @return validated values ready for input into database
169  */
170 function ValidateACHSettings($pEnv, $pSettings, $pJson = false) {
171  $aValidate = array();
172  $aSettings = array();
173  $aJsonSettings = array();
174 
175  if ($pSettings === null) {
176  throw new Exception("Settings not found");
177  }
178 
179  // data can come as array or json
180  if ($pJson) {
181  $aSettings = trim($pSettings);
182  $aSettings = html_entity_decode($aSettings);
183  $aSettings = HCU_JsonDecode($aSettings);
184  } else {
185  $aSettings = $pSettings;
186  }
187 
188  // check for correct format
189  if (!is_array($aSettings)) {
190  throw new Exception("Settings data is invalid");
191  }
192 
193  // check name field
194  if (isset($aSettings['name'])) {
195  $aName = trim($aSettings['name']);
196  $aName = prep_save($aName, 100);
197 
198  $aJsonSettings['name'] = $aName;
199  } else {
200  throw new Exception("Credit union name is missing");
201  }
202 
203  // check account number
204  if (isset($aSettings['account'])) {
205  $aAccount = trim($aSettings['account']);
206  $aAccount = prep_save($aAccount, 12);
207 
208  if (strlen($aAccount) > 12) {
209  throw new Exception("ACH GL Account can only contain up to 12 digits");
210  }
211 
212  $aJsonSettings['account'] = $aAccount;
213  } else {
214  throw new Exception("ACH GL Account is missing");
215 
216  }
217 
218  // check sub-account number mask
219  if (isset($aSettings['sub_account_mask'])) {
220  $aSubAccountMask = trim($aSettings['sub_account_mask']);
221  $aSubAccountMask = prep_save($aSubAccountMask, 16);
222 
223  if (strlen($aSubAccountMask) > 16) {
224  throw new Exception("Sub-account mask can only contain up to 16 characters");
225  }
226  if (!preg_match('/^0*$/', $aSubAccountMask)) {
227  throw new Exception("Sub-account mask can only contain '0' characters");
228  }
229 
230  $aJsonSettings['sub_account_mask'] = $aSubAccountMask;
231  }
232 
233  // check the "offsetting" checked status
234  if (isset($aSettings['offsetting'])) {
235  $aOffset = $aSettings['offsetting'] == 0 ? 0 : 1;
236 
237  $aJsonSettings['offsetting'] = $aOffset;
238  } else {
239  throw new Exception("Micro deposit offsetting entry choice missing");
240  }
241 
242  // check routing number
243  if (isset($aSettings['routing'])) {
244  $aRouting = trim($aSettings['routing']);
245  $aRouting = prep_save($aRouting, 9);
246 
247  if (strlen($aRouting) < 9 || strlen($aRouting) > 9) {
248  throw new Exception("Routing number must be 9 digits");
249  }
250 
251  $aValidate['validate']['routing'] = $aRouting;
252  } else {
253  throw new Exception("Routing number is missing");
254  }
255 
256  // check cutoff time
257  if (isset($aSettings['cutoff'])) {
258  $aTime = trim($aSettings['cutoff']);
259  $aTime = prep_save($aTime, 4);
260  if (strlen($aTime) === 3) {
261  $aTime = "0" . $aTime;
262  }
263 
264  $aJsonSettings['cutoff'] = $aTime;
265  } else {
266  throw new Exception("Cutoff time is missing");
267  }
268 
269  // check the company ID type
270  if (isset($aSettings['type'])) {
271  $aType = $aSettings['type'];
272 
273  if ($aType != "9" && $aType != "1" && $aType != " ") {
274  throw new Exception("Company ID Type is an incorrect value.");
275  }
276 
277  $aJsonSettings['type'] = $aType;
278  } else {
279  throw new Exception("Company ID Type is missing");
280  }
281 
282  // check notification
283  if (isset($aSettings['notify'])) {
284  $aNotify = trim($aSettings['notify']);
285  $aNotify = prep_save($aNotify);
286 
287  // Validate for correct keywords:
288  // company, transactiontype, amount, date,
289  // accountname, routing, accountnumber or accounttype.
290  $allowedKeywords = array('company', 'transactiontype', 'amount', 'date', 'accountname', 'routing', 'accountnumber', 'accounttype');
291  $notAllowed = "";
292 
293  // This will output an array with 2 arrays inside
294  // 1. The list of search patterns found e.g. "{{keywords}}"
295  // 2. Ths list of values from the search patterns found e.g. "keywords"
296  preg_match_all("/\{{2}(.*?)\}{2}/i", $aNotify, $foundKeywords);
297  $keywordPatterns = $foundKeywords[0];
298  $keywordValues = $foundKeywords[1];
299  foreach ($keywordValues as $key => $value) {
300  if (!in_array($value, $allowedKeywords)) {
301  // Append non-allowed keywords for error message
302  // We will display all incorrect keywords at one time.
303 
304  // If the user for some reason doesn't add closing }} to
305  // the keyword they enter, the regex above will pick up
306  // the entire string until it finds closing }} if any exist
307  // which could get quite large in the error popup tab on screen.
308 
309  // This code will truncate the string to only a single token.
310  $tokens = explode(' ', $keywordPatterns[$key]);
311  $token = $tokens[0];
312 
313  // Because the return function to the client JSON encodes
314  // the return data, we cannot use new line or tab characters.
315 
316  // The error popup tab uses a list to display multiple errors
317  // this will take advantage.
318  $notAllowed .= "<li>$token</li>";
319  }
320  }
321 
322  // Any non-allowed keywords, throw error displaying
323  // all that were found.
324  if (strlen($notAllowed) > 0) {
325  $error = "The Email Notification template contains one or more invalid keywords:";
326  $error .= $notAllowed;
327  throw new Exception($error);
328  }
329 
330  $aJsonSettings['achnotify'] = $aNotify;
331  }
332 
333  // encode setting minus routing number
334  // into json string
335  $aJsonSettings = HCU_JsonEncode($aJsonSettings);
336  $aJsonSettings = trim($aJsonSettings);
337 
338  if ($aJsonSettings === "") {
339  throw new Exception("Admin settings are missing");
340  }
341 
342  $aValidate['validate']['settings'] = $aJsonSettings;
343  return $aValidate;
344 }
345 
346 /**
347  * ValidateAutoSettings
348  * @uses return data valid for input into the database
349  * @param assoc $pEnv: environment values
350  * @param json $pSettings: values for update
351  *
352  * @return validated values ready for input into database
353  */
354 function ValidateAutoSettings($pEnv, $pSettings, $pJson = false) {
355  $aValidate = array();
356  $aSettings = array();
357  $aJsonSettings = array();
358 
359  if ($pSettings === null) {
360  throw new Exception("Settings not found");
361  }
362 
363  // data can come as array or json
364  if ($pJson) {
365  $aSettings = trim($pSettings);
366  $aSettings = html_entity_decode($aSettings);
367  $aSettings = HCU_JsonDecode($aSettings);
368  } else {
369  $aSettings = $pSettings;
370  }
371 
372  // check for correct format
373  if (!is_array($aSettings)) {
374  throw new Exception("Settings data is invalid");
375  }
376 
377  // check the profile
378  if (isset($aSettings['profile'])) {
379  $aProfile = trim($aSettings['profile']);
380  $aProfile = strtoupper($aProfile);
381  $aProfile = prep_save($aProfile, 20);
382 
383  $aJsonSettings['profile'] = $aProfile;
384  } else {
385  throw new Exception("Default profile is missing");
386  }
387 
388  // encode setting minus routing number
389  // into json string
390  $aJsonSettings = HCU_JsonEncode($aJsonSettings);
391  $aJsonSettings = trim($aJsonSettings);
392 
393  if ($aJsonSettings === "") {
394  throw new Exception("Admin settings are missing");
395  }
396 
397  $aValidate['validate']['settings'] = $aJsonSettings;
398  return $aValidate;
399 }