scheduler-node-models 1.2.19 → 1.2.21
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.
- package/general/reportStyle.d.ts +0 -0
- package/general/reportStyle.js +1 -0
- package/metrics/reports/drawSummary.d.ts +24 -0
- package/metrics/reports/drawSummary.js +311 -0
- package/metrics/reports/index.d.ts +5 -0
- package/metrics/reports/index.js +21 -0
- package/metrics/reports/missionDay.d.ts +8 -0
- package/metrics/reports/missionDay.js +23 -0
- package/metrics/reports/missionSummary.d.ts +25 -0
- package/metrics/reports/missionSummary.js +421 -0
- package/metrics/reports/missionType.d.ts +20 -0
- package/metrics/reports/missionType.js +314 -0
- package/metrics/reports/outageDay.d.ts +8 -0
- package/metrics/reports/outageDay.js +23 -0
- package/package.json +3 -2
- package/scheduler/employees/variation.d.ts +14 -6
- package/scheduler/employees/variation.js +18 -6
- package/scheduler/employees/web.d.ts +15 -0
- package/scheduler/employees/workday.js +23 -0
- package/scheduler/reports/chargeStatus.d.ts +66 -0
- package/scheduler/reports/chargeStatus.js +752 -0
- package/scheduler/reports/cofsReports.d.ts +11 -0
- package/scheduler/reports/cofsReports.js +36 -0
- package/scheduler/reports/enterpriseSchedule.d.ts +18 -0
- package/scheduler/reports/enterpriseSchedule.js +159 -0
- package/scheduler/reports/index.d.ts +6 -0
- package/scheduler/reports/index.js +22 -0
- package/scheduler/reports/leaveReport.d.ts +52 -0
- package/scheduler/reports/leaveReport.js +755 -0
- package/scheduler/reports/leaves.d.ts +24 -0
- package/scheduler/reports/leaves.js +110 -0
- package/scheduler/reports/scheduleReport.d.ts +17 -0
- package/scheduler/reports/scheduleReport.js +311 -0
|
@@ -0,0 +1,755 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LeaveReport = void 0;
|
|
4
|
+
const exceljs_1 = require("exceljs");
|
|
5
|
+
const general_1 = require("../../general");
|
|
6
|
+
const employees_1 = require("../employees");
|
|
7
|
+
const company_1 = require("../teams/company");
|
|
8
|
+
const leaves_1 = require("./leaves");
|
|
9
|
+
const labor_1 = require("../labor");
|
|
10
|
+
class LeaveReport extends general_1.Report {
|
|
11
|
+
employees;
|
|
12
|
+
holidays;
|
|
13
|
+
fonts;
|
|
14
|
+
fills;
|
|
15
|
+
borders;
|
|
16
|
+
alignments;
|
|
17
|
+
numformats;
|
|
18
|
+
workcodes;
|
|
19
|
+
constructor(holidays, workcodes) {
|
|
20
|
+
super();
|
|
21
|
+
this.employees = [];
|
|
22
|
+
this.holidays = [];
|
|
23
|
+
holidays.forEach(hol => {
|
|
24
|
+
this.holidays.push(new company_1.Holiday(hol));
|
|
25
|
+
});
|
|
26
|
+
this.holidays.sort((a, b) => a.compareTo(b));
|
|
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
|
+
this.workcodes = new Map();
|
|
33
|
+
if (workcodes.length > 0) {
|
|
34
|
+
workcodes.forEach(wc => {
|
|
35
|
+
this.workcodes.set(wc.id, new labor_1.Workcode(wc));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* This method is used to start the workbook creation and will call the other functional
|
|
41
|
+
* sheets to create the report.
|
|
42
|
+
* @param user The user object for the employee who is creating the report
|
|
43
|
+
* @param iEmps A list of employee objects to use in creating the report
|
|
44
|
+
* @param site A string value for the site identifier for the report
|
|
45
|
+
* @param company A string value for the company identifier
|
|
46
|
+
* @param reqDate A date object for the requested date
|
|
47
|
+
* @returns The workbook object with the report data.
|
|
48
|
+
*/
|
|
49
|
+
create(user, iEmps, site, company, reqDate) {
|
|
50
|
+
const start = new Date(Date.UTC(reqDate.getUTCFullYear(), 0, 1));
|
|
51
|
+
const end = new Date(Date.UTC(reqDate.getUTCFullYear() + 1, 0, 1));
|
|
52
|
+
iEmps.forEach(iemp => {
|
|
53
|
+
const emp = new employees_1.Employee(iemp);
|
|
54
|
+
if (emp.atSite(site, start, end)
|
|
55
|
+
&& emp.companyinfo.company.toLowerCase() === company.toLowerCase()) {
|
|
56
|
+
this.employees.push(emp);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
this.employees.sort((a, b) => a.compareTo(b));
|
|
60
|
+
const workbook = new exceljs_1.Workbook();
|
|
61
|
+
workbook.creator = user.getFullName();
|
|
62
|
+
workbook.created = new Date();
|
|
63
|
+
this.createStyles();
|
|
64
|
+
this.createLeaveListing(workbook, start.getFullYear(), this.holidays.length > 0);
|
|
65
|
+
this.createMonthlyListing(workbook, start.getFullYear(), true);
|
|
66
|
+
this.createMonthlyListing(workbook, start.getFullYear(), false);
|
|
67
|
+
return workbook;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* This function will create the basic style information to be used within the sheet
|
|
71
|
+
* cells, which consists for font styles, cell fill styles, borders, and alignments for
|
|
72
|
+
* the text within the cell. Plus a late addition of the various number formats to
|
|
73
|
+
* present.
|
|
74
|
+
*/
|
|
75
|
+
createStyles() {
|
|
76
|
+
// set fonts
|
|
77
|
+
this.fonts.set("bold14", { bold: true, size: 14, color: { argb: 'ff000000' } });
|
|
78
|
+
this.fonts.set("bold12", { bold: true, size: 12, color: { argb: 'ff000000' } });
|
|
79
|
+
this.fonts.set("bold10", { bold: true, size: 10, color: { argb: 'ff000000' } });
|
|
80
|
+
this.fonts.set("nobold10", { bold: false, size: 10, color: { argb: 'ff000000' } });
|
|
81
|
+
this.fonts.set("bold8", { bold: true, size: 8, color: { argb: 'ff000000' } });
|
|
82
|
+
this.fonts.set("blue10", { bold: false, size: 10, color: { argb: 'ff00ffff' } });
|
|
83
|
+
this.fonts.set("noblue10", { bold: false, size: 10, color: { argb: 'ff3366ff' } });
|
|
84
|
+
this.fonts.set("blue8", { bold: true, size: 8, color: { argb: 'ff3366ff' } });
|
|
85
|
+
this.fonts.set("white14", { bold: true, size: 14, color: { argb: 'ffffffff' } });
|
|
86
|
+
this.fonts.set("white12", { bold: true, size: 12, color: { argb: 'ffffffff' } });
|
|
87
|
+
this.fonts.set("white10", { bold: true, size: 10, color: { argb: 'ffffffff' } });
|
|
88
|
+
// set fills
|
|
89
|
+
this.fills.set('ptoname', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ff00ffff' } });
|
|
90
|
+
this.fills.set('asof', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ff800000' } });
|
|
91
|
+
this.fills.set('section', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffcccccc' } });
|
|
92
|
+
this.fills.set('white', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffffffff' } });
|
|
93
|
+
this.fills.set('dkgray', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ff999999' } });
|
|
94
|
+
this.fills.set('yellow', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffffff00' } });
|
|
95
|
+
this.fills.set('month', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ff009933' } });
|
|
96
|
+
this.fills.set('ltblue', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ff66ffff' } });
|
|
97
|
+
this.fills.set('ltbrown', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'fffcd5b4' } });
|
|
98
|
+
this.fills.set('gray', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffc0c0c0' } });
|
|
99
|
+
this.fills.set('ltgray', { type: 'pattern', pattern: 'solid', fgColor: { argb: 'ffbfbfbf' } });
|
|
100
|
+
// set borders
|
|
101
|
+
this.borders.set('blackthin', {
|
|
102
|
+
top: { style: 'thin', color: { argb: 'ff000000' } },
|
|
103
|
+
left: { style: 'thin', color: { argb: 'ff000000' } },
|
|
104
|
+
bottom: { style: 'thin', color: { argb: 'ff000000' } },
|
|
105
|
+
right: { style: 'thin', color: { argb: 'ff000000' } }
|
|
106
|
+
});
|
|
107
|
+
this.borders.set('up', {
|
|
108
|
+
top: { style: 'thick', color: { argb: 'ff000000' } },
|
|
109
|
+
left: { style: 'thin', color: { argb: 'ff000000' } },
|
|
110
|
+
bottom: undefined,
|
|
111
|
+
right: { style: 'thin', color: { argb: 'ff000000' } }
|
|
112
|
+
});
|
|
113
|
+
this.borders.set('dn', {
|
|
114
|
+
top: undefined,
|
|
115
|
+
left: { style: 'thin', color: { argb: 'ff000000' } },
|
|
116
|
+
bottom: { style: 'thick', color: { argb: 'ff000000' } },
|
|
117
|
+
right: { style: 'thin', color: { argb: 'ff000000' } }
|
|
118
|
+
});
|
|
119
|
+
this.borders.set('bottom', {
|
|
120
|
+
top: undefined,
|
|
121
|
+
left: undefined,
|
|
122
|
+
bottom: { style: 'thin', color: { argb: 'ff000000' } },
|
|
123
|
+
right: undefined
|
|
124
|
+
});
|
|
125
|
+
// set alignments
|
|
126
|
+
this.alignments.set('center', { horizontal: 'center', vertical: 'middle', wrapText: true });
|
|
127
|
+
this.alignments.set('leftctr', { horizontal: 'left', vertical: 'middle', wrapText: true });
|
|
128
|
+
// set number formats
|
|
129
|
+
this.numformats.set('num', '0.0;mm/dd/yyy;@');
|
|
130
|
+
this.numformats.set('int', '0;@');
|
|
131
|
+
this.numformats.set('bal', '0.0;[Red]-0.0;@');
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* This function will create the PTO/Holiday Section
|
|
135
|
+
* @param workbook The report object in which a sheet is created into.
|
|
136
|
+
* @param year the integer value for the year of the report
|
|
137
|
+
*/
|
|
138
|
+
createLeaveListing(workbook, year, showHolidays) {
|
|
139
|
+
const sheetLabel = `${year} PTO-Hol`;
|
|
140
|
+
const sheet = workbook.addWorksheet(sheetLabel, {
|
|
141
|
+
pageSetup: {
|
|
142
|
+
paperSize: undefined,
|
|
143
|
+
orientation: 'landscape',
|
|
144
|
+
fitToHeight: 1,
|
|
145
|
+
fitToWidth: 1,
|
|
146
|
+
blackAndWhite: false,
|
|
147
|
+
fitToPage: true,
|
|
148
|
+
showGridLines: false,
|
|
149
|
+
horizontalCentered: true,
|
|
150
|
+
verticalCentered: true
|
|
151
|
+
},
|
|
152
|
+
properties: {
|
|
153
|
+
defaultRowHeight: 20,
|
|
154
|
+
defaultColWidth: 4,
|
|
155
|
+
outlineLevelCol: 0
|
|
156
|
+
},
|
|
157
|
+
views: [{
|
|
158
|
+
state: 'frozen',
|
|
159
|
+
ySplit: 1
|
|
160
|
+
}]
|
|
161
|
+
});
|
|
162
|
+
let extendWidth = 3;
|
|
163
|
+
if (showHolidays) {
|
|
164
|
+
extendWidth += 4;
|
|
165
|
+
}
|
|
166
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
167
|
+
month: '2-digit',
|
|
168
|
+
day: '2-digit',
|
|
169
|
+
year: 'numeric'
|
|
170
|
+
});
|
|
171
|
+
const now = new Date();
|
|
172
|
+
// add current as of reference
|
|
173
|
+
let style = {
|
|
174
|
+
fill: this.fills.get('asof'),
|
|
175
|
+
font: this.fonts.get("white12"),
|
|
176
|
+
alignment: this.alignments.get("center"),
|
|
177
|
+
border: this.borders.get("blackthin")
|
|
178
|
+
};
|
|
179
|
+
this.setCell(sheet, this.getCellID(0, 1), this.getCellID(extendWidth, 1), style, formatter.format(now));
|
|
180
|
+
// set column widths
|
|
181
|
+
if (showHolidays) {
|
|
182
|
+
sheet.getColumn(1).width = 4.5;
|
|
183
|
+
sheet.getColumn(2).width = 13;
|
|
184
|
+
sheet.getColumn(3).width = 30;
|
|
185
|
+
sheet.getColumn(4).width = 13;
|
|
186
|
+
sheet.getColumn(5).width = 19;
|
|
187
|
+
sheet.getColumn(6).width = 19;
|
|
188
|
+
sheet.getColumn(7).width = 7;
|
|
189
|
+
sheet.getColumn(8).width = 7;
|
|
190
|
+
sheet.getColumn(9).width = 7;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
sheet.getColumn(1).width = 19;
|
|
194
|
+
sheet.getColumn(2).width = 19;
|
|
195
|
+
sheet.getColumn(3).width = 7;
|
|
196
|
+
sheet.getColumn(4).width = 7;
|
|
197
|
+
sheet.getColumn(5).width = 7;
|
|
198
|
+
}
|
|
199
|
+
let row = 2;
|
|
200
|
+
this.employees.forEach(emp => {
|
|
201
|
+
row = this.employeePTOHolidaySection(sheet, emp, row, year, showHolidays) + 1;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* This function will create the employee's Holidays and PTO report section
|
|
206
|
+
* @param sheet The worksheet object in which to add this employee's section
|
|
207
|
+
* @param emp The employee object used to determine the information about the section
|
|
208
|
+
* @param row The numeric value for the beginning of the section
|
|
209
|
+
* @param year The numeric value year the report is for.
|
|
210
|
+
* @param showHoliday A boolean value on whether to show the holidays for not.
|
|
211
|
+
* @returns the numeric value for the last row of this employee's section
|
|
212
|
+
*/
|
|
213
|
+
employeePTOHolidaySection(sheet, emp, row, year, showHoliday) {
|
|
214
|
+
let annual = 0.0;
|
|
215
|
+
let carry = 0.0;
|
|
216
|
+
emp.balances.forEach(bal => {
|
|
217
|
+
if (bal.year === year) {
|
|
218
|
+
annual = bal.annual;
|
|
219
|
+
carry = bal.carryover;
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
let extendedWidth = 5;
|
|
223
|
+
if (showHoliday) {
|
|
224
|
+
extendedWidth += 4;
|
|
225
|
+
}
|
|
226
|
+
const tdate = new Date(Date.UTC(year, 5, 1));
|
|
227
|
+
const std = emp.getStandardWorkday(tdate);
|
|
228
|
+
let style = {
|
|
229
|
+
fill: this.fills.get("ptoname"),
|
|
230
|
+
font: this.fonts.get("bold12"),
|
|
231
|
+
alignment: this.alignments.get("center"),
|
|
232
|
+
border: this.borders.get("blackthin")
|
|
233
|
+
};
|
|
234
|
+
this.setCell(sheet, this.getCellID(0, row), this.getCellID(extendedWidth - 1, row), style, emp.name.getLastFirst());
|
|
235
|
+
row++;
|
|
236
|
+
let col = 0;
|
|
237
|
+
style = {
|
|
238
|
+
fill: this.fills.get('section'),
|
|
239
|
+
font: this.fonts.get('bold10'),
|
|
240
|
+
alignment: this.alignments.get('center'),
|
|
241
|
+
border: this.borders.get('blackthin')
|
|
242
|
+
};
|
|
243
|
+
if (showHoliday) {
|
|
244
|
+
this.setCell(sheet, this.getCellID(0, row), this.getCellID(3, row), style, 'Holidays');
|
|
245
|
+
col = 4;
|
|
246
|
+
}
|
|
247
|
+
this.setCell(sheet, this.getCellID(col, row), this.getCellID(col + 4, row), style, 'Leaves');
|
|
248
|
+
// create holidays and leave months
|
|
249
|
+
const months = [];
|
|
250
|
+
for (let i = 0; i < 12; i++) {
|
|
251
|
+
const dtMonth = new Date(Date.UTC(year, i, 1));
|
|
252
|
+
months.push(new leaves_1.LeaveMonth(dtMonth, std, false));
|
|
253
|
+
}
|
|
254
|
+
months.sort((a, b) => a.compareTo(b));
|
|
255
|
+
const holidays = [];
|
|
256
|
+
this.holidays.forEach(hol => {
|
|
257
|
+
const dt = hol.getActual(year);
|
|
258
|
+
if (dt) {
|
|
259
|
+
holidays.push(new leaves_1.LeaveMonth(dt, std, false, hol));
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
holidays.push(new leaves_1.LeaveMonth(new Date(0), std, false, hol));
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
holidays.sort((a, b) => a.compareTo(b));
|
|
266
|
+
// add labels to the sections
|
|
267
|
+
row++;
|
|
268
|
+
col = 0;
|
|
269
|
+
style = {
|
|
270
|
+
fill: this.fills.get('section'),
|
|
271
|
+
font: this.fonts.get('bold8'),
|
|
272
|
+
alignment: this.alignments.get('center'),
|
|
273
|
+
border: this.borders.get('blackthin')
|
|
274
|
+
};
|
|
275
|
+
if (showHoliday) {
|
|
276
|
+
this.setCell(sheet, this.getCellID(0, row), this.getCellID(0, row), style, '');
|
|
277
|
+
this.setCell(sheet, this.getCellID(1, row), this.getCellID(1, row), style, 'Reference Date');
|
|
278
|
+
this.setCell(sheet, this.getCellID(2, row), this.getCellID(2, row), style, 'Hours');
|
|
279
|
+
const rcell = sheet.getCell(this.getCellID(3, row));
|
|
280
|
+
rcell.style = {
|
|
281
|
+
fill: this.fills.get('section'),
|
|
282
|
+
font: this.fonts.get('bold8'),
|
|
283
|
+
alignment: this.alignments.get('center'),
|
|
284
|
+
border: this.borders.get('blackthin')
|
|
285
|
+
};
|
|
286
|
+
rcell.value = { 'richText': [
|
|
287
|
+
{ 'font': { 'size': 8, 'bold': true, 'color': { 'argb': 'ff000000' } }, 'text': 'Date Taken (' },
|
|
288
|
+
{ 'font': { 'size': 8, 'bold': true, 'color': { 'argb': 'ff3366ff' } }, 'text': 'Projected' },
|
|
289
|
+
{ 'font': { 'size': 8, 'bold': true, 'color': { 'argb': 'ff000000' } }, 'text': ')' }
|
|
290
|
+
] };
|
|
291
|
+
col = 4;
|
|
292
|
+
}
|
|
293
|
+
sheet.mergeCells(this.getCellID(col, row), this.getCellID(col + 1, row));
|
|
294
|
+
let cell = sheet.getCell(this.getCellID(col, row));
|
|
295
|
+
cell.style = {
|
|
296
|
+
fill: this.fills.get('section'),
|
|
297
|
+
font: this.fonts.get('bold8'),
|
|
298
|
+
alignment: this.alignments.get('center'),
|
|
299
|
+
border: this.borders.get('blackthin')
|
|
300
|
+
};
|
|
301
|
+
cell.value = { 'richText': [
|
|
302
|
+
{ 'font': { 'size': 8, 'bold': true, 'color': { 'argb': 'ff000000' } }, 'text': 'Leave Taken (' },
|
|
303
|
+
{ 'font': { 'size': 8, 'bold': true, 'color': { 'argb': 'ff3366ff' } }, 'text': 'Projected' },
|
|
304
|
+
{ 'font': { 'size': 8, 'bold': true, 'color': { 'argb': 'ff000000' } }, 'text': ')' }
|
|
305
|
+
] };
|
|
306
|
+
style = {
|
|
307
|
+
fill: this.fills.get('section'),
|
|
308
|
+
font: this.fonts.get('bold8'),
|
|
309
|
+
alignment: this.alignments.get('center'),
|
|
310
|
+
border: this.borders.get('blackthin')
|
|
311
|
+
};
|
|
312
|
+
this.setCell(sheet, this.getCellID(col + 2, row), this.getCellID(col + 2, row), style, "Taken");
|
|
313
|
+
style.font = this.fonts.get('blue8');
|
|
314
|
+
this.setCell(sheet, this.getCellID(col + 3, row), this.getCellID(col + 3, row), style, "Request");
|
|
315
|
+
row++;
|
|
316
|
+
const startAsgmt = emp.assignments[0];
|
|
317
|
+
const endAsgmt = emp.assignments[emp.assignments.length - 1];
|
|
318
|
+
// ensure months are clear, plus check if the month should be disabled.
|
|
319
|
+
months.forEach((month, m) => {
|
|
320
|
+
const startMonth = new Date(Date.UTC(month.month.getUTCFullYear(), month.month.getUTCMonth() + 1, 1));
|
|
321
|
+
month.periods = [];
|
|
322
|
+
month.disabled = (startAsgmt.startDate.getTime() > startMonth.getTime()
|
|
323
|
+
|| endAsgmt.endDate.getTime() < month.month.getTime());
|
|
324
|
+
months[m] = month;
|
|
325
|
+
});
|
|
326
|
+
// ensure the holidays are clear, plus check if the holiday should be disabled.
|
|
327
|
+
// Only holidays with id of "H" can be disabled, floating holidays aren't.
|
|
328
|
+
holidays.forEach((hol, h) => {
|
|
329
|
+
hol.periods = [];
|
|
330
|
+
if (hol.holiday && hol.holiday.id.toLowerCase().substring(0, 1) === 'h') {
|
|
331
|
+
hol.disabled = (startAsgmt.startDate.getTime() > hol.month.getTime()
|
|
332
|
+
|| endAsgmt.endDate.getTime() < hol.month.getTime());
|
|
333
|
+
}
|
|
334
|
+
holidays[h] = hol;
|
|
335
|
+
});
|
|
336
|
+
// sort the employee's leaves, then put the ones for the selected year into arrays
|
|
337
|
+
// for further use.
|
|
338
|
+
emp.leaves.sort((a, b) => a.compareTo(b));
|
|
339
|
+
const empHolidays = [];
|
|
340
|
+
const empOtherLeaves = [];
|
|
341
|
+
emp.leaves.forEach(lv => {
|
|
342
|
+
if (lv.leavedate.getUTCFullYear() === year) {
|
|
343
|
+
if (lv.code.toLowerCase() === 'h') {
|
|
344
|
+
empHolidays.push(new employees_1.Leave(lv));
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
empOtherLeaves.push(new employees_1.Leave(lv));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
// next process the employee's holidays into the holidays array
|
|
352
|
+
// 1. Go through the leaves and place the tagged holidays into the holiday list
|
|
353
|
+
empHolidays.forEach((empHol, eh) => {
|
|
354
|
+
if (empHol.tagday && empHol.tagday !== '') {
|
|
355
|
+
const code = empHol.tagday.substring(0, 1);
|
|
356
|
+
const num = Number(empHol.tagday.substring(1));
|
|
357
|
+
holidays.forEach((hol, h) => {
|
|
358
|
+
if (hol.holiday && hol.holiday.id.toLowerCase() === code
|
|
359
|
+
&& hol.holiday.sort === num && !empHol.used) {
|
|
360
|
+
hol.addLeave(empHol);
|
|
361
|
+
empHol.used = true;
|
|
362
|
+
holidays[h] = hol;
|
|
363
|
+
empHolidays[eh] = empHol;
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
// 2. For those not tagged, actuals are listed first.
|
|
369
|
+
empHolidays.forEach((empHol, eh) => {
|
|
370
|
+
if (!empHol.used && empHol.status.toLowerCase() === 'actual') {
|
|
371
|
+
holidays.forEach((hol, h) => {
|
|
372
|
+
if (!empHol.used && hol.holiday && hol.holiday.id.toLowerCase() === 'h'
|
|
373
|
+
&& !hol.disabled && hol.getHours() + empHol.hours <= 8.0) {
|
|
374
|
+
hol.addLeave(empHol);
|
|
375
|
+
empHol.used = true;
|
|
376
|
+
holidays[h] = hol;
|
|
377
|
+
empHolidays[eh] = empHol;
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
// 3. Next check for those holidays that match the actual date
|
|
383
|
+
empHolidays.forEach((empHol, eh) => {
|
|
384
|
+
if (!empHol.used) {
|
|
385
|
+
holidays.forEach((hol, h) => {
|
|
386
|
+
if (!empHol.used && hol.holiday && hol.holiday.id.toLowerCase() === 'h'
|
|
387
|
+
&& hol.month.getTime() === empHol.leavedate.getTime()
|
|
388
|
+
&& !hol.disabled && hol.getHours() + empHol.hours <= 8.0) {
|
|
389
|
+
hol.addLeave(empHol);
|
|
390
|
+
empHol.used = true;
|
|
391
|
+
holidays[h] = hol;
|
|
392
|
+
empHolidays[eh] = empHol;
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
// 4. next, with any holidays not already used
|
|
398
|
+
empHolidays.forEach((empHol, eh) => {
|
|
399
|
+
if (!empHol.used) {
|
|
400
|
+
let found = false;
|
|
401
|
+
holidays.forEach((hol, h) => {
|
|
402
|
+
if (!found && !hol.disabled) {
|
|
403
|
+
if (hol.getHours() + empHol.hours <= 8.0) {
|
|
404
|
+
hol.addLeave(empHol);
|
|
405
|
+
holidays[h] = hol;
|
|
406
|
+
found = true;
|
|
407
|
+
empHol.used = true;
|
|
408
|
+
empHolidays[eh] = empHol;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
// 5. if there are any unused holidays, plug them into disabled holidays.
|
|
415
|
+
empHolidays.forEach((empHol, eh) => {
|
|
416
|
+
if (!empHol.used) {
|
|
417
|
+
let found = false;
|
|
418
|
+
holidays.forEach((hol, h) => {
|
|
419
|
+
if (!found && hol.disabled) {
|
|
420
|
+
found = true;
|
|
421
|
+
hol.addLeave(empHol);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
// next, place the non-holiday leaves into the months they are using in.
|
|
427
|
+
empOtherLeaves.sort((a, b) => a.compareTo(b));
|
|
428
|
+
empOtherLeaves.forEach(lv => {
|
|
429
|
+
months.forEach((month, m) => {
|
|
430
|
+
if (month.month.getUTCFullYear() === lv.leavedate.getUTCFullYear()
|
|
431
|
+
&& month.month.getUTCMonth() === lv.leavedate.getUTCMonth()) {
|
|
432
|
+
month.addLeave(lv);
|
|
433
|
+
months[m] = month;
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
// now insert the holidays for companies that have holidays designated.
|
|
438
|
+
const now = new Date();
|
|
439
|
+
col = 0;
|
|
440
|
+
if (showHoliday) {
|
|
441
|
+
holidays.sort((a, b) => a.compareTo(b));
|
|
442
|
+
holidays.forEach((hol, h) => {
|
|
443
|
+
hol.periods.sort((a, b) => a.compareTo(b));
|
|
444
|
+
const holRow = row + h;
|
|
445
|
+
style = {
|
|
446
|
+
fill: this.fills.get('white'),
|
|
447
|
+
font: this.fonts.get('bold10'),
|
|
448
|
+
alignment: this.alignments.get('center'),
|
|
449
|
+
border: this.borders.get('blackthin'),
|
|
450
|
+
numFmt: this.numformats.get('num')
|
|
451
|
+
};
|
|
452
|
+
if (hol.disabled) {
|
|
453
|
+
style.fill = this.fills.get('dkgray');
|
|
454
|
+
style.font = this.fonts.get('nobold10');
|
|
455
|
+
}
|
|
456
|
+
else if (hol.holiday && hol.holiday.getActual(year)
|
|
457
|
+
&& hol.holiday.getActual(year).getTime() > now.getTime()) {
|
|
458
|
+
style.fill = this.fills.get('white');
|
|
459
|
+
style.font = this.fonts.get('nobold10');
|
|
460
|
+
}
|
|
461
|
+
this.setCell(sheet, this.getCellID(col, holRow), this.getCellID(col, holRow), style, hol.holiday.toString());
|
|
462
|
+
if (hol.holiday.getActual(year)) {
|
|
463
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
464
|
+
month: 'short',
|
|
465
|
+
day: '2-digit'
|
|
466
|
+
});
|
|
467
|
+
this.setCell(sheet, this.getCellID(col + 1, holRow), this.getCellID(col + 1, holRow), style, formatter.format(hol.holiday.getActual(year)));
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
this.setCell(sheet, this.getCellID(col + 1, holRow), this.getCellID(col + 1, holRow), style, '');
|
|
471
|
+
}
|
|
472
|
+
const cellText = [];
|
|
473
|
+
hol.periods.forEach((prd, p) => {
|
|
474
|
+
prd.leaves.forEach((lv, l) => {
|
|
475
|
+
if (p > 0 || l > 0) {
|
|
476
|
+
cellText.push({ 'font': { 'size': 10, 'bold': true,
|
|
477
|
+
'color': { 'argb': 'ff000000' } }, 'text': ',' });
|
|
478
|
+
}
|
|
479
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
480
|
+
day: '2-digit',
|
|
481
|
+
month: 'short'
|
|
482
|
+
});
|
|
483
|
+
if (lv.status.toLowerCase() === 'actual') {
|
|
484
|
+
cellText.push({ 'font': { 'size': 10, 'bold': true,
|
|
485
|
+
'color': { 'argb': 'ff000000' } }, 'text': formatter.format(lv.leavedate) });
|
|
486
|
+
if (lv.hours < 8) {
|
|
487
|
+
cellText.push({ 'font': { 'size': 7, 'bold': true, 'vertAlign': 'superscript',
|
|
488
|
+
'color': { 'argb': 'ff000000' } }, 'text': `(${lv.hours.toFixed(1)})` });
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
cellText.push({ 'font': { 'size': 10, 'bold': true,
|
|
493
|
+
'color': { 'argb': 'ff3366ff' } }, 'text': formatter.format(lv.leavedate) });
|
|
494
|
+
if (lv.hours < 8) {
|
|
495
|
+
cellText.push({ 'font': { 'size': 7, 'bold': true, 'vertAlign': 'superscript',
|
|
496
|
+
'color': { 'argb': 'ff3366ff' } }, 'text': `(${lv.hours.toFixed(1)})` });
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
});
|
|
501
|
+
this.setCell(sheet, this.getCellID(col + 2, holRow), this.getCellID(col + 2, holRow), {
|
|
502
|
+
fill: this.fills.get('white'),
|
|
503
|
+
alignment: this.alignments.get('center'),
|
|
504
|
+
border: this.borders.get('blackthin')
|
|
505
|
+
}, cellText);
|
|
506
|
+
this.setCell(sheet, this.getCellID(col + 3, holRow), this.getCellID(col + 3, holRow), style, hol.getHours());
|
|
507
|
+
});
|
|
508
|
+
col = 4;
|
|
509
|
+
}
|
|
510
|
+
months.sort((a, b) => a.compareTo(b));
|
|
511
|
+
months.forEach((month, m) => {
|
|
512
|
+
const lvRow = row + m;
|
|
513
|
+
style = {
|
|
514
|
+
fill: this.fills.get('white'),
|
|
515
|
+
font: this.fonts.get('nobold10'),
|
|
516
|
+
alignment: this.alignments.get('leftctr'),
|
|
517
|
+
border: this.borders.get('blackthin'),
|
|
518
|
+
numFmt: this.numformats.get('num')
|
|
519
|
+
};
|
|
520
|
+
if (month.disabled) {
|
|
521
|
+
style = {
|
|
522
|
+
fill: this.fills.get('dkgray'),
|
|
523
|
+
font: this.fonts.get('nobold10'),
|
|
524
|
+
alignment: this.alignments.get('leftctr'),
|
|
525
|
+
border: this.borders.get('blackthin')
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
const cellText = [];
|
|
529
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
530
|
+
month: 'short'
|
|
531
|
+
});
|
|
532
|
+
cellText.push({ 'font': { 'size': 10, 'bold': true,
|
|
533
|
+
'color': { 'argb': 'ffff0000' } }, 'text': `${formatter.format(month.month)}: ` });
|
|
534
|
+
month.periods.forEach((prd, p) => {
|
|
535
|
+
if (p > 0) {
|
|
536
|
+
cellText.push({ 'font': { 'size': 10, 'bold': true,
|
|
537
|
+
'color': { 'argb': 'ff000000' } }, 'text': ',' });
|
|
538
|
+
}
|
|
539
|
+
let text = '';
|
|
540
|
+
let bHours = false;
|
|
541
|
+
if (prd.start.getTime() !== prd.end.getTime()) {
|
|
542
|
+
text = `${prd.start.getDate()}-${prd.end.getDate()}`;
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
text = `${prd.start.getDate()}`;
|
|
546
|
+
if (prd.getHours() < std) {
|
|
547
|
+
bHours = true;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
let color = 'ff';
|
|
551
|
+
if (prd.code.toLowerCase() === 'v' && prd.status.toLowerCase() === 'actual') {
|
|
552
|
+
color += '000000';
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
const wc = this.workcodes.get(prd.code);
|
|
556
|
+
if (wc) {
|
|
557
|
+
color += wc.backcolor;
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
color += '000000';
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
cellText.push({ 'font': { 'size': 10, 'bold': true, 'color': { 'argb': color } },
|
|
564
|
+
'text': text });
|
|
565
|
+
if (bHours) {
|
|
566
|
+
cellText.push({ 'font': { 'size': 7, 'bold': true, 'vertAlign': 'superscript',
|
|
567
|
+
'color': { 'argb': color } }, 'text': `(${prd.getHours().toFixed(1)})` });
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
this.setCell(sheet, this.getCellID(col, lvRow), this.getCellID(col + 1, lvRow), style, cellText);
|
|
571
|
+
style = {
|
|
572
|
+
fill: this.fills.get('white'),
|
|
573
|
+
font: this.fonts.get('nobold10'),
|
|
574
|
+
alignment: this.alignments.get('center'),
|
|
575
|
+
border: this.borders.get('blackthin'),
|
|
576
|
+
numFmt: this.numformats.get('num')
|
|
577
|
+
};
|
|
578
|
+
if (month.disabled) {
|
|
579
|
+
style.fill = this.fills.get('dkgray');
|
|
580
|
+
}
|
|
581
|
+
this.setCell(sheet, this.getCellID(col + 2, lvRow), this.getCellID(col + 2, lvRow), style, month.getHours('v', true));
|
|
582
|
+
style.font = this.fonts.get('noblue10');
|
|
583
|
+
this.setCell(sheet, this.getCellID(col + 3, lvRow), this.getCellID(col + 3, lvRow), style, month.getHours('v', false));
|
|
584
|
+
});
|
|
585
|
+
// now add the totals section to the employee's chart
|
|
586
|
+
if (months.length > holidays.length) {
|
|
587
|
+
row += months.length;
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
row += holidays.length;
|
|
591
|
+
}
|
|
592
|
+
style = {
|
|
593
|
+
fill: this.fills.get('section'),
|
|
594
|
+
font: this.fonts.get('bold8'),
|
|
595
|
+
alignment: this.alignments.get('center'),
|
|
596
|
+
border: this.borders.get('blackthin')
|
|
597
|
+
};
|
|
598
|
+
col = 0;
|
|
599
|
+
if (showHoliday) {
|
|
600
|
+
this.setCell(sheet, this.getCellID(col, row), this.getCellID(col, row), style, '');
|
|
601
|
+
this.setCell(sheet, this.getCellID(col + 1, row), this.getCellID(col + 1, row), style, 'Days Left');
|
|
602
|
+
this.setCell(sheet, this.getCellID(col + 2, row), this.getCellID(col + 2, row), style, 'Hours Left');
|
|
603
|
+
this.setCell(sheet, this.getCellID(col + 3, row), this.getCellID(col + 3, row), style, 'Total Hours');
|
|
604
|
+
let daysLeft = 0;
|
|
605
|
+
let hoursTaken = 0;
|
|
606
|
+
holidays.forEach(hol => {
|
|
607
|
+
if (hol.getHours() < 8 && !hol.disabled) {
|
|
608
|
+
daysLeft++;
|
|
609
|
+
}
|
|
610
|
+
if (hol.getHours() > 0) {
|
|
611
|
+
hoursTaken += hol.getHours();
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
const hoursLeft = (holidays.length * 8.0) - hoursTaken;
|
|
615
|
+
style = {
|
|
616
|
+
fill: this.fills.get('white'),
|
|
617
|
+
font: this.fonts.get('bold10'),
|
|
618
|
+
alignment: this.alignments.get('center'),
|
|
619
|
+
border: this.borders.get('blackthin'),
|
|
620
|
+
numFmt: this.numformats.get('int')
|
|
621
|
+
};
|
|
622
|
+
this.setCell(sheet, this.getCellID(col, row + 1), this.getCellID(col, row + 1), style, '');
|
|
623
|
+
this.setCell(sheet, this.getCellID(col + 1, row + 1), this.getCellID(col + 1, row + 1), style, daysLeft);
|
|
624
|
+
this.setCell(sheet, this.getCellID(col + 2, row + 1), this.getCellID(col + 2, row + 1), style, hoursLeft);
|
|
625
|
+
this.setCell(sheet, this.getCellID(col + 3, row + 1), this.getCellID(col + 3, row + 1), style, hoursTaken);
|
|
626
|
+
col = 4;
|
|
627
|
+
}
|
|
628
|
+
style = {
|
|
629
|
+
fill: this.fills.get('section'),
|
|
630
|
+
font: this.fonts.get('bold8'),
|
|
631
|
+
alignment: this.alignments.get('center'),
|
|
632
|
+
border: this.borders.get('blackthin')
|
|
633
|
+
};
|
|
634
|
+
this.setCell(sheet, this.getCellID(col, row), this.getCellID(col, row), style, 'Annual Leave');
|
|
635
|
+
this.setCell(sheet, this.getCellID(col + 1, row), this.getCellID(col + 1, row), style, 'Carry');
|
|
636
|
+
this.setCell(sheet, this.getCellID(col + 2, row), this.getCellID(col + 2, row), style, 'Total Taken');
|
|
637
|
+
this.setCell(sheet, this.getCellID(col + 3, row), this.getCellID(col + 3, row), style, 'Request');
|
|
638
|
+
this.setCell(sheet, this.getCellID(col + 4, row), this.getCellID(col + 4, row), style, 'Balance');
|
|
639
|
+
let totalTaken = 0;
|
|
640
|
+
let totalRequested = 0;
|
|
641
|
+
months.forEach(month => {
|
|
642
|
+
totalRequested += month.getHours('v', false);
|
|
643
|
+
totalTaken += month.getHours('v', true);
|
|
644
|
+
});
|
|
645
|
+
const balance = (annual + carry) - (totalTaken + totalRequested);
|
|
646
|
+
style = {
|
|
647
|
+
fill: this.fills.get('white'),
|
|
648
|
+
font: this.fonts.get('bold10'),
|
|
649
|
+
alignment: this.alignments.get('center'),
|
|
650
|
+
border: this.borders.get('blackthin'),
|
|
651
|
+
numFmt: this.numformats.get('num')
|
|
652
|
+
};
|
|
653
|
+
this.setCell(sheet, this.getCellID(col, row + 1), this.getCellID(col, row + 1), style, annual);
|
|
654
|
+
this.setCell(sheet, this.getCellID(col + 1, row + 1), this.getCellID(col + 1, row + 1), style, carry);
|
|
655
|
+
this.setCell(sheet, this.getCellID(col + 2, row + 1), this.getCellID(col + 2, row + 1), style, totalTaken);
|
|
656
|
+
style.font = this.fonts.get('noblue10');
|
|
657
|
+
this.setCell(sheet, this.getCellID(col + 3, row + 1), this.getCellID(col + 3, row + 1), style, totalRequested);
|
|
658
|
+
style.fill = this.fills.get('yellow');
|
|
659
|
+
style.font = this.fonts.get('nobold10');
|
|
660
|
+
style.numFmt = this.numformats.get('bal');
|
|
661
|
+
this.setCell(sheet, this.getCellID(col + 4, row + 1), this.getCellID(col + 4, row + 1), style, balance);
|
|
662
|
+
return row + 2;
|
|
663
|
+
}
|
|
664
|
+
createMonthlyListing(workbook, year, bAll) {
|
|
665
|
+
let sheetLabel = `${year} Monthly`;
|
|
666
|
+
if (!bAll) {
|
|
667
|
+
sheetLabel += ' (Minimum)';
|
|
668
|
+
}
|
|
669
|
+
const sheet = workbook.addWorksheet(sheetLabel, {
|
|
670
|
+
pageSetup: {
|
|
671
|
+
paperSize: undefined,
|
|
672
|
+
orientation: 'landscape',
|
|
673
|
+
fitToHeight: 1,
|
|
674
|
+
fitToWidth: 1,
|
|
675
|
+
blackAndWhite: false,
|
|
676
|
+
fitToPage: true,
|
|
677
|
+
showGridLines: false,
|
|
678
|
+
horizontalCentered: true,
|
|
679
|
+
verticalCentered: true
|
|
680
|
+
},
|
|
681
|
+
properties: {
|
|
682
|
+
defaultRowHeight: 20,
|
|
683
|
+
defaultColWidth: 4,
|
|
684
|
+
outlineLevelCol: 0
|
|
685
|
+
},
|
|
686
|
+
views: [{
|
|
687
|
+
state: 'frozen',
|
|
688
|
+
ySplit: 4
|
|
689
|
+
}]
|
|
690
|
+
});
|
|
691
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
692
|
+
month: '2-digit',
|
|
693
|
+
day: '2-digit',
|
|
694
|
+
year: 'numeric'
|
|
695
|
+
});
|
|
696
|
+
const now = new Date();
|
|
697
|
+
// add current as of reference
|
|
698
|
+
let style = {
|
|
699
|
+
fill: this.fills.get('asof'),
|
|
700
|
+
font: this.fonts.get("white12"),
|
|
701
|
+
alignment: this.alignments.get("center"),
|
|
702
|
+
border: this.borders.get("blackthin")
|
|
703
|
+
};
|
|
704
|
+
this.setCell(sheet, this.getCellID(0, 1), this.getCellID(3, 1), style, formatter.format(now));
|
|
705
|
+
let text = `${year} PTO/HOL Quick Reference (${(bAll) ? 'FULL' : 'MINIMUM'})`;
|
|
706
|
+
style = {
|
|
707
|
+
fill: this.fills.get('white'),
|
|
708
|
+
font: this.fonts.get('bold14'),
|
|
709
|
+
alignment: this.alignments.get('center'),
|
|
710
|
+
border: undefined
|
|
711
|
+
};
|
|
712
|
+
this.setCell(sheet, this.getCellID(4, 1), this.getCellID(33, 1), style, text);
|
|
713
|
+
// set column widths
|
|
714
|
+
sheet.getColumn(1).width = 2;
|
|
715
|
+
sheet.getColumn(2).width = 20;
|
|
716
|
+
for (let c = 3; c <= 33; c++) {
|
|
717
|
+
sheet.getColumn(c).width = 4;
|
|
718
|
+
}
|
|
719
|
+
for (let c = 34; c <= 36; c++) {
|
|
720
|
+
sheet.getColumn(c).width = 7;
|
|
721
|
+
}
|
|
722
|
+
// add leave legend codes
|
|
723
|
+
let col = 2;
|
|
724
|
+
let row = 2;
|
|
725
|
+
this.workcodes.forEach(wc => {
|
|
726
|
+
if (wc.isLeave) {
|
|
727
|
+
if (col + 6 > 33) {
|
|
728
|
+
col = 2;
|
|
729
|
+
row++;
|
|
730
|
+
}
|
|
731
|
+
style = {
|
|
732
|
+
fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: `ff${wc.backcolor}` } },
|
|
733
|
+
font: { bold: true, size: 10, color: { argb: `ff${wc.textcolor}` } },
|
|
734
|
+
alignment: this.alignments.get('center'),
|
|
735
|
+
border: this.borders.get('blackthin')
|
|
736
|
+
};
|
|
737
|
+
this.setCell(sheet, this.getCellID(col, row), this.getCellID(col, row), style, '');
|
|
738
|
+
style = {
|
|
739
|
+
fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: `ffffffff` } },
|
|
740
|
+
font: { bold: true, size: 10, color: { argb: `ff000000` } },
|
|
741
|
+
alignment: this.alignments.get('center'),
|
|
742
|
+
border: {
|
|
743
|
+
top: undefined,
|
|
744
|
+
left: undefined,
|
|
745
|
+
bottom: { style: 'thin', color: { argb: 'ff000000' } },
|
|
746
|
+
right: undefined
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
this.setCell(sheet, this.getCellID(col + 1, row), this.getCellID(col + 5, row), style, wc.title);
|
|
750
|
+
col += 6;
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
exports.LeaveReport = LeaveReport;
|