166 lines
6.1 KiB
JavaScript
166 lines
6.1 KiB
JavaScript
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}`;
|
|
}
|
|
};
|