const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('createAbsence', { description: 'Creates a new worker absence', accepts: [{ arg: 'id', type: 'number', description: 'The worker id', http: {source: 'path'} }, { arg: 'businessFk', type: 'number', required: true }, { arg: 'absenceTypeId', type: 'number', required: true }, { arg: 'dated', type: 'date', required: true }], returns: { type: 'Object', root: true }, http: { path: `/:id/createAbsence`, verb: 'POST' } }); Self.createAbsence = async(ctx, id, options) => { const models = Self.app.models; const $t = ctx.req.__; // $translate const args = ctx.args; const userId = ctx.req.accessToken.userId; let tx; const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); if (!myOptions.transaction) { tx = await Self.beginTransaction({}); myOptions.transaction = tx; } try { const isSubordinate = await models.Worker.isSubordinate(ctx, id, myOptions); const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE'); if (!isSubordinate || (isSubordinate && userId == id && !isTeamBoss)) throw new UserError(`You don't have enough privileges`); const canCreateAbsenceInPast = await models.ACL.checkAccessAcl(ctx, 'Worker', 'canCreateAbsenceInPast', 'WRITE'); const now = Date.vnNew(); const newDate = new Date(args.dated).getTime(); if ((now.getTime() > newDate) && !canCreateAbsenceInPast) throw new UserError(`Holidays to past days not available`); const labour = await models.WorkerLabour.findById(args.businessFk, {fields: ['started', 'ended', 'businessFk']}, myOptions); if (args.dated < labour.started || (labour.ended != null && args.dated > labour.ended)) throw new UserError(`The contract was not active during the selected date`); const [hasHoursRecorded] = await Self.rawSql(`SELECT * FROM vn.workerTimeControl WHERE userFk = ? AND timed BETWEEN DATE(?) AND CONCAT(DATE(?), ' 23:59:59') LIMIT 1;`, [id, args.dated, args.dated]); const absenceType = await models.AbsenceType.findById(args.absenceTypeId, null, myOptions); const isNotHalfAbsence = absenceType.code != 'halfHoliday' && absenceType.code != 'halfPaidLeave' && absenceType.code != 'halfFurlough'; if (hasHoursRecorded && isNotHalfAbsence) throw new UserError(`The worker has hours recorded that day`); const date = Date.vnNew(); date.setHours(0, 0, 0, 0); const [result] = await Self.rawSql( `SELECT COUNT(*) halfHolidayCounter FROM vn.calendar c JOIN vn.business b ON b.id = c.businessFk JOIN vn.absenceType at ON at.id = c.dayOffTypeFk WHERE at.code = 'halfHoliday' AND b.workerFk = ? AND c.dated BETWEEN util.firstDayOfYear(?) AND LAST_DAY(DATE_ADD(?, INTERVAL 12 - MONTH(?) MONTH))`, [id, date, now, now]); const hasHalfHoliday = result.halfHolidayCounter > 0; const isHalfHoliday = absenceType.code === 'halfHoliday'; if (isHalfHoliday && hasHalfHoliday) throw new UserError(`Cannot add more than one '1/2 day vacation'`); const isFestive = absenceType.isFestiveEligible; const workCenter = await models.Business.findOne({ where: {id: args.businessFk} },); const [holiday] = await models.CalendarHoliday.find({ where: { dated: args.dated, workCenterFk: workCenter.workCenterFk } }); if ((holiday && isFestive) && (workCenter.workcenterFk === holiday.workCenterFk)) throw new UserError(`Cannot add holidays on this day`); const absence = await models.Calendar.create({ businessFk: labour.businessFk, dayOffTypeFk: args.absenceTypeId, dated: args.dated }, myOptions); const account = await models.VnUser.findById(userId, null, myOptions); const subordinated = await models.VnUser.findById(id, null, myOptions); const worker = await models.Worker.findById(subordinated.id, null, myOptions); const departmentBoss = await models.VnUser.findById(worker.bossFk, null, myOptions); const url = await Self.app.models.Url.getUrl(); const body = $t('Created absence', { author: account.nickname, employee: subordinated.nickname, absenceType: absenceType.name, dated: formatDate(args.dated), workerUrl: `${url}worker/${id}/calendar` }); await models.Mail.create({ subject: $t('Absence change notification on the labour calendar'), body: body, receiver: departmentBoss.email }, myOptions); if (tx) await tx.commit(); return absence; } catch (e) { if (tx) await tx.rollback(); throw e; } }; function formatDate(date) { let day = date.getDate(); if (day < 10) day = `0${day}`; let month = date.getMonth() + 1; if (month < 10) month = `0${month}`; let year = date.getFullYear(); return `${day}-${month}-${year}`; } };