scheduler-node-models 1.0.81 → 1.0.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/general/emailer.d.ts +1 -0
  2. package/general/emailer.js +31 -0
  3. package/general/general.d.ts +12 -0
  4. package/general/general.js +2 -0
  5. package/general/index.d.ts +4 -0
  6. package/general/index.js +20 -0
  7. package/general/report.d.ts +12 -0
  8. package/general/report.js +70 -0
  9. package/general/reportStyle.d.ts +0 -0
  10. package/general/reportStyle.js +1 -0
  11. package/general/viewstate.d.ts +5 -0
  12. package/general/viewstate.js +9 -0
  13. package/index.d.ts +0 -0
  14. package/metrics/images.d.ts +22 -0
  15. package/metrics/images.js +33 -0
  16. package/metrics/index.d.ts +5 -0
  17. package/metrics/index.js +21 -0
  18. package/metrics/mission.d.ts +47 -0
  19. package/metrics/mission.js +81 -0
  20. package/metrics/missionSensorOutage.d.ts +11 -0
  21. package/metrics/missionSensorOutage.js +14 -0
  22. package/metrics/missionsensor.d.ts +67 -0
  23. package/metrics/missionsensor.js +128 -0
  24. package/metrics/outage.d.ts +43 -0
  25. package/metrics/outage.js +55 -0
  26. package/metrics/reports/drawSummary.d.ts +24 -0
  27. package/metrics/reports/drawSummary.js +311 -0
  28. package/metrics/reports/index.d.ts +5 -0
  29. package/metrics/reports/index.js +21 -0
  30. package/metrics/reports/missionDay.d.ts +8 -0
  31. package/metrics/reports/missionDay.js +23 -0
  32. package/metrics/reports/missionSummary.d.ts +25 -0
  33. package/metrics/reports/missionSummary.js +421 -0
  34. package/metrics/reports/missionType.d.ts +20 -0
  35. package/metrics/reports/missionType.js +314 -0
  36. package/metrics/reports/outageDay.d.ts +8 -0
  37. package/metrics/reports/outageDay.js +23 -0
  38. package/metrics/systemdata/classifications.d.ts +18 -0
  39. package/metrics/systemdata/classifications.js +23 -0
  40. package/metrics/systemdata/communications.d.ts +21 -0
  41. package/metrics/systemdata/communications.js +40 -0
  42. package/metrics/systemdata/dcgs.d.ts +19 -0
  43. package/metrics/systemdata/dcgs.js +29 -0
  44. package/metrics/systemdata/exploitations.d.ts +18 -0
  45. package/metrics/systemdata/exploitations.js +23 -0
  46. package/metrics/systemdata/groundSystems.d.ts +86 -0
  47. package/metrics/systemdata/groundSystems.js +143 -0
  48. package/metrics/systemdata/index.d.ts +7 -0
  49. package/metrics/systemdata/index.js +23 -0
  50. package/metrics/systemdata/platform.d.ts +124 -0
  51. package/metrics/systemdata/platform.js +176 -0
  52. package/metrics/systemdata/systeminfo.d.ts +28 -0
  53. package/metrics/systemdata/systeminfo.js +64 -0
  54. package/package.json +2 -2
  55. package/scheduler/employees/assignment.d.ts +139 -0
  56. package/scheduler/employees/assignment.js +304 -0
  57. package/scheduler/employees/balance.d.ts +35 -0
  58. package/scheduler/employees/balance.js +39 -0
  59. package/scheduler/employees/companyinfo.d.ts +16 -0
  60. package/scheduler/employees/companyinfo.js +6 -0
  61. package/scheduler/employees/contact.d.ts +36 -0
  62. package/scheduler/employees/contact.js +40 -0
  63. package/scheduler/employees/employee.d.ts +420 -0
  64. package/scheduler/employees/employee.js +1862 -0
  65. package/scheduler/employees/employeename.d.ts +48 -0
  66. package/scheduler/employees/employeename.js +97 -0
  67. package/scheduler/employees/index.d.ts +14 -0
  68. package/scheduler/employees/index.js +30 -0
  69. package/scheduler/employees/labor.d.ts +31 -0
  70. package/scheduler/employees/labor.js +39 -0
  71. package/scheduler/employees/leave.d.ts +58 -0
  72. package/scheduler/employees/leave.js +73 -0
  73. package/scheduler/employees/leaverequest.d.ts +105 -0
  74. package/scheduler/employees/leaverequest.js +226 -0
  75. package/scheduler/employees/specialty.d.ts +35 -0
  76. package/scheduler/employees/specialty.js +40 -0
  77. package/scheduler/employees/variation.d.ts +80 -0
  78. package/scheduler/employees/variation.js +132 -0
  79. package/scheduler/employees/web.d.ts +6 -0
  80. package/scheduler/employees/web.js +2 -0
  81. package/scheduler/employees/work.d.ts +96 -0
  82. package/scheduler/employees/work.js +133 -0
  83. package/scheduler/employees/workday.d.ts +91 -0
  84. package/scheduler/employees/workday.js +170 -0
  85. package/scheduler/labor/index.d.ts +2 -0
  86. package/scheduler/labor/index.js +18 -0
  87. package/scheduler/labor/laborcode.d.ts +33 -0
  88. package/scheduler/labor/laborcode.js +55 -0
  89. package/scheduler/labor/workcode.d.ts +28 -0
  90. package/scheduler/labor/workcode.js +35 -0
  91. package/scheduler/reports/chargeStatus.d.ts +66 -0
  92. package/scheduler/reports/chargeStatus.js +702 -0
  93. package/scheduler/reports/cofsReports.d.ts +11 -0
  94. package/scheduler/reports/cofsReports.js +36 -0
  95. package/scheduler/reports/enterpriseSchedule.d.ts +18 -0
  96. package/scheduler/reports/enterpriseSchedule.js +159 -0
  97. package/scheduler/reports/index.d.ts +4 -0
  98. package/scheduler/reports/index.js +20 -0
  99. package/scheduler/reports/scheduleReport.d.ts +17 -0
  100. package/scheduler/reports/scheduleReport.js +311 -0
  101. package/scheduler/sites/index.d.ts +1 -0
  102. package/scheduler/sites/index.js +17 -0
  103. package/scheduler/sites/reports/cofsReport.d.ts +41 -0
  104. package/scheduler/sites/reports/cofsReport.js +104 -0
  105. package/scheduler/sites/reports/forecast.d.ts +57 -0
  106. package/scheduler/sites/reports/forecast.js +205 -0
  107. package/scheduler/sites/reports/index.d.ts +4 -0
  108. package/scheduler/sites/reports/index.js +20 -0
  109. package/scheduler/sites/reports/period.d.ts +11 -0
  110. package/scheduler/sites/reports/period.js +27 -0
  111. package/scheduler/sites/reports/section.d.ts +63 -0
  112. package/scheduler/sites/reports/section.js +174 -0
  113. package/scheduler/sites/site.d.ts +39 -0
  114. package/scheduler/sites/site.js +61 -0
  115. package/scheduler/sites/workcenters/index.d.ts +3 -0
  116. package/scheduler/sites/workcenters/index.js +19 -0
  117. package/scheduler/sites/workcenters/position.d.ts +27 -0
  118. package/scheduler/sites/workcenters/position.js +36 -0
  119. package/scheduler/sites/workcenters/shift.d.ts +32 -0
  120. package/scheduler/sites/workcenters/shift.js +47 -0
  121. package/scheduler/sites/workcenters/workcenter.d.ts +43 -0
  122. package/scheduler/sites/workcenters/workcenter.js +123 -0
  123. package/scheduler/teams/company/company.d.ts +99 -0
  124. package/scheduler/teams/company/company.js +256 -0
  125. package/scheduler/teams/company/holiday.d.ts +55 -0
  126. package/scheduler/teams/company/holiday.js +108 -0
  127. package/scheduler/teams/company/index.d.ts +3 -0
  128. package/scheduler/teams/company/index.js +19 -0
  129. package/scheduler/teams/company/modperiod.d.ts +21 -0
  130. package/scheduler/teams/company/modperiod.js +24 -0
  131. package/scheduler/teams/contact.d.ts +18 -0
  132. package/scheduler/teams/contact.js +23 -0
  133. package/scheduler/teams/index.d.ts +3 -0
  134. package/scheduler/teams/index.js +19 -0
  135. package/scheduler/teams/specialty.d.ts +18 -0
  136. package/scheduler/teams/specialty.js +23 -0
  137. package/scheduler/teams/team.d.ts +95 -0
  138. package/scheduler/teams/team.js +351 -0
  139. package/users/index.d.ts +2 -0
  140. package/users/index.js +18 -0
  141. package/users/user.d.ts +130 -0
  142. package/users/user.js +254 -0
  143. package/users/web.d.ts +22 -0
  144. package/users/web.js +2 -0
