scheduler-node-models 1.0.133 → 1.0.135

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