Odyssey
salesOrderDetail.prg
1 <?php
2 /* File: salesOrderDetail.html
3  * Purpose: To initialize grid and CRUD calls on the salesOrderDetail page
4  */
5 $isInEditList = GetIsInEditList($dbh, $Hu);
6 ?>
7 
8 <script type="text/javascript">
9 
10 <?php
11 // Get common JS functions here.
12 getShowWaitFunctions();
13 ?>
14 
15 <?php // ===================
16  // JAVASCRIPT GLOBALS
17  // =================== ?>
18 
19 var salesOrderId = <?php echo intval($SYSENV["BILL"]["salesOrderId"]); ?>;
20 
21 <?php // ===================
22  // VALIDATION FUNCTIONS
23  // =================== ?>
24 
25 <?php
26 /**
27  * function SetupMainForm()
28  * Sets up the homecuValidator for the main form.
29  * This is needed when loading the screen
30  * and when closing dialogs/windows with their validation.
31  */
32 ?>
33 function SetupMainForm() {
34  $.homecuValidator.setup({formValidate:'formMain', formStatusField: 'formValidateMainDiv'});
35 }
36 
37 <?php
38 /**
39  * function SetupProductValidation(form, statusField)
40  * Sets up the validation when adding a product (sales order detail.)
41  *
42  * @param form -- String to be used in "formValidate."
43  * @param statusField -- String to be used in "formStatusField."
44  */
45 ?>
46 function SetupProductValidation(form, statusField) {
47 
48  $.homecuValidator.setup({formValidate: form, formStatusField: statusField, homecuCustomRules: {
49  bhip: function(input) {
50  if (!$(input).is("[name='halfBillDate']")) {
51  return true;
52  }
53  if (productObservable.get("bindOptions.billHalfDateRowVisible") !== true) {
54  return true;
55  }
56  if (productObservable.get("bindOptions.billHalfRowVisible") !== true) {
57  return true;
58  }
59  var billHalfDate = productObservable.get("source.partiallyBilledDate");
60 
61  <?php // First of the month ?>
62  var now = new Date();
63  now.setDate(1);
64  now.setHours(0,0,0,0);
65 
66  if(billHalfDate != null && now.getTime() >= billHalfDate.getTime()) {
67  $(input).attr("data-bhip-msg", "Cannot bill this month or before.");
68  return false;
69  }
70 
71  return true;
72  },
73  crif: function(input) {
74  if (!$(input).is("[name='checkReceived']")) {
75  return true;
76  }
77  if (productObservable.get("bindOptions.billHalfCheckReceivedRowVisible") !== true) {
78  return true;
79  }
80  if (productObservable.get("bindOptions.billHalfRowVisible") !== true) {
81  return true;
82  }
83  var checkReceivedDate = productObservable.get("source.partiallyBilledDate");
84 
85  var now = new Date();
86  now.setHours(0,0,0,0);
87 
88  if (checkReceivedDate != null) {
89  checkReceivedDate.setHours(0,0,0,0);
90  }
91 
92  if(checkReceivedDate != null && now.getTime() < checkReceivedDate.getTime()) {
93  $(input).attr("data-crif-msg", "Cannot receive a check in the future.");
94  return false;
95  }
96 
97  return true;
98  },
99  bojip: function(input) {
100  if (!$(input).is("[name='immediateBillDate']")) {
101  return true;
102  }
103  if (productObservable.get("bindOptions.immediateBillRowVisible") !== true) {
104  return true;
105  }
106  if (productObservable.get("bindOptions.billHalfRowVisible") !== true) {
107  return true;
108  }
109  if (productObservable.get("bindOptions.workflowRowVisible") !== true) {
110  return true;
111  }
112  var immediateBillDate = productObservable.get("source.partiallyBilledDate");
113 
114  <?php // First of the month ?>
115  var now = new Date();
116  now.setDate(1);
117  now.setHours(0,0,0,0);
118 
119  if(immediateBillDate != null && now.getTime() >= immediateBillDate.getTime()) {
120  $(input).attr("data-bojip-msg", "Cannot bill this month or before.");
121  return false;
122  }
123 
124  return true;
125  }
126  }});
127 }
128 
129 <?php
130 /**
131  * function SetupLineItemValidation(form, statusField)
132  * Sets up the validation when adding/editing a line item.
133  *
134  * @param form -- String to be used in "formValidate."
135  * @param statusField -- String to be used in "formStatusField."
136  */
137 ?>
138 function SetupLineItemValidation(form, statusField) {
139  $.homecuValidator.setup({formValidate: form, formStatusField: statusField, homecuCustomRules: {
140  bhip: function(input) {
141  if (!$(input).is("[name='billHalfDate']")) {
142  return true;
143  }
144  if (lineItemObservable.get("bindOptions.billHalfDateRowVisible") !== true) {
145  return true;
146  }
147  var billHalfDate = lineItemObservable.get("source.partiallyBilledDate");
148 
149  <?php // First of the month ?>
150  var now = new Date();
151  now.setDate(1);
152  now.setHours(0,0,0,0);
153 
154  if(billHalfDate != null && now.getTime() >= billHalfDate.getTime()) {
155  $(input).attr("data-bhip-msg", "Cannot bill this month or before.");
156  return false;
157  }
158 
159  return true;
160  },
161  crif: function(input) {
162  if (!$(input).is("[name='checkReceived']")) {
163  return true;
164  }
165  if (lineItemObservable.get("bindOptions.billHalfCheckReceivedRowVisible") !== true) {
166  return true;
167  }
168  var checkReceivedDate = lineItemObservable.get("source.partiallyBilledDate");
169 
170  var now = new Date();
171  now.setHours(0,0,0,0);
172 
173  if (checkReceivedDate != null) {
174  checkReceivedDate.setHours(0,0,0,0);
175  }
176 
177  if(checkReceivedDate != null && now.getTime() < checkReceivedDate.getTime()) {
178  $(input).attr("data-crif-msg", "Cannot receive a check in the future.");
179  return false;
180  }
181 
182  return true;
183  },
184  bojip: function(input) {
185  if (!$(input).is("[name='immediateBillDate']")) {
186  return true;
187  }
188  if (lineItemObservable.get("bindOptions.immediateBillRowVisible") !== true) {
189  return true;
190  }
191  var immediateBillDate = lineItemObservable.get("source.partiallyBilledDate");
192 
193  <?php // First of the month ?>
194  var now = new Date();
195  now.setDate(1);
196  now.setHours(0,0,0,0);
197 
198  if(immediateBillDate != null && now.getTime() >= immediateBillDate.getTime()) {
199  $(input).attr("data-bojip-msg", "Cannot bill this month or before.");
200  return false;
201  }
202 
203  return true;
204  },
205  crreq: function(input) {
206  if (!$(input).is("[name='checkReceivedAmount']")) {
207  return true;
208  }
209  if (lineItemObservable.get("bindOptions.billHalfAmountRowVisible") !== true) {
210  return true;
211  }
212 
213  if ($(input).val().trim() == "") {
214  $(input).attr("data-crreq-msg", "Check amount is required.");
215  return false;
216  }
217 
218  return true;
219  },
220  vres: function(input) {
221  if (!$(input).is("[name='qty2Range']")) {
222  return true;
223  }
224 
225  var qty1 = lineItemObservable.get("source.qty1");
226  var qty2 = lineItemObservable.get("source.qty2");
227 
228  <?php // qty2 is not required because nothing is -1. ?>
229  if (qty1 != null && qty2 != null && qty2 < qty1) {
230  $(input).attr("data-vres-msg", "Range is not valid.");
231  return false;
232  }
233 
234  return true;
235  }
236  }});
237 }
238 
239 <?php // ===================
240  // SETUP ACTIVE GRID DIALOGS
241  // =================== ?>
242 
243 <?php
244 /**
245  * function SetupActiveGridDialogs()
246  * Sets up all the dialogs on the active grid.
247  */
248 ?>
249 function SetupActiveGridDialogs() {
250  <?php
251  /**
252  * @var deleteActiveDialog
253  * The dialog to confirm deletion of a billing line item.
254  */
255  ?>
256  $("#activeGrid").on("click", ".k-grid-customDelete", function() {
257  var activeGrid = $("#activeGrid").data("kendoGrid");
258  var activeTr = $(this).closest("tr");
259  var activeDataItem = activeGrid.dataItem(activeTr);
260  var bottomId = activeDataItem.featureDetailId;
261 
262  var deleteActiveDialog = $("#deleteActiveDialog").data("kendoDialog");
263  if (deleteActiveDialog == null) {
264  deleteActiveDialog = $("<div id='deleteActiveDialog'></div>").appendTo("body").kendoDialog({
265  title: "Confirm Deletion",
266  actions: [
267  {text: "Cancel"},
268  {text: "Delete", primary: true, action: function() {
269 
270  var bottomId = $("#deleteActiveDialog").data("bottomId");
271 
272  var parameters = {operation: "removeBillingFeature", featureDetailId: bottomId};
273 
274  activeGridHelperDs.read(parameters);
275  }}
276  ],
277  visible: false,
278  open: function() {
279  if (window.activeWindows != null) {
280  window.activeWindows.push(this);
281  }
282  },
283  close: function() {
284  if (window.activeWindows != null) {
285  window.activeWindows.pop();
286  }
287  },
288  modal: true,
289  content: "Are you sure that you want to delete this line item?"
290  }).data("kendoDialog");
291  }
292 
293  $("#deleteActiveDialog").data({bottomId: bottomId});
294  deleteActiveDialog.open().center();
295  });
296 
297  $("#activeGrid").on("click", ".k-grid-advanceWorkflow", function() {
298  var grid = $("#activeGrid").data("kendoGrid");
299  var tr = $(this).closest("tr");
300  var dataItem = grid.dataItem($(tr));
301  ShowActiveEndMonthWindow(dataItem.completeButtonText, dataItem.featureDetailId, dataItem.endDate);
302  return false;
303  });
304 
305  $("#activeGrid").on("click", ".k-grid-changePrice", function() {
306  var grid = $("#activeGrid").data("kendoGrid");
307  var tr = $(this).closest("tr");
308  var dataItem = grid.dataItem($(tr));
309  var parameters = {operation: "readSalesOrderActiveLineItem", featureDetailId: dataItem.featureDetailId};
310 
311  activeGridHelperDs.read(parameters);
312  return false;
313  });
314 
315 }
316 
317 <?php
318 /**
319  * function ShowActiveChangePriceWindow(lineItemData, configuration, bindOptions, ddls)
320  * This displays the active change price window.
321  *
322  * @param lineItemData -- the full values of the line item from the line item read.
323  * @param configuration -- the configuration (labels and which controls are shown.)
324  * @param bindOptions -- the values of the dropdownlists and which controls are shown.
325  * @param ddls -- the data for additional dropdownlists.
326  */
327 ?>
328 function ShowActiveChangePriceWindow(lineItemData, configuration, bindOptions, ddls) {
329  var activeChangePriceWindow = $("#activeChangePriceWindow").data("kendoWindow");
330  if (activeChangePriceWindow == null) {
331  <?php
332  /**
333  * @var activeChangePriceWindow
334  * The KendoWindow with the line item observable.
335  * Since the line item is already active,
336  * workflow, bill half, and frequency options are not allowed.
337  */
338  ?>
339  activeChangePriceWindow = $("<div id='activeChangePriceWindow'></div>").appendTo("body").kendoWindow({
340  modal: true,
341  title: "Change Price",
342  visible: false,
343  width: 400,
344  close: function(e) {
345  if (window.activeWindows != null) {
346  window.activeWindows.pop();
347  }
348 
349  SetupMainForm();
350  },
351  open: function() {
352  if (window.activeWindows != null) {
353  window.activeWindows.push(this);
354  }
355 
356  SetupLineItemValidation("activeChangePriceForm", "formValidateChangePrice");
357  }
358  }).data("kendoWindow");
359  } else {
360  kendo.destroy($("#activeChangePriceWindow #activeChangePriceForm"));
361  }
362 
363  lineItemObservable.setupValues(lineItemData, bindOptions);
364 
365  <?php // the configuration part will be used in a couple of windows. Extending it this way. ?>
366  var fullBindText = $("#activeChangePriceTemplate").html();
367 
368  var template = kendo.template($("#detailConfigTemplate").html());
369 
370  configuration.addOrUpdate = "update";
371  fullBindText = fullBindText.replace("<!-- configDiv -->", template(configuration));
372 
373  activeChangePriceWindow.content(fullBindText);
374  kendo.bind(activeChangePriceWindow.element, lineItemObservable);
375  activeChangePriceWindow.open().center();
376 
377  <?php // This is here because the whole window is bound. Therefore, the click events are removed. ?>
378  $("#activeChangePriceWindow .continueBtn").on("click", function() {
379  if ($.homecuValidator.validate()) {
380  $("#activeChangePriceWindow").data("kendoWindow").close();
381 
382  var parameters = lineItemObservable.getSaveParameters();
383  <?php // Won't do it if you don't give it the operation. ?>
384  parameters.operation = "updateActiveBillingFeature";
385 
386  activeGridHelperDs.read(parameters);
387  }
388 
389  return false;
390  });
391 
392  $("#activeChangePriceWindow .cancelBtn").on("click", function() {
393  $("#activeChangePriceWindow").data("kendoWindow").close();
394  return false;
395  });
396 }
397 
398 <?php
399 /**
400  * function ShowActiveEndMonthWindow(buttonText, featureId, endDate)
401  * This displays the window to set the end month.
402  *
403  * @param buttonText -- This is the text of the button clicked.
404  * It will check to see if it is an "undo" and if so, then revert.
405  * @param featureId -- the feature detail id of the line item.
406  * @param endDate -- the end date of the line item.
407  */
408 ?>
409 function ShowActiveEndMonthWindow(buttonText, featureId, endDate) {
410  var activeEndMonthWindow = $("#activeEndMonthWindow").data("kendoWindow");
411  var activeEndMonthDDL = $("#activeEndMonthDDL").data("kendoDropDownList");
412 
413  if (activeEndMonthWindow == null) {
414 
415  <?php
416  /**
417  * @var activeEndMonthWindow
418  * The KendoWindow with the endMonthDDL.
419  */
420  ?>
421  activeEndMonthWindow = $("<div id='activeEndMonthWindow'></div>").appendTo("body").kendoWindow({
422  modal: true,
423  title: "Set End Month",
424  content: {
425  template: $("#changeEndMonthTemplate").html()
426  },
427  visible: false,
428  width: 300,
429  close: function(e) {
430  if (window.activeWindows != null) {
431  window.activeWindows.pop();
432  }
433  },
434  open: function() {
435  if (window.activeWindows != null) {
436  window.activeWindows.push(this);
437  }
438  }
439  }).data("kendoWindow");
440 
441  <?php
442  /**
443  * @var activeEndMonthDDL
444  * The KendoDropDownList that contains a list of month dates.
445  */
446  ?>
447  var activeEndMonthDDL = $("#activeEndMonthDDL").kendoDropDownList({
448  dataSource: {
449  data: lineItemObservable.get("ddls.startMonthOptions"),
450  schema: {
451  model: {
452  id: "value",
453  fields: {
454  text: {type: "string"},
455  value: {type: "string"}
456  }
457  }
458  }
459  },
460  dataTextField: "text",
461  dataValueField: "value"
462  }).data("kendoDropDownList");
463 
464  $("#activeEndMonthWindow .continueBtn").click(function() {
465  $("#activeEndMonthWindow").data("kendoWindow").close();
466 
467  var parameters = {};
468  parameters.childType = $("#activeEndMonthWindow").data("childType");
469  parameters.featureDetailId = $("#activeEndMonthWindow").data("featureDetailId");
470  parameters.operation = "modifyStatus";
471  parameters.endDate = $("#activeEndMonthDDL").data("kendoDropDownList").value();
472  parameters.orderDetailId = $("#activeEndMonthWindow").data("orderDetailId");
473 
474  activeGridHelperDs.read(parameters);
475  });
476 
477  $("#activeEndMonthWindow .cancelBtn").click(function() {
478  $("#activeEndMonthWindow").data("kendoWindow").close();
479  });
480  }
481 
482  var openDialog = true;
483  switch(buttonText) {
484  case "Complete":
485  $("#activeEndMonthWindow").data("childType", "completeActive");
486  $("#activeEndMonthWindow").data("featureDetailId", featureId);
487 
488  if (endDate == null) {
489  activeEndMonthDDL.select(0);
490  } else {
491  activeEndMonthDDL.value(endDate);
492  }
493  break;
494  case "Undo":
495  var parameters = {};
496  parameters.childType = "undoActive";
497  parameters.featureDetailId = featureId;
498  parameters.operation = "modifyStatus";
499 
500  activeGridHelperDs.read(parameters);
501  openDialog = false;
502  break;
503  }
504 
505  if (openDialog) {
506  activeEndMonthWindow.open().center();
507  }
508 
509 }
510 
511 <?php // ===================
512  // SETUP COMPLETED GRID DIALOGS
513  // =================== ?>
514 
515 <?php
516 /**
517  * function SetupCompletedGridDialogs()
518  * Sets up all the dialogs for the completed grid.
519  */
520 ?>
521 function SetupCompletedGridDialogs() {
522  $("#completedGrid").on("click", ".k-grid-advanceWorkflow", function() {
523  var text = $(this).text().trim();
524  var tr = $(this).closest("tr");
525  var grid = $("#completedGrid").data("kendoGrid");
526  var dataItem = grid.dataItem($(tr));
527  var parameters = {};
528  parameters.operation = "modifyStatus";
529  parameters.featureDetailId = dataItem.featureDetailId;
530 
531  switch(text) {
532  case "Reactivate":
533  parameters.childType = "reactivateCompleted";
534  break;
535  case "Undo":
536  parameters.childType = "undoCompleted";
537  break;
538  }
539 
540  completedGridHelperDs.read(parameters);
541  });
542 }
543 
544 <?php // ===================
545  // SETUP PENDING GRID DIALOGS (TOP)
546  // =================== ?>
547 
548 <?php
549 /**
550  * function SetupPendingTopGridDialogs()
551  * Sets up all the dialogs for the top pending grid.
552  */
553 ?>
554 function SetupPendingTopGridDialogs() {
555  <?php
556  /**
557  * @var deletePendingTopDialog
558  * The dialog to confirm deletion of a billing product.
559  */
560  ?>
561  $("#pendingGrid").on("click", ".k-master-row .k-grid-customDelete", function() {
562  var topGrid = $("#pendingGrid").data("kendoGrid");
563  var topTr = $(this).closest("tr");
564  var topDataItem = topGrid.dataItem(topTr);
565  var topId = topDataItem.orderDetailId;
566 
567  var deletePendingTopDialog = $("#deletePendingTopDialog").data("kendoDialog");
568  if (deletePendingTopDialog == null) {
569 
570  <?php
571  /**
572  * @var deletePendingTopDialog
573  * This is the window for confirming a delete at the top level.
574  */
575  ?>
576  deletePendingTopDialog = $("<div id='deletePendingTopDialog'></div>").appendTo("body").kendoDialog({
577  title: "Confirm Deletion",
578  actions: [
579  {text: "Cancel"},
580  {text: "Delete", primary: true, action: function() {
581 
582  var topId = $("#deletePendingTopDialog").data("topId");
583 
584  var parameters = {operation: "removeSalesOrderDetail", orderDetailId: topId};
585 
586  pendingTopGridHelperDs.read(parameters);
587  }}
588  ],
589  visible: false,
590  open: function() {
591  if (window.activeWindows != null) {
592  window.activeWindows.push(this);
593  }
594  },
595  close: function() {
596  if (window.activeWindows != null) {
597  window.activeWindows.pop();
598  }
599  },
600  modal: true,
601  content: "Are you sure that you want to delete this product?"
602  }).data("kendoDialog");
603  }
604 
605  $("#deletePendingTopDialog").data({topId: topId});
606  deletePendingTopDialog.open().center();
607  });
608 
609  $("#pendingGrid").on("click", ".k-grid-addSingle", function() {
610  ShowProductAddWindow();
611  });
612 
613  $("#pendingGrid").on("click", ".k-grid-createBulk", function() {
614  OpenShuttleApplet();
615  });
616 }
617 
618  <?php
619  /**
620  * function OpenShuttleApplet()
621  * This opens the shuttle applet.
622  * If the grids and buttons have not already been initialized, then they will be.
623  */
624  ?>
625 function OpenShuttleApplet() {
626  var shuttleApplet = $("#shuttleApplet").data("kendoWindow");
627 
628  var productList = productObservable.get("ddls.productItems");
629 
630  // This means that we need to initialize everything.
631  if (shuttleApplet == null) {
632 
633  <?php
634  /**
635  * @var shuttleApplet
636  * This is the window for selecting multiple products.
637  */
638  ?>
639  shuttleApplet = $("<div id='shuttleApplet'></div>").appendTo("body").kendoWindow({
640  content: {
641  template: $("#shuttleAppletTemplate").html()
642  },
643  modal: true,
644  title: "Add Multiple Products",
645  visible: false,
646  width: 800,
647  height: 300,
648  autoFocus: false,
649  close: function(e) {
650  if (window.activeWindows != null) {
651  window.activeWindows.pop();
652  }
653  },
654  open: function() {
655  if (window.activeWindows != null) {
656  window.activeWindows.push(this);
657  }
658  }
659  }).data("kendoWindow");
660 
661  <?php
662  /**
663  * @var gridDefinition
664  * This is the grid definition for the shuttle grids.
665  */
666  ?>
667  var gridDefinition = {
668  dataSource: {
669  data: [],
670  schema: {
671  model: {
672  id: "value",
673  fields: {
674  value: {type: "string", editable: false},
675  text: {type: "string", editable: false},
676  hasSetup: {type: "boolean"},
677  hasUnattachedJobs: {type: "boolean", editable: false},
678  productExists: {type: "boolean", editable: false},
679  selectedText: {type: "string"},
680  productOption: {type: "string"},
681  shownWorkflowDivValue: {type: "string"},
682  shownWorkflowDivText: {type: "string"}
683  }
684  }
685  }
686  },
687  columns: [
688  {field: "text", title: "Product"},
689  {field: "productOption", title: "Type", template: "# if (selectedText == '') { # (default) # } else { # #: selectedText # # } #",
690  editor: function (container, options) {
691  if (options.model.selectedText != "(default)") {
692  var productConfigData = productObservable.get("ddls.productOptions");
693  var productConfigData = $.grep(productConfigData, function(n,i) { return n.product == options.model.value; });
694  var input = $("<input name='" + options.field + "'>").appendTo(container).kendoDropDownList({
695  dataSource: {
696  data: productConfigData
697  },
698  dataTextField: "text",
699  dataValueField: "value",
700  filter: "startswith",
701  change: function () {
702  options.model.selectedText = this.text();
703  options.model.productOption = this.value();
704  options.model.hasSetup = this.dataItem().hasSetup;
705  }
706  }).data("kendoDropDownList");
707  } else {
708  $(container).text("(default)");
709  }
710  }
711  },
712  {field: "shownWorkflowDivValue", title: "Job",
713  template: "# if (!hasSetup) { # (None) # } else { # #: shownWorkflowDivText # # } #",
714  editor: function(container, options) {
715  if (!options.model.hasSetup) {
716  $(container).text("(None)");
717  } else {
718  var workflowData = productObservable.get("ddls.unattachedJobs");
719  workflowData = $.grep(workflowData, function(n,i) { return n.product == options.model.value; });
720  workflowData.unshift({text: "(New)", value: -1});
721  workflowData.push({text: "(None)", value: -2});
722 
723  var input = $("<input name='" + options.field + "'>").appendTo(container).kendoDropDownList({
724  dataSource: {
725  data: workflowData
726  },
727  dataTextField: "text",
728  dataValueField: "value",
729  filter: "startswith",
730  change: function () {
731  options.model.shownWorkflowDivText = this.text();
732  options.model.shownWorkflowDivValue = this.value();
733  }
734  }).data("kendoDropDownList");
735  }
736  }
737  }
738  ],
739  editable: true,
740  height: 200,
741  dataBound: function () {
742  this.tbody.find("tr").click(function () {
743  if ($(this).hasClass("k-state-selected")) {
744  $(this).removeClass("k-state-selected");
745  } else {
746  $(this).addClass("k-state-selected");
747  }
748  });
749  }
750  };
751 
752  var selectedGrid = $("#selectedGrid").kendoGrid(gridDefinition).data("kendoGrid");
753 
754  // Add the product filter for the available grid.
755  gridDefinition.toolbar = [{template: "Product Filter: <input id='prodFilter' text='text' class='k-input k-textbox' maxlength='50' style='width: 100px;'>"}];
756  var availableGrid = $("#availableGrid").kendoGrid(gridDefinition).data("kendoGrid");
757 
758  $("#prodFilter").keyup(function (e) {
759  var text = $(this).val().trim();
760  if (text == "") {
761  availableGrid.dataSource.filter({});
762  } else {
763  availableGrid.dataSource.filter({ field: "text", operator: "contains", value: text});
764  }
765  });
766 
767  var okayBtn = $("#shuttleOkayBtn").kendoButton({
768  click: function () {
769 
770  $("#shuttleApplet").data("kendoWindow").close();
771 
772  var rawProductData = $("#selectedGrid").data("kendoGrid").dataSource.data();
773  var productData = [];
774  for (var i = 0, length = rawProductData.length; i != length; i++) {
775  var rawRecord = rawProductData[i];
776  var record = {};
777  record.productId = rawRecord.value;
778  record.productOption = rawRecord.productOption;
779 
780  <?php // These values don't change for the multiple product option. ?>
781  record.aDNID = "";
782  record.partiallyBilledDate = null;
783 
784  if (rawRecord.hasSetup) {
785  record.billHalfValue = "full";
786 
787  switch (rawRecord.shownWorkflowDivValue) {
788  case -1: <?php // (New) ?>
789  record.workflowValue = "create";
790  record.unattachedJobValue = -1;
791  break;
792  case -2: <?php // (None) ?>
793  record.workflowValue = "without";
794  record.unattachedJobValue = -1;
795  break;
796  default:
797  record.workflowValue = "associate";
798  record.unattachedJobValue = rawRecord.shownWorkflowDivValue;
799  break;
800  }
801  } else {
802  record.billHalfValue = "nosetup";
803  record.workflowValue = "none";
804  record.unattachedJobValue = -1;
805  }
806 
807  productData.push(record);
808  }
809 
810  var parameters = {salesOrderId: salesOrderId, operation: "createSalesOrderDetails", productsSelected: kendo.stringify(productData)};
811  pendingTopGridHelperDs.read(parameters);
812 
813  return false;
814  },
815  enable: false
816  }).data("kendoButton");
817 
818  var cancelBtn = $("#shuttleCancelBtn").kendoButton({
819  click: function () {
820  $("#shuttleApplet").data("kendoWindow").close();
821  return false;
822  }
823  }).data("kendoButton");
824 
825  var moveToAvailableBtn = $("#shuttleMoveToAvailableBtn").kendoButton({
826  click: function () {
827  MoveData(availableGrid, selectedGrid, false);
828  if (selectedGrid.dataSource.data().length > 0)
829  {
830  okayBtn.enable(true);
831  moveToAvailableBtn.enable(true);
832  } else {
833  okayBtn.enable(false);
834  moveToAvailableBtn.enable(false);
835  }
836  if (availableGrid.dataSource.data().length > 0) {
837  moveToSelectedBtn.enable(true);
838  } else {
839  moveToSelectedBtn.enable(false);
840  }
841  return false;
842  },
843  enable: false
844  }).data("kendoButton");
845 
846  var moveToSelectedBtn = $("#shuttleMoveToSelectedBtn").kendoButton({
847  click: function () {
848  MoveData(availableGrid, selectedGrid, true);
849  if (selectedGrid.dataSource.data().length > 0)
850  {
851  okayBtn.enable(true);
852  moveToAvailableBtn.enable(true);
853  } else {
854  okayBtn.enable(false);
855  moveToAvailableBtn.enable(false);
856  }
857  if (availableGrid.dataSource.data().length > 0) {
858  moveToSelectedBtn.enable(true);
859  } else {
860  moveToSelectedBtn.enable(false);
861  }
862  return false;
863  }
864  }).data("kendoButton");
865 
866  } // End initializing
867 
868  var fullProductConfigData = productObservable.get("ddls.productOptions");
869  for (var i = 0; i != productList.length; i++) {
870  var record = productList[i];
871  if (!record.hasOptions) {
872  productList[i].productOption = "";
873  productList[i].selectedText = "(default)";
874  } else {
875 
876  var productConfigData = $.grep(fullProductConfigData, function(n,i) { return n.product == record.value; });
877  productList[i].productOption = productConfigData[0].value;
878  productList[i].selectedText = productConfigData[0].text;
879  productList[i].hasSetup = productConfigData[0].hasSetup;
880  }
881 
882  if (record.hasSetup) {
883  productList[i].shownWorkflowDivText = "(New)";
884  productList[i].shownWorkflowDivValue = -1;
885  } else {
886  productList[i].shownWorkflowDivText = "(None)";
887  productList[i].shownWorkflowDivValue = -2;
888  }
889  }
890 
891  $("#availableGrid").data("kendoGrid").dataSource.data(productList);
892  $("#selectedGrid").data("kendoGrid").dataSource.data([]);
893  // Clear out selected products so that products cannot be added twice if you open the applet twice.
894  $("#shuttleOkayBtn").data("kendoButton").enable(false);
895  $("#shuttleMoveToAvailableBtn").data("kendoButton").enable(false);
896  $("#shuttleMoveToSelectedBtn").data("kendoButton").enable(true);
897 
898  // Finally open the applet
899  shuttleApplet.open();
900  shuttleApplet.center();
901 
902  // Clear what was previously filtered
903  $("#prodFilter").val(null);
904  $("#availableGrid").data("kendoGrid").dataSource.filter({});
905  setTimeout(function() {$('#prodFilter').focus();}, 0);
906 }
907 
908 <?php
909 /**
910  * function MoveData(availableGrid, selectedGrid, toSelectedGrid)
911  * This function moves data from the available grid to the selected grid (or vice versa.)
912  *
913  * @param availableGrid -- the kendoGrid object of the availableGrid.
914  * @param selectedGrid -- the kendoGrid object of the selectedGrid.
915  * @param toSelectedGrid -- Boolean to know which way data is going.
916  */
917 ?>
918 function MoveData(availableGrid, selectedGrid, toSelectedGrid) {
919  var selectedData = selectedGrid.dataSource.data().slice(0);
920  var availableData = availableGrid.dataSource.data().slice(0);
921 
922  var addedData = [];
923  var preRemovedData = [];
924  var removedData = [];
925  var addedGrid;
926  var removedGrid;
927 
928  if (toSelectedGrid) {
929  addedData = selectedData;
930  preRemovedData = availableData;
931  addedGrid = selectedGrid;
932  removedGrid = availableGrid;
933  } else {
934  addedData = availableData;
935  preRemovedData = selectedData;
936  addedGrid = availableGrid;
937  removedGrid = selectedGrid;
938  }
939 
940  var selectedRows = removedGrid.tbody.find("tr.k-state-selected");
941  var uidsToRemove = {};
942 
943  for (var i = 0; i != selectedRows.length; i++) {
944  var dataItem = removedGrid.dataItem($(selectedRows[i]));
945  uidsToRemove[dataItem.value] = true;
946  addedData.push(dataItem);
947 
948  if (dataItem.productExists) {
949  if (!toSelectedGrid) {
950  $("#formInfoShuttleDiv ." + dataItem.value).remove();
951  if ($("#formInfoShuttleDiv li:visible").length == 0) {
952  $("#formInfoShuttleDiv").hide();
953  }
954  } else {
955  $("#formInfoShuttleDiv ul").append("<li class='" + dataItem.value + "'>" + dataItem.text + "</li>");
956  $("#formInfoShuttleDiv").show();
957  }
958  }
959  }
960  for (var i = 0; i != preRemovedData.length; i++) {
961  var dataItem = preRemovedData[i];
962  if (typeof(uidsToRemove[dataItem.value]) == "undefined") {
963  removedData.push(dataItem);
964  }
965  }
966  addedGrid.dataSource.data(addedData);
967  removedGrid.dataSource.data(removedData);
968 }
969 
970 <?php
971 /**
972  * function ShowProductAddWindow()
973  * This shows the window for updating a line item after it became active.
974  */
975 ?>
976 function ShowProductAddWindow() {
977  var productAddWindow = $("#productAddWindow").data("kendoWindow");
978  if (productAddWindow == null) {
979 
980  <?php
981  /**
982  * @var productAddWindow
983  * The KendoWindow that gets created for viewing line items.
984  */
985  ?>
986  productAddWindow = $("<div id='productAddWindow'></div>").appendTo("body").kendoWindow({
987  modal: true,
988  title: "Add Product",
989  visible: false,
990  width: 400,
991  close: function(e) {
992  if (window.activeWindows != null) {
993  window.activeWindows.pop();
994  }
995 
996  SetupMainForm();
997  },
998  open: function() {
999  if (window.activeWindows != null) {
1000  window.activeWindows.push(this);
1001  }
1002 
1003  SetupProductValidation("productEditForm", "formValidateAddProduct");
1004  }
1005  }).data("kendoWindow");
1006 
1007  <?php // the configuration part will be used in a couple of windows. Extending it this way. ?>
1008  var fullBindText = $("#addProductWindowTemplate").html();
1009 
1010  var template = kendo.template($("#productConfigTemplate").html());
1011  var configuration = {};
1012 
1013  <?php // Each time that it is opened, do not destroy and rebuild.
1014  // Instead, set the defaultOptions once again. ?>
1015  var defaultOptions = productObservable.get("defaultProductOptions").toJSON();
1016 
1017  productObservable.set("bindOptions", defaultOptions.bindOptions);
1018  productObservable.set("source", defaultOptions.source);
1019 
1020  fullBindText = fullBindText.replace("<!-- configDiv -->", template(configuration));
1021 
1022  productAddWindow.content(fullBindText);
1023  kendo.bind(productAddWindow.element, productObservable);
1024 
1025  <?php // This is here because the whole window is bound. Therefore, the click events are removed. ?>
1026  $("#productAddWindow .continueBtn").on("click", function() {
1027  if ($.homecuValidator.validate()) {
1028  $("#productAddWindow").data("kendoWindow").close();
1029 
1030  var productItem = productObservable.get("source").toJSON();
1031  productItem.billHalfValue = productObservable.get("bindOptions.billHalfValue");
1032  productItem.productId = productObservable.get("bindOptions.productId");
1033  productItem.productOption = productObservable.get("bindOptions.productOption");
1034  productItem.unattachedJobValue = productObservable.get("bindOptions.unattachedJobValue");
1035  productItem.workflowValue = productObservable.get("bindOptions.workflowValue");
1036  productItem.workflowValue = productItem.workflowValue == "" ? "none" : productItem.workflowValue;
1037 
1038  var parameters = {};
1039  parameters.productsSelected = kendo.stringify([productItem]);
1040  parameters.salesOrderId = salesOrderId;
1041  parameters.operation = "createSalesOrderDetails";
1042 
1043  pendingTopGridHelperDs.read(parameters);
1044  }
1045 
1046  return false;
1047  });
1048 
1049  $("#productAddWindow .cancelBtn").on("click", function() {
1050  $("#productAddWindow").data("kendoWindow").close();
1051  return false;
1052  });
1053 
1054  }
1055 
1056  <?php // Each time that it is opened, do not destroy and rebuild.
1057  // Instead, set the defaultOptions once again. ?>
1058  var defaultOptions = productObservable.get("defaultProductOptions").toJSON();
1059 
1060  productObservable.set("bindOptions", defaultOptions.bindOptions);
1061  productObservable.set("source", defaultOptions.source);
1062 
1063  productAddWindow.open().center();
1064 }
1065 
1066 <?php // ===================
1067  // SETUP DETAIL GRID DIALOGS
1068  // =================== ?>
1069 
1070 <?php
1071 /**
1072  * function SetupPendingBottomGridDialogs()
1073  * Sets up all the dialogs for the pending bottom grid.
1074  */
1075 ?>
1076 function SetupPendingBottomGridDialogs() {
1077  <?php
1078  /**
1079  * @var deletePendingBottomDialog
1080  * The dialog to confirm deletion of a billing line item.
1081  */
1082  ?>
1083  $("#pendingGrid").on("click", ".pendingBottomGrid .k-grid-customDelete", function() {
1084  var topGrid = $("#pendingGrid").data("kendoGrid");
1085  var bottomTr = $(this).closest("tr");
1086  var topTr = $(bottomTr).closest(".k-detail-row").prev();
1087  var bottomGrid = $(bottomTr).closest(".pendingBottomGrid").data("kendoGrid");
1088 
1089  var bottomDataItem = bottomGrid.dataItem(bottomTr);
1090  var topDataItem = topGrid.dataItem(topTr);
1091 
1092  var topId = topDataItem.orderDetailId;
1093  var feature = topDataItem.feature;
1094  var detailDescription = topDataItem.detailDescription;
1095  var bottomId = bottomDataItem.featureDetailId;
1096 
1097  var deletePendingBottomDialog = $("#deletePendingBottomDialog").data("kendoDialog");
1098  if (deletePendingBottomDialog == null) {
1099  deletePendingBottomDialog = $("<div id='deletePendingBottomDialog'></div>").appendTo("body").kendoDialog({
1100  title: "Confirm Deletion",
1101  actions: [
1102  {text: "Cancel"},
1103  {text: "Delete", primary: true, action: function() {
1104 
1105  var bottomId = $("#deletePendingBottomDialog").data("bottomId");
1106 
1107  var parameters = {operation: "removeBillingFeature", featureDetailId: bottomId};
1108 
1109  pendingBottomGridHelperDs.read(parameters);
1110 
1111  }}
1112  ],
1113  visible: false,
1114  open: function() {
1115  if (window.activeWindows != null) {
1116  window.activeWindows.push(this);
1117  }
1118  },
1119  close: function() {
1120  if (window.activeWindows != null) {
1121  window.activeWindows.pop();
1122  }
1123  },
1124  modal: true,
1125  content: "Are you sure that you want to delete this line item?"
1126  }).data("kendoDialog");
1127  }
1128 
1129  $("#deletePendingBottomDialog").data({topId: topId, bottomId: bottomId, bottomGrid: bottomGrid, feature: feature, detailDescription: detailDescription});
1130  deletePendingBottomDialog.open().center();
1131  });
1132 
1133  $("#pendingGrid").on("click", ".pendingBottomGrid .k-grid-edit", function() {
1134  var tr = $(this).closest("tr");
1135  var grid = $(tr).closest(".pendingBottomGrid").data("kendoGrid");
1136  var dataItem = grid.dataItem(tr);
1137  var parameters = {operation: "readSalesOrderDetailLineItem", featureDetailId: dataItem.featureDetailId};
1138 
1139  pendingBottomGridHelperDs.read(parameters);
1140  return false;
1141  });
1142 
1143  $("#pendingGrid").on("click", ".pendingBottomGrid .k-grid-add", function() {
1144  var productId = $(this).closest(".pendingBottomGrid").attr("data-productId");
1145  var orderDetailId = $(this).closest(".pendingBottomGrid").attr("data-orderDetailId");
1146  ShowDetailAddWindow(productId, orderDetailId);
1147  return false;
1148  });
1149 
1150  $("#pendingGrid").on("click", ".pendingBottomGrid .k-grid-advanceWorkflow", function() {
1151  var tr = $(this).closest("tr");
1152  var grid = $(tr).closest(".pendingBottomGrid").data("kendoGrid");
1153  var dataItem = grid.dataItem(tr);
1154  ShowPendingStartMonthWindow(dataItem.advanceWorkflowText, dataItem.featureDetailId, dataItem.startDate);
1155  return false;
1156  });
1157 
1158  $("#pendingGrid").on("click", ".pendingBottomGrid .k-grid-startMonthlies", function() {
1159  var orderDetailId = $(this).closest(".pendingBottomGrid").attr("data-orderDetailId");
1160  ShowPendingStartMonthWindow($(this).text().trim(), null, null, orderDetailId);
1161  return false;
1162  });
1163 }
1164 
1165 <?php
1166 /**
1167  * function ShowPendingStartMonthWindow(buttonText, featureId, startDate, orderDetailId)
1168  * This shows the start month on the pending grid.
1169  * This updates the status to active (2) and sets the start date on "Okay."
1170  *
1171  * @param buttonText -- the text of the button.
1172  * This sees if the button is an undo or if it comes from the "Start Recurring" button.
1173  * @param featureId -- the line item id to update.
1174  * @param startDate -- the start date to start.
1175  * @param orderDetailId -- the order detail id.
1176  */
1177 ?>
1178 function ShowPendingStartMonthWindow(buttonText, featureId, startDate, orderDetailId) {
1179  var pendingStartMonthWindow = $("#pendingStartMonthWindow").data("kendoWindow");
1180  var pendingStartMonthDDL = $("#pendingStartMonthDDL").data("kendoDropDownList");
1181 
1182  if (pendingStartMonthWindow == null) {
1183 
1184  <?php
1185  /**
1186  * @var pendingStartMonthWindow
1187  * The KendoWindow of the window to start month.
1188  */
1189  ?>
1190  pendingStartMonthWindow = $("<div id='pendingStartMonthWindow'></div>").appendTo("body").kendoWindow({
1191  modal: true,
1192  title: "Set Start Month",
1193  content: {
1194  template: $("#changeStartMonthTemplate").html()
1195  },
1196  visible: false,
1197  width: 300,
1198  close: function(e) {
1199  if (window.activeWindows != null) {
1200  window.activeWindows.pop();
1201  }
1202  },
1203  open: function() {
1204  if (window.activeWindows != null) {
1205  window.activeWindows.push(this);
1206  }
1207  }
1208  }).data("kendoWindow");
1209 
1210  <?php
1211  /**
1212  * @var pendingStartMonthDDL
1213  * The KendoDropDownList that stores the month selection.
1214  */
1215  ?>
1216  var pendingStartMonthDDL = $("#pendingStartMonthDDL").kendoDropDownList({
1217  dataSource: {
1218  data: lineItemObservable.get("ddls.startMonthOptions"),
1219  schema: {
1220  model: {
1221  id: "value",
1222  fields: {
1223  text: {type: "string"},
1224  value: {type: "string"}
1225  }
1226  }
1227  }
1228  },
1229  dataTextField: "text",
1230  dataValueField: "value"
1231  }).data("kendoDropDownList");
1232 
1233  $("#pendingStartMonthWindow .continueBtn").click(function() {
1234  $("#pendingStartMonthWindow").data("kendoWindow").close();
1235 
1236  var parameters = {};
1237  parameters.childType = $("#pendingStartMonthWindow").data("childType");
1238  parameters.featureDetailId = $("#pendingStartMonthWindow").data("featureDetailId");
1239  parameters.operation = "modifyStatus";
1240  parameters.startDate = $("#pendingStartMonthDDL").data("kendoDropDownList").value();
1241  parameters.orderDetailId = $("#pendingStartMonthWindow").data("orderDetailId");
1242 
1243  pendingBottomGridHelperDs.read(parameters);
1244  });
1245 
1246  $("#pendingStartMonthWindow .cancelBtn").click(function() {
1247  $("#pendingStartMonthWindow").data("kendoWindow").close();
1248  });
1249  }
1250 
1251  var openDialog = true;
1252  switch(buttonText) {
1253  case "Start":
1254  case "Trigger":
1255  $("#pendingStartMonthWindow").data("childType", "startPending");
1256  $("#pendingStartMonthWindow").data("featureDetailId", featureId);
1257 
1258  if (startDate == null) {
1259  pendingStartMonthDDL.select(0);
1260  } else {
1261  pendingStartMonthDDL.value(startDate);
1262  }
1263  break;
1264  case "Undo":
1265  case "Undo Trigger":
1266  var parameters = {};
1267  parameters.childType = "undoPending";
1268  parameters.featureDetailId = featureId;
1269  parameters.operation = "modifyStatus";
1270 
1271  pendingBottomGridHelperDs.read(parameters);
1272  openDialog = false;
1273  break;
1274  case "Start Recurring":
1275  $("#pendingStartMonthWindow").data("childType", "startRecurring");
1276  $("#pendingStartMonthWindow").data("orderDetailId", orderDetailId);
1277  pendingStartMonthDDL.select(0);
1278  break;
1279  case "Undo Recurring":
1280  var parameters = {};
1281  parameters.childType = "undoRecurring";
1282 
1283  <?php // Need to specify here or this might move some already active items to pending.
1284  // This should only affect the line items that were in the pending grid at the beginning of the session. ?>
1285  parameters.includeIds = kendo.stringify(includeExcludeMap["detail#" + orderDetailId].include);
1286  parameters.orderDetailId = orderDetailId;
1287  parameters.operation = "modifyStatus";
1288 
1289  pendingBottomGridHelperDs.read(parameters);
1290  openDialog = false;
1291  break;
1292  case "Change Start":
1293  $("#pendingStartMonthWindow").data("childType", "changeStart");
1294  $("#pendingStartMonthWindow").data("featureDetailId", featureId);
1295 
1296  if (startDate == null) {
1297  pendingStartMonthDDL.select(0);
1298  } else {
1299  pendingStartMonthDDL.value(startDate);
1300  }
1301  break;
1302  }
1303 
1304  if (openDialog) {
1305  pendingStartMonthWindow.open().center();
1306  }
1307 
1308 }
1309 
1310 <?php
1311 /**
1312  * function ShowDetailAddWindow(productId, orderDetailId)
1313  * Shows the add window for the line item (Bottom level of pending grid.)
1314  *
1315  * @param productId -- the product key of the order detail. e.g. ESP.
1316  * @param orderDetailId -- the sales order detail id of the order detail.
1317  * Both are needed because dropdownlist data is compiled before so orderDetailId is not known.
1318  * Order detail id is needed to save the new line item.
1319  */
1320 ?>
1321 function ShowDetailAddWindow(productId, orderDetailId) {
1322  var detailAddWindow = $("#detailAddWindow").data("kendoWindow");
1323  var featureDetailDDL = $("#featureDetailDDL").data("kendoDropDownList");
1324  if (detailAddWindow == null) {
1325 
1326  <?php
1327  /**
1328  * @var detailAddWindow
1329  * The KendoWindow showing a product ddl + all the data to configure each.
1330  */
1331  ?>
1332  detailAddWindow = $("<div id='detailAddWindow'></div>").appendTo("body").kendoWindow({
1333  modal: true,
1334  content: {
1335  template: $("#detailAddWindowTemplate").html()
1336  },
1337  title: "Add Product Feature",
1338  visible: false,
1339  width: 400,
1340  close: function(e) {
1341  if (window.activeWindows != null) {
1342  window.activeWindows.pop();
1343  }
1344 
1345  SetupMainForm();
1346  },
1347  open: function() {
1348  if (window.activeWindows != null) {
1349  window.activeWindows.push(this);
1350  }
1351  }
1352  }).data("kendoWindow");
1353 
1354  <?php
1355  /**
1356  * @var featureDetailDDL
1357  * This is a dropdownlist with logic for configuring that line item.
1358  * Each time that a value is selected, the rest is destroy and config according to logic.
1359  */
1360  ?>
1361  featureDetailDDL = $("#featureDetailDDL").kendoDropDownList({
1362  dataSource: {
1363  data: [],
1364  schema: {
1365  model: {
1366  id: "salesItemValue",
1367  fields: {
1368  salesItemText: {type: "string"},
1369  salesItemValue: {type: "number"},
1370  configuration: {type: "odata"},
1371  lineItemData: {type: "odata"},
1372  bindOptions: {type: "odata"},
1373  ddls: {type: "odata"},
1374  orderDetailId: {type: "number"},
1375  }
1376  }
1377  }
1378  },
1379  dataTextField: "salesItemText",
1380  dataValueField: "salesItemValue",
1381  change: function(e) {
1382  var fullLineItemContent = this.dataItem();
1383  fullLineItemContent.configuration.addOrUpdate = "add";
1384 
1385  lineItemObservable.set("source", fullLineItemContent.lineItemData);
1386  lineItemObservable.set("bindOptions", fullLineItemContent.bindOptions);
1387  lineItemObservable.set("ddls.workflowDDL", fullLineItemContent.ddls.workflows);
1388  lineItemObservable.set("ddls.unattachedJobDDL", fullLineItemContent.ddls.workflowUnattachedJobs);
1389 
1390  var bindDiv = $("#detailAddWindow .configDiv");
1391  kendo.destroy($(bindDiv));
1392  $(bindDiv).empty();
1393 
1394  var template = kendo.template($("#detailConfigTemplate").html());
1395  $(bindDiv).html(template(fullLineItemContent.configuration));
1396  kendo.bind($(bindDiv), lineItemObservable);
1397  SetupLineItemValidation("detailAddForm", "formValidateAddDetail");
1398  }
1399  }).data("kendoDropDownList");
1400 
1401  $("#detailAddWindow").on("click", ".continueBtn", function() {
1402  if ($.homecuValidator.validate()) {
1403  $("#detailAddWindow").data("kendoWindow").close();
1404 
1405  var parameters = lineItemObservable.getSaveParameters();
1406  <?php // Won't do it if you don't give it the operation. ?>
1407  parameters.operation = "createBillingFeature";
1408 
1409  <?php // Now need additional parameters to create the record. ?>
1410  var dataItem = $("#featureDetailDDL").data("kendoDropDownList").dataItem();
1411 
1412  <?php // These has to be done using this method because a brand new product could be created. ?>
1413  parameters.orderDetailId = $("#detailAddWindow").data("orderDetailId");
1414  parameters.salesItemId = dataItem.salesItemValue;
1415 
1416  pendingBottomGridHelperDs.read(parameters);
1417  }
1418 
1419  return false;
1420  });
1421 
1422  $("#detailAddWindow").on("click", ".cancelBtn", function() {
1423  $("#detailAddWindow").data("kendoWindow").close();
1424  return false;
1425  });
1426  }
1427 
1428  var fullLineItems = lineItemObservable.get("ddls.billingTemplateItems");
1429  var lineItems = $.grep(fullLineItems, function(n,i) { return n.productId == productId });
1430 
1431  featureDetailDDL.dataSource.data(lineItems);
1432  featureDetailDDL.select(0);
1433 
1434  var fullLineItemContent = featureDetailDDL.dataItem();
1435  fullLineItemContent.configuration.addOrUpdate = "add";
1436 
1437  lineItemObservable.setupValues(fullLineItemContent.lineItemData, fullLineItemContent.bindOptions);
1438 
1439  lineItemObservable.set("ddls.workflowDDL", fullLineItemContent.ddls.workflows);
1440  lineItemObservable.set("ddls.unattachedJobDDL", fullLineItemContent.ddls.workflowUnattachedJobs);
1441 
1442  var bindDiv = $("#detailAddWindow .configDiv");
1443  kendo.destroy($(bindDiv));
1444  $(bindDiv).empty();
1445 
1446  var template = kendo.template($("#detailConfigTemplate").html());
1447  $(bindDiv).html(template(fullLineItemContent.configuration));
1448  kendo.bind($(bindDiv), lineItemObservable);
1449 
1450  detailAddWindow.open().center();
1451  SetupLineItemValidation("detailAddForm", "formValidateAddDetail");
1452 
1453  $("#detailAddWindow").data("orderDetailId", orderDetailId);
1454 }
1455 
1456 <?php
1457 /**
1458  * function ShowDetailEditWindow(lineItemData, configuration, bindOptions, ddls)
1459  * This shows the edit window for changing a line item.
1460  *
1461  * @param lineItemData -- the data from the database for the line item.
1462  * @param configuration -- determines which DIVs are removed and which remain.
1463  * @param bindOptions -- determines which ddl values are shown and which DIVs are shown.
1464  * @param ddls -- additional dropdownlist data for the line item.
1465  */
1466 ?>
1467 function ShowDetailEditWindow(lineItemData, configuration, bindOptions, ddls) {
1468  var detailEditWindow = $("#detailEditWindow").data("kendoWindow");
1469  if (detailEditWindow == null) {
1470 
1471  <?php
1472  /**
1473  * @var detailEditWindow
1474  * The KendoWindow to display for editing a line item.
1475  */
1476  ?>
1477  detailEditWindow = $("<div id='detailEditWindow'></div>").appendTo("body").kendoWindow({
1478  modal: true,
1479  title: "Edit Product Feature",
1480  visible: false,
1481  width: 400,
1482  close: function(e) {
1483  if (window.activeWindows != null) {
1484  window.activeWindows.pop();
1485  }
1486 
1487  SetupMainForm();
1488  },
1489  open: function() {
1490  if (window.activeWindows != null) {
1491  window.activeWindows.push(this);
1492  }
1493 
1494  SetupLineItemValidation("detailEditForm", "formValidateEditDetail");
1495  }
1496  }).data("kendoWindow");
1497  } else {
1498  kendo.destroy($("#detailEditWindow #detailEditForm"));
1499  }
1500 
1501  lineItemObservable.setupValues(lineItemData, bindOptions);
1502 
1503  lineItemObservable.set("ddls.workflowDDL", ddls.workflows);
1504  lineItemObservable.set("ddls.unattachedJobDDL", ddls.workflowUnattachedJobs);
1505 
1506  <?php // the configuration part will be used in a couple of windows. Extending it this way. ?>
1507  var fullBindText = $("#detailEditWindowTemplate").html();
1508 
1509  var template = kendo.template($("#detailConfigTemplate").html());
1510 
1511  configuration.addOrUpdate = "update";
1512  fullBindText = fullBindText.replace("<!-- configDiv -->", template(configuration));
1513 
1514  detailEditWindow.content(fullBindText);
1515  kendo.bind(detailEditWindow.element, lineItemObservable);
1516  detailEditWindow.open().center();
1517 
1518  <?php // This is here because the whole window is bound. Therefore, the click events are removed. ?>
1519  $("#detailEditWindow .continueBtn").on("click", function() {
1520  if ($.homecuValidator.validate()) {
1521  $("#detailEditWindow").data("kendoWindow").close();
1522 
1523  var parameters = lineItemObservable.getSaveParameters();
1524  <?php // Won't do it if you don't give it the operation. ?>
1525  parameters.operation = "updatePendingBillingFeature";
1526 
1527  pendingBottomGridHelperDs.read(parameters);
1528  }
1529 
1530  return false;
1531  });
1532 
1533  $("#detailEditWindow .cancelBtn").on("click", function() {
1534  $("#detailEditWindow").data("kendoWindow").close();
1535  return false;
1536  });
1537 }
1538 
1539 <?php
1540 /**
1541  * function ShowWorkflowStatusWindow(workflowStatuses)
1542  * This shows when workflows should have been created.
1543  * Each one shows as "successful" or not so successful.
1544  *
1545  * @param workflowStatuses -- a list of product names and if a workflow was created.
1546  */
1547 ?>
1548 function ShowWorkflowStatusWindow(workflowStatuses) {
1549  if (workflowStatuses.length > 0) {
1550  var template = "<ul>";
1551  for (var i = 0; i != workflowStatuses.length; i++) {
1552  var item = workflowStatuses[i];
1553  if (item.created) {
1554  template += "<li class='k-success-colored'>Workflow created for " + item.text + "</li>";
1555  }
1556  else {
1557  template += "<li class='k-error-colored'>No workflow created for " + item.text + "</li>";
1558  }
1559  }
1560  template += "</ul>";
1561  var workflowCreatedNotification = $("#workflowCreatedNotification").data("kendoWindow");
1562  if (workflowCreatedNotification == null) {
1563 
1564  <?php
1565  /**
1566  * @var workflowCreatedNotification
1567  * The KendoWindow that shows a list of workflows and if they were successful or not.
1568  */
1569  ?>
1570  workflowCreatedNotification = $("<div id='workflowCreatedNotification'></div>").appendTo("body").kendoWindow({
1571  title: false,
1572  modal: true,
1573  visible: false,
1574  close: function(e) {
1575  if (window.activeWindows != null) {
1576  window.activeWindows.pop();
1577  }
1578  },
1579  open: function() {
1580  if (window.activeWindows != null) {
1581  window.activeWindows.push(this);
1582  }
1583  }
1584  }).data("kendoWindow");
1585 
1586  $("#workflowCreatedNotification").closest(".k-window").click(function() {
1587  workflowCreatedNotification.close();
1588  });
1589  }
1590 
1591  workflowCreatedNotification.content(template).open().center();
1592  }
1593 }
1594 
1595 <?php // ===================
1596  // SETUP GRIDS
1597  // =================== ?>
1598 
1599 <?php
1600 /**
1601  * @var includeExcludeMap
1602  * Stores the featureDetailIds that are temporarily in the wrong grid.
1603  * Before, there was logic to update the button only to "undo."
1604  * Now, since all operations refresh the corresponding grid(s), pass the ids down.
1605  */
1606 ?>
1607 var includeExcludeMap = {
1608  active: {
1609  include: [],
1610  exclude: []
1611  },
1612  completed: {
1613  include: [],
1614  exclude: []
1615  }
1616 };
1617 
1618 <?php
1619 /**
1620  * function SetupGrids()
1621  * Sets up all the grids with datasources.
1622  * There are no click events or dialogs created here.
1623  */
1624 ?>
1625 function SetupGrids() {
1626 
1627  <?php
1628  /**
1629  * @var activeGrid
1630  * This is the initialization of the activeGrid.
1631  * RowTemplate and title are defined here.
1632  * No click events or dialogs are defined here.
1633  */
1634  ?>
1635  var activeGrid = $("#activeGrid").kendoGrid({
1636  dataSource: {
1637  transport: {
1638  read: {
1639  url: "index.prg",
1640  dataType: "json",
1641  type: "POST",
1642  data: {
1643  operation: "readActiveDetails",
1644  salesOrderId: salesOrderId
1645  }
1646  },
1647  parameterMap: function (data, type) {
1648 
1649  data.includeIds = kendo.stringify(includeExcludeMap.active.include);
1650  data.excludeIds = kendo.stringify(includeExcludeMap.active.exclude);
1651  return data;
1652  }
1653  },
1654  schema: {
1655  model: {
1656  id: "featureDetailId",
1657  fields: {
1658  featureDetailId: {type: "number"},
1659  productName: {type: "string"},
1660  featureName: {type: "string"},
1661  featureDescription: {type: "string"},
1662  partialBillingStatus: {type: "string"},
1663  frequencyDescr: {type: "string"},
1664  showCompleteButton: {type: "boolean"},
1665  completeButtonText: {type: "string"},
1666  endDate: {type: "string"}
1667  }
1668  },
1669  parse: function (data) {
1670  if (data.status !== "000") {
1671  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
1672  }
1673 
1674  var indexOf = toHideWindow.indexOf("active");
1675  if (indexOf != -1) {
1676  toHideWindow.splice(indexOf, 1);
1677  if (toHideWindow.length == 0) {
1678  hideWaitWindow();
1679  }
1680  }
1681 
1682  return data.record;
1683  }
1684  }
1685  },
1686  columns: [
1687  <?php if ($isInEditList) { ?>
1688  {width: 220},
1689  <?php } ?>
1690  {title: "Product", width: "15%"},
1691  {title: "Feature", width: "15%"},
1692  {title: "Bill Half Date", width: "15%"},
1693  {title: "Status", width: "15%"},
1694  {title: "Description"},
1695  {title: "Frequency"}
1696  ],
1697  toolbar: "Active:",
1698  rowTemplate: $("#activeRowTemplate").html()
1699  }).data("kendoGrid");
1700 
1701  <?php
1702  /**
1703  * @var pendingGrid
1704  * This is the initialization of the pendingGrid.
1705  * RowTemplate and title are defined here.
1706  * No click events or dialogs are defined here.
1707  */
1708  ?>
1709  var pendingGrid = $("#pendingGrid").kendoGrid({
1710  dataSource: {
1711  transport: {
1712  read: {
1713  url: "index.prg",
1714  dataType: "json",
1715  type: "POST",
1716  data: {
1717  operation: "readPendingDetailsTop",
1718  salesOrderId: salesOrderId
1719  }
1720  },
1721  parameterMap: function (data, type) {
1722  return data;
1723  }
1724  },
1725  schema: {
1726  model: {
1727  id: "orderDetailId",
1728  fields: {
1729  orderDetailId: {type: "number"},
1730  lastModifiedBy: {type: "string"},
1731  lastModifiedDate: {type: "date"},
1732  numDetails: {type: "number"},
1733  opened: {type: "boolean"}
1734  }
1735  },
1736  parse: function (data) {
1737  if (data.status !== "000") {
1738  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
1739  }
1740 
1741  var indexOf = toHideWindow.indexOf("pending");
1742  if (indexOf != -1) {
1743  toHideWindow.splice(indexOf, 1);
1744  if (toHideWindow.length == 0) {
1745  hideWaitWindow();
1746  }
1747  }
1748 
1749  return data.record;
1750  }
1751  }
1752  },
1753  columns: [
1754  <?php if ($isInEditList) { ?> {width: "5%"}, <?php } ?>
1755  {title: "Feature"},
1756  {title: "Last Modified"},
1757  {title: "Last Modified By"}
1758  ],
1759  <?php if ($isInEditList) { ?>
1760  toolbar: $("#pendingToolbarTemplate").html(),
1761  <?php } ?>
1762  detailTemplate: $("#detailTemplate").html(),
1763  detailInit: SetupDetailGrid,
1764  detailExpand: function(e) {
1765  e.detailRow.find(".pendingBottomGrid").data("kendoGrid").dataSource.read();
1766  },
1767  rowTemplate: $("#topRowTemplate").html(),
1768  dataBound: function(e) {
1769  $("#pendingGrid .k-master-row.opened").each(function() {
1770  $("#pendingGrid").data("kendoGrid").expandRow($(this));
1771  })
1772  }
1773  }).data("kendoGrid");
1774 
1775  <?php
1776  /**
1777  * @var completedGrid
1778  * This is the initialization of the completedGrid.
1779  * RowTemplate and title are defined here.
1780  * No click events or dialogs are defined here.
1781  */
1782  ?>
1783  var completedGrid = $("#completedGrid").kendoGrid({
1784  dataSource: {
1785  transport: {
1786  read: {
1787  url: "index.prg",
1788  dataType: "json",
1789  type: "POST",
1790  data: {
1791  operation: "readCompletedDetails",
1792  salesOrderId: salesOrderId
1793  }
1794  },
1795  parameterMap: function (data, type) {
1796 
1797  data.includeIds = kendo.stringify(includeExcludeMap.completed.include);
1798  data.excludeIds = kendo.stringify(includeExcludeMap.completed.exclude);
1799  return data;
1800  }
1801  },
1802  schema: {
1803  model: {
1804  id: "featureDetailId",
1805  fields: {
1806  featureDetailId: {type: "number"},
1807  productName: {type: "string"},
1808  featureName: {type: "string"},
1809  featureDescription: {type: "string"},
1810  partialBillingStatus: {type: "string"},
1811  frequencyDescr: {type: "string"},
1812  showAdvanceWorkflow: {type: "boolean"},
1813  advanceWorkflowText: {type: "string"}
1814  }
1815  },
1816  parse: function (data) {
1817  if (data.status !== "000") {
1818  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
1819  }
1820 
1821  var indexOf = toHideWindow.indexOf("completed");
1822  if (indexOf != -1) {
1823  toHideWindow.splice(indexOf, 1);
1824  if (toHideWindow.length == 0) {
1825  hideWaitWindow();
1826  }
1827  }
1828 
1829  return data.record;
1830  }
1831  }
1832  },
1833  columns: [
1834  <?php if ($isInEditList) { ?>
1835  {width: 100},
1836  <?php } ?>
1837  {title: "Product", width: "15%"},
1838  {title: "Feature", width: "15%"},
1839  {title: "Bill Half Date", width: "15%"},
1840  {title: "Status", width: "15%"},
1841  {title: "Description"},
1842  {title: "Frequency"}
1843  ],
1844  toolbar: "Completed:",
1845  rowTemplate: $("#completedRowTemplate").html()
1846  }).data("kendoGrid");
1847 }
1848 
1849 <?php
1850 /**
1851  * function SetupDetailGrid(e)
1852  * This is a helper function to setup the detail grid.
1853  *
1854  * @param e -- this is a parameter setup by kendo.
1855  * @see kendo grid api > detailInit.
1856  */
1857 ?>
1858 function SetupDetailGrid(e) {
1859 
1860  var key = "detail#" + e.data.orderDetailId;
1861  includeExcludeMap[key] = {};
1862  includeExcludeMap[key].include = [];
1863  includeExcludeMap[key].exclude = [];
1864 
1865  <?php
1866  /**
1867  * @var detailGrid
1868  * This is the initialization of the detailGrid (bottom level of pending products).
1869  * RowTemplate and title are defined here.
1870  * No click events or dialogs are defined here.
1871  */
1872  ?>
1873  var detailGrid = e.detailRow.find(".pendingBottomGrid").kendoGrid({
1874  dataSource: {
1875  transport: {
1876  read: {
1877  url: "index.prg",
1878  dataType: "json",
1879  type: "POST",
1880  data: {
1881  operation: "readPendingDetailsBottom",
1882  orderDetailId: e.data.orderDetailId
1883  }
1884  },
1885  parameterMap: function(data, type) {
1886 
1887  data.includeIds = kendo.stringify(includeExcludeMap[key].include);
1888  data.excludeIds = kendo.stringify(includeExcludeMap[key].exclude);
1889  return data;
1890  }
1891  },
1892  schema: {
1893  model: {
1894  id: "featureDetailId",
1895  fields: {
1896  featureDetailId: {type: "number"},
1897  actualDescription: {type: "string"},
1898  textDescription: {type: "string"},
1899  billingStatusLabel: {type: "string"},
1900  partialBillingStatus: {type: "string"},
1901  frequencyDescr: {type: "string"},
1902  deletable: {type: "boolean"},
1903  showAdvanceWorkflow: {type: "boolean"},
1904  advanceWorkflowText: {type: "string"},
1905  startDate: {type: "string"}
1906  }
1907  },
1908  parse: function (data) {
1909  if (data.status !== "000") {
1910  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
1911  }
1912 
1913  var indexOf = toHideWindow.indexOf(key);
1914  if (indexOf != -1) {
1915  toHideWindow.splice(indexOf, 1);
1916  if (toHideWindow.length == 0) {
1917  hideWaitWindow();
1918  }
1919  }
1920 
1921  return data.record;
1922  }
1923  }
1924  },
1925  autoBind: false,
1926  columns: [
1927  <?php if ($isInEditList) { ?>
1928  {width: "10%"},
1929  {width: "15%"},
1930  <?php } ?>
1931  {title: "Bill Half Date", width: "15%"},
1932  {title: "Status", width: "15%"},
1933  {title: "Title", width: "20%"},
1934  {title: "Description"},
1935  {title: "Frequency"}
1936  ],
1937  <?php if ($isInEditList) { ?>
1938  toolbar: $("#detailToolbarTemplate").html(),
1939  <?php } ?>
1940  rowTemplate: $("#detailRowTemplate").html()
1941  }).data("kendoGrid");
1942 }
1943 
1944 <?php // ===================
1945  // SETUP DATASOURCES
1946  // =================== ?>
1947 
1948 var activeGridHelperDs = null;
1949 var completedGridHelperDs = null;
1950 var pendingTopGridHelperDs = null;
1951 var pendingBottomGridHelperDs = null;
1952 var warningDs = null;
1953 
1954 <?php
1955 /**
1956  * function SetupDataSources()
1957  * This sets up all the helper dataSource.
1958  * The purpose of these is to delete, add, or another action.
1959  * Then the helper dataSource calls the read on the corresponding grid(s).
1960  */
1961 ?>
1962 function SetupDataSources() {
1963  <?php
1964  /**
1965  * @var setupDs
1966  * This is a datasource that only exists to populate information used for dropdownlists and the top text on the page.
1967  */
1968  ?>
1969  var setupDs = new kendo.data.DataSource({
1970  transport: {
1971  read: {
1972  url: "index.prg",
1973  dataType: "json",
1974  type: "POST",
1975  data: {
1976  operation: "readSalesOrderDetailInit",
1977  salesOrderId: salesOrderId
1978  }
1979  },
1980  parameterMap: function (data, type) {
1981  return data;
1982  }
1983  },
1984  schema: {
1985  parse: function (data) {
1986  if (data.status !== "000") {
1987  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
1988  }
1989 
1990  var indexOf = toHideWindow.indexOf("setup");
1991  if (indexOf != -1) {
1992  toHideWindow.splice(indexOf, 1);
1993  if (toHideWindow.length == 0) {
1994  hideWaitWindow();
1995  }
1996  }
1997 
1998  $("#cuLabel").text(data.cuName + " (" + data.cu + ")");
1999  $("#cu").text(data.cu);
2000  $("#cuName").text(data.cuName);
2001 
2002  var pendingBottomDDLData = {};
2003  pendingBottomDDLData.setupBillingDDL = $.grep(data.ddls.setupBillingOptions, function (n,i) { return n.value != "nosetup"; });
2004  pendingBottomDDLData.monthDDL = data.ddls.monthDDL;
2005  pendingBottomDDLData.frequencyDDL = data.ddls.frequencyDDL;
2006  pendingBottomDDLData.billingTemplateItems = data.ddls.billingTemplateItems;
2007  pendingBottomDDLData.startMonthOptions = data.ddls.startMonthOptions;
2008 
2009  lineItemObservable.set("ddls", pendingBottomDDLData);
2010 
2011  <?php // This has two parts for ddls: these are the static ones.
2012  // When opened and when the product changes, same of the other ddls will change. ?>
2013  var pendingTopDDLData = {};
2014  pendingTopDDLData.setupBillingDDL = data.ddls.setupBillingOptions;
2015  pendingTopDDLData.productItems = data.ddls.productItems;
2016  pendingTopDDLData.productWorkflowOptions = data.ddls.productWorkflowOptions;
2017  pendingTopDDLData.unattachedJobs = data.ddls.unattachedJobs;
2018  pendingTopDDLData.productOptions = data.ddls.productOptions;
2019 
2020  productObservable.set("ddls", pendingTopDDLData);
2021  productObservable.set("defaultProductOptions", data.defaultProductOptions);
2022 
2023  return []; <?php // No data is returned to the dataSource. ?>
2024  }
2025  }
2026  });
2027 
2028  setupDs.read();
2029 
2030  <?php
2031  /**
2032  * @var warningDs
2033  * This is a dataSource for calling the warnings.
2034  * No warnings are created on frontend side (old style.)
2035  */
2036  ?>
2037  warningDs = new kendo.data.DataSource({
2038  transport: {
2039  read: {
2040  url: "index.prg",
2041  dataType: "json",
2042  type: "POST",
2043  data: {
2044  operation: "readSalesOrderDetailWarnings",
2045  salesOrderId: salesOrderId
2046  }
2047  },
2048  parameterMap: function (data, type) {
2049  return data;
2050  }
2051  },
2052  schema: {
2053  parse: function (data) {
2054  if (data.status !== "000") {
2055  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
2056  hideWaitWindow();
2057  } else {
2058  var indexOf = toHideWindow.indexOf("warnings");
2059  if (indexOf != -1) {
2060  toHideWindow.splice(indexOf, 1);
2061  if (toHideWindow.length == 0) {
2062  hideWaitWindow();
2063  }
2064  }
2065 
2066  if (data.warnings.length > 0) {
2067  $("#warningDiv").show();
2068  $("#warningDiv").html(data.warnings.join("<br>") + "</div>");
2069  } else {
2070  $("#warningDiv").hide();
2071  }
2072  }
2073 
2074  return []; <?php // No data is returned to the dataSource. ?>
2075  }
2076  }
2077  });
2078 
2079  warningDs.read();
2080 
2081  <?php
2082  /**
2083  * @var activeGridHelperDs
2084  * This is a helper dataSource to run add/modify/delete operations on the active grid.
2085  */
2086  ?>
2087  activeGridHelperDs = new kendo.data.DataSource({
2088  transport: {
2089  read: {
2090  url: "index.prg",
2091  dataType: "json",
2092  type: "POST",
2093  data: {
2094  operation: "none"
2095  }
2096  },
2097  parameterMap: function (data, type) {
2098  showWaitWindow();
2099  return data;
2100  }
2101  },
2102  schema: {
2103  parse: function (data) {
2104  if (data.status !== "000") {
2105  hideWaitWindow();
2106  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
2107  } else {
2108  switch(data.type) {
2109  case "delete":
2110  toHideWindow = ["active", "warnings"];
2111  $("#activeGrid").data("kendoGrid").dataSource.read();
2112  warningDs.read();
2113  break;
2114  case "advanceStatus":
2115  toHideWindow = ["active"];
2116 
2117  includeExcludeMap.active.include = includeExcludeMap.active.include.concat(data.ids);
2118  includeExcludeMap.completed.exclude = includeExcludeMap.completed.exclude.concat(data.ids);
2119  $("#activeGrid").data("kendoGrid").dataSource.read();
2120  break;
2121  case "revertStatus":
2122  toHideWindow = ["active"];
2123 
2124  var activeInclude = $.grep(includeExcludeMap.active.include, function(n,i) { return data.ids.indexOf(n) === -1; });
2125  var completedExclude = $.grep(includeExcludeMap.completed.exclude, function(n,i) { return data.ids.indexOf(n) === -1; });
2126 
2127  includeExcludeMap.active.include = activeInclude;
2128  includeExcludeMap.completed.exclude = completedExclude;
2129  $("#activeGrid").data("kendoGrid").dataSource.read();
2130  break;
2131  <?php // Also need to read configuration and values for line item.
2132  // This is pulled off of the previous read function that got everything for the page.
2133  // Now, each grid only has the data needed to display the grid. ?>
2134  case "read":
2135  hideWaitWindow();
2136  ShowActiveChangePriceWindow(data.lineItemData, data.configuration, data.bindOptions, data.ddls);
2137  break;
2138 
2139  case "modify":
2140  toHideWindow = ["active", "warnings"];
2141  $("#activeGrid").data("kendoGrid").dataSource.read();
2142  warningDs.read();
2143  break;
2144  }
2145  }
2146 
2147  return []; <?php // No data is returned to the dataSource. ?>
2148  }
2149  }
2150  });
2151 
2152  <?php
2153  /**
2154  * @var pendingBottomGridHelperDs
2155  * This is a helper dataSource to run add/modify/delete operations on the bottom level of the pending grid.
2156  */
2157  ?>
2158  pendingBottomGridHelperDs = new kendo.data.DataSource({
2159  transport: {
2160  read: {
2161  url: "index.prg",
2162  dataType: "json",
2163  type: "POST",
2164  data: {
2165  operation: "none"
2166  }
2167  },
2168  parameterMap: function (data, type) {
2169  showWaitWindow();
2170  return data;
2171  }
2172  },
2173  schema: {
2174  parse: function (data) {
2175 
2176  if (data.status !== "000") {
2177  hideWaitWindow();
2178  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
2179  } else {
2180 
2181  var key = "detail#" + data.orderDetailId;
2182  switch(data.type) {
2183  case "delete":
2184  <?php // The whole product is removed so refresh the whole pending grid. ?>
2185  if (data.removeContractDetail) {
2186  toHideWindow = ["pending"];
2187  $("#pendingGrid").data("kendoGrid").dataSource.read();
2188  } else {
2189  toHideWindow = [key];
2190  $("#pendingGrid .pendingBottomGrid[data-orderDetailId='" + data.orderDetailId + "']:visible").data("kendoGrid").dataSource.read();
2191  }
2192  break;
2193 
2194  <?php // Also need to read configuration and values for line item.
2195  // This is pulled off of the previous read function that got everything for the page.
2196  // Now, each grid only has the data needed to display the grid. ?>
2197  case "read":
2198  hideWaitWindow();
2199  ShowDetailEditWindow(data.lineItemData, data.configuration, data.bindOptions, data.ddls);
2200  break;
2201 
2202  case "modify":
2203  toHideWindow = [key, "warnings"];
2204  $("#pendingGrid .pendingBottomGrid[data-orderDetailId='" + data.orderDetailId + "']:visible").data("kendoGrid").dataSource.read();
2205  warningDs.read();
2206 
2207  <?php // Update last modified by, last modified. It is silly to refresh the grid for this. ?>
2208  var masterRow = $("#pendingGrid .k-master-row[data-orderDetailId='" + data.orderDetailId + "']:visible");
2209  $(masterRow).find("td:eq(3)").text(kendo.toString(new Date(), "d"));
2210  $(masterRow).find("td:eq(4)").text("<?php echo $Hu; ?>");
2211 
2212  ShowWorkflowStatusWindow(data.workflowStatuses);
2213  break;
2214  case "advanceStatus":
2215  toHideWindow = [key];
2216 
2217  includeExcludeMap[key].include = includeExcludeMap[key].include.concat(data.ids);
2218  includeExcludeMap.active.exclude = includeExcludeMap.active.exclude.concat(data.ids);
2219  $("#pendingGrid .pendingBottomGrid[data-orderDetailId='" + data.orderDetailId + "']:visible").data("kendoGrid").dataSource.read();
2220 
2221  if (data.isRecurringBtn) {
2222  $("#pendingGrid .pendingBottomGrid[data-orderDetailId='" + data.orderDetailId + "']:visible .k-grid-startMonthlies").text("Undo Recurring");
2223  }
2224  break;
2225  case "revertStatus":
2226  toHideWindow = [key];
2227 
2228  var keyInclude = $.grep(includeExcludeMap[key].include, function(n,i) { return data.ids.indexOf(n) === -1; });
2229  var activeExclude = $.grep(includeExcludeMap.active.exclude, function(n,i) { return data.ids.indexOf(n) === -1; });
2230 
2231  includeExcludeMap[key].include = keyInclude;
2232  includeExcludeMap.active.exclude = activeExclude;
2233  $("#pendingGrid .pendingBottomGrid[data-orderDetailId='" + data.orderDetailId + "']:visible").data("kendoGrid").dataSource.read();
2234 
2235  if (data.isRecurringBtn) {
2236  $("#pendingGrid .pendingBottomGrid[data-orderDetailId='" + data.orderDetailId + "']:visible .k-grid-startMonthlies").text("Start Recurring");
2237  }
2238  break;
2239  case "changeStart":
2240  toHideWindow = [key];
2241 
2242  includeExcludeMap[key].include = includeExcludeMap[key].include.concat(data.ids);
2243  includeExcludeMap.active.exclude = includeExcludeMap.active.exclude.concat(data.ids);
2244  $("#pendingGrid .pendingBottomGrid[data-orderDetailId='" + data.orderDetailId + "']:visible").data("kendoGrid").dataSource.read();
2245  break;
2246  }
2247  }
2248 
2249  return []; <?php // No data is returned to the dataSource. ?>
2250  }
2251  }
2252  });
2253 
2254  <?php
2255  /**
2256  * @var pendingTopGridHelperDs
2257  * This is a helper dataSource to run add/modify/delete operations on the top level of the pending grid.
2258  */
2259  ?>
2260  pendingTopGridHelperDs = new kendo.data.DataSource({
2261  transport: {
2262  read: {
2263  url: "index.prg",
2264  dataType: "json",
2265  type: "POST",
2266  data: {
2267  operation: "none"
2268  }
2269  },
2270  parameterMap: function (data, type) {
2271  showWaitWindow();
2272  return data;
2273  }
2274  },
2275  schema: {
2276  parse: function (data) {
2277  if (data.status !== "000") {
2278  hideWaitWindow();
2279  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
2280  } else {
2281  switch(data.type) {
2282  case "delete":
2283  toHideWindow = ["pending", "warnings"];
2284  $("#pendingGrid").data("kendoGrid").dataSource.read();
2285  warningDs.read();
2286  break;
2287  case "modify":
2288  toHideWindow = ["pending", "warnings"];
2289  $("#pendingGrid").data("kendoGrid").dataSource.read({orderDetailIds: kendo.stringify(data.orderDetailIds)});
2290  warningDs.read();
2291  ShowWorkflowStatusWindow(data.workflowStatuses);
2292 
2293  break;
2294 
2295  }
2296  }
2297 
2298  return []; <?php // No data is returned to the dataSource. ?>
2299  }
2300  }
2301  });
2302 
2303  <?php
2304  /**
2305  * @var completedGridHelperDs
2306  * This is a helper dataSource to run add/modify/delete operations on the completed grid.
2307  */
2308  ?>
2309  completedGridHelperDs = new kendo.data.DataSource({
2310  transport: {
2311  read: {
2312  url: "index.prg",
2313  dataType: "json",
2314  type: "POST",
2315  data: {
2316  operation: "none"
2317  }
2318  },
2319  parameterMap: function (data, type) {
2320  showWaitWindow();
2321  return data;
2322  }
2323  },
2324  schema: {
2325  parse: function (data) {
2326  if (data.status !== "000") {
2327  hideWaitWindow();
2328  $.homecuValidator.displayMessage(data.error, $.homecuValidator.settings.statusError );
2329  } else {
2330  switch(data.type) {
2331  case "advanceStatus":
2332  toHideWindow = ["completed"];
2333 
2334  includeExcludeMap.completed.include = includeExcludeMap.completed.include.concat(data.ids);
2335  includeExcludeMap.active.exclude = includeExcludeMap.active.exclude.concat(data.ids);
2336  $("#completedGrid").data("kendoGrid").dataSource.read();
2337  break;
2338  case "revertStatus":
2339  toHideWindow = ["completed"];
2340 
2341  var completedInclude = $.grep(includeExcludeMap.completed.include, function(n,i) { return data.ids.indexOf(n) === -1; });
2342  var activeExclude = $.grep(includeExcludeMap.active.exclude, function(n,i) { return data.ids.indexOf(n) === -1; });
2343 
2344  includeExcludeMap.completed.include = completedInclude;
2345  includeExcludeMap.active.exclude = activeExclude;
2346  $("#completedGrid").data("kendoGrid").dataSource.read();
2347  break;
2348  }
2349 
2350  }
2351 
2352  return []; <?php // No data is returned to the dataSource. ?>
2353  }
2354  }
2355  });
2356 }
2357 
2358 <?php // ===================
2359  // SETUP OBSERVABLES
2360  // =================== ?>
2361 
2362 var toHideWindow = ["setup", "completed", "active", "pending", "warnings"];
2363 var lineItemObservable = null;
2364 var productObservable = null;
2365 
2366 <?php
2367 /**
2368  * function SetupObservables()
2369  * This sets up all the observables.
2370  */
2371 ?>
2372 function SetupObservables() {
2373 
2374  <?php
2375  /**
2376  * @var lineItemObservable
2377  * This is the observable for line items.
2378  * The values are broken up into "source", "ddls", and "bindOptions."
2379  * "source" -- the actual values of the line item. e.g. fixed and variable.
2380  * "ddls" -- the dropdownlist data needed for the observable.
2381  * "bindOptions" -- the values of the selected ddls
2382  * and visibility of DIVs that are visible depending on ddl setting.
2383  * Values from "configuration" ARE NOT in the observable. Those DIVs are removed.
2384  */
2385  ?>
2386  lineItemObservable = new kendo.observable({
2387  dirty: false,
2388  source: null,
2389  ddls: null,
2390  bindOptions: null,
2391  setupValues: function(lineItemData, bindOptions) {
2392 
2393  <?php // Set dates to date objects. ?>
2394  lineItemData.partiallyBilledDate = kendo.parseDate(lineItemData.partiallyBilledDate);
2395 
2396  <?php // -1 is used to indicate infinity. ?>
2397  lineItemData.qty2 = lineItemData.qty2 == -1 ? null : lineItemData.qty2;
2398 
2399  this.set("source", lineItemData);
2400  this.set("bindOptions", bindOptions);
2401  },
2402  getSaveParameters: function() {
2403  var json = lineItemObservable.toJSON();
2404  var parameters = {};
2405  for (var key in json.source) {
2406  parameters[key] = json.source[key];
2407  }
2408  <?php // Add other parameters from bindOptions. ?>
2409 
2410  var showWorkflowDiv = $("#detailAddWindow .workflowDiv").length > 0;
2411  parameters.workflowValue = !showWorkflowDiv ? "none" : json.bindOptions.workflowValue;
2412  parameters.frequencyValue = json.bindOptions.frequencyValue;
2413  parameters.billsOn1Value = json.bindOptions.billsOn1Value;
2414  parameters.billsOn2Value = json.bindOptions.billsOn2Value;
2415  parameters.billHalfValue = json.bindOptions.billHalfValue;
2416 
2417  <?php // Format dates in acceptable format. ?>
2418  parameters.partiallyBilledDate = kendo.toString(parameters.partiallyBilledDate, "yyyy-MM-dd");
2419 
2420  <?php // Set infinity from null in the observable to "-1" in the database. ?>
2421  parameters.qty2 = json.bindOptions.qtyRangeVisible && json.source.qty2 == null ? -1 : json.source.qty2;
2422 
2423  return parameters;
2424  },
2425  showOverride: function(e) {
2426  this.set("bindOptions.isOverrideCheckboxShown", false);
2427  this.set("bindOptions.isOverrideDescrShown", true);
2428  },
2429  billHalfChange: function(e) {
2430  switch(this.bindOptions.billHalfValue) {
2431  case "partial":
2432  this.set("bindOptions.billHalfCheckReceivedRowVisible", true);
2433  this.set("bindOptions.billHalfDateRowVisible", false);
2434  this.set("bindOptions.billHalfAmountRowVisible", true);
2435  this.set("bindOptions.billHalfDateLabel", "Check Received:");
2436  this.set("source.partiallyBilledDate", new Date());
2437  this.set("source.partiallyBilledAmount", this.source.fixed / 2.0);
2438  break;
2439  case "future":
2440  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2441  this.set("bindOptions.billHalfDateRowVisible", true);
2442  this.set("bindOptions.billHalfAmountRowVisible", false);
2443  this.set("bindOptions.billHalfDateLabel", "Date to Bill Half:");
2444 
2445  <?php // Default boolean to true, billed date to next month. ?>
2446  var nextMonth = new Date();
2447  nextMonth.setDate(1);
2448  nextMonth.setMonth(nextMonth.getMonth() + 1);
2449 
2450  this.set("source.partiallyBilledDate", nextMonth);
2451 
2452  break;
2453  case "upfront":
2454  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2455  this.set("bindOptions.billHalfDateRowVisible", true);
2456  this.set("bindOptions.billHalfAmountRowVisible", false);
2457  this.set("bindOptions.billHalfDateLabel", "Date to Bill:");
2458 
2459  <?php // Default boolean to true, billed date to next month. ?>
2460  var nextMonth = new Date();
2461  nextMonth.setDate(1);
2462  nextMonth.setMonth(nextMonth.getMonth() + 1);
2463 
2464  this.set("source.partiallyBilledDate", nextMonth);
2465  break;
2466  case "full":
2467  default:
2468  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2469  this.set("bindOptions.billHalfDateRowVisible", false);
2470  this.set("bindOptions.billHalfAmountRowVisible", false);
2471  break;
2472  }
2473  },
2474  workflowChange: function(e) {
2475  switch(this.bindOptions.workflowValue) {
2476  case "associate":
2477  this.set("bindOptions.associateToJobRowVisible", true);
2478  this.set("bindOptions.immediateBillRowVisible", false);
2479  this.set("bindOptions.billHalfDDLEnabled", true);
2480  break;
2481  case "without":
2482  this.set("bindOptions.associateToJobRowVisible", false);
2483  this.set("bindOptions.immediateBillRowVisible", true);
2484 
2485  <?php // Set value to next month. ?>
2486  var date = new Date();
2487  date.setMonth(date.getMonth() + 1);
2488  date.setDate(1);
2489 
2490  this.set("source.partiallyBilledDate", date);
2491 
2492  this.set("bindOptions.billHalfDDLEnabled", false);
2493  this.set("bindOptions.billHalfValue", "full");
2494  this.set("bindOptions.billHalfDateRowVisible", false);
2495  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2496  this.set("bindOptions.billHalfAmountRowVisible", false);
2497  break;
2498  case "create":
2499  default:
2500  this.set("bindOptions.associateToJobRowVisible", false);
2501  this.set("bindOptions.immediateBillRowVisible", false);
2502  this.set("bindOptions.billHalfDDLEnabled", true);
2503  break;
2504  }
2505  },
2506  frequencyChange: function(e) {
2507  var id = $(e.sender.element).attr("id").trim();
2508  id = id.split("_")[0];
2509 
2510  switch(id) {
2511  case "frequencies":
2512  switch(this.bindOptions.frequencyValue) {
2513  case 2:
2514  this.set("bindOptions.billsOn1Value", 0);
2515  this.set("bindOptions.billsOn1RowVisible", true);
2516  this.set("bindOptions.billsOn2RowVisible", false);
2517  break;
2518  case 1:
2519  this.set("bindOptions.billsOn1Value", 0);
2520  this.set("bindOptions.billsOn2Value", 6);
2521  this.set("bindOptions.billsOn1RowVisible", true);
2522  this.set("bindOptions.billsOn2RowVisible", true);
2523  break;
2524  case 0:
2525  default:
2526  this.set("bindOptions.billsOn1RowVisible", false);
2527  this.set("bindOptions.billsOn2RowVisible", false);
2528  break;
2529  }
2530  break;
2531  case "billsOn1s":
2532  var val1 = e.sender.value();
2533  var val2 = (val1 + 6) % 12;
2534  this.set("bindOptions.billsOn2Value", val2);
2535  break;
2536  case "billsOn2s":
2537  var val2 = e.sender.value();
2538  var val1 = (24 + val2 - 6) % 12;
2539  this.set("bindOptions.billsOn1Value", val1);
2540  break;
2541  }
2542 
2543  }
2544  });
2545 
2546  <?php
2547  /**
2548  * @var productObservable
2549  * This is the observable for adding a single product.
2550  * Adding multiple products is largely unchanged from before.
2551  * The values are broken up into "source", "ddls", and "bindOptions."
2552  * "source" -- the actual values of the line item. e.g. fixed and variable.
2553  * "ddls" -- the dropdownlist data needed for the observable.
2554  * "bindOptions" -- the values of the selected ddls
2555  * and visibility of DIVs that are visible depending on ddl setting.
2556  */
2557  ?>
2558  productObservable = new kendo.observable({
2559  dirty: false,
2560  source: null,
2561  ddls: null,
2562  bindOptions: null,
2563  billHalfChange: function(e) {
2564  switch(this.bindOptions.billHalfValue) {
2565  case "partial":
2566  this.set("bindOptions.billHalfCheckReceivedRowVisible", true);
2567  this.set("bindOptions.billHalfDateRowVisible", false);
2568  this.set("bindOptions.billHalfDateLabel", "Check Received:");
2569  this.set("source.partiallyBilledDate", new Date());
2570  this.toggleWorkflowDivs(true, false);
2571  break;
2572  case "future":
2573  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2574  this.set("bindOptions.billHalfDateRowVisible", true);
2575  this.set("bindOptions.billHalfDateLabel", "Date to Bill Half:");
2576 
2577  <?php // Default boolean to true, billed date to next month. ?>
2578  var nextMonth = new Date();
2579  nextMonth.setDate(1);
2580  nextMonth.setMonth(nextMonth.getMonth() + 1);
2581 
2582  this.set("source.partiallyBilledDate", nextMonth);
2583  this.toggleWorkflowDivs(true, false);
2584  break;
2585  case "upfront":
2586  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2587  this.set("bindOptions.billHalfDateRowVisible", true);
2588  this.set("bindOptions.billHalfDateLabel", "Date to Bill:");
2589 
2590  <?php // Default boolean to true, billed date to next month. ?>
2591  var nextMonth = new Date();
2592  nextMonth.setDate(1);
2593  nextMonth.setMonth(nextMonth.getMonth() + 1);
2594 
2595  this.set("source.partiallyBilledDate", nextMonth);
2596  this.toggleWorkflowDivs(true, false);
2597  break;
2598  case "nosetup":
2599  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2600  this.set("bindOptions.billHalfDateRowVisible", false);
2601  this.toggleWorkflowDivs(false, false);
2602  break;
2603  case "full":
2604  default:
2605  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2606  this.set("bindOptions.billHalfDateRowVisible", false);
2607  this.toggleWorkflowDivs(true, false);
2608  break;
2609  }
2610  },
2611  toggleWorkflowDivs(showThem, init) {
2612  var toggle = null;
2613 
2614  if (init) {
2615  toggle = showThem;
2616  } else {
2617  if (this.get("bindOptions.hasSetup") !== true) {
2618  toggle = null;
2619  } else if (showThem && this.get("bindOptions.workflowRowVisible") !== true) {
2620  toggle = true;
2621  } else if (!showThem && this.get("bindOptions.workflowRowVisible") === true) {
2622  toggle = false;
2623  }
2624  }
2625 
2626  if (toggle === true) {
2627  this.set("bindOptions.workflowValue", "create");
2628  this.set("bindOptions.workflowRowVisible", true);
2629  this.set("bindOptions.associateToJobRowVisible", false);
2630  this.set("bindOptions.immediateBillRowVisible", false);
2631  } else if (toggle === false) {
2632  this.set("bindOptions.workflowValue", "none");
2633  this.set("bindOptions.workflowRowVisible", false);
2634  this.set("bindOptions.associateToJobRowVisible", false);
2635  this.set("bindOptions.immediateBillRowVisible", false);
2636  }
2637  },
2638  toggleBillHalfDivs(showThem, init) {
2639  var toggle = null;
2640 
2641  if (init) {
2642  toggle = showThem;
2643  } else {
2644  if (this.get("bindOptions.hasSetup") !== true) {
2645  toggle = null;
2646  } else if (showThem && this.get("bindOptions.billHalfRowVisible") !== true) {
2647  toggle = true;
2648  } else if (!showThem && this.get("bindOptions.billHalfRowVisible") === true) {
2649  toggle = false;
2650  }
2651  }
2652 
2653  if (toggle === true) {
2654  this.set("bindOptions.billHalfRowVisible", true);
2655  this.set("bindOptions.billHalfValue", "full");
2656  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2657  this.set("bindOptions.billHalfDateRowVisible", false);
2658  this.set("bindOptions.billHalfDDLEnabled", true);
2659  } else if (toggle === false) {
2660  this.set("bindOptions.billHalfRowVisible", false);
2661  this.set("bindOptions.billHalfValue", "full");
2662  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2663  this.set("bindOptions.billHalfDateRowVisible", false);
2664  }
2665  },
2666  toggleProductExistsDiv(showIt) {
2667  if (showIt) {
2668  if (this.get("bindOptions.productWarningVisible") !== true) {
2669  this.set("bindOptions.productWarningVisible", true);
2670  this.toggleWorkflowDivs(false, true);
2671 
2672  if (this.get("bindOptions.billHalfRowVisible") === true) {
2673  this.set("bindOptions.billHalfValue", "nosetup");
2674  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2675  this.set("bindOptions.billHalfDateRowVisible", false);
2676  this.set("bindOptions.billHalfDDLEnabled", true);
2677  }
2678 
2679  }
2680  } else {
2681  if (this.get("bindOptions.productWarningVisible") === true) {
2682  this.set("bindOptions.productWarningVisible", false);
2683 
2684  this.toggleWorkflowDivs(true, true);
2685  this.toggleBillHalfDivs(true, true);
2686  this.set("bindOptions.billHalfValue", "full");
2687  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2688  this.set("bindOptions.billHalfDateRowVisible", false);
2689  }
2690  }
2691  },
2692  workflowChange: function(e) {
2693  switch(this.bindOptions.workflowValue) {
2694  case "associate":
2695  this.set("bindOptions.associateToJobRowVisible", true);
2696  this.set("bindOptions.immediateBillRowVisible", false);
2697  this.set("bindOptions.billHalfDDLEnabled", true);
2698  break;
2699  case "without":
2700  this.set("bindOptions.associateToJobRowVisible", false);
2701  this.set("bindOptions.immediateBillRowVisible", true);
2702 
2703  <?php // Set value to next month. ?>
2704  var date = new Date();
2705  date.setMonth(date.getMonth() + 1);
2706  date.setDate(1);
2707 
2708  this.set("source.partiallyBilledDate", date);
2709 
2710  this.set("bindOptions.billHalfDDLEnabled", false);
2711  this.set("bindOptions.billHalfValue", "full");
2712  this.set("bindOptions.billHalfDateRowVisible", false);
2713  this.set("bindOptions.billHalfCheckReceivedRowVisible", false);
2714  this.set("bindOptions.billHalfAmountRowVisible", false);
2715  break;
2716  case "create":
2717  default:
2718  this.set("bindOptions.associateToJobRowVisible", false);
2719  this.set("bindOptions.immediateBillRowVisible", false);
2720  this.set("bindOptions.billHalfDDLEnabled", true);
2721  break;
2722  }
2723  },
2724  productChange: function(e) {
2725  var dataItem = e.sender.dataItem();
2726 
2727  if (dataItem.hasOptions !== true) {
2728  if (dataItem.hasSetup === true) {
2729  this.set("bindOptions.hasSetup", true);
2730  this.toggleBillHalfDivs(true, true);
2731  this.toggleWorkflowDivs(true, true);
2732  } else {
2733  this.set("bindOptions.hasSetup", false);
2734  this.toggleBillHalfDivs(false, true);
2735  this.toggleWorkflowDivs(false, true);
2736  }
2737  }
2738 
2739  if (dataItem.useDNID === true) {
2740  this.set("bindOptions.dnidRowVisible", true);
2741  } else {
2742  this.set("bindOptions.dnidRowVisible", false);
2743  }
2744 
2745  if (dataItem.hasOptions === true) {
2746  this.set("bindOptions.configRowVisible", true);
2747  } else {
2748  this.set("bindOptions.configRowVisible", false);
2749  }
2750 
2751  this.toggleProductExistsDiv(dataItem.productExists);
2752  },
2753  configChange: function(e) {
2754  var dataItem = e.sender.dataItem();
2755  if (dataItem != null) {
2756  if (dataItem.hasSetup === true) {
2757  this.set("bindOptions.hasSetup", true);
2758  this.toggleBillHalfDivs(true);
2759  this.toggleWorkflowDivs(true);
2760  } else {
2761  this.set("bindOptions.hasSetup", false);
2762  this.toggleBillHalfDivs(false);
2763  this.toggleWorkflowDivs(false);
2764  }
2765  }
2766  }
2767  });
2768 }
2769 
2770 <?php // ===================
2771  // DOCUMENT READY
2772  // =================== ?>
2773 
2774 var activeWindows = [];
2775 $(document).ready(function () {
2776 
2777  <?php // Needed from https://docs.telerik.com/kendo-ui/controls/editors/dropdownlist/cascading ?>
2778  kendo.data.binders.widget.cascade = kendo.data.Binder.extend({
2779  init: function (widget, bindings, options) {
2780  kendo.data.Binder.fn.init.call(this, widget.element[0], bindings, options);
2781 
2782  this.widget = widget;
2783 
2784  this._cascade = $.proxy(this.cascade, this);
2785  this.widget.bind("cascade", this._cascade);
2786  },
2787  cascade: function () {
2788  if (this.widget.options.cascadeFrom) {
2789  this.widget.trigger("change");
2790  }
2791  },
2792  refresh: function () { },
2793  destroy: function () {
2794  this.widget.unbind("cascade", this._cascade);
2795  }
2796  });
2797 
2798  SetupMainForm();
2799  showWaitWindow();
2800  SetupObservables();
2801  SetupGrids();
2802  SetupDataSources();
2803  SetupActiveGridDialogs();
2804  SetupCompletedGridDialogs();
2805  SetupPendingTopGridDialogs();
2806  SetupPendingBottomGridDialogs();
2807 
2808  $("body").on("click", ".k-overlay", function() { if (activeWindows.length > 0) activeWindows[activeWindows.length - 1].close(); return false; });
2809 
2810 });
2811 </script>
2812 
2813 <?php // ======================================
2814  // PENDING TOP GRID TEMPLATES
2815  // ====================================== ?>
2816 
2817 <?php
2818 /**
2819  * @var topRowTemplate
2820  * This is the row template for the top level of the pending grid.
2821  */
2822 ?>
2823 <script type="k-kendo-template" id="topRowTemplate">
2824  <tr class="k-master-row # if (opened) { # opened # } #" data-uid="#= uid #" data-orderDetailId="#: orderDetailId #">
2825  <td class="k-hierarchy-cell" aria-expanded="false">
2826  # if (numDetails > 0) { #
2827  <a class="k-icon k-i-expand" href="\\#" aria-label="Expand"></a>
2828  # } #
2829  </td>
2830  <?php if ($isInEditList) { ?>
2831  <td>
2832  # if (numDetails == 0) { #
2833  <a class="k-button k-grid-customDelete" href="\\#">
2834  <span class="fa fa-2x fa-trash"></span>
2835  </a>
2836  # } #
2837  </td>
2838  <?php } ?>
2839  <td>#: detailDescription #</td>
2840  <td># if (lastModifiedDate == null) { # &nbsp; # } else { # #: kendo.toString(lastModifiedDate, 'd') # # } #</td>
2841  <td>#: lastModifiedBy #</td>
2842  </tr>
2843 </script>
2844 
2845 <?php
2846 /**
2847  * @var detailTemplate
2848  * This is the template of the row for the detail grid.
2849  */
2850 ?>
2851 <script type="k-kendo-template" id="detailTemplate">
2852  <div class="detailGrid pendingBottomGrid" data-orderDetailId="#: orderDetailId #" data-productId="#: productId #"></div>
2853 </script>
2854 
2855 <?php
2856 /**
2857  * @var addProductWindowTemplate
2858  * This is the template for the add product window.
2859  */
2860 ?>
2861 <script type="k-kendo-template" id="addProductWindowTemplate">
2862  <div class="k-edit-form-container">
2863  <div id="formValidateAddProduct"></div>
2864  <form id="productEditForm">
2865  <div class="container_12">
2866 
2867  <!-- configDiv -->
2868  </div>
2869  </form>
2870  <div class="k-edit-buttons k-state-default">
2871  <a class="k-button k-button-icontext k-primary continueBtn" href="#">
2872  <span class="k-icon k-update"></span>Okay
2873  </a>
2874  <a class="k-button k-button-icontext cancelBtn" href="#">
2875  <span class="k-icon k-cancel"></span>Cancel
2876  </a>
2877  </div>
2878  </div>
2879 </script>
2880 
2881 <?php
2882 /**
2883  * @var productConfigTemplate
2884  * This is the template for the config of the product.
2885  * This is bound to the productObservable.
2886  */
2887 ?>
2888 <script type="k-kendo-template" id="productConfigTemplate">
2889  <div class="grid_12" data-bind="visible: bindOptions.productWarningVisible">
2890  <div id="formInfoPopupDiv" class="homecu-formStatus k-block k-info-colored">
2891  <b>Product already exists.</b>
2892  <br> A save here will append configured line items to the current product.
2893  </div>
2894  </div>
2895 
2896  <div class="grid_12">
2897  <div class="grid_4 alpha">
2898  <label>New Item:</label>
2899  </div>
2900  <div class="grid_7">
2901  <div id="products_top" data-role="dropdownlist" data-text-field="text" data-value-field="value"
2902  data-bind="source: ddls.productItems, value: bindOptions.productId, events: { change: productChange }"></div>
2903  </div>
2904  <div class="grid_1 omega">
2905  <span class='k-invalid-msg'></span>
2906  </div>
2907  </div>
2908  <div class="grid_12" data-bind="visible: bindOptions.configRowVisible">
2909  <div class="grid_4 alpha">
2910  <label>Configuration:</label>
2911  </div>
2912  <div class="grid_7">
2913  <div id="productOptions_top" data-role="dropdownlist" data-text-field="text" data-value-field="value"
2914  data-cascade-from="products_top" data-cascade-from-field="product"
2915  data-bind="source: ddls.productOptions, value: bindOptions.productOption, cascade: bindOptions.productOption,
2916  events: { change: configChange }"></div>
2917  </div>
2918  </div>
2919  <div class="grid_12" data-bind="visible: bindOptions.billHalfRowVisible">
2920  <div class="grid_4 alpha">Setup Options:</div>
2921  <div class="grid_7">
2922  <div id="billHalfs_top" data-role="dropdownlist" data-text-field="text" data-value-field="value"
2923  data-bind="source: ddls.setupBillingDDL, value: bindOptions.billHalfValue,
2924  events: { change: billHalfChange },
2925  enabled: bindOptions.billHalfDDLEnabled"></div>
2926  </div>
2927  <div class="grid_1 omega">
2928  &nbsp;
2929  </div>
2930  </div>
2931  <div class="grid_12" data-bind="visible: bindOptions.billHalfCheckReceivedRowVisible">
2932  <div class="grid_4 alpha">
2933  <span data-bind="text: bindOptions.billHalfDateLabel"></span>
2934  </div>
2935  <div class="grid_7">
2936  <input type="text" name="checkReceived" style="width: 100%"
2937  data-role="datepicker" data-bind="value: source.partiallyBilledDate">
2938  </div>
2939  <div class="grid_1 omega">
2940  <span data-for='checkReceived' class='k-invalid-msg'></span>
2941  </div>
2942  </div>
2943  <div class="grid_12" data-bind="visible: bindOptions.billHalfDateRowVisible">
2944  <div class="grid_4 alpha">
2945  <span data-bind="text: bindOptions.billHalfDateLabel"></span>
2946  </div>
2947  <div class="grid_7">
2948  <input type="text" name="halfBillDate" style="width: 100%"
2949  data-role="datepicker" data-bind="value: source.partiallyBilledDate" data-depth="year" data-start="year" data-format="MMM yyyy">
2950  </div>
2951  <div class="grid_1 omega">
2952  <span data-for='halfBillDate' class='k-invalid-msg'></span>
2953  </div>
2954  </div>
2955  <div class="grid_12" data-bind="visible: bindOptions.workflowRowVisible">
2956  <div class="grid_4 alpha">
2957  <label>Workflow:</label>
2958  </div>
2959  <div class="grid_7">
2960  <select id="workflows_top" data-role="dropdownlist" data-text-field="text" data-value-field="value"
2961  data-cascade-from="products_top" data-cascade-from-field="product"
2962  data-bind="source: ddls.productWorkflowOptions,
2963  value: bindOptions.workflowValue, events: { change: workflowChange }, cascade: bindOptions.workflowValue"></select>
2964  </div>
2965  <div class="grid_1 omega">
2966  &nbsp;
2967  </div>
2968  </div>
2969  <div class="grid_12" data-bind="visible: bindOptions.associateToJobRowVisible">
2970  <div class="grid_4 alpha">
2971  <label>Associate to Job:</label>
2972  </div>
2973  <div class="grid_7">
2974  <div id="unattacheds_top" data-role="dropdownlist" data-text-field="text" data-value-field="value"
2975  data-cascade-from="products_top" data-cascade-from-field="product"
2976  data-bind="source: ddls.unattachedJobs, value: bindOptions.unattachedJobValue", cascade: bindOptions.unattachedJobValue"></div>
2977  </div>
2978  <div class="grid_1 omega">
2979  &nbsp;
2980  </div>
2981  </div>
2982  <div class="grid_12" data-bind="visible: bindOptions.immediateBillRowVisible">
2983  <div class="grid_4 alpha">
2984  <label>Starts:</label>
2985  </div>
2986  <div class="grid_7">
2987  <input type="text" name="immediateBillDate" style="width: 100%"
2988  data-role="datepicker" data-bind="value: source.partiallyBilledDate" data-depth="year" data-start="year" data-format="MMM yyyy">
2989  </div>
2990  <div class="grid_1 omega">
2991  <span data-for='immediateBillDate' class='k-invalid-msg'></span>
2992  </div>
2993  </div>
2994  <div class="grid_12" data-bind="visible: bindOptions.dnidRowVisible">
2995  <div class="grid_4 alpha">
2996  <label class="custLabel">Long Code:</label>
2997  </div>
2998  <div class="grid_4">
2999  <input name="aDNID" style="width: 100%"
3000  data-role="maskedtextbox" data-mask="<?php echo str_repeat('0', 15); ?>" data-bind="value: source.aDNID" data-prompt-char=" ">
3001  </div>
3002  <div class="grid_1 omega">
3003  <span data-for='aDNID' class='k-invalid-msg'></span>
3004  </div>
3005  </div>
3006 </script>
3007 
3008 <?php
3009 /**
3010  * @var shuttleAppletTemplate
3011  * This is the template for the shuttleApplet/window.
3012  */
3013 ?>
3014 <script id="shuttleAppletTemplate" type="k-kendo-template">
3015  <div class="k-edit-form-container">
3016  <div class="container_12">
3017  <div classs="grid_12">
3018  <div id="formInfoShuttleDiv" class="homecu-formStatus k-block k-info-colored" style="display:none;">
3019  <b>These Products already exist: </b>
3020  <ul></ul>
3021  </div>
3022  </div>
3023  <div class="grid_12">
3024  <div class="grid_5">Available</div>
3025  <div class="grid_2">&nbsp;</div>
3026  <div class="grid_5">Selected</div>
3027  </div>
3028  <div class="grid_12">
3029  <div class="grid_5">
3030  <div id="availableGrid" style="width:100%"></div>
3031  </div>
3032  <div class="grid_2">
3033  <a class="k-button k-button-icontext" id="shuttleMoveToSelectedBtn" href="\\#" style="width:60%">--&raquo;</a>
3034  <a class="k-button k-button-icontext" id="shuttleMoveToAvailableBtn" href="\\#" style="width:60%">&laquo;--</a>
3035  </div>
3036  <div class="grid_5" style="min-height:100px">
3037  <div id="selectedGrid" style="width:100%"></div>
3038  </div>
3039  </div>
3040  </div>
3041  <div class="k-edit-buttons k-state-default">
3042  <a class="k-button k-button-icontext k-primary" id="shuttleOkayBtn" href="\\#">
3043  <span class="k-icon k-update"></span>Okay
3044  </a>
3045  <a class="k-button k-button-icontext" id="shuttleCancelBtn" href="\\#">
3046  <span class="k-icon k-cancel"></span>Cancel
3047  </a>
3048  </div>
3049  </div>
3050 </script>
3051 
3052 <?php
3053 /**
3054  * @var pendingToolbarTemplate
3055  * This is the template for the toolbar on the pending grid (top level.)
3056  */
3057 ?>
3058 <script id="pendingToolbarTemplate" type="k-kendo-template">
3059  <a class="k-button k-grid-addSingle" href="\\#">
3060  <span class="fa fa-2x fa-plus"></span>
3061  </a>
3062  <a class="k-button k-grid-createBulk" href="\\#">
3063  <span class="fa fa-2x fa-clipboard"></span>
3064  </a>
3065 </script>
3066 
3067 <?php // ======================================
3068  // PENDING BOTTOM GRID TEMPLATES
3069  // ====================================== ?>
3070 
3071 <?php
3072 /**
3073  * @var detailRowTemplate
3074  * This is the row template for the bottom level of the pending grid.
3075  */
3076 ?>
3077 <script type="k-kendo-template" id="detailRowTemplate">
3078  <tr data-uid="#= uid #">
3079  <?php if ($isInEditList) { ?>
3080  <td>
3081  <a class="k-button k-grid-edit" href="\\#">
3082  <span class="fa fa-2x fa-edit"></span>
3083  </a>
3084  # if (deletable) { #
3085  <a class="k-button k-grid-customDelete" href="\\#">
3086  <span class="fa fa-2x fa-trash"></span>
3087  </a>
3088  # } #
3089  </td>
3090  <td>
3091  # if (showAdvanceWorkflow) { #
3092  <a class="k-button k-grid-advanceWorkflow" href="\\#">
3093  #: advanceWorkflowText #
3094  </a>
3095  # } #
3096  </td>
3097  <?php } ?>
3098  <td>#: partialBillingStatus #</td>
3099  <td>#: billingStatusLabel #</td>
3100  <td>#: actualDescription #</td>
3101  <td>#: textDescription #</td>
3102  <td>#: frequencyDescr #</td>
3103  </tr>
3104 </script>
3105 
3106 <?php
3107 /**
3108  * @var detailEditWindowTemplate
3109  * This is the template for editing a line item.
3110  */
3111 ?>
3112 <script type="k-kendo-template" id="detailEditWindowTemplate">
3113  <div class="k-edit-form-container">
3114  <div id="formValidateEditDetail" style="display:none;"></div>
3115  <form id="detailEditForm">
3116  <div class="container_12">
3117  <div class="grid_12">
3118  <div class="grid_4 alpha">
3119  <label>Description:</label>
3120  </div>
3121  <div class="grid_7 omega">
3122  <span data-bind="text: source.actualDescription"></span>
3123  </div>
3124  </div>
3125 
3126  <!-- configDiv -->
3127  </div>
3128  </form>
3129  <div class="k-edit-buttons k-state-default">
3130  <a class="k-button k-button-icontext k-primary continueBtn" href="#">
3131  <span class="k-icon k-update"></span>Okay
3132  </a>
3133  <a class="k-button k-button-icontext cancelBtn" href="#">
3134  <span class="k-icon k-cancel"></span>Cancel
3135  </a>
3136  </div>
3137  </div>
3138 </script>
3139 
3140 <?php
3141 /**
3142  * @var detailAddWindowTemplate
3143  * This is the template for adding a line item.
3144  */
3145 ?>
3146 <script type="k-kendo-template" id="detailAddWindowTemplate">
3147  <div class="k-edit-form-container">
3148  <div id="formValidateAddDetail" style="display:none;"></div>
3149  <form id="detailAddForm">
3150  <div class="container_12">
3151  <div class="grid_12" id="descriptionLabelLine">
3152  <div class="grid_4 alpha">
3153  <label>Description:</label>
3154  </div>
3155  <div class="grid_7 omega">
3156  <div id="featureDetailDDL"></div>
3157  </div>
3158  </div>
3159 
3160  <div class="configDiv"></div>
3161  </div>
3162  </form>
3163  <div class="k-edit-buttons k-state-default">
3164  <a class="k-button k-button-icontext k-primary continueBtn" href="\\#">
3165  <span class="k-icon k-update"></span>Okay
3166  </a>
3167  <a class="k-button k-button-icontext cancelBtn" href="\\#">
3168  <span class="k-icon k-cancel"></span>Cancel
3169  </a>
3170  </div>
3171  </div>
3172 </script>
3173 
3174 <?php
3175 /**
3176  * @var detailConfigTemplate
3177  * This is the template for the line items.
3178  * This goes through a template to remove unused DIVs.
3179  * Then it is bound to the lineItemObservable.
3180  */
3181 ?>
3182 <script type="k-kendo-template" id="detailConfigTemplate">
3183  # if (showOverrideRow) { #
3184  <div class="grid_12">
3185  <div class="grid_4 alpha">Override:</div>
3186  <div class="grid_7">
3187  <input type="checkbox" data-bind="click: showOverride, visible: bindOptions.isOverrideCheckboxShown">
3188  <input class="k-input" type="text" name="descriptionOverride" data-bind="value: source.overrideDescription, visible: bindOptions.isOverrideDescrShown">
3189  </div>
3190  <div class="grid_1 omega">
3191  <span data-for='descriptionOverride' class='k-invalid-msg'></span>
3192  </div>
3193  </div>
3194  # } #
3195  # if (showFixedRow) { #
3196  <div class="grid_12">
3197  <div class="grid_4 alpha">
3198  <label class="custLabel" data-for="fixed"># if (fixedLabel == "") { # &nbsp; # } else { # #: fixedLabel # # } #</label>
3199  </div>
3200  <div class="grid_4">
3201  <input type="text" name="fixed" required data-required-msg="Fixed is required" style="width: 100%"
3202  data-role="numerictextbox" data-format="#= format #" data-decimals="#: decimals #" data-bind="value: source.fixed">
3203  </div>
3204  <div class="grid_1 omega">
3205  <span data-for='fixed' class='k-invalid-msg'></span>
3206  </div>
3207  </div>
3208  # } #
3209  # if (showBillHalfDiv) { #
3210  <div class="grid_12">
3211  <div class="grid_4 alpha">Setup Options:</div>
3212  <div class="grid_7">
3213  <div id="billHalfs_#: addOrUpdate #" data-role="dropdownlist" data-text-field="text" data-value-field="value"
3214  data-bind="source: ddls.setupBillingDDL, value: bindOptions.billHalfValue,
3215  events: { change: billHalfChange }, enabled: bindOptions.billHalfDDLEnabled"></div>
3216  </div>
3217  <div class="grid_1 omega">
3218  &nbsp;
3219  </div>
3220  </div>
3221  <div class="grid_12" data-bind="visible: bindOptions.billHalfCheckReceivedRowVisible">
3222  <div class="grid_4 alpha">
3223  <span data-bind="text: bindOptions.billHalfDateLabel"></span>
3224  </div>
3225  <div class="grid_7">
3226  <input type="text" name="checkReceived" style="width: 100%"
3227  data-role="datepicker" data-bind="value: source.partiallyBilledDate">
3228  </div>
3229  <div class="grid_1 omega">
3230  <span data-for='checkReceived' class='k-invalid-msg'></span>
3231  </div>
3232  </div>
3233  <div class="grid_12" data-bind="visible: bindOptions.billHalfDateRowVisible">
3234  <div class="grid_4 alpha">
3235  <span data-bind="text: bindOptions.billHalfDateLabel"></span>
3236  </div>
3237  <div class="grid_7">
3238  <input type="text" name="billHalfDate" style="width: 100%"
3239  data-role="datepicker" data-bind="value: source.partiallyBilledDate" data-depth="year" data-start="year" data-format="MMM yyyy">
3240  </div>
3241  <div class="grid_1 omega">
3242  <span data-for='billHalfDate' class='k-invalid-msg'></span>
3243  </div>
3244  </div>
3245  <div class="grid_12" data-bind="visible: bindOptions.billHalfAmountRowVisible">
3246  <div class="grid_4 alpha">
3247  <label>Amount Received:</label>
3248  </div>
3249  <div class="grid_4">
3250  <input type="text" name="checkReceivedAmount" style="width: 100%"
3251  data-role="numerictextbox" data-min="0" data-decimals="2" data-format="{0:c}" data-bind="value: source.partiallyBilledAmount">
3252  </div>
3253  <div class="grid_1 omega">
3254  <span data-for='checkReceivedAmount' class='k-invalid-msg'></span>
3255  </div>
3256  </div>
3257  # } #
3258  # if (showWorkflowDiv) { #
3259  <div class="grid_12 workflowDiv">
3260  <div class="grid_4 alpha">
3261  <label>Workflow:</label>
3262  </div>
3263  <div class="grid_7">
3264  <select id="workflows_#: addOrUpdate #" data-role="dropdownlist" data-text-field="text" data-value-field="value"
3265  data-bind="source: ddls.workflowDDL, value: bindOptions.workflowValue, events: { change: workflowChange }"></select>
3266  </div>
3267  <div class="grid_1 omega">
3268  &nbsp;
3269  </div>
3270  </div>
3271  <div class="grid_12" data-bind="visible: bindOptions.associateToJobRowVisible">
3272  <div class="grid_4 alpha">
3273  <label>Associate to Job:</label>
3274  </div>
3275  <div class="grid_7">
3276  <div id="unattacheds_#: addOrUpdate #" data-role="dropdownlist" data-text-field="text" data-value-field="value"
3277  data-bind="source: ddls.unattachedJobDDL, value: bindOptions.unattachedJobValue"></div>
3278  </div>
3279  <div class="grid_1 omega">
3280  &nbsp;
3281  </div>
3282  </div>
3283  <div class="grid_12" data-bind="visible: bindOptions.immediateBillRowVisible">
3284  <div class="grid_4 alpha">
3285  <label>Starts:</label>
3286  </div>
3287  <div class="grid_7">
3288  <input type="text" name="immediateBillDate" style="width: 100%"
3289  data-role="datepicker" data-bind="value: source.partiallyBilledDate" data-depth="year" data-start="year" data-format="MMM yyyy">
3290  </div>
3291  <div class="grid_1 omega">
3292  <span data-for='immediateBillDate' class='k-invalid-msg'></span>
3293  </div>
3294  </div>
3295  # } #
3296  # if (showVariableRow) { #
3297  <div class="grid_12">
3298  <div class="grid_4 alpha">
3299  <label class="custLabel" data-for="variable"># if (variableLabel == "") { # &nbsp; # } else { # #: variableLabel # # } #</label>
3300  </div>
3301  <div class="grid_4">
3302  <input type="text" name="variable" required data-required-msg="Variable is required" style="width: 100%"
3303  data-role="numerictextbox" data-decimals="#: decimals #" data-format="#= format #" data-bind="value: source.variable">
3304  </div>
3305  <div class="grid_1 omega">
3306  <span data-for='variable' class='k-invalid-msg'></span>
3307  </div>
3308  </div>
3309  # } #
3310  # if (showQuantity1Row) { #
3311  <div class="grid_12">
3312  <div class="grid_4 alpha">
3313  <label data-for="qty1"># if (quantity1Label1 == "") { # &nbsp; # } else { # #: quantity1Label1 # # } #</label>
3314  </div>
3315  <div class="grid_4">
3316  <input type="text" name="qty1" required data-required-msg="Quantity 1 is required" style="width: 100%"
3317  data-role="numerictextbox" data-decimals="0" data-format="\\#" data-min="0" data-bind="value: source.qty1">
3318  </div>
3319  <div class="grid_3">
3320  <label data-for="qty1"># if (quantity1Label2 == "") { # &nbsp; # } else { # #: quantity1Label2 # # } #</label>
3321  </div>
3322  <div class="grid_1 omega">
3323  <span data-for='qty1' class='k-invalid-msg'></span>
3324  </div>
3325  </div>
3326  # } #
3327  # if (showQuantity2Row) { #
3328  <div class="grid_12">
3329  <div class="grid_4 alpha">
3330  <label data-for="qty2"># if (quantity2Label1 == "") { # &nbsp; # } else { # #: quantity2Label1 # # } #</label>
3331  </div>
3332  <div class="grid_4">
3333  <input type="text" name="qty2" required data-required-msg="Quantity 2 is required" style="width: 100%"
3334  data-role="numerictextbox" data-decimals="0" data-format="\\#" data-min="0" data-bind="value: source.qty2">
3335  </div>
3336  <div class="grid_3">
3337  <label data-for="qty2"># if (quantity2Label2 == "") { # &nbsp; # } else { # #: quantity2Label2 # # } #</label>
3338  </div>
3339  <div class="grid_1 omega">
3340  <span data-for='qty2' class='k-invalid-msg'></span>
3341  </div>
3342  </div>
3343  # } #
3344  # if (showQuantityRangeRow) { #
3345  <div class="grid_12">
3346  <div class="grid_4 alpha">
3347  <label># if (quantityRangeLabel1 == "") { # &nbsp; # } else { # #: quantityRangeLabel1 # # } #</label>
3348  </div>
3349  <div class="grid_3">
3350  <input type="text" name="qty1Range" required data-required-msg="Quantity 1 is required" style="width: 100%"
3351  data-role="numerictextbox" data-decimals="0" data-format="\\#" data-min="0" data-bind="value: source.qty1">
3352  </div>
3353  <div class="grid_1">To</div>
3354  <div class="grid_3">
3355  <input type="text" name="qty2Range" style="width: 100%"
3356  data-role="numerictextbox" data-decimals="0" data-format="\\#" data-min="0" data-bind="value: source.qty2" placeholder="">
3357  </div>
3358  <div class="grid_1 omega">
3359  <span data-for='qty1Range' class='k-invalid-msg'></span>
3360  <span data-for='qty2Range' class='k-invalid-msg'></span>
3361  </div>
3362  </div>
3363  # } #
3364  # if (showDNIDDiv) { #
3365  <div class="grid_12">
3366  <div class="grid_4 alpha">
3367  <label class="custLabel" data-for="aDNID">Long Code:</label>
3368  </div>
3369  <div class="grid_4">
3370  <input name="aDNID" style="width: 100%"
3371  data-role="maskedtextbox" data-mask="<?php echo str_repeat('0', 15); ?>" data-bind="value: source.aDNID" data-prompt-char=" ">
3372  </div>
3373  <div class="grid_1 omega">
3374  <span data-for='aDNID' class='k-invalid-msg'></span>
3375  </div>
3376  </div>
3377  # } #
3378  # if (showFrequencyDiv) { #
3379  <div class="grid_12">
3380  <div class="grid_4 alpha">
3381  <label>Frequency:</label>
3382  </div>
3383  <div class="grid_3">
3384  <div id="frequencies_#: addOrUpdate #" data-role="dropdownlist" data-text-field="text" data-value-field="value"
3385  data-bind="source: ddls.frequencyDDL, value: bindOptions.frequencyValue, events: { change: frequencyChange }"></div>
3386  </div>
3387  <div class="grid_1 omega">
3388  &nbsp;
3389  </div>
3390  </div>
3391  <div class="grid_12" data-bind="visible: bindOptions.billsOn1RowVisible">
3392  <div class="grid_4 alpha">
3393  <label>Bills On:</label>
3394  </div>
3395  <div class="grid_3">
3396  <div id="billsOn1s_#: addOrUpdate #" data-role="dropdownlist" data-text-field="text" data-value-field="value"
3397  data-bind="source: ddls.monthDDL, value: bindOptions.billsOn1Value, events: { change: frequencyChange }"></div>
3398  </div>
3399  <div class="grid_1 omega">
3400  &nbsp;
3401  </div>
3402  </div>
3403  <div class="grid_12" data-bind="visible: bindOptions.billsOn2RowVisible">
3404  <div class="grid_4 alpha">
3405  <label>And:</label>
3406  </div>
3407  <div class="grid_3">
3408  <div id="billsOn2s_#: addOrUpdate #" data-role="dropdownlist" data-text-field="text" data-value-field="value"
3409  data-bind="source: ddls.monthDDL, value: bindOptions.billsOn2Value, events: { change: frequencyChange }"></div>
3410  </div>
3411  <div class="grid_1 omega">
3412  &nbsp;
3413  </div>
3414  </div>
3415  # } #
3416 </script>
3417 
3418 <?php
3419 /**
3420  * @var changeStartMonthTemplate
3421  * This is the template for changing the month in the pending detail grid.
3422  */
3423 ?>
3424 <script id="changeStartMonthTemplate" type="k-kendo-template">
3425  <div class="k-edit-form-container added">
3426  <div class="container_12">
3427  <div class="grid_12">
3428  <div class="grid_4 alpha">Start Date:</div>
3429  <div class="grid_7 omega"><div id="pendingStartMonthDDL"></div></div>
3430  </div>
3431  </div>
3432  <div class="k-edit-buttons k-state-default">
3433  <a class="k-button k-button-icontext k-primary continueBtn" href="\\#">
3434  <span class="k-icon k-update"></span>Okay
3435  </a>
3436  <a class="k-button k-button-icontext cancelBtn" href="\\#">
3437  <span class="k-icon k-cancel"></span>Cancel
3438  </a>
3439  </div>
3440  </div>
3441 </script>
3442 
3443 <?php
3444 /**
3445  * @var detailToolbarTemplate
3446  * This is the template for the toolbar: pending grid, bottom level.
3447  */
3448 ?>
3449 <script id="detailToolbarTemplate" type="k-kendo-template">
3450  <a class="k-button k-grid-add" href="\\#">
3451  <span class="fa fa-2x fa-plus"></span>
3452  </a>
3453  <a class="k-button k-grid-startMonthlies" href="\\#">
3454  Start Recurring
3455  </a>
3456 </script>
3457 
3458 <?php // ======================================
3459  // ACTIVE GRID TEMPLATES
3460  // ====================================== ?>
3461 
3462 <?php
3463 /**
3464  * @var activeRowTemplate
3465  * This is the row template for the active grid.
3466  */
3467 ?>
3468 <script type="k-kendo-template" id="activeRowTemplate">
3469  <tr data-uid="#= uid#">
3470  <?php if ($isInEditList) { ?>
3471  <td>
3472  # if (showCompleteButton) { #
3473  <a class="k-button k-grid-advanceWorkflow" href="\\#">#: completeButtonText #</a>
3474  # } #
3475  <a class="k-button k-grid-changePrice" href="\\#">Change Price</a>
3476  <a class="k-button k-grid-customDelete" href="\\#">
3477  <span class="fa fa-2x fa-trash"></span>
3478  </a>
3479  </td>
3480  <?php } ?>
3481  <td>#: productName #</td>
3482  <td>#: featureName #</td>
3483  <td>#: partialBillingStatus #</td>
3484  <td>#: status #</td>
3485  <td>#: featureDescription #</td>
3486  <td>#: frequencyDescr #</td>
3487  </tr>
3488 </script>
3489 
3490 <?php
3491 /**
3492  * @var changeEndMonthTemplate
3493  * This is the template for the change end month window.
3494  */
3495 ?>
3496 <script id="changeEndMonthTemplate" type="k-kendo-template">
3497  <div class="k-edit-form-container added">
3498  <div class="container_12">
3499  <div class="grid_12">
3500  <div class="grid_4 alpha">End Date:</div>
3501  <div class="grid_7 omega"><div id="activeEndMonthDDL"></div></div>
3502  </div>
3503  </div>
3504  <div class="k-edit-buttons k-state-default">
3505  <a class="k-button k-button-icontext k-primary continueBtn" href="\\#">
3506  <span class="k-icon k-update"></span>Okay
3507  </a>
3508  <a class="k-button k-button-icontext cancelBtn" href="\\#">
3509  <span class="k-icon k-cancel"></span>Cancel
3510  </a>
3511  </div>
3512  </div>
3513 </script>
3514 
3515 <?php
3516 /**
3517  * @var activeChangePriceTemplate
3518  * This is the template for the change price window.
3519  */
3520 ?>
3521 <script type="k-kendo-template" id="activeChangePriceTemplate">
3522  <div class="k-edit-form-container">
3523  <div id="formValidateChangePrice" style="display:none;"></div>
3524  <form id="activeChangePriceForm">
3525  <div class="container_12">
3526  <div class="grid_12">
3527  <div class="grid_4 alpha">
3528  <label>Description:</label>
3529  </div>
3530  <div class="grid_7 omega">
3531  <span data-bind="text: source.actualDescription"></span>
3532  </div>
3533  </div>
3534 
3535  <!-- configDiv -->
3536  </div>
3537  </form>
3538  <div class="k-edit-buttons k-state-default">
3539  <a class="k-button k-button-icontext k-primary continueBtn" href="#">
3540  <span class="k-icon k-update"></span>Okay
3541  </a>
3542  <a class="k-button k-button-icontext cancelBtn" href="#">
3543  <span class="k-icon k-cancel"></span>Cancel
3544  </a>
3545  </div>
3546  </div>
3547 </script>
3548 
3549 <?php // ======================================
3550  // COMPLETED GRID TEMPLATES
3551  // ====================================== ?>
3552 
3553 <?php
3554 /**
3555  * @var completedRowTemplate
3556  * This is the row template for the completed grid.
3557  */
3558 ?>
3559 <script type="k-kendo-template" id="completedRowTemplate">
3560  <tr data-uid="#= uid#">
3561  <?php if ($isInEditList) { ?>
3562  <td>
3563  # if (showAdvanceWorkflow) { #
3564  <a class="k-button k-grid-advanceWorkflow" href="\\#">
3565  #: advanceWorkflowText #
3566  </a>
3567  # } #
3568  </td>
3569  <?php } ?>
3570  <td>#: productName #</td>
3571  <td>#: featureName #</td>
3572  <td>#: partialBillingStatus #</td>
3573  <td>#: status #</td>
3574  <td>#: featureDescription #</td>
3575  <td>#: frequencyDescr #</td>
3576  </tr>
3577 </script>
3578 
3579 <?php // ======================================
3580  // PAGE HTML
3581  // ====================================== ?>
3582 
3583 <div class="container_12">
3584  <div class="grid_12">
3585  <h2>Showing details for <span id="cuLabel"></span></h2>
3586  <div id="cu" style="display:none"></div><div id="cuName" style="display:none;"></div>
3587  </div>
3588  <div id="formMain"></div>
3589  <div id="formValidateMainDiv" style="display:none;"></div>
3590  <div class="grid_12">
3591  <div id="warningDiv" class="k-block" style="display:none;"></div>
3592  </div>
3593  <div class="grid_12">
3594  <div id="activeGrid" class="detailGrid minifiedActionGrid"></div>
3595  </div>
3596  <div class="grid_12">
3597  <div id="pendingGrid" class="detailGrid minifiedActionGrid"></div>
3598  </div>
3599  <div class="grid_12">
3600  <div id="completedGrid" class="detailGrid minifiedActionGrid"></div>
3601  </div>
3602 </div>