@@ -0,0 +1,702 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChargeStatusReport = void 0;
4
+ const exceljs_1 = require("exceljs");
5
+ const general_1 = require("../../general");
6
+ const sites_1 = require("../sites");
7
+ const labor_1 = require("../labor");
8
+ const employees_1 = require("../employees");
9
+ class ChargeStatusReport extends general_1.Report {
10
+ site;
11
+ workcodes;
12
+ lastWorked;
13
+ fonts;
14
+ fills;
15
+ borders;
16
+ alignments;
17
+ numformats;
18
+ constructor(isite, workcodes) {
19
+ super();
20
+ this.site = new sites_1.Site(isite);
21
+ this.workcodes = new Map();
22
+ workcodes.forEach(wc => {
23
+ const wCode = new labor_1.Workcode(wc);
24
+ this.workcodes.set(wCode.id, wCode);
25
+ });
26
+ this.lastWorked = new Date(0);
27
+ this.fonts = new Map();
28
+ this.fills = new Map();
29
+ this.borders = new Map();
30
+ this.alignments = new Map();
31
+ this.numformats = new Map();
32
+ }
33
+ create(user, iEmps, companyID, reqDate) {
34
+ const workbook = new exceljs_1.Workbook();
35
+ workbook.creator = user.getFullName();
36
+ workbook.created = new Date();
37
+ // determine the lastworked date for the report
38
+ const employees = [];
39
+ this.lastWorked = new Date(0);
40
+ iEmps.forEach(iEmp => {
41
+ const emp = new employees_1.Employee(iEmp);
42
+ const last = emp.getLastWorkday();
43
+ if (emp.companyinfo.company.toLowerCase() === companyID
44
+ && emp.isActive(reqDate)) {
45
+ if (last.getTime() > this.lastWorked.getTime()) {
46
+ this.lastWorked = new Date(last);
47
+ }
48
+ }
49
+ employees.push(emp);
50
+ });
51
+ employees.sort((a, b) => a.compareTo(b));
52
+ this.createStyles();
53
+ // create the statistics sheet first, so the other sheets can feed it data
54
+ const stats = this.createStatisticsSheet(workbook);
55
+ let statsRow = 3;
56
+ // step through the forecast reports, to see if valid, create current and forecast
57
+ // sheets.
58
+ this.site.forecasts.forEach(rpt => {
59
+ if (rpt.use(reqDate, companyID)) {
60
+ let row = this.addReport(workbook, 'Current', rpt, employees, stats, statsRow);
61
+ if (row) {
62
+ statsRow = row;
63
+ }
64
+ row = this.addReport(workbook, 'Forecast', rpt, employees, stats, statsRow);
65
+ if (row) {
66
+ statsRow = row;
67
+ }
68
+ }
69
+ });
70
+ return workbook;
71
+ }
72
+ /**
73
+ * This function will create the basic style information to be used within the sheet
74
+ * cells, which consists for font styles, cell fill styles, borders, and alignments for
75
+ * the text within the cell. Plus a late addition of the various number formats to
76
+ * present.
77
+ */
78
+ createStyles() {
79
+ // set fonts
80
+ this.fonts.set("bold18", { bold: true, size: 14, color: { argb: 'ff000000' } });
81
+ this.fonts.set("bold14", { bold: true, size: 14, color: { argb: 'ff000000' } });
82
+ this.fonts.set("bold12", { bold: true, size: 12, color: { argb: 'ff000000' } });
83
+ this.fonts.set("white12", { bold: false, size: 12, color: { argb: 'ffffffff' } });
84
+ this.fonts.set("blue12", { bold: true, size: 12, color: { argb: 'ff0000ff' } });
85
+ this.fonts.set("nobold9", { bold: false, size: 9, color: { argb: 'ff000000' } });
86
+ this.fonts.set('notnorm', { bold: false, size: 9, color: { argb: 'ff0070c0' } });
87
+ // set fills
88
+ this.fills.set('black', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ff000000' } });
89
+ this.fills.set('white', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffffffff' } });
90
+ this.fills.set('blue', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ff99ccff' } });
91
+ this.fills.set('ltblue', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffccffff' } });
92
+ this.fills.set('green', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ff99cc00' } });
93
+ this.fills.set('ltgreen', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffccffcc' } });
94
+ this.fills.set('dkblush', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffda9694' } });
95
+ this.fills.set('yellow', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffffff00' } });
96
+ this.fills.set('ltbrown', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'fffcd5b4' } });
97
+ this.fills.set('gray', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffc0c0c0' } });
98
+ this.fills.set('ltgray', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffbfbfbf' } });
99
+ // set borders
100
+ this.borders.set('blackthin', {
101
+ top: { style: 'thin', color: { argb: 'ff000000' } },
102
+ left: { style: 'thin', color: { argb: 'ff000000' } },
103
+ bottom: { style: 'thin', color: { argb: 'ff000000' } },
104
+ right: { style: 'thin', color: { argb: 'ff000000' } }
105
+ });
106
+ this.borders.set('blackthinNoRight', {
107
+ top: { style: 'thin', color: { argb: 'ff000000' } },
108
+ left: { style: 'thin', color: { argb: 'ff000000' } },
109
+ bottom: { style: 'thin', color: { argb: 'ff000000' } },
110
+ right: { style: 'thin', color: { argb: 'ffffffff' } }
111
+ });
112
+ this.borders.set('blackthinNoLeft', {
113
+ top: { style: 'thin', color: { argb: 'ff000000' } },
114
+ left: { style: 'thin', color: { argb: 'ffffffff' } },
115
+ bottom: { style: 'thin', color: { argb: 'ff000000' } },
116
+ right: { style: 'thin', color: { argb: 'ff000000' } }
117
+ });
118
+ // set alignments
119
+ this.alignments.set('center', { horizontal: 'center', vertical: 'middle', wrapText: true });
120
+ this.alignments.set('leftctr', { horizontal: 'left', vertical: 'middle', wrapText: true });
121
+ this.alignments.set('rightctr', { horizontal: 'right', vertical: 'middle', wrapText: true });
122
+ this.alignments.set('centerslant', { horizontal: 'center', vertical: 'middle',
123
+ wrapText: false, textRotation: 45 });
124
+ // set number formats
125
+ this.numformats.set('sum', '##0.0;[Red]##0.0;-;@');
126
+ this.numformats.set('monthsum', '_(* #,##0.0_);_(* (#,##0.0);_(* \"-\"??_);_(@_)');
127
+ this.numformats.set('pct', '##0.0%;[Red]##0.0%;-;@');
128
+ }
129
+ /**
130
+ * This function will create the various pages of the workbook which hold the actual
131
+ * data for the workbook. They will consist of a header section, then list the
132
+ * employee's work/forecast work hours by labor code. lastly, if the stats worksheet
133
+ * is provided, it will add the statistics formulas to the rows of data on this sheet,
134
+ * by report type (current or forecast);
135
+ * @param workbook A reference to the workbook object so worksheet creation is possible
136
+ * @param type A string value to indicate if the report is for current or forecast data
137
+ * @param report The forecast object used to define the period and labor codes for use
138
+ * @param employees The list of site employees used for the report.
139
+ * @param stats A reference to the statistics worksheet to allow this to add the
140
+ * correct formulas to it.
141
+ * @param statsRow The numeric value for the last row used in the statistics worksheet.
142
+ * @return The numeric value for the last row used in the statistics worksheet.
143
+ */
144
+ addReport(workbook, type, report, employees, stats, statsRow) {
145
+ const current = (type.toLowerCase() === 'current');
146
+ const sheetLabel = `${report.name}_${type}`;
147
+ // add a worksheet to the workbook and set the page options (landscape, etc)
148
+ const sheet = workbook.addWorksheet(sheetLabel, {
149
+ pageSetup: {
150
+ paperSize: undefined,
151
+ orientation: 'landscape',
152
+ fitToHeight: 1,
153
+ fitToWidth: 1,
154
+ blackAndWhite: false,
155
+ fitToPage: true,
156
+ showGridLines: false,
157
+ horizontalCentered: true,
158
+ verticalCentered: true
159
+ }
160
+ });
161
+ sheet.properties.defaultRowHeight = 20;
162
+ sheet.properties.defaultColWidth = 4;
163
+ sheet.properties.outlineLevelCol = 0;
164
+ // set column widths
165
+ const widths = [8, 10.57, 9, 14.57, 10.57, 20, 18.14, 17.57, 14.57, 14.57, 14.57, 55.14];
166
+ const months = ['January', 'Febuary', 'March', 'April', 'May', 'June', 'July',
167
+ 'August', 'September', 'October', 'November', 'December'];
168
+ widths.forEach((width, w) => {
169
+ sheet.getColumn(w + 1).width = width;
170
+ });
171
+ let columns = 12;
172
+ report.periods.forEach(period => {
173
+ const sumCol = columns + 1;
174
+ const startCol = columns + 2;
175
+ const endCol = startCol + (period.periods.length - 1);
176
+ sheet.getColumn(sumCol).width = 12;
177
+ sheet.getColumn(sumCol).outlineLevel = 0;
178
+ for (let i = startCol; i <= endCol; i++) {
179
+ sheet.getColumn(i).width = 9;
180
+ sheet.getColumn(i).outlineLevel = 1;
181
+ }
182
+ columns = endCol;
183
+ });
184
+ sheet.getColumn(columns + 1).width = 15.43;
185
+ sheet.getColumn(columns + 1).outlineLevel = 0;
186
+ // add page's headers
187
+ let style = {
188
+ fill: this.fills.get('white'),
189
+ font: this.fonts.get("bold18"),
190
+ alignment: this.alignments.get("leftctr"),
191
+ border: this.borders.get("blackthin")
192
+ };
193
+ this.setCell(sheet, "A1", "G1", style, `FFP Labor: CLIN ${report.laborCodes[0].clin}`
194
+ + ` SUMMARY`);
195
+ const formatter = new Intl.DateTimeFormat('en-US', {
196
+ month: '2-digit',
197
+ day: '2-digit',
198
+ year: 'numeric'
199
+ });
200
+ this.setCell(sheet, "A2", "G2", style, `${report.name} Year - `
201
+ + `${formatter.format(report.startDate)} - ${formatter.format(report.endDate)}`);
202
+ style.font = this.fonts.get('bold14');
203
+ this.setCell(sheet, "L1", "L1", style, "Weeks Per Accounting Month");
204
+ this.setCell(sheet, "L2", "L2", style, "Accounting Month");
205
+ this.setCell(sheet, "L3", "L3", style, "Week Ending");
206
+ // Set headers for the employee information columns
207
+ style = {
208
+ fill: this.fills.get('black'),
209
+ font: this.fonts.get('white12'),
210
+ alignment: this.alignments.get('center'),
211
+ border: this.borders.get('blackthin')
212
+ };
213
+ this.setCell(sheet, "A4", "A4", style, "CLIN");
214
+ this.setCell(sheet, "B4", "B4", style, "SLIN");
215
+ this.setCell(sheet, "C4", "C4", style, "Company");
216
+ this.setCell(sheet, "D4", "D4", style, "Location");
217
+ this.setCell(sheet, "E4", "E4", style, "WBS");
218
+ this.setCell(sheet, "F4", "F4", style, "Labor NWA");
219
+ this.setCell(sheet, "G4", "G4", style, "Last Name");
220
+ this.setCell(sheet, "H4", "H4", style, "Labor Category");
221
+ this.setCell(sheet, "I4", "I4", style, "Employee ID");
222
+ this.setCell(sheet, "J4", "J4", style, "PeopleSoft ID");
223
+ this.setCell(sheet, "K4", "K4", style, "Cost Center");
224
+ this.setCell(sheet, "L4", "L4", style, "Comments/Remarks");
225
+ // set headers for periods and sub-periods
226
+ columns = 11;
227
+ report.periods.forEach(period => {
228
+ columns++;
229
+ style = {
230
+ fill: this.fills.get('white'),
231
+ font: this.fonts.get('bold14'),
232
+ alignment: this.alignments.get('center'),
233
+ border: this.borders.get('blackthin')
234
+ };
235
+ this.setCell(sheet, this.getCellID(columns, 1), this.getCellID(columns, 1), style, period.periods.length);
236
+ this.setCell(sheet, this.getCellID(columns, 2), this.getCellID(columns + period.periods.length, 2), style, months[period.month.getMonth()].toUpperCase());
237
+ style.font = this.fonts.get('bold14');
238
+ this.setCell(sheet, this.getCellID(columns, 3), this.getCellID(columns, 3), style, "Month Total");
239
+ style = {
240
+ fill: this.fills.get('dkblush'),
241
+ font: this.fonts.get('bold12'),
242
+ alignment: this.alignments.get('center'),
243
+ border: this.borders.get('blackthin')
244
+ };
245
+ const dFormat = new Intl.DateTimeFormat('en-US', {
246
+ month: 'short',
247
+ day: '2-digit'
248
+ });
249
+ this.setCell(sheet, this.getCellID(columns, 4), this.getCellID(columns, 4), style, dFormat.format(period.month));
250
+ const dtStyle = {
251
+ fill: this.fills.get('white'),
252
+ font: this.fonts.get('bold14'),
253
+ alignment: this.alignments.get('center'),
254
+ border: this.borders.get('blackthin')
255
+ };
256
+ const wkStyle = {
257
+ fill: this.fills.get('yellow'),
258
+ font: this.fonts.get('bold12'),
259
+ alignment: this.alignments.get('center'),
260
+ border: this.borders.get('blackthin')
261
+ };
262
+ period.periods.forEach((prd, p) => {
263
+ let cellID = this.getCellID(columns + p + 1, 3);
264
+ this.setCell(sheet, cellID, cellID, dtStyle, dFormat.format(prd));
265
+ cellID = this.getCellID(columns + p + 1, 4);
266
+ this.setCell(sheet, cellID, cellID, wkStyle, `Week ${p + 1}`);
267
+ });
268
+ columns += period.periods.length;
269
+ });
270
+ // Add a totals column header for the overall totals
271
+ style = {
272
+ fill: this.fills.get('white'),
273
+ font: this.fonts.get('bold12'),
274
+ alignment: this.alignments.get('center'),
275
+ border: this.borders.get('blackthin')
276
+ };
277
+ let cellID = this.getCellID(columns + 1, 4);
278
+ this.setCell(sheet, cellID, cellID, style, 'EAC');
279
+ // create list of leave and work codes for comparison to determine working or
280
+ // not working criteria
281
+ let row = 4;
282
+ const compareCodes = [];
283
+ this.workcodes.forEach(wc => {
284
+ compareCodes.push({
285
+ code: wc.id,
286
+ isLeave: wc.isLeave
287
+ });
288
+ });
289
+ let column = 0;
290
+ // this report is listed by labor code, then employees with hours
291
+ report.laborCodes.forEach(lCode => {
292
+ // step through the employees to see if they have hours for this labor code
293
+ let lastWorked = new Date(0);
294
+ employees.forEach(emp => {
295
+ // employee has used this labor code, if they have some actual or forecast hours.
296
+ const actual = emp.getWorkedHours(report.startDate, report.endDate, lCode.chargeNumber, lCode.extension);
297
+ const forecast = emp.getForecastHours(lCode, report.startDate, report.endDate, compareCodes);
298
+ if (actual > 0 || forecast > 0) {
299
+ row++;
300
+ if (emp.getLastWorkday().getTime() > lastWorked.getTime()) {
301
+ lastWorked = new Date(emp.getLastWorkday());
302
+ }
303
+ const col = this.employeeRow(sheet, lCode, row, emp, report, current, compareCodes);
304
+ if (col > column) {
305
+ column = col;
306
+ }
307
+ }
308
+ });
309
+ if (stats && statsRow) {
310
+ // this is used to create the dates in the statistics labor rows
311
+ const dFormat = new Intl.DateTimeFormat('en-US', {
312
+ month: '2-digit',
313
+ day: '2-digit',
314
+ year: 'numeric'
315
+ });
316
+ const codeText = `${lCode.chargeNumber} ${lCode.extension}`;
317
+ // determine the period to date total hours that should have been used based
318
+ // upon an even spread of hours throughout the period.
319
+ let codeHours = 0.0;
320
+ let totalHours = 0.0;
321
+ if (lCode.startDate && lCode.endDate) {
322
+ const days = Math.ceil((lCode.endDate.getTime() - lCode.startDate.getTime())
323
+ / (24 * 3600000));
324
+ let daysToNow = 0.0;
325
+ if (lastWorked.getTime() > lCode.startDate.getTime()) {
326
+ daysToNow = Math.ceil((lastWorked.getTime() - lCode.startDate.getTime())
327
+ / (24 * 3600000));
328
+ }
329
+ if (lCode.hoursPerEmployee && lCode.minimumEmployees) {
330
+ totalHours = lCode.hoursPerEmployee * lCode.minimumEmployees;
331
+ }
332
+ let perDay = 0.0;
333
+ if (daysToNow > 0) {
334
+ perDay = totalHours / days;
335
+ }
336
+ codeHours = perDay * daysToNow;
337
+ }
338
+ let style = {
339
+ fill: this.fills.get('white'),
340
+ font: this.fonts.get('bold12'),
341
+ alignment: this.alignments.get("center"),
342
+ border: this.borders.get('blackthin')
343
+ };
344
+ if (current) {
345
+ // this branch will add the labor codes and start and end dates, plus the
346
+ // current formulas to the statistics worksheet. It will modify the statsRow
347
+ // value to reflect each row used by labor code. Rows need to alternate fills,
348
+ // so that rows are easier to delinate. Columns A to G.
349
+ statsRow++;
350
+ style.numFmt = undefined;
351
+ const bLight = (statsRow % 2) === 0;
352
+ // labor code, and dates cells first three columns
353
+ if (bLight) {
354
+ style.fill = this.fills.get('gray');
355
+ }
356
+ else {
357
+ style.fill = this.fills.get('white');
358
+ }
359
+ this.setCell(stats, this.getCellID(0, statsRow), this.getCellID(0, statsRow), style, codeText);
360
+ this.setCell(stats, this.getCellID(1, statsRow), this.getCellID(1, statsRow), style, dFormat.format(lCode.startDate));
361
+ this.setCell(stats, this.getCellID(2, statsRow), this.getCellID(2, statsRow), style, dFormat.format(lCode.endDate));
362
+ // next current information next four columns, hours to date, total worked
363
+ // hours, +/- hours, percentage of hours to date.
364
+ if (bLight) {
365
+ style.fill = this.fills.get('blue');
366
+ }
367
+ else {
368
+ style.fill = this.fills.get('ltblue');
369
+ }
370
+ style.numFmt = this.numformats.get('sum');
371
+ this.setCell(stats, this.getCellID(3, statsRow), this.getCellID(3, statsRow), style, codeHours);
372
+ let formula = `SUMIF(${sheetLabel}!${this.getCellID(5, 5)}:`
373
+ + `${this.getCellID(5, row)}, "*${codeText}*", ${sheetLabel}!`
374
+ + `${this.getCellID(column, 5)}:${this.getCellID(column, row)})`;
375
+ this.setCell(stats, this.getCellID(4, statsRow), this.getCellID(4, statsRow), style, new general_1.Formula(formula));
376
+ formula = `${this.getCellID(3, statsRow)} - ${this.getCellID(4, statsRow)}`;
377
+ this.setCell(stats, this.getCellID(5, statsRow), this.getCellID(5, statsRow), style, new general_1.Formula(formula));
378
+ formula = `IFERROR(${this.getCellID(4, statsRow)}/`
379
+ + `${this.getCellID(3, statsRow)},"N/A")`;
380
+ style.numFmt = this.numformats.get('pct');
381
+ this.setCell(stats, this.getCellID(6, statsRow), this.getCellID(6, statsRow), style, new general_1.Formula(formula));
382
+ }
383
+ else {
384
+ // this branch will add only the forecast data formulas to the statistics. It
385
+ // will first find the correct row based on the labor code, then determine the
386
+ // fill style to use, then add the formula. Columns H to K
387
+ let row = 0;
388
+ for (let r = 3; r <= statsRow && row === 0; r++) {
389
+ const cell = stats.getCell(r, 1);
390
+ if (cell.text.toLowerCase() === codeText.toLowerCase()) {
391
+ row = r;
392
+ }
393
+ }
394
+ // row greater than zero means the labor code was found and
395
+ if (row > 0) {
396
+ const bLight = (row % 2) === 0;
397
+ // forecast information next four columns, total hours, total forecasted
398
+ // hours, +/- hours, percentage of hours to date.
399
+ if (bLight) {
400
+ style.fill = this.fills.get('green');
401
+ }
402
+ else {
403
+ style.fill = this.fills.get('ltgreen');
404
+ }
405
+ style.numFmt = this.numformats.get('sum');
406
+ this.setCell(stats, this.getCellID(7, row), this.getCellID(7, row), style, totalHours);
407
+ let formula = `SUMIF(${sheetLabel}!${this.getCellID(5, 5)}:`
408
+ + `${this.getCellID(5, row)}, "*${codeText}*", ${sheetLabel}!`
409
+ + `${this.getCellID(column, 5)}:${this.getCellID(column, row)})`;
410
+ this.setCell(stats, this.getCellID(8, row), this.getCellID(8, row), style, new general_1.Formula(formula));
411
+ formula = `${this.getCellID(7, row)} - ${this.getCellID(8, row)}`;
412
+ this.setCell(stats, this.getCellID(9, row), this.getCellID(9, row), style, new general_1.Formula(formula));
413
+ style.numFmt = this.numformats.get('pct');
414
+ const oformula = new general_1.Formula(`IFERROR(${this.getCellID(8, row)}/`
415
+ + `${this.getCellID(7, row)},"N/A")`);
416
+ this.setCell(stats, this.getCellID(10, row), this.getCellID(10, row), style, oformula);
417
+ }
418
+ }
419
+ }
420
+ });
421
+ return statsRow;
422
+ }
423
+ /**
424
+ * This function focuses on an employee, who has hours in the labor code provided. This
425
+ * will create a row of data on the worksheet for this employee's work in this
426
+ * category
427
+ * @param sheet The reference to the worksheet to add a row of data to.
428
+ * @param lCode The labor code object, which allows the work to focus on a single code.
429
+ * @param row The numeric value for the worksheet row to use in filling in the data
430
+ * @param emp The employee object to pull the work data.
431
+ * @param report The forecast report object which provides the periods and other data
432
+ * used in constructing the employee's row.
433
+ * @param current The boolean value which signifies whether only actual work performed
434
+ * or add in forecast work hours in this report sheet.
435
+ * @param compare A short workcode array, used to determine leaves and other non-work
436
+ * periods.
437
+ */
438
+ employeeRow(sheet, lCode, row, emp, report, current, compare) {
439
+ const lastWorked = emp.getLastWorkday();
440
+ // create two style objects for filling in the employee's employment information as
441
+ // pertains to the object
442
+ let style = {
443
+ fill: this.fills.get('white'),
444
+ font: this.fonts.get('bold12'),
445
+ alignment: this.alignments.get('center'),
446
+ border: this.borders.get('blackthin'),
447
+ numFmt: this.numformats.get('sum')
448
+ };
449
+ // lstyle is used for a section of the employee's information which highlights the
450
+ // individual as working in a liaison capability.
451
+ const lStyle = {
452
+ fill: this.fills.get('white'),
453
+ font: this.fonts.get('bold12'),
454
+ alignment: this.alignments.get('leftctr'),
455
+ border: this.borders.get('blackthin')
456
+ };
457
+ if (emp.companyinfo.jobtitle
458
+ && emp.companyinfo.jobtitle?.toLowerCase().indexOf('liaison') >= 0) {
459
+ style.fill = this.fills.get('ltbrown');
460
+ lStyle.fill = this.fills.get('ltbrown');
461
+ }
462
+ // this section sets the various required columns with information about the
463
+ // employment in the labor code.
464
+ this.setCell(sheet, this.getCellID(0, row), this.getCellID(0, row), style, (lCode.clin) ? lCode.clin : '');
465
+ this.setCell(sheet, this.getCellID(1, row), this.getCellID(1, row), style, (lCode.slin) ? lCode.slin : '');
466
+ this.setCell(sheet, this.getCellID(2, row), this.getCellID(2, row), style, (emp.companyinfo.division) ? emp.companyinfo.division.toUpperCase() : '');
467
+ this.setCell(sheet, this.getCellID(3, row), this.getCellID(3, row), style, (lCode.location) ? lCode.location : '');
468
+ this.setCell(sheet, this.getCellID(4, row), this.getCellID(4, row), style, (lCode.wbs) ? lCode.wbs : '');
469
+ this.setCell(sheet, this.getCellID(5, row), this.getCellID(5, row), style, `${lCode.chargeNumber} ${lCode.extension}`);
470
+ this.setCell(sheet, this.getCellID(6, row), this.getCellID(6, row), lStyle, emp.name.lastname);
471
+ this.setCell(sheet, this.getCellID(7, row), this.getCellID(7, row), style, (emp.companyinfo.rank) ? emp.companyinfo.rank : '');
472
+ this.setCell(sheet, this.getCellID(8, row), this.getCellID(8, row), style, emp.companyinfo.employeeid);
473
+ this.setCell(sheet, this.getCellID(9, row), this.getCellID(9, row), style, (emp.companyinfo.alternateid) ? emp.companyinfo.alternateid : '');
474
+ this.setCell(sheet, this.getCellID(10, row), this.getCellID(10, row), style, (emp.companyinfo.costcenter) ? emp.companyinfo.costcenter : '');
475
+ // This section steps though the forecast report periods to provide the hours worked/
476
+ // or forecasted to work, in the period. Each period corresponds to an accounting
477
+ // month and its weekly periods. These are determined by the contract administrator
478
+ // and put in the forecast report object.
479
+ let column = 11;
480
+ const sumlist = []; // used to provide a total hours from the monthly values
481
+ report.periods.forEach(period => {
482
+ column++;
483
+ style = {
484
+ fill: this.fills.get('dkblush'),
485
+ font: this.fonts.get('bold12'),
486
+ alignment: this.alignments.get('rightctr'),
487
+ border: this.borders.get('blackthin'),
488
+ numFmt: this.numformats.get('sum')
489
+ };
490
+ // create the formula to obtain the monthly total of hours and set the formula to
491
+ // the summary cell.
492
+ let formula = '';
493
+ if (period.periods.length > 1) {
494
+ formula = `SUM(${this.getCellID(column + 1, row)}:`
495
+ + `${this.getCellID(column + period.periods.length, row)})`;
496
+ }
497
+ else {
498
+ formula = `${this.getCellID(column + 1, row)}`;
499
+ }
500
+ this.setCell(sheet, this.getCellID(column, row), this.getCellID(column, row), style, new general_1.Formula(formula));
501
+ // step through the weekly periods to get the employee's work hours.
502
+ period.periods.forEach(prd => {
503
+ column++;
504
+ let last = new Date(prd);
505
+ let first = new Date(last.getTime() - (7 * 24 * 3600000));
506
+ if (first.getTime() < report.startDate.getTime()) {
507
+ first = new Date(Date.UTC(report.startDate.getFullYear(), report.startDate.getMonth(), report.startDate.getDate()));
508
+ }
509
+ if (last.getTime() > report.endDate.getTime()) {
510
+ last = new Date(Date.UTC(report.endDate.getFullYear(), report.endDate.getMonth(), report.endDate.getDate()));
511
+ }
512
+ style = {
513
+ fill: this.fills.get('ltgray'),
514
+ font: this.fonts.get('bold12'),
515
+ alignment: this.alignments.get('center'),
516
+ border: this.borders.get('blackthin')
517
+ };
518
+ let hours = emp.getWorkedHours(first, new Date(last.getTime() + (24 * 3600000)), lCode.chargeNumber, lCode.extension);
519
+ // if the worksheet displays forecast data and the last date is after the
520
+ // employee's last recorded actual workday, show as a forecast value and get the
521
+ // forecast hours added to the actual hours.
522
+ if (!current) {
523
+ if (last.getTime() > lastWorked.getTime()) {
524
+ style.font = this.fonts.get('blue12');
525
+ }
526
+ hours += emp.getForecastHours(lCode, first, new Date(last.getTime() + (24 * 3600000)), compare);
527
+ }
528
+ let cellID = this.getCellID(column, row);
529
+ this.setCell(sheet, cellID, cellID, style, hours);
530
+ // this sets an excel conditional formatting relationship for if the resultant
531
+ // value is equal to zero (0), changes fill color and displays a dash.
532
+ sheet.addConditionalFormatting({
533
+ ref: `${cellID}:${cellID}`,
534
+ rules: [
535
+ {
536
+ type: 'cellIs',
537
+ priority: 1,
538
+ operator: 'equal',
539
+ formulae: [0],
540
+ style: {
541
+ fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: `ffffb5b5` } },
542
+ font: { bold: true, size: 12, color: { argb: `ff000000` } },
543
+ alignment: { horizontal: 'center', vertical: 'middle', wrapText: true },
544
+ border: {
545
+ top: { style: 'thin', color: { argb: 'ff000000' } },
546
+ left: { style: 'thin', color: { argb: 'ff000000' } },
547
+ bottom: { style: 'thin', color: { argb: 'ff000000' } },
548
+ right: { style: 'thin', color: { argb: 'ff000000' } }
549
+ },
550
+ numFmt: "##0.0;[Red]##0.0;-;@"
551
+ }
552
+ }
553
+ ]
554
+ });
555
+ // lastly, set the totals column and conditional style format
556
+ style = {
557
+ fill: this.fills.get('dkblush'),
558
+ font: this.fonts.get('bold12'),
559
+ alignment: this.alignments.get('center'),
560
+ border: this.borders.get('blackthin'),
561
+ numFmt: this.numformats.get('monthsum')
562
+ };
563
+ column++;
564
+ cellID = this.getCellID(column, row);
565
+ formula = '';
566
+ sumlist.forEach(c => {
567
+ if (formula !== '') {
568
+ formula += "+";
569
+ }
570
+ formula += c;
571
+ });
572
+ this.setCell(sheet, cellID, cellID, style, new general_1.Formula(formula));
573
+ // these conditional formatting provides fill color change for if the employee
574
+ // works more than his/her alloted hours or less than alloted hours.
575
+ sheet.addConditionalFormatting({
576
+ ref: `${cellID}`,
577
+ rules: [
578
+ {
579
+ type: 'cellIs',
580
+ priority: 1,
581
+ operator: 'greaterThan',
582
+ formulae: [lCode.hoursPerEmployee],
583
+ style: {
584
+ fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: `ffffb5b5` } },
585
+ font: { bold: true, size: 12, color: { argb: `ff000000` } },
586
+ alignment: { horizontal: 'center', vertical: 'middle', wrapText: true },
587
+ border: {
588
+ top: { style: 'thin', color: { argb: 'ff000000' } },
589
+ left: { style: 'thin', color: { argb: 'ff000000' } },
590
+ bottom: { style: 'thin', color: { argb: 'ff000000' } },
591
+ right: { style: 'thin', color: { argb: 'ff000000' } }
592
+ },
593
+ numFmt: "##0.0;[Red]##0.0;-;@"
594
+ }
595
+ }
596
+ ]
597
+ });
598
+ sheet.addConditionalFormatting({
599
+ ref: `${cellID}`,
600
+ rules: [
601
+ {
602
+ type: 'cellIs',
603
+ priority: 1,
604
+ operator: 'lessThan',
605
+ formulae: [lCode.hoursPerEmployee],
606
+ style: {
607
+ fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: `ff99cc00` } },
608
+ font: { bold: true, size: 12, color: { argb: `ff000000` } },
609
+ alignment: { horizontal: 'center', vertical: 'middle', wrapText: true },
610
+ border: {
611
+ top: { style: 'thin', color: { argb: 'ff000000' } },
612
+ left: { style: 'thin', color: { argb: 'ff000000' } },
613
+ bottom: { style: 'thin', color: { argb: 'ff000000' } },
614
+ right: { style: 'thin', color: { argb: 'ff000000' } }
615
+ },
616
+ numFmt: "##0.0;[Red]##0.0;-;@"
617
+ }
618
+ }
619
+ ]
620
+ });
621
+ });
622
+ });
623
+ return column;
624
+ }
625
+ /**
626
+ * This function will create the statistics page for the cover of the workbook, which
627
+ * will hold all the formulas for overall labor usage.
628
+ * @param workbook The excel workbook object use for creating worksheets within it.
629
+ * @returns The reference to the statistics worksheet to allow other functions to fill
630
+ * in the formulas to use.
631
+ */
632
+ createStatisticsSheet(workbook) {
633
+ // Create the sheet just like the others but with the label statistics
634
+ const sheetname = "Statistics";
635
+ const sheet = workbook.addWorksheet(sheetname, {
636
+ pageSetup: {
637
+ paperSize: undefined,
638
+ orientation: 'landscape',
639
+ fitToHeight: 1,
640
+ fitToWidth: 1,
641
+ blackAndWhite: false,
642
+ fitToPage: true,
643
+ showGridLines: false,
644
+ horizontalCentered: true,
645
+ verticalCentered: true
646
+ }
647
+ });
648
+ // set the width of all the columns
649
+ sheet.getColumn("A").width = 30;
650
+ for (let i = 2; i < 12; i++) {
651
+ sheet.getColumn(i).width = 12;
652
+ }
653
+ // this is used to create the current as of date on the sheet
654
+ const dFormat = new Intl.DateTimeFormat('en-US', {
655
+ day: '2-digit',
656
+ month: 'short',
657
+ year: 'numeric'
658
+ });
659
+ let style = {
660
+ fill: this.fills.get('white'),
661
+ font: this.fonts.get('bold18'),
662
+ alignment: this.alignments.get('center'),
663
+ border: this.borders.get('blackthin'),
664
+ };
665
+ const now = new Date();
666
+ this.setCell(sheet, "A1", "K1", style, `Current As Of ${dFormat.format(now)}`);
667
+ sheet.getRow(1).height = 20;
668
+ sheet.getRow(2).height = 77;
669
+ style = {
670
+ fill: this.fills.get('white'),
671
+ font: this.fonts.get('bold12'),
672
+ alignment: this.alignments.get('centerslant'),
673
+ border: this.borders.get("blackthin")
674
+ };
675
+ // Set the column headers with column B & C, inclusive dates in white/slanted 45
676
+ this.setCell(sheet, "B2", "B2", style, "Start");
677
+ this.setCell(sheet, "C2", "C2", style, "End");
678
+ // To Date section headers in a blue/slant 45
679
+ style.fill = this.fills.get('blue');
680
+ this.setCell(sheet, "D2", "D2", style, "Alloted");
681
+ this.setCell(sheet, "E2", "E2", style, "Used");
682
+ this.setCell(sheet, "F2", "F2", style, "Over/Under");
683
+ this.setCell(sheet, "G2", "G2", style, "Percent");
684
+ // Overall/Projected section headers in a blue/slant 45
685
+ style.fill = this.fills.get('green');
686
+ this.setCell(sheet, "H2", "H2", style, "Alloted");
687
+ this.setCell(sheet, "I2", "I2", style, "Used");
688
+ this.setCell(sheet, "J2", "J2", style, "Over/Under");
689
+ this.setCell(sheet, "K2", "K2", style, "Percent");
690
+ // labels for the sections
691
+ style.fill = this.fills.get('white');
692
+ style.alignment = this.alignments.get('center');
693
+ this.setCell(sheet, "A3", "A3", style, "Contract No/Ext");
694
+ this.setCell(sheet, "B3", "C3", style, "Contract Period");
695
+ style.fill = this.fills.get('blue');
696
+ this.setCell(sheet, "D3", "G3", style, "Current");
697
+ style.fill = this.fills.get('green');
698
+ this.setCell(sheet, "H3", "K3", style, "Forecast");
699
+ return sheet;
700
+ }
701
+ }
702
+ exports.ChargeStatusReport = ChargeStatusReport;