Odyssey
aGroupRights.prg
1 <?php
2 /**
3  * @package GroupHub
4  * @author MGHandy
5  *
6  * @uses This script will allow for the printing of the javascript/html components needed
7  * to open and use the group rights window.
8  *
9  * @uses Change profile: this script facilitates the need to change which profile a group belongs to. Upon changin a profile the group rights will be completely reset the groups rights to default. the admin will be warned if and users have different user rights from the new profile.
10  *
11  * @uses View profile rights: a popup can be shown fr the admin to view the profiles current rights.
12  *
13  * @uses Update group rights: set options, quantities and amounts for any features available to the group.
14  */
15 require_once("$admLibrary/aGroupSupport.i");
16 
17 try {
18  $admVars = array();
19  $admOk = array(
20  "operation" => array("filter" => FILTER_SANITIZE_STRING),
21  "payload" => array("filter" => FILTER_SANITIZE_STRING),
22  "gList" => array("filter" => FILTER_SANITIZE_STRING),
23  "gProfile" => array('filter' => FILTER_SANITIZE_STRING)
24  );
25  HCU_ImportVars($admVars, "GROUP_RIGHTS", $admOk);
26 
27  $rOperation = isset($admVars["GROUP_RIGHTS"]["operation"]) ? $admVars["GROUP_RIGHTS"]["operation"] : null;
28  $rPayload = isset($admVars["GROUP_RIGHTS"]["payload"]) ? $admVars["GROUP_RIGHTS"]["payload"] : null;
29  $rList = isset($admVars["GROUP_RIGHTS"]["gList"]) ? $admVars["GROUP_RIGHTS"]["gList"] : null;
30  $rProfile = isset($admVars["GROUP_RIGHTS"]["gProfile"]) ? $admVars["GROUP_RIGHTS"]["gProfile"] : null;
31 
32  $rGroup = $rPayload ?
33  GroupDecrypt($SYSENV, $Cu, $rPayload) :
34  null;
35 
36  $rContext = $rPayload ?
37  GroupContext($SYSENV, $Cu, $rGroup['group']) :
38  GroupContext($SYSENV, $Cu);
39 
40  $aryResult = array();
41  $aryReply = array();
42 
43  switch ($rOperation) {
44  case "":
45  PrintCardContent();
46  break;
47  case "readGroupRights":
48  header('Content-type: application/json');
49 
50  $gRights = ReadGroupRights($SYSENV, $dbh, $rContext);
51  $gProfiles = ReadProfiles($SYSENV, $dbh, $rContext);
52  $aryResult['data']['gRights'] = $gRights['rights'];
53  $aryResult['data']['gProfiles'] = $gProfiles['profiles'];
54  GroupReply($aryResult, $aryReply, $rOperation);
55  break;
56  case "readProfileRights":
57  header('Content-type: application/json');
58 
59  $pRights = ReadProfileRights($SYSENV, $dbh, $rContext);
60  $aryResult['data']['pRights'] = $pRights['rights'];
61  GroupReply($aryResult, $aryReply, $rOperation);
62  break;
63  case "updateGroupRights":
64  header('Content-type: application/json');
65 
66  $gValidate = ValidateGroupRights($SYSENV, $rContext, $rList);
67  $gCreate = CreateGroupRights($SYSENV, $dbh, $rContext, $gValidate['create']);
68  $gUpdate = UpdateGroupRights($SYSENV, $dbh, $rContext, $gValidate['update']);
69  $gDelete = DeleteGroupRights($SYSENV, $dbh, $rContext, $gValidate['delete']);
70  $aryResult['info'] = "Features have been updated successfully.";
71  $aryResult['data']['create'] = isset($gCreate['rights']) ? $gCreate['rights'] : $gCreate;
72  $aryResult['data']['update'] = isset($gUpdate['rights']) ? $gUpdate['rights'] : $gUpdate;
73  $aryResult['data']['delete'] = isset($gDelete['rights']) ? $gDelete['rights'] : $gDelete;
74  GroupReply($aryResult, $aryReply, $rOperation);
75  break;
76  case "updateGroupProfile":
77  header('Content-type: application/json');
78 
79  $gProfile = UpdateGroupProfile($SYSENV, $dbh, $rContext, $rProfile);
80  // update group
81  $rGroup['group']['p_id'] = $gProfile['profile']['id'];
82  $rGroup['group']['g_profile'] = $gProfile['profile']['name'];
83 
84  // update context
85  // read group rights for new profile
86  $rContext = GroupContext($SYSENV, $Cu, $rGroup['group']);
87  $gRights = ReadGroupRights($SYSENV, $dbh, $rContext);
88 
89  $aryResult['data']['rights'] = $gRights['rights'];
90  $aryResult['data']['group'] = $rGroup;
91  $aryResult['data']['encrypt'] = GroupEncrypt($SYSENV, $Cu, $rGroup);
92  $aryResult['info'] = $gProfile['message'];
93  GroupReply($aryResult, $aryReply, $rOperation);
94  break;
95  }
96 
97 } catch (Exception $e) {
98  $aryReply['errors'][] = $e->getMessage();
99  $aryResult['data'] = array();
100  $aryResult['info'] = array();
101 
102  GroupReply($aryResult, $aryReply, $rOperation);
103 }
104 
105 
106 /**
107  * ValidateGroupRights:
108  * @uses this function validates the incoing update information.
109  * @param $pEnv array : environment variable for debugging
110  * @param $pContext array : context variable holding decrypted data for update functions
111  * @param $pList json : list of all group features being updated, this will result in one array for creating features, one for updating features, and one for deleting features. Each array will be sent to it's corresponding update function.
112  *
113  * @return $vList array : associative array of the features to be created, updated or deleted
114  */
115 function ValidateGroupRights($pEnv, $pContext, $pList) {
116  $gId = $pContext['g_id'];
117  $pId = $pContext['p_id'];
118 
119  $hList = html_entity_decode($pList);
120  $jList = json_decode($hList, true);
121 
122  $vListCreate = array();
123  $vListUpdate = array();
124  $vListDelete = array();
125  $vList = array();
126 
127  // SET UP ARRAY FOR CREATE
128  foreach ($jList['create'] as $row => $value) {
129  $vListCreate[] = array(
130  "_action" => "create",
131  "group_id" => intval($gId),
132  "feature_code" => prep_save($value['fCode'], 10),
133  "amount_per_transaction" => $value['gApt'] == null ? "NULL" : floatval($value['gApt']),
134  "amount_per_day" => $value['gApd'] == null ? "NULL" : floatval($value['gApd']),
135  "amount_per_month" => $value['gApm'] == null ? "NULL" : floatval($value['gApm']),
136  "amount_per_account_per_day" => $value['gApa'] == null ? "NULL" : floatval($value['gApa']),
137  "count_per_day" => $value['gCpd'] == null ? "NULL" : intval($value['gCpd']),
138  "count_per_month" => $value['gCpm'] == null ? "NULL" : intval($value['gCpm']),
139  "count_per_account_per_day" => $value['gCpa'] == null ? "NULL" : intval($value['gCpa']),
140  "confirm_required" => boolval($value['gCfm']) == 1 ? "TRUE" : "FALSE"
141  );
142  }
143 
144  // SET UP ARRAY FOR UPDATE
145  foreach ($jList['update'] as $row => $value) {
146  $vListUpdate[] = array(
147  "_action" => "update",
148  "group_id" => intval($gId),
149  "feature_code" => prep_save($value['fCode'], 10),
150  "amount_per_transaction" => $value['gApt'] == null ? "NULL" : floatval($value['gApt']),
151  "amount_per_day" => $value['gApd'] == null ? "NULL" : floatval($value['gApd']),
152  "amount_per_month" => $value['gApm'] == null ? "NULL" : floatval($value['gApm']),
153  "amount_per_account_per_day" => $value['gApa'] == null ? "NULL" : floatval($value['gApa']),
154  "count_per_day" => $value['gCpd'] == null ? "NULL" : intval($value['gCpd']),
155  "count_per_month" => $value['gCpm'] == null ? "NULL" : intval($value['gCpm']),
156  "count_per_account_per_day" => $value['gCpa'] == null ? "NULL" : intval($value['gCpa']),
157  "confirm_required" => boolval($value['gCfm']) == 1 ? "TRUE" : "FALSE"
158  );
159  }
160 
161  // SET UP ARRAY FOR DELETE
162  foreach ($jList['delete'] as $row => $value) {
163  $vListDelete[] = array(
164  "_action" => "delete",
165  "group_id" => intval($gId),
166  "feature_code" => prep_save($value['fCode'], 10)
167  );
168  }
169 
170  $vList['create'] = $vListCreate;
171  $vList['update'] = $vListUpdate;
172  $vList['delete'] = $vListDelete;
173 
174  return $vList;
175 }
176 
177 /**
178  * CreatreGroupRights
179  * @uses this function is used to create features rights that don't yet exist for a group.
180  *
181  * @param $pEnv array : environment variable for debugging
182  * @param $pDbh object : databse object, used for queries
183  * @param $pContext array : context variable holding decrypted data for update functions
184  * @param $pList array : list of feature to be added to the group rights table
185  *
186  * @return $sqlReturn array : array of successfully created data/success messages
187  */
188 function CreateGroupRights($pEnv, $pDbh, $pContext, $pList) {
189  if (count($pList) == 0) { return array(); }
190 
191  $gId = $pContext['g_id'];
192  $pId = $pContext['p_id'];
193  $cuTable = $pContext['cu_table'];
194  $cuCode = $pContext['cu_code'];
195 
196  $sqlReturn = array();
197  $sqlCreate = "";
198  $sqlColumns = "
199  group_id,
200  feature_code,
201  amount_per_transaction,
202  amount_per_account_per_day,
203  amount_per_day,
204  amount_per_month,
205  count_per_account_per_day,
206  count_per_day,
207  count_per_month,
208  confirm_required";
209 
210  foreach ($pList as $key => $value) {
211  $sqlValues = "";
212  $sqlValues .= $value['group_id'] . ",";
213  $sqlValues .= "'" . $value['feature_code'] . "',";
214  $sqlValues .= $value['amount_per_transaction'] . ",";
215  $sqlValues .= $value['amount_per_account_per_day'] . ",";
216  $sqlValues .= $value['amount_per_day'] . ",";
217  $sqlValues .= $value['amount_per_month'] . ",";
218  $sqlValues .= $value['count_per_account_per_day'] . ",";
219  $sqlValues .= $value['count_per_day'] . ",";
220  $sqlValues .= $value['count_per_month'] . ",";
221  $sqlValues .= $value['confirm_required'];
222 
223  $sqlCreate .= "INSERT INTO {$cuTable}grouprights
224  ($sqlColumns) VALUES ($sqlValues);";
225 
226  $sqlReturn['rights'][] = $value['feature_code'];
227  }
228 
229  $sqlCreateRs = db_query($sqlCreate, $pDbh);
230  if (!$sqlCreateRs) {
231  $pEnv['logger']->error(db_last_error());
232  throw new Exception("Failed to create group rights");
233  }
234 
235  return $sqlReturn;
236 }
237 
238 /**
239  * UpdateGroupRights
240  * @uses this function is used to update features rights that currently exist for a group.
241  *
242  * @param $pEnv array : environment variable for debugging
243  * @param $pDbh object : databse object, used for queries
244  * @param $pContext array : context variable holding decrypted data for update functions
245  * @param $pList array : list of feature to be updated in the group rights table
246  *
247  * @return $sqlReturn array : array of successfully updated data/success messages
248  */
249 function UpdateGroupRights($pEnv, $pDbh, $pContext, $pList) {
250  if (count($pList) == 0) { return array(); }
251 
252  $gId = $pContext['g_id'];
253  $pId = $pContext['p_id'];
254  $cuTable = $pContext['cu_table'];
255  $cuCode = $pContext['cu_code'];
256 
257  $sqlReturn = array();
258  $sqlUpdate = "";
259  $sqlColumns = "
260  amount_per_transaction,
261  amount_per_account_per_day,
262  amount_per_day,
263  amount_per_month,
264  count_per_account_per_day,
265  count_per_day,
266  count_per_month,
267  confirm_required";
268 
269  foreach ($pList as $key => $value) {
270  $sqlValues = "
271  {$value['amount_per_transaction']},
272  {$value['amount_per_account_per_day']},
273  {$value['amount_per_day']},
274  {$value['amount_per_month']},
275  {$value['count_per_account_per_day']},
276  {$value['count_per_day']},
277  {$value['count_per_month']},
278  {$value['confirm_required']}";
279 
280  $sqlUpdate .= "UPDATE {$cuTable}grouprights
281  SET ($sqlColumns) = ($sqlValues)
282  WHERE group_id = $gId
283  AND feature_code = '{$value['feature_code']}';";
284 
285  $sqlReturn['rights'][] = $value['feature_code'];
286  }
287 
288  $sqlUpdateRs = db_query($sqlUpdate, $pDbh);
289  if (!$sqlUpdateRs) {
290  $pEnv['logger']->error(db_last_error());
291  throw new Exception("Failed to update group rights");
292  }
293 
294  return $sqlReturn;
295 }
296 
297 /**
298  * DeleteGroupRights
299  * @uses this function is used to delete feature rights that currenty exist for a group.
300  *
301  * @param $pEnv array : environment variable for debugging
302  * @param $pDbh object : databse object, used for queries
303  * @param $pContext array : context variable holding decrypted data for update functions
304  * @param $pList array : list of feature to be added to the group rights table
305  *
306  * @return $sqlReturn array : array of successfully created data/success messages
307  */
308 function DeleteGroupRights($pEnv, $pDbh, $pContext, $pList) {
309  if (count($pList) == 0) { return array(); }
310 
311  $gId = $pContext['g_id'];
312  $pId = $pContext['p_id'];
313  $cuTable = $pContext['cu_table'];
314  $cuCode = $pContext['cu_code'];
315 
316  $sqlReturn = array();
317  $sqlDelete = "";
318 
319  foreach ($pList as $key => $value) {
320 
321  $sqlDelete .= "DELETE FROM {$cuTable}grouprights
322  WHERE group_id = $gId
323  AND feature_code = '{$value['feature_code']}';";
324 
325  $sqlReturn['rights'][] = $value['feature_code'];
326  }
327 
328  $sqlDeleteRs = db_query($sqlDelete, $pDbh);
329  if(!$sqlDeleteRs) {
330  $pEnv['logger']->error(db_last_error());
331  throw new Exception("Failed to delete group rights");
332  }
333 
334  return $sqlReturn;
335 }
336 
337 /**
338  * ReadGroupRights
339  * @uses this function is used to read features rights that currently exist for a group.
340  *
341  * @param $pEnv array : environment variable for debugging
342  * @param $pDbh object : databse object, used for queries
343  * @param $pContext array : context variable holding decrypted data for update functions
344  * @param $pList array : list of feature to be added to the group rights table
345  *
346  * @return $sqlReturn array : array of successfully read data
347  */
348 function ReadGroupRights($pEnv, $pDbh, $pContext) {
349  $maxAmount = FEATURE_LIMIT_MAX_AMOUNT;
350  $maxCount = FEATURE_LIMIT_MAX_COUNT;
351 
352  $gId = $pContext['g_id'];
353  $pId = $pContext['p_id'];
354  $cuTable = $pContext['cu_table'];
355  $cuCode = $pContext['cu_code'];
356 
357  $sqlReturn = array();
358  $sqlColumns = "
359  f.feature_code AS f_code,
360  f.description AS f_desc,
361  f.limit_type AS f_type,
362  p.profile_code AS p_code,
363  gr.feature_code AS g_dft,
364  gr.amount_per_transaction AS g_apt,
365  gr.amount_per_day AS g_apd,
366  gr.amount_per_month AS g_apm,
367  gr.amount_per_account_per_day AS g_apa,
368  gr.count_per_day AS g_cpd,
369  gr.count_per_month AS g_cpm,
370  gr.count_per_account_per_day AS g_cpa,
371  gr.confirm_required AS g_cfm,
372  pr.confirm_required AS p_cfm,
373  COALESCE(pr.amount_per_transaction, $maxAmount) AS m_apt,
374  COALESCE(pr.amount_per_day, $maxAmount) AS m_apd,
375  COALESCE(pr.amount_per_month, $maxAmount) AS m_apm,
376  COALESCE(pr.amount_per_account_per_day, $maxAmount) AS m_apa,
377  COALESCE(pr.count_per_day, $maxCount) AS m_cpd,
378  COALESCE(pr.count_per_month, $maxCount) AS m_cpm,
379  COALESCE(pr.count_per_account_per_day, $maxCount) AS m_cpa";
380  $sqlSelect = "SELECT $sqlColumns
381  FROM {$cuTable}group g
382  INNER JOIN cu_profile p ON g.profile_id = p.profile_id
383  INNER JOIN cu_profilerights pr ON g.profile_id = pr.profile_id
384  INNER JOIN cu_feature f ON pr.feature_code = f.feature_code
385  LEFT JOIN {$cuTable}grouprights gr ON g.group_id = gr.group_id
386  AND gr.feature_code = f.feature_code
387  WHERE g.group_id = $gId
388  AND f.enabled = 'TRUE'
389  ORDER BY f.description ASC";
390  $sqlSelectRs = db_query($sqlSelect, $pDbh);
391  if (!$sqlSelectRs) {
392  $pEnv['logger']->error(db_last_error());
393  throw new Exception("Failed to read group rights");
394  }
395 
396  $sqlReturn['rights'] = db_fetch_all($sqlSelectRs);
397  return $sqlReturn;
398 }
399 
400 /**
401  * UpdateGroupProfile
402  * @uses this function is used to change the profile associated with a group. This function will delete all feature rights for the group.
403  *
404  * @param $pEnv array : environment variable for debugging
405  * @param $pDbh object : databse object, used for queries
406  * @param $pContext array : context variable holding decrypted data for update functions
407  * @param $pProfile string : new profile name to associate with group
408  *
409  * @return $sqlReturn array : array of successfully updated group encryption
410  */
411 function UpdateGroupProfile($pEnv, $pDbh, $pContext, $pProfile) {
412  $gId = $pContext['g_id'];
413  $pId = $pContext['p_id'];
414  $cuTable = $pContext['cu_table'];
415  $cuCode = $pContext['cu_code'];
416 
417  $sqlReturn = array();
418 
419  $pDesc = prep_save($pProfile, 255);
420  $sqlSelect = "SELECT profile_id AS p_id
421  FROM cu_profile
422  WHERE description = '$pDesc'
423  AND cu = '$cuCode'";
424 
425  $sqlSelectRs = db_query($sqlSelect, $pDbh);
426  $sqlSelectRow = db_fetch_assoc($sqlSelectRs);
427  $pId = intval($sqlSelectRow['p_id']);
428 
429  // UPDATE GROUP PROFILE ID
430  $sqlUpdate = "UPDATE {$cuTable}group
431  SET profile_id = $pId
432  WHERE group_id = $gId";
433  $sqlUpdateRs = db_query($sqlUpdate, $pDbh);
434  if (!$sqlUpdateRs) {
435  $pEnv['logger']->error(db_last_error());
436  throw new Exception("Failed to update group profile.");
437  }
438 
439  // DELETE GROUP RIGHTS FOR GROUP ID
440  $sqlDelete = "DELETE FROM {$cuTable}grouprights
441  WHERE group_id = $gId";
442  $sqlDeleteRs = db_query($sqlDelete, $pDbh);
443  if (!$sqlDeleteRs) {
444  $pEnv['logger']->error(db_last_error());
445  throw new Exception("Failed to update group rights.");
446  }
447 
448  // DELETE USER RIGHTS NOT IN NEW PROFILE
449  $sqlDelete = "DELETE FROM {$cuTable}userrights ur
450  USING {$cuTable}user u
451  WHERE ur.user_id = u.user_id
452  AND u.group_id = $gId
453  AND ur.feature_code NOT IN
454  (SELECT pr.feature_code FROM cu_profilerights pr WHERE pr.profile_id = $pId)";
455  $sqlDeleteRs = db_query($sqlDelete, $pDbh);
456  $sqlDeleteRs = db_query($sqlDelete, $pDbh);
457  if (!$sqlDeleteRs) {
458  $pEnv['logger']->error(db_last_error());
459  throw new Exception("Failed to update user rights rights.");
460  }
461 
462  // SELECT USER RIGHTS WITH DIFFERENCES TO NEW PROFILE
463  $sqlColumns = "
464  f.feature_code AS f_code,
465  f.description AS f_desc,
466  u.user_name AS u_user";
467  $sqlDiff = "
468  ur.amount_per_transaction != pr.amount_per_transaction
469  OR ur.amount_per_account_per_day != pr.amount_per_account_per_day
470  OR ur.amount_per_day != pr.amount_per_day
471  OR ur.amount_per_month != pr.amount_per_month
472  OR ur.count_per_account_per_day != pr.count_per_account_per_day
473  OR ur.count_per_day != pr.count_per_day
474  OR ur.count_per_month != pr.count_per_month
475  OR ur.confirm_required != pr.confirm_required";
476  $sqlSelect = "SELECT $sqlColumns
477  FROM {$cuTable}userrights ur
478  INNER JOIN {$cuTable}user u ON u.user_id = ur.user_id
479  INNER JOIN cu_feature f ON f.feature_code = ur.feature_code
480  FULL OUTER JOIN cu_profilerights pr ON pr.feature_code = ur.feature_code
481  WHERE pr.profile_id = $pId
482  AND u.group_id = $gId
483  AND ($sqlDiff)";
484  $sqlSelectRs = db_query($sqlSelect, $pDbh);
485  if (!$sqlSelectRs) {
486  $pEnv['logger']->error(db_last_error());
487  throw new Exception("Failed to read user rights.");
488  }
489 
490  $sqlReturn['message'] = "Group Profile has been updated successfully.";
491  $sqlReturn['profile'] = array("name"=>$pDesc, "id"=>$pId);
492  if (db_num_rows($sqlSelectRs) > 0) {
493  $sqlReturn['message'] .= "<br>&emsp;&emsp;The following users may have feature limits that differ from the new profile.";
494 
495  while ($row = db_fetch_assoc($sqlSelectRs)) {
496  $sqlReturn['message'] .= "<br>&emsp;&emsp;&mdash; User: " . $row['u_user'] . ", Feature: " . $row['f_desc'];
497  }
498  }
499 
500  return $sqlReturn;
501 }
502 
503 /**
504  * ReadProfiles
505  * @uses this function is used to read all available profiles for the CU
506  *
507  * @param $pEnv array : environment variable for debugging
508  * @param $pDbh object : databse object, used for queries
509  * @param $pContext array : context variable holding decrypted data for update functions
510  *
511  * @return $sqlReturn array : array of successfully read profiles
512  */
513 function ReadProfiles($pEnv, $pDbh, $pContext) {
514  $cuCode = $pContext['cu_code'];
515 
516  $sqlReturn = array();
517  $sqlColumn = "
518  profile_code AS p_code,
519  description AS p_desc";
520 
521  $sqlSelect = "SELECT $sqlColumn
522  FROM cu_profile
523  WHERE cu = '$cuCode'
524  ORDER BY description ASC";
525 
526  $sqlSelectRs = db_query($sqlSelect, $pDbh);
527  if (!$sqlSelectRs) {
528  $pEnv['logger']->error(db_last_error());
529  throw new Exception("Failed to read profiles.");
530  }
531 
532  $sqlReturn['profiles'] = db_fetch_all($sqlSelectRs);
533  return $sqlReturn;
534 }
535 
536 /**
537  * ReadProfileRights
538  * @uses this function is used to read all feature rights of the profile associated with the group.
539  *
540  * @param $pEnv array : environment variable for debugging
541  * @param $pDbh object : databse object, used for queries
542  * @param $pContext array : context variable holding decrypted data for update functions
543  *
544  * @return $sqlReturn array : array of successfully read profile rights
545  */
546 function ReadProfileRights($pEnv, $pDbh, $pContext) {
547  $gId = $pContext['g_id'];
548  $pId = $pContext['p_id'];
549 
550  $sqlReturn = array();
551  $sqlColumns = "
552  f.feature_code AS f_code,
553  f.description AS f_desc,
554  f.limit_type AS f_type,
555  pr.amount_per_transaction AS p_apt,
556  pr.amount_per_day AS p_apd,
557  pr.amount_per_month AS p_apm,
558  pr.amount_per_account_per_day AS p_apa,
559  pr.count_per_day AS p_cpd,
560  pr.count_per_month AS p_cpm,
561  pr.count_per_account_per_day AS p_cpa,
562  pr.confirm_required AS p_cfm";
563  $sqlSelect = "SELECT $sqlColumns
564  FROM cu_profilerights pr
565  INNER JOIN cu_feature f ON pr.feature_code = f.feature_code
566  WHERE profile_id = $pId
567  AND f.enabled = 'TRUE'
568  ORDER BY description ASC";
569  $sqlSelectRs = db_query($sqlSelect, $pDbh);
570  if (!$sqlSelectRs) {
571  $pEnv['logger']->error(db_last_error());
572  throw new Exception("Failed to read profile rights.");
573  }
574 
575  $sqlReturn['rights'] = db_fetch_all($sqlSelectRs);
576  return $sqlReturn;
577 }
578 ?>
579 
580 
581 <?php
582 /**
583  * PrintCardContent
584  * @uses this function is used to print all javascript and html necessary for
585  * display and use of the group rights feature.
586  */
587 function PrintCardContent() {
588 ?>
589 
590 <div id="grRights">
591  <div id="status"></div>
592  <div class="well well-sm col-sm-12">
593  <div class="row">
594  <div class="col-sm-12">
595  <input id="grInpProfiles" style="min-width: 200px; max-width: 350px;">
596  <span class="hidden-xs">&emsp;</span>
597  <br class="hidden-sm hidden-md hidden-lg">
598  <a href="#" id="lnkProfiles">View Profile Rights</a>
599  </div>
600  </div>
601  &nbsp;
602  <div class="row">
603  <div class="col-sm-12">
604  <div class="row">
605  <div class="radio-spacer">
606  <input type="radio" name="column" value="o" checked="true">
607  <label for="co">Options</label>
608  </div>
609  <div class="radio-spacer">
610  <input type="radio" name="column" value="q">
611  <label for="cq">Quantity</label>
612  </div>
613  <div class="radio-spacer">
614  <input type="radio" name="column" value="d">
615  <label for="cd">Amount</label>
616  </div>
617  <div class="radio-spacer">
618  <input type="radio" name="column" value="a">
619  <label for="ca">All</label>
620  </div>
621  </div>
622  </div>
623  </div>
624  </div>
625 
626  <div>&nbsp;</div>
627 
628  <div class="">
629  <div id="grRightsGrid"></div>
630  </div>
631 
632  <div class="hcu-template">
633  <div class="hcu-edit-buttons k-state-default">
634  <span class="hcu-icon-delete">
635  <!--<a href="##" id="lnkDelete">
636  <i class="fa fa-trash fa-lg"></i>
637  </a>-->
638  </span>
639  <a href="##" id="lnkCancel">
640  Cancel &emsp;
641  </a>
642  <a href="##" id="btnUpdate" class="k-button k-primary">
643  <i class="fa fa-check fa-lg"></i>
644  Update
645  </a>
646  </div>
647  </div>
648 </div>
649 
650 <div id="grProfile" style="padding: 0;">
651  <div id="grProfileGrid"></div>
652 </div>
653 
654 <div id="grConfirm" class="row">
655  <div class="col-sm-12">
656  <p>You are about to change the profile for this group.</p>
657  <p>This will remove any configured rights for the group and any user rights not in the new profile.</p>
658  <p>Do you wish to continue?</p>
659  </div>
660 </div>
661 
662 <div id="grDiscard" class="row">
663  <div class="col-sm-12">
664  <p>You have made changes to the current group rights.</p>
665  <p>Do you wish to discard these changes?</p>
666  </div>
667 </div>
668 
669 <script type="text/x-kendo-template" id="templateProfiles">
670  <tr class="k-master-row">
671  <td>#= fDesc #</td>
672  <td>
673  # if (fType == "B" || fType == "D") { #
674  # if (pApt >= FEATURE_LIMIT_MAX_AMOUNT || pApt == null) { #
675  Amount per transaction: No Limit, <br>
676  # } else { #
677  Amount per transaction: #= kendo.toString(pApt, "c2") #, <br>
678  # } #
679 
680  # if (pApa >= FEATURE_LIMIT_MAX_AMOUNT || pApa == null) { #
681  Amount per account per day: No Limit, <br>
682  # } else { #
683  Amount per account per day: #= kendo.toString(pApa, "c2") #, <br>
684  # } #
685 
686  # if (pApd >= FEATURE_LIMIT_MAX_AMOUNT || pApd == null) { #
687  Amount per day: No Limit, <br>
688  # } else { #
689  Amount per day: #= kendo.toString(pApd, "c2") #, <br>
690  # } #
691 
692  # if (pApm >= FEATURE_LIMIT_MAX_AMOUNT || pApm == null) { #
693  Amount per month: No Limit, <br>
694  # } else { #
695  Amount per month: #= kendo.toString(pApm, "c2") #, <br>
696  # } #
697  # } #
698 
699  # if (fType == "B" || fType == "Q") { #
700  # if (pCpa >= FEATURE_LIMIT_MAX_COUNT || pCpa == null) { #
701  Count per account per day: No Limit, <br>
702  # } else { #
703  Count per account per day: #= kendo.toString(pCpa, "n0") #, <br>
704  # } #
705 
706  # if (pCpd >= FEATURE_LIMIT_MAX_COUNT || pCpd == null) { #
707  Count per day: No Limit, <br>
708  # } else { #
709  Count per day: #= kendo.toString(pCpd, "n0") #, <br>
710  # } #
711 
712  # if (pCpm >= FEATURE_LIMIT_MAX_COUNT || pCpm == null) { #
713  Count per month: No Limit, <br>
714  # } else { #
715  Count per month: #= kendo.toString(pCpm, "n0") #, <br>
716  # } #
717  # } #
718 
719  # if (fType == "A") { #
720  Access Allowed<br>
721  # } #
722 
723  # if (fType == "B" || fType == "D") { #
724  # if (pCfm) { #
725  Confirmation Required: Yes
726  # } else { #
727  Confirmation Required: No
728  # } #
729  # } #
730  </td>
731  </tr>
732 </script>
733 <?php
734 /**
735  * @package GroupRights:
736  * @uses This object is used to display and interact with the group rights feature.
737  *
738  * @var Init public: public call to initialize data/view/action objects
739  * @var Data public: public call to set/reset encrypted data
740  * @var Open public: public call to open the group rights module/window
741  * @var Close public: public call to close the group rights module/window
742  *
743  * @var InitDataSources private: initialize all needed data sources/objects
744  * @var InitDataViews private: initialize all data views/html elements
745  * @var InitDataActions private: initialize all user actions on html.
746  *
747  * @var EventOpenDialog private: open kendoDialog/kendoWindow objects
748  * @var EventClosedialog private: close kendoDialog/kendoWindow objects
749  * @var EventPopDialog private: remove the correct window from the window stack.
750  *
751  * @var EventOpenRights private: send request to read/open group rights info
752  * @var EventCancelRights private: close group rights window, canceling changes
753  * @var EventUpdateRights private: send crud request for group rights, profile update.
754  * @var Event* private: the other event functions not listed above are custom
755  * calls for kendo bjects and other helper functions that are explained by the
756  * function name.
757  *
758  * @var DataBuild* private: these functions facilitate re-constructing data for
759  * proper use in the other js functions and html displays.
760  *
761  * @var Action* private: these functions are calls from kendoDialog actions
762  * uses explained by function name.
763  *
764  * @var ClearGroupInfo private: clear information displayed in the information bar.
765  * @var ShowGroupInfo private: show any information return by the server.
766  */
767 ?>
768 <script type="text/javascript">
769 var FEATURE_LIMIT_MAX_AMOUNT = <?php echo FEATURE_LIMIT_MAX_AMOUNT; ?>;
770 var FEATURE_LIMIT_MAX_COUNT = <?php echo FEATURE_LIMIT_MAX_COUNT; ?>;
771 
772 var GroupRights = function() {
773  var grCardContainer = null;
774  var grCardWindows = null;
775 
776  var grPayload = null;
777  var grGroup = null;
778  var grCall = null;
779  var grAction = null;
780  var grDataSource = null;
781 
782  var grRights = null;
783  var grProfile = null;
784  var grConfirm = null;
785  var grDiscard = null;
786 
787  var grDropDown = null;
788  var grDropDownData = null;
789  var grGrid = null;
790  var grGridData = null;
791  var grProfileGrid = null;
792  var grProfileGridData = null;
793 
794  var grProfileNext = null;
795  var grProfilePrev = null;
796 
797  var grUpdate = null;
798  var grCancel = null;
799  var grProfileLink = null;
800 
801  var DirtyCheck = function() {
802  var dirty = false;
803  var data = grGrid.dataSource.data();
804  for (var i = 0; i < data.length; i++) {
805  var row = data[i];
806  if (row.dirty) {
807  dirty = true;
808  break;
809  }
810  }
811 
812  return dirty;
813  }
814 
815  var DataUpdateRights = function(data, action) {
816  var dataE = grGrid.dataSource.data();
817 
818  // ITERATE UPDATED CODES
819  for (var i = 0; i < data.length; i++) {
820 
821  // CHECK AGAINST DATASOURCES
822  for (var j = 0; j < dataE.length; j++) {
823 
824  // UPDATE DEFAULT FLAG BASED ON ACTION
825  if (dataE[j].fCode == data[i]) {
826  dataE[j].gDft = action == "delete";
827 
828  // UPDATE DISABLED FLAG FOR DEFAULT CHECKBOX
829  if (action == "delete") {
830  $("#chk_" + data[i]).closest("td").addClass("vsgDisabled");
831  } else {
832  $("#chk_" + data[i]).closest("td").removeClass("vsgDisabled");
833  }
834  }
835  }
836  }
837  }
838 
839  var DataBuildFeature = function(data) {
840  var gFeature = {
841  fCode: data.f_code.trim(),
842  fDesc: data.f_desc.trim(),
843  fType: data.f_type.trim(),
844  pCode: data.p_code.trim(),
845  pCfm: (data.p_cfm == "t") ? true : false,
846  gCfm: (data.g_cfm == "t") ? true : false,
847  gDft: (data.g_dft == null) ? true : false,
848  gApt: data.g_apt == null ? null : parseFloat(data.g_apt),
849  gApa: data.g_apa == null ? null : parseFloat(data.g_apa),
850  gApd: data.g_apd == null ? null : parseFloat(data.g_apd),
851  gApm: data.g_apm == null ? null : parseFloat(data.g_apm),
852  gCpa: data.g_cpa == null ? null : parseInt(data.g_cpa),
853  gCpd: data.g_cpd == null ? null : parseInt(data.g_cpd),
854  gCpm: data.g_cpm == null ? null : parseInt(data.g_cpm),
855  mApt: parseFloat(data.m_apt),
856  mApa: parseFloat(data.m_apa),
857  mApd: parseFloat(data.m_apd),
858  mApm: parseFloat(data.m_apm),
859  mCpa: parseInt(data.m_cpa),
860  mCpd: parseInt(data.m_cpd),
861  mCpm: parseInt(data.m_cpm)
862  };
863 
864  // IF GREATER THAN MAX
865  gFeature.gApt = (gFeature.gApt >= gFeature.mApt) ? null : gFeature.gApt;
866  gFeature.gApa = (gFeature.gApa >= gFeature.mApa) ? null : gFeature.gApa;
867  gFeature.gApd = (gFeature.gApd >= gFeature.mApd) ? null : gFeature.gApd;
868  gFeature.gApm = (gFeature.gApm >= gFeature.mApm) ? null : gFeature.gApm;
869  gFeature.gCpa = (gFeature.gCpa >= gFeature.mCpa) ? null : gFeature.gCpa;
870  gFeature.gCpd = (gFeature.gCpd >= gFeature.mCpd) ? null : gFeature.gCpd;
871  gFeature.gCpm = (gFeature.gCpm >= gFeature.mCpm) ? null : gFeature.gCpm;
872 
873  return gFeature;
874  }
875 
876  var DataBuildRights = function(data) {
877  grGridData = [];
878  for (var i = 0; i < data.length; i++) {
879  var gFeature = DataBuildFeature(data[i]);
880  grGridData.push(gFeature);
881  }
882 
883  grGrid.dataSource.data(grGridData);
884  grDropDown.value(grGroup.g_profile);
885  }
886 
887  var DataBuildProfiles = function(data) {
888  grDropDownData = [];
889  for (var i = 0; i < data.length; i++) {
890  var gProfile = {
891  pCode: data[i].p_code.trim(),
892  pDesc: data[i].p_desc.trim()
893  };
894 
895  grDropDownData.push(gProfile);
896  }
897 
898  grDropDown.setDataSource(grDropDownData);
899  }
900 
901  var DataBuildProfileRights = function(data) {
902  grProfileGridData = [];
903  for (var i = 0; i < data.length; i++) {
904  var pFeature = {
905  fCode: data[i].f_code.trim(),
906  fDesc: data[i].f_desc.trim(),
907  fType: data[i].f_type.trim(),
908  pCfm: (data[i].p_cfm == "t") ? true : false,
909  pApt: (data[i].p_apt == null) ? null : parseFloat(data[i].p_apt),
910  pApd: (data[i].p_apd == null) ? null : parseFloat(data[i].p_apd),
911  pApm: (data[i].p_apm == null) ? null : parseFloat(data[i].p_apm),
912  pApa: (data[i].p_apa == null) ? null : parseFloat(data[i].p_apa),
913  pCpd: (data[i].p_cpd == null) ? null : parseInt(data[i].p_cpd),
914  pCpm: (data[i].p_cpm == null) ? null : parseInt(data[i].p_cpm),
915  pCpa: (data[i].p_cpa == null) ? null : parseInt(data[i].p_cpa)
916  };
917 
918  grProfileGridData.push(pFeature);
919  }
920 
921  grProfileGrid.dataSource.data(grProfileGridData);
922  }
923 
924  var EventOpenProfile = function(e) {
925  var rightsRequest = {
926  operation: "readProfileRights",
927  payload: grPayload
928  };
929 
930  grDataSource.transport.options.read.type = "POST";
931  grDataSource.read(rightsRequest);
932  }
933 
934  var EventSelectDropDown = function(e) {
935  grProfilePrev = this.value();
936  }
937 
938  var EventChangeDropDown = function (e) {
939  grProfileNext = this.value();
940  grConfirm.open();
941  }
942 
943  var EventRadioChange = function(e) {
944  var input = $(this);
945  var inputValue = input.val();
946 
947  switch (inputValue) {
948  case "a":
949  grGrid.showColumn(2);
950  grGrid.showColumn(3);
951  grGrid.showColumn(4);
952  break;
953  case "o":
954  grGrid.hideColumn(3);
955  grGrid.hideColumn(4);
956  grGrid.showColumn(2);
957  break;
958  case "q":
959  grGrid.hideColumn(2);
960  grGrid.hideColumn(4);
961  grGrid.showColumn(3);
962  break;
963  case "d":
964  grGrid.hideColumn(2);
965  grGrid.hideColumn(3);
966  grGrid.showColumn(4);
967  break;
968  }
969 
970  grRights.center();
971  grRights.wrapper.css({top: 100});
972  }
973 
974  var EventCheckboxChange = function(e) {
975  var box = $(e);
976  var boxId = box.attr("id");
977  var boxValue = box.prop("checked");
978 
979  if (!boxValue) {
980  $("input[id=chk_DEFAULT]").prop("checked", false);
981  }
982 
983  if (boxId == "chk_DEFAULT") {
984  $("input[id^=chk_]:not(:disabled)").each(function(e) {
985  if (e > 0) {
986  $(this).prop("checked", boxValue);
987  $(this).trigger("change");
988  }
989  });
990  } else {
991  var row = $(box).closest("tr");
992  var rowData = grGridData[row[0].rowIndex];
993  var fields = $(row).find("td");
994 
995  // SET CORRECT TEXT AND CLASSES FOR DISABLING ROWS
996  // SEE FUNCTION : EventShowTip to view what each class is for
997  $(fields).each(function(e) {
998  var field = $(this);
999  var fieldName = field.attr("name");
1000  var fieldMax = fieldName.replace("g", "m");
1001  var fieldPro = fieldName.replace("g", "p");
1002  var fieldClass = null;
1003 
1004  var span = field.find("span");
1005  var spanClass = null;
1006  var spanText = null;
1007 
1008  if (e > 1) {
1009 
1010  // REMOVE CLASSES FROM TD AND SPAN
1011  $(field).removeClass();
1012  $(span).removeClass();
1013 
1014  if (e == 2) {
1015  // OPTION FIELDS
1016  fieldClass = rowData[fieldPro] || boxValue ? "vsgDisabled" : "";
1017  spanClass = rowData[fieldPro] ? "not-allowed" : (boxValue ? "set-default" : "");
1018  spanText = rowData[fieldPro] ? rowData[fieldPro] : rowData[fieldName];
1019  spanText = spanText ? "Yes" : "No";
1020  } else if (e >= 3 && e <= 5) {
1021  // QUATITY FIELDS
1022  fieldClass = rowData.fType == "D" || boxValue ? "vsgDisabled" : "";
1023  spanClass = rowData.fType == "D" ? "limit-not-configured" : (boxValue ? "set-default" : "");
1024  spanText = rowData.fType == "D" ? "" : (boxValue ? "Default" : rowData[fieldName]);
1025  spanText = spanText == null ? "Default" : spanText;
1026  } else if (e >= 6 && e <= 9) {
1027  // AMOUNT FIELDS
1028  fieldClass = rowData.fType == "Q" || boxValue ? "vsgDisabled" : "";
1029  spanClass = rowData.fType == "Q" ? "limit-not-configured" : (boxValue ? "set-default" : "");
1030  spanText = rowData.fType == "Q" ? "" : (boxValue ? "Default" : rowData[fieldName]);
1031  spanText = spanText == null ? "Default" : spanText;
1032  } else {
1033  // DO NOTHING
1034  }
1035 
1036  $(field).attr("class", fieldClass);
1037  $(span).attr("class", spanClass);
1038  $(span).text(spanText);
1039  }
1040  });
1041  }
1042  }
1043 
1044  var EventEditGridNumeric = function(container, options) {
1045  if (container.hasClass("vsgDisabled")) {
1046  grGrid.closeCell();
1047  return false;
1048  }
1049 
1050  var dataModelGrid = options.model;
1051  var dataModelIndex = $(container).closest("tr").index();
1052  var dataModelSource = grGridData[dataModelIndex];
1053  var dataKeySource = options.field;
1054  var dataKeyMax = dataKeySource.replace("g", "m");
1055  var dataDirty = dataModelGrid.dirty;
1056 
1057  var dataInput = $("<input name=\"" + dataKeySource + "\">");
1058  dataInput.appendTo(container)
1059  dataInput.kendoNumericTextBox({
1060  min: 0,
1061  max: dataModelGrid[dataKeyMax],
1062  step: dataModelGrid[dataKeyMax],
1063  value: dataModelGrid[dataKeySource],
1064  upArrowText: "Set To Default",
1065  downArrowText: "Set to 0",
1066  change: function(e) {
1067  var valueCurrent = this.value();
1068  var valueOriginal = dataModelSource[dataKeySource];
1069  var valueMax = dataModelSource[dataKeyMax];
1070 
1071  if (valueCurrent >= valueMax) { valueCurrent = null; }
1072  if (valueCurrent == valueOriginal) {
1073  if (!dataDirty) { dataModelGrid.dirty = true; }
1074 
1075  $(container).removeClass("k-dirty-cell");
1076  $(container).find(".k-dirty").remove();
1077  } else {
1078  $(container).addClass("k-dirty-cell");
1079  $(container).prepend("<span class='k-dirty'></span>");
1080  }
1081 
1082  dataModelGrid[dataKeySource] = valueCurrent;
1083  this.value(valueCurrent);
1084  }
1085  });
1086  }
1087 
1088  var EventEditGridBoolean = function(container, options) {
1089  if (container.hasClass("vsgDisabled")) {
1090  grGrid.closeCell();
1091  return false;
1092  }
1093 
1094  var dataModelGrid = options.model;
1095  var dataModelIndex = $(container).closest("tr").index();
1096  var dataModelSource = grGridData[dataModelIndex];
1097  var dataKeySource = options.field;
1098  var dataDirty = dataModelGrid.dirty;
1099 
1100  dataInput = $("<input type=\"checkbox\" name=\"" + dataKeySource + "\">");
1101  dataInput.change(function(e) {
1102  var valueCurrent = this.checked;
1103  var valueOriginal = dataModelSource[dataKeySource];
1104 
1105  if (valueCurrent == valueOriginal) {
1106  $(container).removeClass("k-dirty-cell");
1107  $(container).find(".k-dirty").remove();
1108  } else {
1109  if (!dataDirty) { dataModelGrid.dirty = true; }
1110 
1111  $(container).addClass("k-dirty-cell");
1112  $(container).prepend("<span class='k-dirty'></span>");
1113  }
1114 
1115  dataModelGrid[dataKeySource] = valueCurrent;
1116  this.checked = valueCurrent;
1117  });
1118  dataInput.appendTo(container);
1119  }
1120 
1121  var EventBindGrid = function(e) {
1122  $("#rightsGrid .k-grid-content").css("max-height", "275px");
1123  $("input[id^=chk_]").off();
1124  $("input[id^=chk_]").change(function(e) {
1125  EventCheckboxChange(e.target);
1126  });
1127 
1128  $("input[id=chk_DEFAULT]").prop("checked", false);
1129 
1130  // ITERATE ROWS AND FIELDS TO SET DISABLED CLASS
1131  // DISABLED WILL BE USED IN THE EDITOR FUNCTIONS TO PREVENT EDITING
1132  var table = this.tbody;
1133  var rows = $(table).find("tr");
1134  for (var i = 0; i < rows.length; i++) {
1135  var rowIndex = rows[i].rowIndex;
1136  var rowData = grGridData[i];
1137  var fields = $(rows[i]).find("td");
1138 
1139  if (rowData.gDft || rowData.fType == "A") {
1140  $(fields[1]).addClass("vsgDisabled");
1141  }
1142 
1143  if (rowData.pCfm || rowData.fType == "A" || rowData.fType == "Q") {
1144  $(fields[2]).addClass("vsgDisabled");
1145  }
1146  if (rowData.fType == "D" || rowData.fType == "A") {
1147  $(fields[3]).addClass("vsgDisabled");
1148  $(fields[4]).addClass("vsgDisabled");
1149  $(fields[5]).addClass("vsgDisabled");
1150  }
1151  if (rowData.fType == "Q" || rowData.fType == "A") {
1152  $(fields[6]).addClass("vsgDisabled");
1153  $(fields[7]).addClass("vsgDisabled");
1154  $(fields[8]).addClass("vsgDisabled");
1155  $(fields[9]).addClass("vsgDisabled");
1156  }
1157  }
1158  }
1159 
1160  var EventChangeGrid = function(e) {
1161  var cell = this.select();
1162  var cellIndex = cell.index();
1163 
1164  var dataIndex = cell.closest("tr")[0].rowIndex;
1165  var dataItem = grGridData[dataIndex];
1166 
1167  if (cellIndex == 1 && !dataItem.gDft) {
1168  var box = cell.find("input[id^=\"chk_\"]")[0];
1169  $(box).trigger("click");
1170  }
1171 
1172  $(cell).removeClass("k-state-selected");
1173  }
1174 
1175  var EventShowTip = function(e) {
1176  var target = $(e.target).find("span");
1177  var targetType = target.attr("class");
1178  var targetContent = "";
1179  switch (targetType) {
1180  case "not-allowed":
1181  targetContent = "This limit is set at the profile level.";
1182  break;
1183  case "limit-not-configured":
1184  targetContent = "This limit is not configured for this feature.";
1185  break;
1186  case "feature-not-configured":
1187  targetContent = "This feature does not have limits.";
1188  break;
1189  case "set-default":
1190  targetContent = "Set to default.";
1191  break;
1192  case "rdy-default":
1193  targetContent = "This feature is already set to the defaults.";
1194  break;
1195  default:
1196  targetContent = $(e.target).text().trim();
1197  break;
1198  }
1199 
1200  return targetContent;
1201  }
1202 
1203  var EventUpdateRights = function() {
1204  var dataA = "";
1205  var dataE = grGrid.dataSource.data();
1206  var dataO = grGridData;
1207  var dataU = {
1208  create: [],
1209  update: [],
1210  delete: []
1211  };
1212 
1213  for (var i = 0; i < dataE.length; i++) {
1214  var dataItemE = dataE[i];
1215  var dataItemO = dataO[i];
1216 
1217  var inputDefault = $("#chk_" + dataItemE.fCode);
1218  var inputChecked = $(inputDefault).prop("checked");
1219 
1220  if (inputChecked) {
1221  dataItemE.gApt = null;
1222  dataItemE.gApa = null;
1223  dataItemE.gApm = null;
1224  dataItemE.gApd = null;
1225  dataItemE.gCpa = null;
1226  dataItemE.gCpm = null;
1227  dataItemE.gCpd = null;
1228  dataItemE.gCfm = dataItemE.pCfm;
1229  dataItemE.dirty = true;
1230  dataU.delete.push(dataItemE);
1231  continue;
1232  }
1233 
1234  if (dataItemE.dirty) {
1235 
1236  if (dataItemE.gApt == dataItemO.gApt && dataItemE.gCpa == dataItemO.gCpa &&
1237  dataItemE.gApa == dataItemO.gApa && dataItemE.gCpd == dataItemO.gCpd &&
1238  dataItemE.gApd == dataItemO.gApd && dataItemE.gCpm == dataItemO.gCpm &&
1239  dataItemE.gApm == dataItemO.gApm && dataItemE.gCfm == dataItemO.gCfm) {
1240 
1241  dataItemE.dirty = false;
1242  continue;
1243  }
1244 
1245  if (dataItemE.gApt == null && dataItemE.gCpa == null &&
1246  dataItemE.gApa == null && dataItemE.gCpd == null &&
1247  dataItemE.gApd == null && dataItemE.gCpm == null &&
1248  dataItemE.gApm == null && dataItemE.gCfm == dataItemE.pCfm) {
1249 
1250  dataU.delete.push(dataItemE);
1251  continue;
1252  }
1253 
1254  if (dataItemE.gDft) {
1255  dataU.create.push(dataItemE);
1256  } else {
1257  dataU.update.push(dataItemE);
1258  }
1259  }
1260  }
1261 
1262  if (dataU.create.length == 0 && dataU.update.length == 0 && dataU.delete.length == 0) {
1263  return false;
1264  }
1265 
1266  var dataList = JSON.stringify(dataU);
1267  var rightsRequest = {
1268  operation: "updateGroupRights",
1269  payload: grPayload,
1270  gList: dataList
1271  };
1272 
1273  grDataSource.transport.options.read.type = "POST";
1274  grDataSource.read(rightsRequest);
1275  }
1276 
1277  var EventCancelRights = function() {
1278  grRights.close();
1279  }
1280 
1281  var EventOpenRights = function() {
1282  grDropDownData = [];
1283  grGridData = [];
1284 
1285  $("input[value=o]").trigger("click");
1286  $("input[value=o]").trigger("change");
1287 
1288  var rightsRequest = {
1289  operation: "readGroupRights",
1290  payload: grPayload
1291  };
1292 
1293  grDataSource.transport.options.read.type = "POST";
1294  grDataSource.read(rightsRequest);
1295  }
1296 
1297  var EventOpenWindow = function(e) {
1298  var windowElement = this.element[0];
1299  var windowId = windowElement.id;
1300 
1301  switch (windowId) {
1302  case "profile":
1303 
1304  break;
1305 
1306  }
1307 
1308  grCardWindows.push(this);
1309  }
1310 
1311  var EventCloseWindow = function(e) {
1312  var windowElement = this.element[0];
1313  var windowId = windowElement.id;
1314 
1315  switch (grAction) {
1316  case "profileConfirm":
1317  EventPopWindow(windowId);
1318  var rightsRequest = {
1319  operation: "updateGroupProfile",
1320  payload: grPayload,
1321  gProfile: grProfileNext
1322  };
1323 
1324  // CANCEL ANY GRID CHANGES
1325  grGrid.cancelChanges();
1326 
1327  grDataSource.transport.options.read.type = "POST";
1328  grDataSource.read(rightsRequest);
1329  break;
1330  case "profileDeny":
1331  EventPopWindow(windowId);
1332  grDropDown.value(grProfilePrev);
1333  break;
1334  case "discardConfirm":
1335  EventPopWindow(windowId);
1336  grAction = null;
1337  grGrid.cancelChanges();
1338  grRights.close();
1339  default:
1340  if (windowId == "grConfirm") {
1341  EventPopWindow(windowId);
1342  grDropDown.value(grProfilePrev);
1343  } else if (windowId == "grRights") {
1344  if (DirtyCheck()) {
1345  e.preventDefault();
1346  grDiscard.open();
1347  } else {
1348  EventPopWindow(windowId);
1349  // reset validator to use hub script
1350  $.homecuValidator.setup({
1351  formStatusField: "formStatus",
1352  formValidate: "cardContainerDiv"
1353  });
1354  }
1355  } else {
1356  EventPopWindow(windowId);
1357  }
1358  break;
1359  }
1360 
1361  grAction = null;
1362  }
1363 
1364  var EventPopWindow = function(windowId) {
1365  var popIndex = -1;
1366  for (var i = 0; i < grCardWindows.length; i++) {
1367  var openWindow = grCardWindows[i].element[0];
1368  var openId = openWindow.id;
1369 
1370  if (openId == windowId) {
1371  popIndex = i;
1372  break;
1373  }
1374  }
1375 
1376  if (popIndex > -1) {
1377  grCardWindows.splice(popIndex, 1);
1378  }
1379  }
1380 
1381  var InitDataSources = function() {
1382  grGridData = [];
1383  grProfileGridData = [];
1384  grDropDownData = [];
1385  grDataSource = new kendo.data.DataSource({
1386  transport: {
1387  read: {
1388  url: "main.prg",
1389  dataType: "json",
1390  contentType: "application/x-www-form-urlencoded",
1391  type: "GET",
1392  data: {
1393  ft: "102103"
1394  },
1395  cache: false
1396  }
1397  },
1398  requestStart: function(request) {
1399  showWaitWindow();
1400  },
1401  requestEnd: function(response) {
1402  setTimeout(hideWaitWindow, 500);
1403 
1404  if (response.hasOwnProperty("response")) {
1405  if (response.response.hasOwnProperty("Results")) {
1406  var results = response.response.Results;
1407 
1408  if (results.hasOwnProperty("error")) {
1409  $.homecuValidator.homecuResetMessage = true;
1410  $.homecuValidator.displayMessage(results.error, $.homecuValidator.settings.statusError);
1411  } else if (results.hasOwnProperty("info")) {
1412  $.homecuValidator.homecuResetMessage = true;
1413  $.homecuValidator.displayMessage(results.info, $.homecuValidator.settings.statusSuccess);
1414  }
1415  } else {
1416  $.homecuValidator.displayMessage("Error Parsing Server", $.homecuValidator.settings.statusError);
1417  }
1418  } else {
1419  $.homecuValidator.displayMessage("Error Parsing Server", $.homecuValidator.settings.statusError);
1420  }
1421  },
1422  schema: {
1423  parse: function(response) {
1424 
1425  var results = null;
1426  var resultData = null;
1427  var resultOperation = null;
1428 
1429  if (response.hasOwnProperty("Results")) {
1430  results = response.Results;
1431  resultData = results.data;
1432  resultOperation = results.operation;
1433  }
1434 
1435  if (results.hasOwnProperty("errors")) {
1436  return [];
1437  }
1438 
1439  if (resultData == undefined || resultData == null) {
1440  return [];
1441  }
1442 
1443 
1444  setTimeout(function() {
1445  switch (resultOperation) {
1446  case "readGroupRights":
1447  DataBuildProfiles(resultData.gProfiles);
1448  DataBuildRights(resultData.gRights);
1449  grGroup.cardTitle= "Group Rights";
1450  var template= kendo.template($("#titleTemplate").html());
1451  grRights.title(template(grGroup)).center().open();
1452  break;
1453  case "readProfileRights":
1454  DataBuildProfileRights(resultData.pRights);
1455  grProfile.center();
1456  grProfile.open();
1457  break;
1458  case "updateGroupRights":
1459  DataUpdateRights(resultData.create, "create");
1460  DataUpdateRights(resultData.update, "update");
1461  DataUpdateRights(resultData.delete, "delete");
1462  grGrid.saveChanges();
1463  break;
1464  case "updateGroupProfile":
1465  grGroup = resultData.group.group;
1466  grPayload = resultData.encrypt;
1467  grCall("updateGroupInfo", resultData.group);
1468  grCall("updateGroupEncrypt", resultData.encrypt);
1469  DataBuildRights(resultData.rights);
1470  break;
1471  }
1472  }, 500);
1473 
1474  return [];
1475  }
1476  }
1477  });
1478  }
1479 
1480  var InitDataViews = function() {
1481  grRights = $("#grRights").kendoWindow({
1482  title: "Group Rights",
1483  minWidth: 300,
1484  maxWidth: "90%",
1485  maxHeight: 750,
1486  modal: true,
1487  visible: false,
1488  resizable: false,
1489  activate: EventOpenWindow,
1490  close: EventCloseWindow,
1491  open: function(e) { this.wrapper.css({ top: 100 }); },
1492  }).data("kendoWindow");
1493 
1494  grProfile = $("#grProfile").kendoWindow({
1495  title: "Profile Rights",
1496  minWidth: 300,
1497  maxWidth: 600,
1498  maxHeight: 500,
1499  modal: true,
1500  visible: false,
1501  resizable: false,
1502  activate: EventOpenWindow,
1503  close: EventCloseWindow,
1504  open: function(e) { this.wrapper.css({ top: 100 }); }
1505  }).data("kendoWindow");
1506 
1507  grConfirm = $("#grConfirm").kendoDialog({
1508  title: "Change Profile",
1509  minWidth: 300,
1510  maxWidth: 750,
1511  visible: false,
1512  resizable: false,
1513  show: EventOpenWindow,
1514  close: EventCloseWindow,
1515  actions: [
1516  { text: "No",
1517  action: function() { grAction = "profileDeny"; }
1518  },
1519  { text: "Yes", primary: true,
1520  action: function() { grAction = "profileConfirm"; }
1521  }
1522  ]
1523  }).data("kendoDialog");
1524 
1525  grDiscard = $("#grDiscard").kendoDialog({
1526  title: "Discard Changes",
1527  minWidth: 300,
1528  maxWidth: 750,
1529  visible: false,
1530  resizable: false,
1531  show: EventOpenWindow,
1532  close: EventCloseWindow,
1533  actions: [
1534  { text: "No",
1535  action: function() { grAction = "discardDeny"; }
1536  },
1537  { text: "Yes", primary: true,
1538  action: function() { grAction = "discardConfirm"; }
1539  }
1540  ]
1541  }).data("kendoDialog");
1542 
1543  grDropDown = $("#grInpProfiles").kendoDropDownList({
1544  dataTextField: "pDesc",
1545  dataValueField: "pDesc",
1546  dataSource: grDropDownData,
1547  select: EventSelectDropDown,
1548  change: EventChangeDropDown
1549  }).data("kendoDropDownList");
1550 
1551  grGrid = $("#grRightsGrid").kendoGrid({
1552  change: EventChangeGrid,
1553  dataBound: EventBindGrid,
1554  selectable: "cell",
1555  scrollable: true,
1556  editable: true,
1557  noRecords: {
1558  template: "There are no features assigned to this group"
1559  },
1560  dataSource: {
1561  data: grGridData,
1562  schema: {
1563  model: {
1564  id: "fCode",
1565  fields: {
1566  fDesc: { type: "string", editable: false },
1567  gCfm: { type: "boolean" },
1568  gCpd: { type: "number" },
1569  gCpm: { type: "number" },
1570  gCpa: { type: "number" },
1571  gApt: { type: "number" },
1572  gApd: { type: "number" },
1573  gApm: { type: "number" },
1574  gApa: { type: "number" },
1575  }
1576  }
1577  }
1578  },
1579  columns: [
1580  { title: "Feature",
1581  columns: [
1582  { field: "fDesc", title: " ", width: "200px",
1583  attributes: { "name": "fDesc", "class": "showEllipsis" },
1584  template: "<span>#=fDesc#</span>" }
1585  ]
1586  },
1587  { title: "Set to Default",
1588  columns: [
1589  { width: "150px",
1590  attributes: { "name": "fCode" },
1591  template: "#if(gDft){#<span class=\"rdy-default\"></span>#}else{#<input type=\"checkbox\" style=\"margin-top: -2px;\" id=\"chk_#=fCode#\">#}#",
1592  headerTemplate: "<input type=\"checkbox\" style=\"margin-top: -2px;\" id=\"chk_DEFAULT\">" }
1593  ]
1594  },
1595  { title: "Options",
1596  columns: [
1597  { field: "gCfm", title: "Confirm Required", type: "boolean", width: "150px", editor: EventEditGridBoolean, attributes: { "name": "gCfm"},
1598  template: "#if(fType == \"A\"){# <span class=\"feature-not-configured\"></span> #}else if(fType == \"Q\"){# <span class=\"limit-not-configured\"></span> #} else if (pCfm){# <span class=\"not-allowed\">Yes</span> #}else if (gCfm){# <span>Yes</span> #}else{# <span>No</span> #}#" }
1599 
1600  ]
1601  },
1602  { title: "Count Per",
1603  columns: [
1604  { field: "gCpa", title: "Account/Day", type: "number", width: "150px", editor: EventEditGridNumeric, attributes: { "name": "gCpa"},
1605  template: "#if(fType == \"A\"){# <span class=\"feature-not-configured\"></span> #}else if(fType == \"D\"){# <span class=\"limit-not-configured\"></span>#}else if(gCpa == null || gCpa >= mCpa){# <span>Default</span> #}else{# <span>#=kendo.toString(gCpa, \"n0\")#</span> #}#" },
1606  { field: "gCpd", title: "Day", type: "number", width: "150px", editor: EventEditGridNumeric, attributes: { "name": "gCpd"},
1607  template: "#if(fType == \"A\"){# <span class=\"feature-not-configured\"></span> #}else if(fType == \"D\"){# <span class=\"limit-not-configured\"></span>#}else if(gCpd == null || gCpd >= mCpd){# <span>Default</span> #}else{# <span>#=kendo.toString(gCpd, \"n0\")#</span> #}#" },
1608  { field: "gCpm", title: "Month", type: "number", width: "150px", editor: EventEditGridNumeric, attributes: { "name": "gCpm"},
1609  template: "#if(fType == \"A\"){# <span class=\"feature-not-configured\"></span> #}else if(fType == \"D\"){# <span class=\"limit-not-configured\"></span>#}else if(gCpm == null || gCpm >= mCpm){# <span>Default</span> #}else{# <span>#=kendo.toString(gCpm, \"n0\")#</span> #}#" }
1610  ]
1611  },
1612  { title: "Amount Per",
1613  columns: [
1614  { field: "gApt", title: "Transaction", type: "number", width: "150px", editor: EventEditGridNumeric, attributes: { "name": "gApt"},
1615  template: "#if(fType == \"A\"){# <span class=\"feature-not-configured\"></span> #}else if(fType == \"Q\"){# <span class=\"limit-not-configured\"></span>#}else if(gApt == null || gApt >= mApt){# <span>Default</span> #}else{# <span>#=kendo.toString(gApt, \"c2\")#</span> #}#" },
1616  { field: "gApa", title: "Account/Day", type: "number", width: "150px", editor: EventEditGridNumeric, attributes: { "name": "gApa"},
1617  template: "#if(fType == \"A\"){# <span class=\"feature-not-configured\"></span> #}else if(fType == \"Q\"){# <span class=\"limit-not-configured\"></span>#}else if(gApa == null || gApa >= mApa){# <span>Default</span> #}else{# <span>#=kendo.toString(gApa, \"c2\")#</span> #}#" },
1618  { field: "gApd", title: "Day", type: "number", width: "150px", editor: EventEditGridNumeric, attributes: { "name": "gApd"},
1619  template: "#if(fType == \"A\"){# <span class=\"feature-not-configured\"></span> #}else if(fType == \"Q\"){# <span class=\"limit-not-configured\"></span>#}else if(gApd == null || gApd >= mApd){# <span>Default</span> #}else{# <span>#=kendo.toString(gApd, \"c2\")#</span> #}#" },
1620  { field: "gApm", title: "Month", type: "number", width: "150px", editor: EventEditGridNumeric, attributes: { "name": "gApm"},
1621  template: "#if(fType == \"A\"){# <span class=\"feature-not-configured\"></span> #}else if(fType == \"Q\"){# <span class=\"limit-not-configured\"></span>#}else if(gApm == null || gApm >= mApm){# <span>Default</span> #}else{# <span>#=kendo.toString(gApm, \"c2\")#</span> #}#" }
1622  ]
1623  }
1624  ]
1625  }).data("kendoGrid");
1626 
1627  grProfileGrid = $("#grProfileGrid").kendoGrid({
1628  scrollable: true,
1629  rowTemplate: kendo.template($("#templateProfiles").html()),
1630  dataBound: function(e) {
1631  $("#grProfileGrid").css("border", "none");
1632  $("#grProfileGrid .k-grid-content").css("max-height", "500px");
1633  },
1634  dataSource: {
1635  data: grProfileGridData
1636  },
1637  noRecords: {
1638  template: "There are no features for this profile"
1639  },
1640  columns: [
1641  { title: "Feature" },
1642  { title: "Limits", width: "325px" }
1643  ]
1644  }).data("kendoGrid");
1645 
1646  // USE THIS TO SELECT OVERFLOW IN JQUERY SELECTORS FOR TOOLTIP BELOW
1647  jQuery.extend(jQuery.expr[':'], {
1648  overflown: function (el) {
1649  return el.offsetHeight < el.scrollHeight || el.offsetWidth < el.scrollWidth;
1650  }
1651  });
1652 
1653  grGridTip = homecuTooltip.defaults;
1654  grGridTip.filter = ".showEllipsis:overflown, .vsgDisabled";
1655  grGridTip.content = EventShowTip
1656  $("#grRightsGrid").kendoTooltip(grGridTip);
1657 
1658  grProfileLink = $("#lnkProfiles");
1659  grCancel = $("#lnkCancel");
1660  grUpdate = $("#btnUpdate");
1661  grStatus = $("#grStatus");
1662  grStatus.hide();
1663  }
1664 
1665  var InitDataActions = function() {
1666  grProfileLink.on("click", EventOpenProfile);
1667 
1668  $("input[name=column]").on("change", EventRadioChange);
1669  $("input[value=o]").trigger("click");
1670  $("input[value=o]").trigger("change");
1671 
1672  $("label[for^=c]").on("click", function(e) {
1673  var column = $(this).attr("for");
1674  var value = column.substring(1, column.length);
1675  var input = $("input[value=" + value + "]");
1676  $(input).trigger("click");
1677  });
1678 
1679  grUpdate.on("click", EventUpdateRights);
1680  grCancel.on("click", EventCancelRights);
1681  }
1682 
1683  this.Open = function(windowStack) {
1684  // setup validator
1685  $.homecuValidator.setup({
1686  formStatusField: "status",
1687  formValidate: "grRights"
1688  });
1689 
1690  grCardWindows = windowStack;
1691  $("input[value=o]").trigger("click");
1692  $("input[value=o]").trigger("change");
1693 
1694  var rightsRequest = {
1695  operation: "readGroupRights",
1696  payload: grPayload
1697  };
1698 
1699  grDataSource.transport.options.read.type = "POST";
1700  grDataSource.read(rightsRequest);
1701  }
1702 
1703  this.Close = function() {
1704  grRights.destroy();
1705  grProfile.destroy();
1706  grConfirm.destroy();
1707  grDiscard.destroy();
1708  }
1709 
1710  this.Data = function(payload, group) {
1711  grPayload = payload;
1712  grGroup = group;
1713  }
1714 
1715  this.Init = function(hubCall, cardContainer) {
1716  grCall = hubCall;
1717  grCardContainer = cardContainer;
1718 
1719  InitDataSources();
1720  InitDataViews();
1721  InitDataActions();
1722 
1723  grCall("GroupRights", this);
1724  }
1725 }
1726 </script>
1727 <?php } ?>