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 args = ctx.args; const myOptions = {}; const conn = Self.dataSource.connector; if (typeof options == 'object') Object.assign(myOptions, options); const stmts = []; let stmt; 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)]; } if (!args.week || !args.year) { const from = new Date(); const to = new Date(); 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'); stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.timeControlCalculate1'); stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.timeBusinessCalculate1'); stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.error'); 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(?, ?, ?) `, [args.workerId, started, ended]); stmts.push(stmt); stmt = new ParameterizedSQL( `CALL vn.timeBusiness_calculateByUser(?, ?, ?) `, [args.workerId, started, ended]); 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); } stmts.push(`CREATE TEMPORARY TABLE tmp.timeControlCalculate1 SELECT * FROM tmp.timeControlCalculate`); stmts.push(`CREATE TEMPORARY TABLE tmp.timeBusinessCalculate1 SELECT * FROM tmp.timeBusinessCalculate`); stmt = new ParameterizedSQL(` SELECT CONCAT(u.name, '@verdnatura.es'), 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 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 user u2 ON u2.id = w.bossFk JOIN (SELECT tb.userFk, SUM(IF(tb.type IS NULL, IF(tc.timeWorkDecimal > 0, FALSE, IF(tb.timeWorkDecimal > 0, TRUE, FALSE)), TRUE))isTeleworkingWeek FROM tmp.timeBusinessCalculate1 tb LEFT JOIN tmp.timeControlCalculate1 tc ON tc.userFk = tb.userFk 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]); const index = stmts.push(stmt) - 1; const sql = ParameterizedSQL.join(stmts, ';'); const days = await conn.executeStmt(sql, myOptions); for (let day of days[index]) { if (day.timeWorkDecimal > 0 && day.timeWorkedDecimal == null && (day.permissionRate ? day.permissionRate : true)) { if (day.timeTable == null) { const timed = new Date(day.dated); await models.WorkerTimeControl.create({ userFk: day.workerFk, timed: timed.setHours(8), manual: true, direction: 'in', isSendMail: true }, myOptions); if (day.timeWorkDecimal >= 5) { await models.WorkerTimeControl.create({ userFk: day.workerFk, timed: timed.setHours(9), manual: true, direction: 'middle', isSendMail: true }, myOptions); await models.WorkerTimeControl.create({ userFk: day.workerFk, timed: timed.setHours(9, 20), manual: true, direction: 'middle', isSendMail: true }, myOptions); } const [hoursWork, minutesWork, secondsWork] = getTime(day.timeWorkSexagesimal); await models.WorkerTimeControl.create({ userFk: day.workerFk, timed: timed.setHours(8 + hoursWork, minutesWork, secondsWork), 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 } }, myOptions); let timeTableDecimalInSeconds = 0; for (let journey of journeys) { const start = new Date(); const [startHours, startMinutes, startSeconds] = getTime(journey.start); start.setHours(startHours, startMinutes, startSeconds); const end = new Date(); const [endHours, endMinutes, endSeconds] = getTime(journey.end); end.setHours(endHours, endMinutes, endSeconds); 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.start); await models.WorkerTimeControl.create({ userFk: day.workerFk, timed: timed.setHours(startHours, startMinutes, startSeconds), manual: true, isSendMail: true }, myOptions); const [endHours, endMinutes, endSeconds] = getTime(journey.end); 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.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); } } if (day.timeWorkDecimal >= 5) { 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); } } } 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', limit: 1 }, myOptions); if (firstWorkerTimeControl) 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', limit: 1 }, myOptions); if (lastWorkerTimeControl) lastWorkerTimeControl.updateAttribute('direction', 'out', myOptions); } } } return true; }; };