Odyssey
userSupportScheduledTransactions.prg
1 <?php
2 /**
3  * @package userSupportRepeatingTransfers
4  * @author SPB
5  *
6  * This script is run when the user opens up the delete card in the user hub. It cannot be run independently of that. You can activate inactive scheduled transfers.
7  * Or you can skip or cancel active transfers.
8  */
9 
10 $string = array("filter" => HCUFILTER_INPUT_STRING);
11 $parameters = array("a" => array("operation" => "", "payload" => ""));
12 HCU_ImportVars($parameters, "a", array("operation" => $string, "payload" => $string, "changeList" => $string));
13 extract($parameters["a"]);
14 
15 $operation = !isset($operation) ? "" : trim($operation);
16 $payload = !isset($payload) ? "" : trim($payload);
17 $changeList = !isset($changeList) ? "" : trim($changeList);
18 
19 // Need to translate to translate list.
20 require_once("$sharedLibrary/hcuTranslate.i");
21 require_once("$bankingLibrary/hcuTransferScheduled.i");
22 $MC = new hcu_talk_base("en_US");
23 
24 $userId = null;
25 try { $userId = HCU_PayloadDecode($Cu, $payload); } catch(exception $e) {}
26 $userId = isset($userId) ? $userId["user_id"] : null;
27 
28 if ($operation != "") {
29  if (isset($userId)) {
30  switch($operation) {
31  case "cancelTrans":
32  $returnArray = SetStatusTrans($dbh, $Cu, $userId, $changeList, $MC, true);
33  break;
34  case "activateTrans":
35  $returnArray = SetStatusTrans($dbh, $Cu, $userId, $changeList, $MC, false);
36  break;
37  case "skipTrans":
38  $returnArray = SkipTrans($dbh, $Cu, $userId, $changeList, $MC);
39  break;
40  default: // Won't get here
41  $returnArray = array("error" => array("Operation not specified: '$operation'"), "record" => array());
42  }
43  } else {
44  $returnArray = array("error" => "No User Found", "record" => array(), "sql" => array());
45  }
46 
47  header('Content-type: application/json');
48  print HCU_JsonEncode($returnArray);
49 } else {
50  if (isset($userId)) {
51  PrintPage("$menu_link?ft=$ft", ReadTrans($dbh, $Cu, $userId, $MC), $payload);
52  } else { ?>
53  <div class='noUserFound'><div>No User Found</div></div>
54  <?php }
55 }
56 
57 /**
58  * function SetStatusTrans($dbh, $Cu, $userId, $changeList, $MC, $isCancel = true)
59  * Data call to update the status to "A" for active or "I" for inactive.
60  *
61  * @param $dbh -- the database connection
62  * @param $Cu -- the credit union
63  * @param $userId -- the banking user
64  * @param $changeList -- a JSON list of ids to change
65  * @param $MC -- the dictionary (since I am using a DDL from the banking side, I need this to translate into English.)
66  * @param $isCancel -- If the operation is to cancel records or to activate records
67  *
68  * @return "status" -- "000" if successful, nonzero otherwise
69  * @return "error" -- "" if successful, nonempty otherwise
70  * @return "repeatingTransfers" -- a list of repeating transfers
71  * @return "info" -- if successful, give a success message
72  */
73 function SetStatusTrans($dbh, $Cu, $userId, $changeList, $MC, $isCancel = true) {
74  try {
75  if ($changeList == "") {
76  throw new exception("Nothing to change.", 301);
77  }
78  $changeList = HCU_JsonDecode($changeList);
79  if (!is_array($changeList)) {
80  throw new exception("Change List is malformed.", 302);
81  }
82  if (count($changeList) == 0) {
83  throw new exception("Nothing to change.", 304);
84  }
85  foreach($changeList as $changeListId) {
86  if (!is_integer($changeListId)) {
87  throw new exception("Change List is malformed.", 303);
88  }
89  }
90 
91  // SQL to check that records are valid for skipping.
92  $sql = "select id, approved_status, status from cu_scheduledtxn where cu = '$Cu' and user_id = $userId and id in (" . implode(", ", $changeList) . ")";
93  $sth = db_query($sql, $dbh);
94  if (!$sth) {
95  throw new exception("Select query failed.", 305);
96  }
97  $updateList = array();
98  for($i = 0; $row = db_fetch_assoc($sth, $i); $i++) {
99  if ($isCancel && $row["status"] != "A") {
100  throw new exception("Cancel can only happen on active records.", 306);
101  }
102  if (!$isCancel && $row["status"] == "A") {
103  throw new exception("Reactivate can only happen on inactive records.", 307);
104  }
105  if ($row["approved_status"] != 10) {
106  throw new exception(($isCancel ? "Cancel" : "Reactivate") . " can only happen on approved records.", 308);
107  }
108  $updateList[] = $row["id"];
109  }
110  if (count($updateList) != count($changeList)) { // Some ids do not exist or are attached to the wrong user/Cu.
111  throw new exception("Some ids in the changeList are invalid.", 309);
112  }
113  unset($changeList);
114 
115  $sql = "update cu_scheduledtxn set status= '" . ($isCancel ? "I" : "A") . "' where id in (" . implode(", ", $updateList) . ") and cu = '$Cu' and user_id = $userId";
116  $sth = db_query($sql, $dbh);
117  if (!$sth) {
118  throw new exception("Update query failed.", 310);
119  }
120 
121  $readResults = ReadTrans($dbh, $Cu, $userId, $MC);
122 
123  if ($readResults["status"] != "000") {
124  throw new exception($readResults["error"][0], $readResults["code"]);
125  }
126  $repeatingTransfers = $readResults["repeatingTransfers"];
127  unset($readResults);
128 
129  $returnArray = array("status" => "000", "error" => "", "repeatingTransfers" => $repeatingTransfers,
130  "info" => (count($updateList) == 1 ? "Transfer was " : "Transfers were ") . ($isCancel ? "cancelled" : "reactivated") . " successfully.");
131  } catch(exception $e) {
132  $returnArray = array("status" => $e->getCode(), "error" => $e->getMessage());
133  }
134  return $returnArray;
135 }
136 
137 /**
138  * function PrintPage($self, $readData, $payload)
139  * This function will print out the repeating transfers card.
140  *
141  * @param $self -- the URL of this script
142  * @param $readData -- the results from the read function. (@see the ReadTrans function.)
143  * @param $payload -- the payload to send the data calls
144  */
145 function PrintPage($self, $readData, $payload) { ?>
146  <script type="text/javascript">
147  //# sourceURL=repeatingTransfers.js
148 
149  <?php
150  /**
151  * function Init()
152  * This will define the scheduled transfers grid and any click events that are also necessary.
153  */
154  ?>
155  function Init() {
156  $.homecuValidator.setup({formValidate: "repeatingDiv", formStatusField: "formValidateDiv"});
157  $("#externalTabWindow").data("preferredHeight", "auto");
158 
159  $(".repeatingDiv").on("click", ".closeBtn", function() {
160  postPostPostPost();
161  return false;
162  });
163 
164  var dateTemplateTemplate = kendo.template("\\# if (#: column # == null) { \\# &nbsp; \\# } else { \\# \\#= kendo.toString(#: column #, 'MM/dd/yyyy') \\# \\# } \\#");
165 
166  window.repeatingTransfers = [];
167  var repeatingTransfersGrid = $("#repeatingTransfersGrid").kendoGrid({
168  dataSource: {
169  transport: {
170  read: function(options) {
171  options.success(window.repeatingTransfers);
172  }
173  },
174  schema: {
175  model: {
176  id: "id",
177  fields: {
178  id: {type: "number"},
179  feature_code: {type: "string"},
180  feature: {type: "string"},
181  create_date: {type: "date"},
182  next_trigger_date: {type: "date"},
183  start_date: {type: "date"},
184  end_date: {type: "date"},
185  status: {type: "string"},
186  statusText: {type: "string"},
187  interval: {type: "string"},
188  intervalText: {type: "string"},
189  details: {type: "string"},
190  checked: {type: "boolean", defaultValue: false}
191  }
192  }
193  }
194  },
195  autoBind: false,
196  columns: [
197  {headerTemplate: "<input type='checkbox' class='allCheckbox'>", width: 40},
198  {field: "feature", title: "Feature", width: 200},
199  {field: "details", title: "Details", width: 300},
200  {field: "create_date", title: "Created", width: 50, headerAttributes: {"class": "hidden-xs hidden-sm"}},
201  {field: "start_date", title: "Range", width: 150, headerAttributes: {"class": "hidden-xs hidden-sm hidden-md"}},
202  {field: "next_trigger_date", title: "Next Trigger Date", width: 50},
203  {field: "intervalText", title: "Interval", width: 200, headerAttributes: {"class": "hidden-xs hidden-sm"}},
204  {field: "statusText", title: "Status", width: 100, attributes: {"class": "statusTD"}}
205  ],
206  sortable: true,
207  toolbar: "<div id='actionDDL'></div>",
208  rowTemplate: $("#rowTemplate").html(),
209  scrollable: false
210  }).data("kendoGrid");
211 
212  var actionDDL = $("#actionDDL").kendoDropDownList({
213  dataSource: {
214  data: [{value: "", text: "Action"}]
215  },
216  dataTextField: "text",
217  dataValueField: "value",
218  change: function(e) {
219  var text = this.text();
220  if (text != "") {
221  OpenConfirm(text.toLowerCase(), this.value());
222  }
223  }
224  }).data("kendoDropDownList");
225 
226  actionDDL.select(0);
227  actionDDL.enable(false);
228 
229  var data = <?php echo HCU_JsonEncode($readData); ?>;
230  if (data.error.length > 0) {
231  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
232  } else {
233  window.repeatingTransfers = new kendo.data.ObservableArray(data.repeatingTransfers);
234  repeatingTransfersGrid.dataSource.read();
235  }
236 
237  <?php printCheckboxEvents("#repeatingTransfersGrid"); ?>
238 
239  var inThisEvent = false;
240  $("#repeatingTransfersGrid").on("click", ".allCheckbox, .rowCheckbox", function() {
241  if (inThisEvent) { <?php // Prevent this logic from being executed more than once. ?>
242  return;
243  }
244  inThisEvent = true;
245  actionDDL.select(0);
246 
247  var checkedList = $("#repeatingTransfersGrid .rowCheckbox:checked");
248 
249  if ($("#repeatingTransfersGrid .rowCheckbox:checked").length == 0) {
250  actionDDL.enable(false);
251  } else {
252  var activate = false;
253  var cancel = false;
254  var skip = false;
255  var hasNull = false;
256 
257  $(checkedList).each(function() {
258 
259  var record = repeatingTransfersGrid.dataItem($(this).closest("tr"));
260 
261  activate = activate || record.status == "I";
262  cancel = cancel || record.status == "A";
263  skip = skip || record.status == "A";
264  hasNull = hasNull || record.next_trigger_date == null;
265 
266  if (activate && cancel && skip && hasNull) {
267  return false; <?php // No need to continue. ?>
268  }
269 
270  });
271 
272  if (activate && cancel) { <?php // Records are there for both so neither action is true. ?>
273  actionDDL.enable(false);
274  } else {
275  actionDDL.enable(true);
276  var ddlData = [{value: "", text: "Action"}];
277  if (activate) {
278  ddlData.push({value: "activateTrans", text: "Activate"});
279  }
280  if (cancel) {
281  ddlData.push({value: "cancelTrans", text: "Cancel"});
282  }
283  if (skip && !hasNull) {
284  ddlData.push({value: "skipTrans", text: "Skip"});
285  }
286 
287  actionDDL.dataSource.data(ddlData);
288  actionDDL.select(0);
289  }
290  }
291 
292  inThisEvent = false;
293  });
294 
295  $("#repeatingTransfersGrid").on("click", "tbody tr", function(e) {
296  if ($(e.target).is(".rowCheckbox")) {
297  return;
298  }
299 
300  $(this).find(".rowCheckbox").click();
301  });
302 
303  $("#repeatingTransfersGrid").find("colgroup").each(function() {
304  $(this).find("col:eq(4)").addClass("hidden-xs hidden-sm hidden-md");
305  $(this).find("col:eq(3), col:eq(6)").addClass("hidden-xs hidden-sm"); <?php // hide details, created, and interval on iPad. ?>
306  });
307 
308  $("#repeatingTransfersGrid thead tr").addClass("showClickable");
309  }
310 
311  <?php
312  /**
313  * function postPostPostPost()
314  * This obviously happens after everything else.
315  */
316  ?>
317  function postPostPostPost() {
318  $("#externalTabWindow").data("isClosing", true);
319  $("#externalTabWindow").data("kendoWindow").close();
320  $("#externalTabWindow").data("isClosing", false);
321  }
322 
323  <?php
324  /**
325  * function OpenConfirm()
326  * This opens up the confirmation message.
327  */
328  ?>
329  function OpenConfirm(actionText, actionValue) {
330  var confirmDialog = $("#confirmActionDialog").data("kendoDialog");
331 
332  if (confirmDialog == null) {
333  var content = "Do you wish to continue?";
334  confirmDialog = $("<div id='confirmActionDialog'></div>").appendTo("body").kendoDialog({
335  content: content,
336  actions: [{text: "No", action: function() {
337  confirmDialog.close();
338  var actionDDL = $("#actionDDL").data("kendoDropDownList");
339  actionDDL.value("");
340  return false;
341  }}, {text: "Yes", primary: true, action: function() {
342  confirmDialog.close();
343 
344  var actionValue = $("#confirmActionDialog").data("actionValue");
345  var repeatingTransfersGrid = $("#repeatingTransfersGrid").data("kendoGrid");
346  var actionDDL = $("#actionDDL").data("kendoDropDownList");
347 
348  var gridData = repeatingTransfersGrid.dataSource.data();
349  var changeList = [];
350  for(var i = 0, length = gridData.length; i != length; i++) {
351  var record = gridData[i];
352  if (record.checked) {
353  changeList.push(record.id);
354  }
355  }
356  var parameters = {changeList: kendo.stringify(changeList), payload: "<?php echo $payload; ?>"};
357  showWaitWindow();
358  $.post("<?php echo $self; ?>&operation=" + actionValue, parameters, function(data) {
359  hideWaitWindow();
360  if (data.error.length > 0) {
361  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
362  } else {
363  if (data.info != "") {
364  $.homecuValidator.displayMessage(data.info, $.homecuValidator.settings.statusInfo );
365  }
366 
367  repeatingTransfers = new kendo.data.ObservableArray(data.repeatingTransfers);
368  repeatingTransfersGrid.dataSource.read();
369 
370  actionDDL.value("");
371  actionDDL.enable(false);
372  $("#repeatingTransfersGrid .allCheckbox").prop("checked", false);
373  }
374  });
375  return false;
376  }}],
377  visible: false,
378  open: function() {
379  if (window.activeWindows != null) {
380  window.activeWindows.push(this);
381  }
382  },
383  close: function() {
384  if (window.activeWindows != null) {
385  window.activeWindows.pop();
386  }
387  },
388  visible: false,
389  modal: true,
390  minWidth: 300
391  }).data("kendoDialog");
392  }
393 
394  $("#confirmActionDialog").data("actionText", actionText);
395  $("#confirmActionDialog").data("actionValue", actionValue);
396 
397  var count = 0;
398  var gridData = $("#repeatingTransfersGrid").data("kendoGrid").dataSource.data();
399  for(var i = 0, length = gridData.length; i != length; i++) {
400  if (gridData[i].checked) {
401  count++;
402  }
403  }
404 
405  var contents = "<p>You are about to " + actionText + " " + count + " scheduled transaction" + (count == 1 ? "" : "s") + "." + (actionText == "skip" ? " This cannot be undone." : "")
406  + "</p><p>Are you sure you want to " + actionText + (count == 1 ? " this record" : " these records") + "?</p>";
407  confirmDialog.title("Confirm "+ actionText[0].toUpperCase() + actionText.slice(1)).content(contents).open();
408  }
409 
410  Init();
411 
412  </script>
413 
414  <?php
415  /**
416  * <script id="rowTemplate" ...
417  * This is the script for the kendoGrid's rowTemplate. The main addition is the removal of some columns on the smaller sizes.
418  */
419  ?>
420  <script id="rowTemplate" type="text/x-kendo-template">
421  <tr uid='#= uid #' class="showClickable">
422  <td class="checkboxTD"><input type='checkbox' class='rowCheckbox'></td>
423  <td># if (feature == '') { # &nbsp; # } else { # #: feature # # } #</td>
424  <td>#= details #</td> <?php // Put together on the backend depending on the txnData according to feature. Uses htmlentities. May add a <br>. ?>
425  <td class="hidden-xs hidden-sm"># if (create_date == null) { # &nbsp; # } else { # #: kendo.toString(create_date, "d") # # } #</td>
426  <td class="hidden-xs hidden-sm hidden-md"><b>From</b> # if (start_date == null) { # &nbsp; # } else { # #: kendo.toString(start_date, "d") # # } #
427  # if (end_date != null) { # <br><b>To</b> #: kendo.toString(end_date, "d") # # } #</td>
428  <td># if (next_trigger_date == null) { # &nbsp; # } else { # #: kendo.toString(next_trigger_date, "d") # # } #</td>
429  <td class="hidden-xs hidden-sm"># if (intervalText == '') { # &nbsp; # } else { # #: intervalText # # } #</td>
430  <td class="restriction # if (status == 'A') { # allow # } else { # ban # } #"># if (statusText == '') { # &nbsp; # } else { # #: statusText # # } #</td>
431  </tr>
432  </script>
433 
434  <div class="container hcu-all-100 repeatingDiv vsgPrimary hcu-template" id="repeatingDiv">
435  <div class="row">
436  <div class="col-xs-12 hcu-secondary">
437  <div class="small vsgSecondary">Click on a row to select/unselect. Actions are skip and cancel for active records.
438  For inactive records, there is an option to reactivate.<span class="hidden-md hidden-lg"> Rotate to see more columns.</span></div>
439  </div>
440  </div>
441  <div class="row notificationRow hcuSpacer"></div>
442  <div class="row">
443  <div id="formValidateDiv" class="k-block k-error-colored formValidateDiv" style="display:none"></div>
444  </div>
445  <div class="row">
446  <div class="hcu-all-100" id="repeatingTransfersGrid"></div>
447  </div>
448  <div class="hcu-edit-buttons k-state-default row">
449  <a class="closeBtn k-button k-primary" href="#"><i class="fa fa-check"></i>Close</a>
450  </div>
451  </div>
452 <?php }
Definition: User.php:7