salix/modules/worker/back/methods/worker-time-control/sendMail.js

416 lines
18 KiB
JavaScript

const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethodCtx('sendMail', {
description: `Send an email with the hours booked to the employees who telecommuting.
It also inserts booked hours in cases where the employee is telecommuting`,
accessType: 'WRITE',
accepts: [{
arg: 'workerId',
type: 'number',
description: 'The worker id'
},
{
arg: 'week',
type: 'number'
},
{
arg: 'year',
type: 'number'
}],
returns: [{
type: 'Object',
root: true
}],
http: {
path: `/sendMail`,
verb: 'POST'
}
});
Self.sendMail = async(ctx, options) => {
const models = Self.app.models;
const conn = Self.dataSource.connector;
const args = ctx.args;
let tx;
const myOptions = {userId: ctx.req.accessToken.userId};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmts = [];
let stmt;
if (!args.week || !args.year) {
const from = Date.vnNew();
const to = Date.vnNew();
const time = await models.Time.findOne({
where: {
dated: {between: [from.setDate(from.getDate() - 10), to.setDate(to.getDate() - 4)]}
},
order: 'week ASC'
}, myOptions);
args.week = time.week;
args.year = time.year;
}
const started = getStartDateOfWeekNumber(args.week, args.year);
started.setHours(0, 0, 0, 0);
const ended = new Date(started);
ended.setDate(started.getDate() + 6);
ended.setHours(23, 59, 59, 999);
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.timeControlCalculate');
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.timeBusinessCalculate');
if (args.workerId) {
await models.WorkerTimeControl.destroyAll({
userFk: args.workerId,
timed: {between: [started, ended]},
isSendMail: true
}, myOptions);
const where = {
workerFk: args.workerId,
year: args.year,
week: args.week
};
await models.WorkerTimeControlMail.updateAll(where, {
updated: Date.vnNew(), state: 'SENDED'
}, myOptions);
stmt = new ParameterizedSQL('DROP TEMPORARY TABLE IF EXISTS tmp.`user`');
stmts.push(stmt);
stmt = new ParameterizedSQL('CREATE TEMPORARY TABLE tmp.`user` SELECT id userFk FROM account.user WHERE id = ?', [args.workerId]);
stmts.push(stmt);
} else {
await models.WorkerTimeControl.destroyAll({
timed: {between: [started, ended]},
isSendMail: true
}, myOptions);
const where = {
year: args.year,
week: args.week
};
await models.WorkerTimeControlMail.updateAll(where, {
updated: Date.vnNew(), state: 'SENDED'
}, myOptions);
stmt = new ParameterizedSQL('DROP TEMPORARY TABLE IF EXISTS tmp.`user`');
stmts.push(stmt);
stmt = new ParameterizedSQL('CREATE TEMPORARY TABLE IF NOT EXISTS tmp.`user` SELECT id as userFk FROM vn.worker w JOIN account.`user` u ON u.id = w.id WHERE id IS NOT NULL');
stmts.push(stmt);
}
stmt = new ParameterizedSQL(
`CALL vn.timeControl_calculate(?, ?)
`, [started, ended]);
stmts.push(stmt);
stmt = new ParameterizedSQL(
`CALL vn.timeBusiness_calculate(?, ?)
`, [started, ended]);
stmts.push(stmt);
stmt = new ParameterizedSQL(
`CALL vn.timeControl_getError(?, ?)
`, [started, ended]);
stmts.push(stmt);
stmt = new ParameterizedSQL(`
INSERT INTO mail (receiver, subject, body)
SELECT CONCAT(u.name, '@verdnatura.es'),
CONCAT('Error registro de horas semana ', ?, ' año ', ?) ,
CONCAT('No se ha podido enviar el registro de horas al empleado/s: ',
GROUP_CONCAT(DISTINCT CONCAT('<br>', w.id, ' ', w.firstName, ' ', w.lastName)))
FROM tmp.timeControlError tce
JOIN vn.workerTimeControl wtc ON wtc.id = tce.id
JOIN worker w ON w.id = wtc.userFK
JOIN account.user u ON u.id = w.bossFk
GROUP BY w.bossFk
`, [args.week, args.year]);
stmts.push(stmt);
stmt = new ParameterizedSQL(`
SELECT CONCAT(u.name, '@verdnatura.es') receiver,
u.id workerFk,
tb.dated,
tb.timeWorkDecimal,
tb.timeWorkSexagesimal timeWorkSexagesimal,
tb.timeTable,
tc.timeWorkDecimal timeWorkedDecimal,
tc.timeWorkSexagesimal timeWorkedSexagesimal,
tb.type,
tb.businessFk,
tb.permissionRate,
d.isTeleworking
FROM tmp.timeBusinessCalculate tb
JOIN account.user u ON u.id = tb.userFk
JOIN department d ON d.id = tb.departmentFk
JOIN business b ON b.id = tb.businessFk
LEFT JOIN tmp.timeControlCalculate tc ON tc.userFk = tb.userFk AND tc.dated = tb.dated
LEFT JOIN worker w ON w.id = u.id
LEFT JOIN (
SELECT DISTINCT wtc.userFk
FROM tmp.timeControlError tce
JOIN vn.workerTimeControl wtc ON wtc.id = tce.id
)sub ON sub.userFk = tb.userFk
WHERE sub.userFK IS NULL
AND IFNULL(?, u.id) = u.id
AND b.companyCodeFk = 'VNL'
AND w.businessFk
AND d.isTeleworking
ORDER BY u.id, tb.dated
`, [args.workerId]);
const index = stmts.push(stmt) - 1;
stmts.push('DROP TEMPORARY TABLE tmp.timeControlCalculate');
stmts.push('DROP TEMPORARY TABLE tmp.timeBusinessCalculate');
const sql = ParameterizedSQL.join(stmts, ';');
const days = await conn.executeStmt(sql, myOptions);
let previousWorkerFk = days[index][0].workerFk;
let previousReceiver = days[index][0].receiver;
const workerTimeControlConfig = await models.WorkerTimeControlConfig.findOne(null, myOptions);
for (let day of days[index]) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
try {
workerFk = day.workerFk;
if (day.timeWorkDecimal > 0 && day.timeWorkedDecimal == null
&& (day.permissionRate == null ? true : day.permissionRate)) {
if (day.timeTable == null) {
const timed = new Date(day.dated);
await models.WorkerTimeControl.create({
userFk: day.workerFk,
timed: timed.setHours(workerTimeControlConfig.teleworkingStart / 3600),
manual: true,
direction: 'in',
isSendMail: true
}, myOptions);
if (day.timeWorkDecimal >= workerTimeControlConfig.timeToBreakTime / 3600) {
await models.WorkerTimeControl.create({
userFk: day.workerFk,
timed: timed.setHours(workerTimeControlConfig.teleworkingStartBreakTime / 3600),
manual: true,
direction: 'middle',
isSendMail: true
}, myOptions);
await models.WorkerTimeControl.create({
userFk: day.workerFk,
timed: timed.setHours(
workerTimeControlConfig.teleworkingStartBreakTime / 3600,
workerTimeControlConfig.breakTime / 60
),
manual: true,
direction: 'middle',
isSendMail: true
}, myOptions);
}
const [hoursWork, minutesWork, secondsWork] = getTime(day.timeWorkSexagesimal);
await models.WorkerTimeControl.create({
userFk: day.workerFk,
timed: timed.setHours(
workerTimeControlConfig.teleworkingStart / 3600 + hoursWork,
minutesWork,
secondsWork
),
manual: true,
direction: 'out',
isSendMail: true
}, myOptions);
} else {
const weekDay = day.dated.getDay();
const journeys = await models.BusinessSchedule.find({
where: {
businessFk: day.businessFk,
weekday: weekDay
}
}, myOptions);
let timeTableDecimalInSeconds = 0;
for (let journey of journeys) {
const start = Date.vnNew();
const [startHours, startMinutes, startSeconds] = getTime(journey.started);
start.setHours(startHours, startMinutes, startSeconds, 0);
const end = Date.vnNew();
const [endHours, endMinutes, endSeconds] = getTime(journey.ended);
end.setHours(endHours, endMinutes, endSeconds, 0);
const result = (end - start) / 1000;
timeTableDecimalInSeconds += result;
}
for (let journey of journeys) {
const timeTableDecimal = timeTableDecimalInSeconds / 3600;
if (day.timeWorkDecimal == timeTableDecimal) {
const timed = new Date(day.dated);
const [startHours, startMinutes, startSeconds] = getTime(journey.started);
await models.WorkerTimeControl.create({
userFk: day.workerFk,
timed: timed.setHours(startHours, startMinutes, startSeconds),
manual: true,
isSendMail: true
}, myOptions);
const [endHours, endMinutes, endSeconds] = getTime(journey.ended);
await models.WorkerTimeControl.create({
userFk: day.workerFk,
timed: timed.setHours(endHours, endMinutes, endSeconds),
manual: true,
isSendMail: true
}, myOptions);
} else {
const minStart = journeys.reduce(function(prev, curr) {
return curr.start < prev.start ? curr : prev;
});
if (journey == minStart) {
const timed = new Date(day.dated);
const [startHours, startMinutes, startSeconds] = getTime(journey.started);
await models.WorkerTimeControl.create({
userFk: day.workerFk,
timed: timed.setHours(startHours, startMinutes, startSeconds),
manual: true,
isSendMail: true
}, myOptions);
const [hoursWork, minutesWork, secondsWork] = getTime(day.timeWorkSexagesimal);
await models.WorkerTimeControl.create({
userFk: day.workerFk,
timed: timed.setHours(
startHours + hoursWork,
startMinutes + minutesWork,
startSeconds + secondsWork
),
manual: true,
isSendMail: true
}, myOptions);
}
}
if (day.timeWorkDecimal >= workerTimeControlConfig.timeToBreakTime / 3600) {
const minStart = journeys.reduce(function(prev, curr) {
return curr.start < prev.start ? curr : prev;
});
if (journey == minStart) {
const timed = new Date(day.dated);
const [startHours, startMinutes, startSeconds] = getTime(journey.started);
await models.WorkerTimeControl.create({
userFk: day.workerFk,
timed: timed.setHours(startHours + 1, startMinutes, startSeconds),
manual: true,
isSendMail: true
}, myOptions);
await models.WorkerTimeControl.create({
userFk: day.workerFk,
timed: timed.setHours(startHours + 1, startMinutes + 20, startSeconds),
manual: true,
isSendMail: true
}, myOptions);
}
}
}
const timed = new Date(day.dated);
const firstWorkerTimeControl = await models.WorkerTimeControl.findOne({
where: {
userFk: day.workerFk,
timed: {between: [timed.setHours(0, 0, 0, 0), timed.setHours(23, 59, 59, 999)]}
},
order: 'timed ASC'
}, myOptions);
if (firstWorkerTimeControl)
await firstWorkerTimeControl.updateAttribute('direction', 'in', myOptions);
const lastWorkerTimeControl = await models.WorkerTimeControl.findOne({
where: {
userFk: day.workerFk,
timed: {between: [timed.setHours(0, 0, 0, 0), timed.setHours(23, 59, 59, 999)]}
},
order: 'timed DESC'
}, myOptions);
if (lastWorkerTimeControl)
await lastWorkerTimeControl.updateAttribute('direction', 'out', myOptions);
}
}
const lastDay = days[index][days[index].length - 1];
if (day.workerFk != previousWorkerFk || day == lastDay) {
const query = `INSERT IGNORE INTO workerTimeControlMail (workerFk, year, week)
VALUES(?, ?, ?);`;
await Self.rawSql(query, [previousWorkerFk, args.year, args.week]);
ctx.args = {
recipient: previousReceiver,
year: args.year,
week: args.week,
workerId: previousWorkerFk,
state: 'SENDED'
};
await models.WorkerTimeControl.weeklyHourRecordEmail(ctx, myOptions);
previousWorkerFk = day.workerFk;
previousReceiver = day.receiver;
}
if (tx) await tx.commit();
} catch (e) {
const stmts = [];
let stmt;
stmt = new ParameterizedSQL(`
INSERT INTO mail (receiver, subject, body)
SELECT CONCAT(u.name, '@verdnatura.es'),
CONCAT('Error registro de horas semana ', ?, ' año ', ?) ,
CONCAT('No se ha podido enviar el registro de horas al empleado: ',
w.id, ' ', w.firstName, ' ', w.lastName, ' por el motivo: ', ?)
FROM worker w
JOIN account.user u ON u.id = w.bossFk
WHERE w.id = ?
`, [args.week, args.year, e.message, day.workerFk]);
stmts.push(stmt);
const sql = ParameterizedSQL.join(stmts, ';');
await conn.executeStmt(sql);
previousWorkerFk = day.workerFk;
previousReceiver = day.receiver;
if (tx) await tx.rollback();
continue;
}
}
return true;
};
function getStartDateOfWeekNumber(week, year) {
const simple = new Date(year, 0, 1 + (week - 1) * 7);
const dow = simple.getDay();
const weekStart = simple;
if (dow <= 4)
weekStart.setDate(simple.getDate() - simple.getDay() + 1);
else
weekStart.setDate(simple.getDate() + 8 - simple.getDay());
return weekStart;
}
function getTime(timeString) {
const [hours, minutes, seconds] = timeString.split(':');
return [parseInt(hours), parseInt(minutes), parseInt(seconds)];
}
};