2022-10-31 06:34:34 +00:00
|
|
|
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',
|
2022-10-31 12:00:32 +00:00
|
|
|
type: 'number'
|
2022-10-31 06:34:34 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
arg: 'year',
|
2022-10-31 12:00:32 +00:00
|
|
|
type: 'number'
|
2022-10-31 06:34:34 +00:00
|
|
|
}],
|
|
|
|
returns: [{
|
|
|
|
type: 'Object',
|
|
|
|
root: true
|
|
|
|
}],
|
|
|
|
http: {
|
|
|
|
path: `/sendMail`,
|
|
|
|
verb: 'POST'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Self.sendMail = async(ctx, options) => {
|
|
|
|
const models = Self.app.models;
|
2022-11-02 13:22:18 +00:00
|
|
|
const conn = Self.dataSource.connector;
|
2022-10-31 06:34:34 +00:00
|
|
|
const args = ctx.args;
|
2022-11-02 13:22:18 +00:00
|
|
|
let tx;
|
2022-10-31 06:34:34 +00:00
|
|
|
const myOptions = {};
|
|
|
|
|
|
|
|
if (typeof options == 'object')
|
|
|
|
Object.assign(myOptions, options);
|
|
|
|
|
2022-11-02 13:22:18 +00:00
|
|
|
const stmts = [];
|
|
|
|
let stmt;
|
2022-10-31 12:00:32 +00:00
|
|
|
|
2023-01-18 13:23:05 +00:00
|
|
|
if (!args.week || !args.year) {
|
|
|
|
const from = new Date();
|
|
|
|
const to = new Date();
|
2022-10-31 12:00:32 +00:00
|
|
|
|
2023-01-18 13:23:05 +00:00
|
|
|
const time = await models.Time.findOne({
|
|
|
|
where: {
|
|
|
|
dated: {between: [from.setDate(from.getDate() - 10), to.setDate(to.getDate() - 4)]}
|
|
|
|
},
|
|
|
|
order: 'week ASC'
|
|
|
|
}, myOptions);
|
2022-10-31 12:00:32 +00:00
|
|
|
|
2023-01-18 13:23:05 +00:00
|
|
|
args.week = time.week;
|
|
|
|
args.year = time.year;
|
|
|
|
}
|
2022-10-31 12:00:32 +00:00
|
|
|
|
2023-01-18 13:23:05 +00:00
|
|
|
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: new Date(), state: 'SENDED'
|
|
|
|
}, myOptions);
|
|
|
|
|
|
|
|
stmt = new ParameterizedSQL(
|
|
|
|
`CALL vn.timeControl_calculateByUser(?, ?, ?)
|
2022-10-31 12:30:08 +00:00
|
|
|
`, [args.workerId, started, ended]);
|
2023-01-18 13:23:05 +00:00
|
|
|
stmts.push(stmt);
|
2022-10-31 06:34:34 +00:00
|
|
|
|
2023-01-18 13:23:05 +00:00
|
|
|
stmt = new ParameterizedSQL(
|
|
|
|
`CALL vn.timeBusiness_calculateByUser(?, ?, ?)
|
2022-10-31 12:30:08 +00:00
|
|
|
`, [args.workerId, started, ended]);
|
2023-01-18 13:23:05 +00:00
|
|
|
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: new Date(), state: 'SENDED'
|
|
|
|
}, myOptions);
|
|
|
|
|
|
|
|
stmt = new ParameterizedSQL(`CALL vn.timeControl_calculateAll(?, ?)`, [started, ended]);
|
|
|
|
stmts.push(stmt);
|
|
|
|
|
|
|
|
stmt = new ParameterizedSQL(`CALL vn.timeBusiness_calculateAll(?, ?)`, [started, ended]);
|
|
|
|
stmts.push(stmt);
|
|
|
|
}
|
2022-10-31 06:34:34 +00:00
|
|
|
|
2023-01-18 13:23:05 +00:00
|
|
|
stmt = new ParameterizedSQL(`
|
2022-10-31 13:48:37 +00:00
|
|
|
SELECT CONCAT(u.name, '@verdnatura.es') receiver,
|
2022-10-31 12:30:08 +00:00
|
|
|
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
|
2022-11-23 09:09:09 +00:00
|
|
|
JOIN account.user u ON u.id = tb.userFk
|
2022-10-31 12:30:08 +00:00
|
|
|
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
|
|
|
|
JOIN (SELECT tb.userFk,
|
|
|
|
SUM(IF(tb.type IS NULL,
|
|
|
|
IF(tc.timeWorkDecimal > 0, FALSE, IF(tb.timeWorkDecimal > 0, TRUE, FALSE)),
|
|
|
|
TRUE))isTeleworkingWeek
|
2022-11-04 12:41:38 +00:00
|
|
|
FROM tmp.timeBusinessCalculate tb
|
2022-11-23 09:09:09 +00:00
|
|
|
LEFT JOIN tmp.timeControlCalculate tc ON tc.userFk = tb.userFk
|
2022-10-31 12:30:08 +00:00
|
|
|
AND tc.dated = tb.dated
|
|
|
|
GROUP BY tb.userFk
|
|
|
|
HAVING isTeleworkingWeek > 0
|
|
|
|
)sub ON sub.userFk = u.id
|
|
|
|
WHERE d.hasToRefill
|
|
|
|
AND IFNULL(?, u.id) = u.id
|
|
|
|
AND b.companyCodeFk = 'VNL'
|
|
|
|
AND w.businessFk
|
|
|
|
ORDER BY u.id, tb.dated
|
|
|
|
`, [args.workerId]);
|
2023-01-18 13:23:05 +00:00
|
|
|
const index = stmts.push(stmt) - 1;
|
2022-10-31 06:34:34 +00:00
|
|
|
|
2023-01-18 13:23:05 +00:00
|
|
|
stmts.push('DROP TEMPORARY TABLE tmp.timeControlCalculate');
|
|
|
|
stmts.push('DROP TEMPORARY TABLE tmp.timeBusinessCalculate');
|
2022-11-02 13:22:18 +00:00
|
|
|
|
2023-01-18 13:23:05 +00:00
|
|
|
const sql = ParameterizedSQL.join(stmts, ';');
|
|
|
|
const days = await conn.executeStmt(sql, myOptions);
|
2022-10-31 06:34:34 +00:00
|
|
|
|
2023-01-18 13:23:05 +00:00
|
|
|
let previousWorkerFk = days[index][0].workerFk;
|
|
|
|
let previousReceiver = days[index][0].receiver;
|
2022-11-07 11:21:14 +00:00
|
|
|
|
2023-01-18 13:23:05 +00:00
|
|
|
const workerTimeControlConfig = await models.WorkerTimeControlConfig.findOne(null, myOptions);
|
|
|
|
|
|
|
|
for (let day of days[index]) {
|
2023-01-19 07:54:26 +00:00
|
|
|
if (!myOptions.transaction) {
|
|
|
|
tx = await Self.beginTransaction({});
|
|
|
|
myOptions.transaction = tx;
|
|
|
|
}
|
2023-01-18 13:23:05 +00:00
|
|
|
try {
|
2022-11-02 13:22:18 +00:00
|
|
|
workerFk = day.workerFk;
|
|
|
|
if (day.timeWorkDecimal > 0 && day.timeWorkedDecimal == null
|
2023-01-18 12:05:02 +00:00
|
|
|
&& (day.permissionRate == null ? true : day.permissionRate)) {
|
2022-11-02 13:22:18 +00:00
|
|
|
if (day.timeTable == null) {
|
|
|
|
const timed = new Date(day.dated);
|
2022-10-31 06:34:34 +00:00
|
|
|
await models.WorkerTimeControl.create({
|
|
|
|
userFk: day.workerFk,
|
2023-01-12 07:50:03 +00:00
|
|
|
timed: timed.setHours(workerTimeControlConfig.teleworkingStart / 3600),
|
2022-10-31 06:34:34 +00:00
|
|
|
manual: true,
|
2022-11-02 13:22:18 +00:00
|
|
|
direction: 'in',
|
2022-10-31 06:34:34 +00:00
|
|
|
isSendMail: true
|
|
|
|
}, myOptions);
|
|
|
|
|
2022-11-07 11:21:14 +00:00
|
|
|
if (day.timeWorkDecimal >= workerTimeControlConfig.timeToBreakTime / 3600) {
|
2022-10-31 06:34:34 +00:00
|
|
|
await models.WorkerTimeControl.create({
|
|
|
|
userFk: day.workerFk,
|
2023-01-12 07:50:03 +00:00
|
|
|
timed: timed.setHours(workerTimeControlConfig.teleworkingStartBreakTime / 3600),
|
2022-10-31 06:34:34 +00:00
|
|
|
manual: true,
|
2022-11-02 13:22:18 +00:00
|
|
|
direction: 'middle',
|
2022-10-31 06:34:34 +00:00
|
|
|
isSendMail: true
|
|
|
|
}, myOptions);
|
|
|
|
|
|
|
|
await models.WorkerTimeControl.create({
|
|
|
|
userFk: day.workerFk,
|
2023-01-12 07:50:03 +00:00
|
|
|
timed: timed.setHours(
|
|
|
|
workerTimeControlConfig.teleworkingStartBreakTime / 3600,
|
|
|
|
workerTimeControlConfig.breakTime / 60
|
|
|
|
),
|
2022-10-31 06:34:34 +00:00
|
|
|
manual: true,
|
2022-11-02 13:22:18 +00:00
|
|
|
direction: 'middle',
|
2022-10-31 06:34:34 +00:00
|
|
|
isSendMail: true
|
|
|
|
}, myOptions);
|
2022-11-02 13:22:18 +00:00
|
|
|
}
|
2022-10-31 06:34:34 +00:00
|
|
|
|
2022-11-02 13:22:18 +00:00
|
|
|
const [hoursWork, minutesWork, secondsWork] = getTime(day.timeWorkSexagesimal);
|
|
|
|
await models.WorkerTimeControl.create({
|
|
|
|
userFk: day.workerFk,
|
2023-01-12 07:50:03 +00:00
|
|
|
timed: timed.setHours(
|
|
|
|
workerTimeControlConfig.teleworkingStart / 3600 + hoursWork,
|
|
|
|
minutesWork,
|
|
|
|
secondsWork
|
|
|
|
),
|
2022-11-02 13:22:18 +00:00
|
|
|
manual: true,
|
|
|
|
direction: 'out',
|
|
|
|
isSendMail: true
|
|
|
|
}, myOptions);
|
|
|
|
} else {
|
|
|
|
const weekDay = day.dated.getDay();
|
|
|
|
const journeys = await models.Journey.find({
|
|
|
|
where: {
|
|
|
|
business_id: day.businessFk,
|
|
|
|
day_id: weekDay
|
2022-10-31 06:34:34 +00:00
|
|
|
}
|
2022-11-02 13:22:18 +00:00
|
|
|
}, myOptions);
|
|
|
|
|
|
|
|
let timeTableDecimalInSeconds = 0;
|
|
|
|
for (let journey of journeys) {
|
|
|
|
const start = new Date();
|
|
|
|
const [startHours, startMinutes, startSeconds] = getTime(journey.start);
|
2022-11-03 14:00:55 +00:00
|
|
|
start.setHours(startHours, startMinutes, startSeconds, 0);
|
2022-11-02 13:22:18 +00:00
|
|
|
|
|
|
|
const end = new Date();
|
|
|
|
const [endHours, endMinutes, endSeconds] = getTime(journey.end);
|
2022-11-03 14:00:55 +00:00
|
|
|
end.setHours(endHours, endMinutes, endSeconds, 0);
|
2022-11-02 13:22:18 +00:00
|
|
|
|
|
|
|
const result = (end - start) / 1000;
|
|
|
|
timeTableDecimalInSeconds += result;
|
2022-10-31 06:34:34 +00:00
|
|
|
}
|
|
|
|
|
2022-11-02 13:22:18 +00:00
|
|
|
for (let journey of journeys) {
|
|
|
|
const timeTableDecimal = timeTableDecimalInSeconds / 3600;
|
|
|
|
if (day.timeWorkDecimal == timeTableDecimal) {
|
2022-10-31 12:00:32 +00:00
|
|
|
const timed = new Date(day.dated);
|
|
|
|
const [startHours, startMinutes, startSeconds] = getTime(journey.start);
|
2022-10-31 06:34:34 +00:00
|
|
|
await models.WorkerTimeControl.create({
|
|
|
|
userFk: day.workerFk,
|
2022-11-02 13:22:18 +00:00
|
|
|
timed: timed.setHours(startHours, startMinutes, startSeconds),
|
2022-10-31 06:34:34 +00:00
|
|
|
manual: true,
|
|
|
|
isSendMail: true
|
|
|
|
}, myOptions);
|
|
|
|
|
2022-11-02 13:22:18 +00:00
|
|
|
const [endHours, endMinutes, endSeconds] = getTime(journey.end);
|
2022-10-31 06:34:34 +00:00
|
|
|
await models.WorkerTimeControl.create({
|
|
|
|
userFk: day.workerFk,
|
2022-11-02 13:22:18 +00:00
|
|
|
timed: timed.setHours(endHours, endMinutes, endSeconds),
|
2022-10-31 06:34:34 +00:00
|
|
|
manual: true,
|
|
|
|
isSendMail: true
|
|
|
|
}, myOptions);
|
2022-11-02 13:22:18 +00:00
|
|
|
} 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.start);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-07 11:21:14 +00:00
|
|
|
if (day.timeWorkDecimal >= workerTimeControlConfig.timeToBreakTime / 3600) {
|
2022-11-02 13:22:18 +00:00
|
|
|
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.start);
|
|
|
|
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);
|
|
|
|
}
|
2022-10-31 06:34:34 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-02 13:22:18 +00:00
|
|
|
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)
|
2023-01-18 12:05:02 +00:00
|
|
|
await firstWorkerTimeControl.updateAttribute('direction', 'in', myOptions);
|
2022-11-02 13:22:18 +00:00
|
|
|
|
|
|
|
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)
|
2023-01-18 12:05:02 +00:00
|
|
|
await lastWorkerTimeControl.updateAttribute('direction', 'out', myOptions);
|
2022-10-31 06:34:34 +00:00
|
|
|
}
|
2022-11-02 13:22:18 +00:00
|
|
|
}
|
2022-10-31 06:34:34 +00:00
|
|
|
|
2022-11-02 13:22:18 +00:00
|
|
|
const lastDay = days[index][days[index].length - 1];
|
|
|
|
if (day.workerFk != previousWorkerFk || day == lastDay) {
|
|
|
|
const salix = await models.Url.findOne({
|
2022-10-31 06:34:34 +00:00
|
|
|
where: {
|
2022-11-02 13:22:18 +00:00
|
|
|
appName: 'salix',
|
|
|
|
environment: process.env.NODE_ENV || 'dev'
|
|
|
|
}
|
2022-10-31 06:34:34 +00:00
|
|
|
}, myOptions);
|
|
|
|
|
2022-11-02 13:22:18 +00:00
|
|
|
const timestamp = started.getTime() / 1000;
|
2022-11-28 12:56:21 +00:00
|
|
|
const url = `${salix.url}worker/${previousWorkerFk}/time-control?timestamp=${timestamp}`;
|
2022-10-31 06:34:34 +00:00
|
|
|
|
2022-11-28 12:56:21 +00:00
|
|
|
await models.WorkerTimeControl.weeklyHourRecordEmail(ctx, previousReceiver, args.week, args.year, url);
|
2022-10-31 06:34:34 +00:00
|
|
|
|
2022-11-02 13:22:18 +00:00
|
|
|
previousWorkerFk = day.workerFk;
|
|
|
|
previousReceiver = day.receiver;
|
2022-10-31 06:34:34 +00:00
|
|
|
}
|
2022-10-31 13:48:37 +00:00
|
|
|
|
2023-01-19 07:54:26 +00:00
|
|
|
if (tx) {
|
|
|
|
await tx.commit();
|
|
|
|
delete myOptions.transaction;
|
|
|
|
}
|
2023-01-18 13:23:05 +00:00
|
|
|
} catch (e) {
|
|
|
|
if (tx) await tx.rollback();
|
|
|
|
throw e;
|
|
|
|
}
|
2022-10-31 06:34:34 +00:00
|
|
|
}
|
2023-01-18 13:23:05 +00:00
|
|
|
|
|
|
|
return true;
|
2022-10-31 06:34:34 +00:00
|
|
|
};
|
2022-11-02 13:22:18 +00:00
|
|
|
|
|
|
|
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)];
|
|
|
|
}
|
2022-10-31 06:34:34 +00:00
|
|
|
};
|