Odyssey
ProdImpStat.prg
1 <?php
2 /*
3  * File: ProdImpStat
4  *
5  * Purpose: This script handles the GUI portion for maintaining the cuprodimpstat table. It is used to track the
6  * current implementation status of various features of HomeCU and HomeCU products.
7  *
8  * History:
9  * 06/15/13 mbl - Modified to link with Implementation menu; stopped using some fields. Added e-mail notification of some
10  * steps (into and out of Published). One-click Next Status button.
11  */
12 
13  $monLibrary= dirname(__FILE__) . "/../library";
14  $sharedLibrary= dirname(__FILE__) . "/../../shared/library";
15  require_once("$monLibrary/cu_top.i");
16  require_once("$monLibrary/ck_hticket.i");
17 
18  if (!CheckPerm($link, $Hu, basename($_SERVER['SCRIPT_NAME']), $_SERVER['REMOTE_ADDR'])) {
19  // ** Permissions failed
20  // ** redirect to new page
21  header("Location: /hcuadm/hcu_noperm.prg");
22  exit;
23  }
24 
25 $dms_ok = array('edress'=>'string','generate'=>'string');
26 dms_import($dms_ok);
27 
28 $dbh = $link;
29 
30 header ("Pragma: no-cache");
31 header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
32 header ("Cache-Control: no-cache, no-store, must-revalidate, max_age=0");
33 header ("Expires: 0");
34 ?>
35 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
36  "http://www.w3.org/TR/html4/loose.dtd">
37 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
38 <head>
39  <title>HomeCU Product Feature Status</title>
40 
41  <!--<link href="/monitor/hcudocs/HomeCU/examples-offline.css" rel="stylesheet">-->
42  <link href="/monitor/css/jquery/css/KendoUI/kendo.common.min.css" rel="stylesheet">
43  <link href="/monitor/css/jquery/css/KendoUI/kendo.<?php echo GetMonitorDefaultKendoStyle(); ?>.min.css" rel="stylesheet">
44 
45  <script src="/monitor/css/jquery/js/jquery-1.8.2.js"></script>
46  <script src="/monitor/css/jquery/js/KendoUI/kendo.web.js"></script>
47  <!--<script src="console.js"></script> -->
48  <style>
49 
50  .floatWrap:after,#prodGrid:after{content:"";display:block;clear:both}
51  .floatWrap,#prodGrid{display:inline-block}
52  .floatWrap,#prodGrid{display:block}
53  .clear{clear:both}
54 
55  html
56  {
57  overflow-y:scroll;
58  font:75% 'Lucida Sans Unicode','Lucida Grande',arial,helvetica,sans-serif;
59  background-color:#e2e2e2;
60  }
61  #prodGrid
62  {
63  margin: 20px 0;
64  }
65  #backExit
66  {
67  color: blue;
68  }
69  </style>
70 </head>
71 <body>
72 
73  <h2>HomeCU Product Feature Status</h2>
74 
75  <div id="prodGrid" class="k-content">
76  <div id="grid"></div>
77 
78  <script id="toolbarTemplate" type="text/x-kendo-template">
79  <a class="k-button k-button-icontent k-grid-add" id="addRecord" onclick="return AddRecord();"><span class="k-icon k-add"></span>Add New Record</a>
80  <a class="k-button" id="filterToggle" onclick="return CheckShowFiltered()">Remove Filter</a>
81  <a class="k-button" id="pageToggle" onclick="return CheckShowAll()">Show All</a>
82  <a class="k-button" onclick="return CheckReload()">Reload Page</a>
83  &nbsp;
84  <a class="k-button" id="backExit" onclick="return CheckExit()">Credit Union List</a>
85  <span id="displayStatus"></span>
86  </script>
87  <script>
88 
89  var initialFilter = { logic: "and", filters: [{ field: "impStatus", operator: "neq", value: "Complete" }] };
90 // var filterStatus = [
91 // { field: "impStatus", operator: "neq", value: "Complete" }
92 // ];
93  var filterDeveloper = { logic: "or", filters: [
94  { field: "developer", operator: "eq", value: "Unassigned" }
95  ] };
96  <?php
97 
98  // set up a default filter based on cookie/user (filter different for different people)
99  if ( strlen( $Hu ) )
100  {
101  // NOTE: spelling/case needs to match dmsmonitorusers.user_name
102  if ( $Hu == "jan" ) {
103  // reset to just Published
104  print "filterDeveloper = { logic: \"or\", filters: [ { field: \"impStatus\", operator: \"eq\", value: \"Published\" } ] );";
105  } else if ( $Hu == "cerise" ) {
106  // reset to just either Billing
107  print "filterDeveloper = { logic: \"or\", filters: [ { field: \"impStatus\", operator: \"eq\", value: \"Bill Setup\" }, { field: \"impStatus\", operator: \"eq\", value: \"Bill Month\" } ] );";
108  } else if ( $Hu == "Mike" || $Hu == "Mark" || $Hu == "Kim" | $Hu == "miki" ) {
109  // add to the developer filter
110  print "filterDeveloper.filters.push( { field: \"developer\", operator: \"eq\", value: \"$Hu\" } );";
111  } else if ( $Hu == "jayme" || $Hu == "Elaine" ) {
112  // add to the developer filter
113  print "filterDeveloper.filters.push( { field: \"developer\", operator: \"eq\", value: \"jayme\" } );";
114  print "filterDeveloper.filters.push( { field: \"developer\", operator: \"eq\", value: \"Elaine\" } );";
115  }
116  }
117 ?>
118 // initialFilter.filters.push( filterStatus );
119  initialFilter.filters.push( filterDeveloper );
120 
121  var filteredNow = true;
122  function CheckShowFiltered() {
123  if ( filteredNow ) {
124  $("#grid").data("kendoGrid").dataSource.filter( {} );
125  filteredNow = false;
126  $("#filterToggle").html("Filter For Me");
127  } else {
128  $("#grid").data("kendoGrid").dataSource.filter( initialFilter );
129  filteredNow = true;
130  $("#filterToggle").html("Remove Filters");
131  }
132  }
133 
134  function AddRecord() {
135  // drop the filters first
136  $("#grid").data("kendoGrid").dataSource.filter( {} );
137  $("#grid").data("kendoGrid").addRow();
138  }
139 
140  var showingPages = true;
141  function CheckShowAll() {
142  var pageSize = 5;
143  if ( showingPages ) {
144  $("#grid").data("kendoGrid").pageable = false;
145  pageSize = $("#grid").data("kendoGrid").dataSource.total();
146 
147  showingPages = false;
148  $("#pageToggle").html("Show Pages");
149  } else {
150  $("#grid").data("kendoGrid").pageable = true;
151 
152  showingPages = true;
153  $("#pageToggle").html("Show All");
154  }
155 
156  $("#grid").data("kendoGrid").dataSource.pageSize(pageSize);
157 
158  }
159 
160  function CheckExit() {
161  if(doesDataSourceHaveChanges($("#grid").data("kendoGrid").dataSource)) {
162  if ( !confirm("Abandon Changes?") ) {
163  return;
164  }
165  }
166 
167  location.href = "/monitor/mindex.html";
168  }
169 
170  function CheckReload() {
171  if(doesDataSourceHaveChanges($("#grid").data("kendoGrid").dataSource)) {
172  if ( !confirm("Abandon Changes?") ) {
173  return;
174  }
175  }
176 
177  location.reload(true);
178  }
179 
180 function doesDataSourceHaveChanges(ds)
181 {
182  var dirty = false;
183 
184  $.each(ds._data, function ()
185  {
186  if (this.dirty == true)
187  {
188  dirty = true;
189  }
190  });
191 
192  if (ds._destroyed.length > 0)
193  {
194  dirty = true;
195  }
196 
197  return dirty;
198 }
199 
200  $(document).ready(function() {
201 
202  var cuCodeSource = new kendo.data.DataSource({
203  autoSync: false,
204  batch: true,
205  transport: {
206  read: {
207  url: "ProdImpStat.data",
208  dataType: "json",
209  data: {
210  action: "readculist"
211  },
212  type: "GET",
213  cache: true
214  }
215  },
216  requestEnd: function( e ) {
217  var test = this.data;
218  if ( e.type === "read" ) {
219 //alert( "Read cu code!" );
220  }
221  },
222  schema: {
223  model: {
224  fields: {
225  cuCode: {type: "string"},
226  cuName: {type: "string"}
227  }
228  },
229  errors: "Errors"
230  },
231  error: function (e) {
232  alert("cuCodeSource: " + e.errors);
233  }
234  });
235 
236  var cuEmployeeSource = new kendo.data.DataSource({
237  autoSync: true,
238  batch: true,
239  transport: {
240  read: {
241  url: "ProdImpStat.data",
242  dataType: "json",
243  data: {
244  action: "reademployees"
245  },
246  type: "GET",
247  cache: true
248  }
249  },
250  requestEnd: function( e ) {
251  var test = this.data;
252  if ( e.type === "read" ) {
253 //alert( "Read employees!" );
254  }
255  },
256  schema: {
257  model: {
258  fields: {
259  cuEmployee: {type: "string"}
260  }
261  },
262  errors: "Errors"
263  },
264  error: function (e) {
265  alert("cuEmployeeSource: " + e.errors);
266  }
267  });
268 
269  var dataSource = new kendo.data.DataSource({
270  autoSync: false,
271  batch: false,
272  pageSize: 10,
273  transport: {
274  read: {
275  url: "ProdImpStat.data",
276  dataType: "json",
277  contentType: "application/json",
278  data: {
279  action: "read"
280  },
281  type: "GET",
282  cache: false
283  },
284  update: {
285  url: "ProdImpStat.data",
286  contentType: "application/x-www-form-urlencoded",
287  data: {
288  action: "update"
289  },
290  type: "POST",
291  cache: false
292  },
293  create: {
294  url: "ProdImpStat.data",
295  contentType: "application/x-www-form-urlencoded",
296  data: {
297  action: "create"
298  },
299  type: "POST",
300  cache: false
301  },
302  parameterMap: function (options, operation) {
303  // if the current operation is an update
304  if ( operation === "create" || operation === "update" ) {
305  // create a new JavaScript date object based on the current
306  // date parameter value and save in correct format
307  if ( options.eneteredOn && options.enteredOn.toString().length > 0 ) {
308  var d = new Date(options.enteredOn);
309  options.enteredOn = kendo.toString(new Date(d), "MM/dd/yyyy");
310  }
311  if ( options.targetDate && options.targetDate.toString().length > 0 ) {
312  var d = new Date(options.targetDate);
313  options.targetDate = kendo.toString(new Date(d), "MM/dd/yyyy");
314  }
315  if ( options.startOn && options.startOn.toString().length > 0 ) {
316  var d = new Date(options.startOn);
317  options.startOn = kendo.toString(new Date(d), "MM/dd/yyyy");
318  }
319  if ( options.finishOn && options.finishOn.toString().length > 0 ) {
320  var d = new Date(options.finishOn);
321  options.finishOn = kendo.toString(new Date(d), "MM/dd/yyyy");
322  }
323  if ( options.billedSetup && options.billedSetup.toString().length > 0 ) {
324  var d = new Date(options.billedSetup);
325  options.billedSetup = kendo.toString(new Date(d), "MM/dd/yyyy");
326  }
327  if ( options.billedMonthly && options.billedMonthly.toString().length > 0 ) {
328  var d = new Date(options.billedMonthly);
329  options.billedMonthly = kendo.toString(new Date(d), "MM/dd/yyyy");
330  }
331  }
332  // ALWAYS return options
333  return options;
334  }
335  },
336 
337  requestEnd: function( e ) {
338  var error = null;
339  // see if there is an error
340  if ( e.response && e.response.error )
341  error = e.response.error;
342 
343  if ( error && error.length > 0 ) {
344  e.preventDefault();
345  alert( error );
346  // refresh the grid if it was an update or create
347  if ( e.type === "update" || e.type === "create" )
348  e.sender.read();
349  }
350  else
351  if ( e.type === "update" ) {
352  showStatus( "Data Saved Successfully" );
353 //alert( "Update!" );
354  }
355  else if ( e.type === "read" ) {
356 //alert( "Read!" );
357  }
358  else if ( e.type === "create" ) {
359 //alert( "Create!" );
360  showStatus( "Data Added Successfully" );
361  }
362  else if ( e.type === "destroy" ) {
363 //alert( "Destroy!" );
364  }
365  },
366 
367  // code to run if the request fails; the raw request and
368  // status codes are passed to the function
369  error: function( e ) {
370  alert( "Sorry, update had a problem! Status: " + e.status );
371  },
372 // never sort in the dataSource as it seems to cause problems with adding records
373  schema: {
374  model: {
375  id: "impid",
376  fields: {
377  impid: {type: "number"},
378  md5hash: {type: "string"},
379  cuCode: {nullable: false, validation: {required: true}},
380  impStatus: {type: "string", validation: {required: true}, defaultValue: "New"},
381  cuName: {type: "string", editable: false },
382  author: {type: "string", validation: {required: true}, defaultValue: "Unassigned"},
383  cuProduct: {type: "string", validation: {required: true}, defaultValue: "Unassigned"},
384  enteredOn: {type: "date", parseFormats: ["yyyy-MM-dd"]},
385  developer: {type: "string", defaultValue: "Unassigned"},
386  targetDate: {type: "date", defaultValue: null},
387  startOn: {type: "date", defaultValue: null},
388  finishOn: {type: "date", defaultValue: null},
389  billedSetup: {type: "date", defaultValue: null},
390  billedMonthly: {type: "date", defaultValue: null},
391  vendor: {type: "string", defaultValue: "N/A"}
392  }
393  },
394  errors: "Errors"
395  }
396  });
397 
398  function showStatus( status ) {
399  var el = $("#displayStatus");
400  el.text( status );
401  el.css('background-color','greenyellow');
402  el.css("visibility", "visible");
403  var effect = kendo.fx(el).fadeOut().duration(10000);
404 
405  effect.play().then(function() {
406  $("#displayStatus").text( "" );
407  });
408  }
409 
410  var cuVendorSource = new kendo.data.DataSource({
411  autoSync: false,
412  batch: true,
413  transport: {
414  read: {
415  url: "ProdImpStat.data",
416  dataType: "json",
417  data: {
418  action: "readvendor"
419  },
420  type: "GET",
421  cache: true
422  }
423  },
424  requestEnd: function( e ) {
425  var test = this.data;
426  if ( e.type === "read" ) {
427 //alert( "Read vendor!" );
428  }
429  },
430  schema: {
431  model: {
432  fields: {
433  cuVendor: {type: "string"}
434  }
435  },
436  errors: "error"
437  },
438  error: function (e) {
439  alert("cuVendorSource: " + e.errors);
440  }
441  });
442 
443  var nextStatusDS = new kendo.data.DataSource({
444  transport: {
445  read: {
446  url: "ProdImpStat.data",
447  dataType: "json",
448  contentType: "application/json",
449  type: "GET",
450  cache: false,
451  data: {
452  action: "nextstatus"
453  }
454  }
455  },
456  requestEnd: function( e ) {
457  var error = null;
458  // see if there is an error
459  if ( e.response && e.response.error )
460  error = e.response.error;
461 
462  if ( error && error.length > 0 ) {
463  e.preventDefault();
464  alert( error );
465  }
466  else if ( e.type === "read" ) {
467  // refesh the grid
468  dataSource.read();
469  }
470  },
471 
472  // code to run if the request fails; the raw request and
473  // status codes are passed to the function
474  error: function( e ) {
475  alert( "Error occurred. Please refresh! Status: " + e.status );
476  }
477  });
478 
479 
480 
481  var productList = [
482  { text: "Unassigned", value: "Unassigned" },
483  { text: "Bill Pay", value: "BP" },
484  { text: "IVR Product", value: "IVR" },
485  { text: "Loan App", value: "LNAPP" },
486  { text: "Mobile Android App", value: "MBLADA" },
487  { text: "Mobile Bill Pay", value: "MBLBP" },
488  { text: "Mobile iPhone App", value: "MBLAPP" },
489  { text: "Mobile Text Banking", value: "MBLTXT" },
490  { text: "Mobile Web Classic", value: "MBLCLS" },
491  { text: "Mobile Web (New)", value: "MBLWEB" },
492  { text: "Remote Deposit Capture", value: "RDC" },
493  { text: "Website Devel", value: "WEBS" }
494  ];
495  // Note: These names cannot change as there are code checks on the extact string.
496  var statusList = [
497  { text: "New", value: "New" },
498  { text: "In Devel", value: "In Devel" },
499  { text: "In Review", value: "In Review" },
500  { text: "Published", value: "Published" },
501  { text: "Billing Setup", value: "Bill Setup" },
502  { text: "Billing Monthly", value: "Bill Month" },
503  { text: "Complete", value: "Complete" }
504  ];
505 
506  dataSource.filter(initialFilter);
507 
508 
509 // sorting goofs up the add record
510 // dataSource.sort({ field: "contractDate", dir: "asc" });
511  var currEdit = null;
512  var grid = $("#grid").kendoGrid({
513  autoBind: true,
514  dataSource: dataSource,
515  toolbar: ["cancel",
516  { template: kendo.template($("#toolbarTemplate").html()) }
517  ],
518  scrollable: true,
519  sortable: true,
520  selectable: "row",
521  groupable: true,
522  filterable: true,
523  editable: "popup",
524  pageable: {
525  input: false,
526  numeric: false,
527  pageSize: 5,
528  pageSizes : true,
529  refresh: true,
530  messages: {
531  refresh: "Refreshment, please"
532  }
533  },
534  columns: [
535  { command: [
536  {
537  text: "Next Status",
538  click: onClickNextStatus
539  },
540  { name: "edit",
541  text: "Edit"
542  } // built-in "edit" command
543  ],
544  title: "", width: "170px"},
545  { field: "cuCode", title: "CU Code", width: "80px", groupable:false, editor: cuCodeEditor, filterable: { ui: cuListFilter } },
546  { field: "impStatus", title: "Status", width: "70px", values: statusList },
547  { field: "cuName", title: "Name", width: "150px", resizeable: true, readonly: true,
548  template: function(dataItem) {
549  if ( !dataItem.cuName ) {
550  dataItem.cuName = "Available after update";
551  }
552 
553  return dataItem.cuName;
554  }
555  },
556  { field: "author", title: "Author", width: "90px", editor: cuEmpEditor, filterable: { ui: cuEmpFilter } },
557  { field: "cuProduct", title: "Product", width: "140px", values: productList },
558  { field: "enteredOn", title: "Entered On", format: "{0:MM/dd/yyyy}", parseFormat: "{0:MM/dd/yyyy}", width: "110px"},
559  { field: "billedSetup", title: "Billed Setup", format: "{0:MM/dd/yyyy}", width: "110px" },
560  { field: "billedMonthly", title: "Billed Monthly", format: "{0:MM/dd/yyyy}", width: "120px" },
561  { field: "developer", title: "Developer", width: "100px", editor: cuEmpEditor, filterable: { ui: cuEmpFilter } },
562  { field: "targetDate", title: "Target Date", format: "{0:MM/dd/yyyy}", width: "110px" },
563  { field: "startOn", title: "Start Date", format: "{0:MM/dd/yyyy}", width: "110px" },
564  { field: "finishOn", title: "Finish Date", format: "{0:MM/dd/yyyy}", width: "110px" },
565  { field: "vendor", title: "Vendor", width: "70px", editor: cuVendorEditor, filterable: { ui: cuVendorFilter } }
566  ],
567  dataBound: function() {
568  var data = this._data;
569  for(var x = 0; x< data.length; x++)
570  {
571  var dataItem = data[x];
572  var tr = $("#grid").find("[data-uid='" + dataItem.uid + "']");
573  var cell = $("td:nth-child(3)", tr);
574  var color = "red"
575  if ( dataItem.impStatus === "New" ) color = "yellow";
576  else if ( dataItem.impStatus === "In Devel" ) color = "orange";
577  else if ( dataItem.impStatus === "In Review" ) color = "cyan";
578  else if ( dataItem.impStatus === "Published" ) color = "lightblue";
579  else if ( dataItem.impStatus === "Bill Setup" ) color = "lightgreen";
580  else if ( dataItem.impStatus === "Bill Month" ) color = "greenyellow";
581  else if ( dataItem.impStatus === "Complete" ) color = "green";
582 
583  cell.css("background-color", color);
584  }
585  },
586  saveChanges: function(e) {
587  // This isn't used because the Save command button isn't shown
588 /*
589  if (!confirm("Are you sure you want to save all changes?")) {
590  e.preventDefault();
591  } else {
592  $("#script_doc").html(JSON.stringify(dataSource.data()));
593  if (!confirm("Submit Changes?")) {
594 // document.preview.submit();
595 // dataSource.sync();
596  e.preventDefault();
597  }
598  }
599 */
600  },
601  edit: function(e) {
602  // save a reference to what is being edited
603  currEdit = e.model;
604 // var grid = $("#grid").data("kendoGrid");
605 
606  // clear any filter
607 // grid.dataSource.filter([]);
608 
609  // clear any sort
610 // grid.dataSource.sort([]);
611  },
612  save : function(e) {
613  // saving an edit so refresh
614 // var grid = $("#grid").data("kendoGrid");
615 // grid.refresh();
616  }
617  });
618 
619  function cuListFilter(element) {
620  element.kendoDropDownList({
621  dataTextField: "cuName",
622  dataValueField: "cuCode",
623  dataSource: cuCodeSource,
624  optionLabel: "--Select Value--"
625  });
626  }
627 
628  function cuEmpFilter(element) {
629  element.kendoDropDownList({
630  dataTextField: "cuEmployee",
631  dataValueField: "cuEmployee",
632  dataSource: cuEmployeeSource,
633  optionLabel: "--Select Value--"
634  });
635  }
636 
637  function cuVendorFilter(element) {
638  element.kendoDropDownList({
639  dataTextField: "cuVendor",
640  dataValueField: "cuVendor",
641  dataSource: cuVendorSource,
642  optionLabel: "--Select Value--"
643  });
644  }
645 
646  function cuCodeEditor(container, options) {
647  $('<input data-bind="value:' + options.field + '"/>')
648  .appendTo(container)
649  .kendoDropDownList({
650  dataTextField: "cuName",
651  dataValueField: "cuCode",
652  autoBind: true,
653  optionLabel: "--Select Value--",
654  dataSource: cuCodeSource,
655  change: function(e) {
656  var value = this.dataItem();
657  if ( value.cuName ) {
658  currEdit.cuName = value.cuName;
659  }
660  }
661  });
662  }
663 
664  function cuEmpEditor(container, options) {
665  $('<input data-bind="value:' + options.field + '"/>')
666  .appendTo(container)
667  .kendoDropDownList({
668  dataTextField: "cuEmployee",
669  dataValueField: "cuEmployee",
670  autoBind: true,
671  optionLabel: "--Select--",
672  dataSource: cuEmployeeSource
673  });
674  }
675 
676  function cuVendorEditor(container, options) {
677  $('<input data-bind="value:' + options.field + '"/>')
678  .appendTo(container)
679  .kendoDropDownList({
680  dataTextField: "cuVendor",
681  dataValueField: "cuVendor",
682  autoBind: true,
683  optionLabel: "--Select Vendor--",
684  dataSource: cuVendorSource
685  });
686  }
687 
688  // Handle the "Next Step" process
689  function onClickNextStatus(e) {
690  var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
691 
692  var request = { action: "nextstatus", impid: dataItem.impid };
693 
694  nextStatusDS.read( request );
695  }
696 
697  });
698 
699  </script>
700  </div>
701 <?php
702 /* Not used at this point since each row updates as it is changed.
703 ?>
704 <form name="preview" action="/hcuadm/DocMaint" method="post">
705  <input type="hidden" name="action" value="saveedit">
706  <input type="hidden" name="csub" value="HomeCU">
707  <input type="hidden" name="cdir" value="HomeCU">
708  <input type="hidden" name="efile" value="MobileProductData.js">
709  <br>
710  <textarea id="script_doc" name="script_doc" rows=40 cols=120></textarea>
711 
712  <input type="submit" name="btnSubmit" value="Manual Submit" id="btnSubmit">
713 </form>
714 <?php
715  */
716 ?>
717 </body>
718 </html>