#6274 workerTimeControl #1858
|
@ -1,14 +1,5 @@
|
||||||
const UserError = require('vn-loopback/util/user-error');
|
|
||||||
const {models} = require('vn-loopback/server/server');
|
const {models} = require('vn-loopback/server/server');
|
||||||
|
|
||||||
const handlePromiseLogout = (Self, {id}, courtesyTime) => {
|
|
||||||
new Promise(res => {
|
|
||||||
setTimeout(() => {
|
|
||||||
res(Self.logout(id));
|
|
||||||
}
|
|
||||||
, courtesyTime * 1000);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('renewToken', {
|
Self.remoteMethodCtx('renewToken', {
|
||||||
description: 'Checks if the token has more than renewPeriod seconds to live and if so, renews it',
|
description: 'Checks if the token has more than renewPeriod seconds to live and if so, renews it',
|
||||||
|
@ -28,14 +19,26 @@ module.exports = Self => {
|
||||||
const {accessToken: token} = ctx.req;
|
const {accessToken: token} = ctx.req;
|
||||||
|
|
||||||
// Check if current token is valid
|
// Check if current token is valid
|
||||||
const isValid = await validateToken(token);
|
|
||||||
if (isValid)
|
const {renewPeriod, courtesyTime} = await models.AccessTokenConfig.findOne({
|
||||||
|
fields: ['renewPeriod', 'courtesyTime']
|
||||||
|
});
|
||||||
|
const now = Date.now();
|
||||||
|
const differenceMilliseconds = now - token.created;
|
||||||
|
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
|
||||||
|
const isNotExceeded = differenceSeconds < renewPeriod - courtesyTime;
|
||||||
|
if (isNotExceeded)
|
||||||
return token;
|
return token;
|
||||||
|
|
||||||
const {courtesyTime} = await models.AccessTokenConfig.findOne({fields: ['courtesyTime']});
|
|
||||||
|
|
||||||
// Schedule to remove current token
|
// Schedule to remove current token
|
||||||
handlePromiseLogout(Self, token, courtesyTime);
|
setTimeout(async() => {
|
||||||
|
try {
|
||||||
|
await Self.logout(token.id);
|
||||||
|
} catch (err) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}, courtesyTime * 1000);
|
||||||
|
|
||||||
// Create new accessToken
|
// Create new accessToken
|
||||||
const user = await Self.findById(token.userId);
|
const user = await Self.findById(token.userId);
|
||||||
|
@ -43,14 +46,4 @@ module.exports = Self => {
|
||||||
|
|
||||||
return {id: accessToken.id, ttl: accessToken.ttl};
|
return {id: accessToken.id, ttl: accessToken.ttl};
|
||||||
};
|
};
|
||||||
|
|
||||||
async function validateToken(token) {
|
|
||||||
const accessTokenConfig = await models.AccessTokenConfig.findOne({fields: ['renewPeriod', 'courtesyTime']});
|
|
||||||
const now = Date.now();
|
|
||||||
const differenceMilliseconds = now - token.created;
|
|
||||||
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
|
|
||||||
const isValid = differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime;
|
|
||||||
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -95,27 +95,30 @@
|
||||||
"principalType": "ROLE",
|
"principalType": "ROLE",
|
||||||
"principalId": "$everyone",
|
"principalId": "$everyone",
|
||||||
"permission": "ALLOW"
|
"permission": "ALLOW"
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
"property": "recoverPassword",
|
"property": "recoverPassword",
|
||||||
"accessType": "EXECUTE",
|
"accessType": "EXECUTE",
|
||||||
"principalType": "ROLE",
|
"principalType": "ROLE",
|
||||||
"principalId": "$everyone",
|
"principalId": "$everyone",
|
||||||
"permission": "ALLOW"
|
"permission": "ALLOW"
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
"property": "validateAuth",
|
"property": "validateAuth",
|
||||||
"accessType": "EXECUTE",
|
"accessType": "EXECUTE",
|
||||||
"principalType": "ROLE",
|
"principalType": "ROLE",
|
||||||
"principalId": "$everyone",
|
"principalId": "$everyone",
|
||||||
"permission": "ALLOW"
|
"permission": "ALLOW"
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
"property": "privileges",
|
"property": "privileges",
|
||||||
"accessType": "*",
|
"accessType": "*",
|
||||||
"principalType": "ROLE",
|
"principalType": "ROLE",
|
||||||
"principalId": "$authenticated",
|
"principalId": "$authenticated",
|
||||||
"permission": "ALLOW"
|
"permission": "ALLOW"
|
||||||
|
}, {
|
||||||
|
"property": "renewToken",
|
||||||
|
"accessType": "WRITE",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$authenticated",
|
||||||
|
"permission": "ALLOW"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scopes": {
|
"scopes": {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
DELETE FROM `salix`.`ACL`
|
||||||
|
WHERE model = 'VnUser'
|
||||||
|
AND property = 'renewToken';
|
||||||
|
|
||||||
|
INSERT INTO `account`.`role` (name, description)
|
||||||
|
VALUES ('timeControl','Tablet para fichar');
|
||||||
|
|
||||||
|
INSERT INTO `account`.`roleInherit` (role, inheritsFrom)
|
||||||
|
VALUES (127, 11);
|
||||||
|
|
||||||
|
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||||
|
VALUES
|
||||||
jorgep marked this conversation as resolved
Outdated
|
|||||||
|
('WorkerTimeControl', 'login', 'READ', 'ALLOW', 'ROLE', 'timeControl'),
|
||||||
|
('WorkerTimeControl', 'getClockIn', 'READ', 'ALLOW', 'ROLE', 'timeControl'),
|
||||||
|
('WorkerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', 'timeControl');
|
||||||
|
|
||||||
|
CALL `account`.`role_sync`();
|
|
@ -200,5 +200,6 @@
|
||||||
"Try again": "Try again",
|
"Try again": "Try again",
|
||||||
"keepPrice": "keepPrice",
|
"keepPrice": "keepPrice",
|
||||||
"Cannot past travels with entries": "Cannot past travels with entries",
|
"Cannot past travels with entries": "Cannot past travels with entries",
|
||||||
"It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}"
|
"It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}",
|
||||||
|
"Incorrect pin": "Incorrect pin."
|
||||||
}
|
}
|
||||||
|
|
|
@ -331,7 +331,7 @@
|
||||||
"Cannot past travels with entries": "No se pueden pasar envíos con entradas",
|
"Cannot past travels with entries": "No se pueden pasar envíos con entradas",
|
||||||
"It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}",
|
"It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}",
|
||||||
"This user does not have an assigned tablet": "Este usuario no tiene tablet asignada",
|
"This user does not have an assigned tablet": "Este usuario no tiene tablet asignada",
|
||||||
|
"Incorrect pin": "Pin incorrecto.",
|
||||||
jorgep marked this conversation as resolved
Outdated
jgallego
commented
ayer no hablamos de no poner puntos? son estos casos? ayer no hablamos de no poner puntos? son estos casos?
jorgep
commented
cierto cierto
|
|||||||
"You already have the mailAlias": "Ya tienes este alias de correo",
|
"You already have the mailAlias": "Ya tienes este alias de correo",
|
||||||
"The alias cant be modified": "Este alias de correo no puede ser modificado"
|
"The alias cant be modified": "Este alias de correo no puede ser modificado"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,16 +43,9 @@ module.exports = Self => {
|
||||||
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
|
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
|
||||||
const isHimself = userId == workerId;
|
const isHimself = userId == workerId;
|
||||||
|
|
||||||
if (!isSubordinate || (isSubordinate && isHimself && !isTeamBoss))
|
if (!isSubordinate || (isHimself && !isTeamBoss))
|
||||||
throw new UserError(`You don't have enough privileges`);
|
throw new UserError(`You don't have enough privileges`);
|
||||||
|
|
||||||
query = `CALL vn.workerTimeControl_clockIn(?,?,?)`;
|
return Self.clockIn(workerId, args.timed, args.direction, myOptions);
|
||||||
const [response] = await Self.rawSql(query, [workerId, args.timed, args.direction], myOptions);
|
|
||||||
if (response[0] && response[0].error)
|
|
||||||
throw new UserError(response[0].error);
|
|
||||||
|
|
||||||
await models.WorkerTimeControl.resendWeeklyHourEmail(ctx, workerId, args.timed, myOptions);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
jorgep marked this conversation as resolved
Outdated
jgallego
commented
veo que existe un archivo muy similar que llama al mismo procedimiento, lo has tenido en cuenta? conviene juntarlo en uno? veo que existe un archivo muy similar que llama al mismo procedimiento, lo has tenido en cuenta? conviene juntarlo en uno?
modules/worker/back/methods/worker-time-control/addTimeEntry.js
jorgep
commented
Ya se ha implementado, tenemos que mirarlo juntos conforme hemos hablado por rocket. Ya se ha implementado, tenemos que mirarlo juntos conforme hemos hablado por rocket.
jorgep
commented
Refactor aplicado tras revisión en persona. Refactor aplicado tras revisión en persona.
|
|||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('clockIn', {
|
||||||
|
description: 'Check if the employee can clock in',
|
||||||
|
accessType: 'WRITE',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'workerFk',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'timed',
|
||||||
|
type: 'date'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'direction',
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
|
||||||
|
],
|
||||||
|
http: {
|
||||||
|
path: `/clockIn`,
|
||||||
|
verb: 'POST'
|
||||||
|
},
|
||||||
|
returns: {
|
||||||
|
type: 'Object',
|
||||||
|
root: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.clockIn = async(workerFk, timed, direction, options) => {
|
||||||
|
const myOptions = {};
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
const query = 'CALL vn.workerTimeControl_clockIn(?, ?, ?)';
|
||||||
|
const [[response]] = await Self.rawSql(query, [workerFk, timed, direction], myOptions);
|
||||||
jorgep marked this conversation as resolved
Outdated
alexm
commented
Si es el caso puedes hacer:
Es decir, hacer Si es el caso puedes hacer:
```
const myArray = [[{}]]
const [[myNewArray]] = myArray
console.log(myNewArray) // Devuelve {}
```
Es decir, hacer `const [[response]] =` y te evitas luego hacer response[0]
|
|||||||
|
if (response && response.error)
|
||||||
|
throw new UserError(response.error);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,32 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('getClockIn', {
|
||||||
|
description: 'Shows the clockings for each day, in columns per day',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'workerFk',
|
||||||
|
type: 'int',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
],
|
||||||
|
http: {
|
||||||
|
path: `/getClockIn`,
|
||||||
|
verb: 'GET'
|
||||||
|
},
|
||||||
|
returns: {
|
||||||
|
type: ['Object'],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.getClockIn = async(workerFk, options) => {
|
||||||
|
const myOptions = {};
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
const query = `CALL vn.workerTimeControl_getClockIn(?, ?)`;
|
||||||
|
const [result] = await Self.rawSql(query, [workerFk, Date.vnNew()], myOptions);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,35 @@
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('login', {
|
||||||
|
description: 'Consult the user\'s information and the buttons that must be activated after logging in',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'pin',
|
||||||
|
type: 'string',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: 'Object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/login`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.login = async(ctx, pin, options) => {
|
||||||
|
const myOptions = {};
|
||||||
|
const $t = ctx.req.__;
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
const query = `CALL vn.workerTimeControl_login(?)`;
|
||||||
|
const [[user]] = await Self.rawSql(query, [pin], myOptions);
|
||||||
|
if (!user) throw new UserError($t('Incorrect pin'));
|
||||||
jorgep marked this conversation as resolved
Outdated
alexm
commented
Falta traduccion Falta traduccion
|
|||||||
|
return user;
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,6 +1,6 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('resendWeeklyHourEmail', {
|
Self.remoteMethodCtx('resendWeeklyHourEmail', {
|
||||||
description: 'Adds a new hour registry',
|
description: 'Send the records for the week of the date provided',
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'id',
|
arg: 'id',
|
||||||
|
|
|
@ -0,0 +1,581 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
|
describe('workerTimeControl clockIn()', () => {
|
||||||
|
const workerId = 9;
|
||||||
|
const salesBossId = 19;
|
||||||
|
const hankPymId = 1107;
|
||||||
|
const jessicaJonesId = 1110;
|
||||||
|
const HHRRId = 37;
|
||||||
|
const teamBossId = 13;
|
||||||
|
const monday = 1;
|
||||||
|
const tuesday = 2;
|
||||||
|
const thursday = 4;
|
||||||
|
const friday = 5;
|
||||||
|
const sunday = 7;
|
||||||
|
const inTime = '2001-01-01T00:00:00.000Z';
|
||||||
|
const activeCtx = {
|
||||||
|
accessToken: {userId: 50},
|
||||||
|
};
|
||||||
|
const ctx = {req: activeCtx};
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||||
|
active: activeCtx
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly clock in', async() => {
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
await models.WorkerTimeControl.clockIn(workerId, inTime, 'in', options);
|
||||||
|
const isClockIn = await models.WorkerTimeControl.findOne({
|
||||||
|
where: {
|
||||||
|
userFk: workerId
|
||||||
|
}
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
expect(isClockIn).toBeDefined();
|
||||||
|
expect(isClockIn.direction).toBe('in');
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('as Role errors', () => {
|
||||||
|
it('should add if the current user is team boss and the target user is himself', async() => {
|
||||||
|
activeCtx.accessToken.userId = teamBossId;
|
||||||
|
const workerId = teamBossId;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const todayAtOne = Date.vnNew();
|
||||||
|
todayAtOne.setHours(1, 0, 0, 0);
|
||||||
|
|
||||||
|
ctx.args = {timed: todayAtOne, direction: 'in'};
|
||||||
|
const createdTimeEntry = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
expect(createdTimeEntry.id).toBeDefined();
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the created time entry for the team boss as himself', async() => {
|
||||||
|
activeCtx.accessToken.userId = teamBossId;
|
||||||
|
const workerId = teamBossId;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const todayAtOne = Date.vnNew();
|
||||||
|
todayAtOne.setHours(1, 0, 0, 0);
|
||||||
|
|
||||||
|
ctx.args = {timed: todayAtOne, direction: 'in'};
|
||||||
|
const createdTimeEntry = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
expect(createdTimeEntry.id).toBeDefined();
|
||||||
|
|
||||||
|
await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options);
|
||||||
|
|
||||||
|
const deletedTimeEntry = await models.WorkerTimeControl.findById(createdTimeEntry.id, null, options);
|
||||||
|
|
||||||
|
expect(deletedTimeEntry).toBeNull();
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should edit the created time entry for the team boss as HHRR', async() => {
|
||||||
|
activeCtx.accessToken.userId = HHRRId;
|
||||||
|
const workerId = teamBossId;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const todayAtOne = Date.vnNew();
|
||||||
|
todayAtOne.setHours(1, 0, 0, 0);
|
||||||
|
|
||||||
|
ctx.args = {timed: todayAtOne, direction: 'in'};
|
||||||
|
const createdTimeEntry = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
expect(createdTimeEntry.id).toBeDefined();
|
||||||
|
|
||||||
|
ctx.args = {direction: 'out'};
|
||||||
|
const updatedTimeEntry = await models.WorkerTimeControl.updateTimeEntry(
|
||||||
|
ctx, createdTimeEntry.id, options
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(updatedTimeEntry.direction).toEqual('out');
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('as saleBoss editor', () => {
|
||||||
|
let workerId;
|
||||||
|
beforeEach(() => {
|
||||||
|
activeCtx.accessToken.userId = salesBossId;
|
||||||
|
workerId = hankPymId;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail to add a time entry if the target user has an absence that day', async() => {
|
||||||
|
const date = Date.vnNew();
|
||||||
|
date.setHours(8, 0, 0);
|
||||||
|
date.setDate(date.getDate() - 16);
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
try {
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`No está permitido trabajar`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail to add a time entry for a worker without an existing contract', async() => {
|
||||||
|
const date = Date.vnNew();
|
||||||
|
date.setFullYear(date.getFullYear() - 2);
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
try {
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`No hay un contrato en vigor`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail to add a time entry for a worker without an existing contract and exceeding time', async() => {
|
||||||
|
let date = Date.vnNew();
|
||||||
|
date.setDate(date.getDate() - 2);
|
||||||
|
let error;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
date.setHours(0, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date.setHours(20, 0, 1);
|
||||||
|
ctx.args = {timed: date, direction: 'out'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`Superado el tiempo máximo entre entrada y salida`);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('direction errors', () => {
|
||||||
|
let date = Date.vnNew();
|
||||||
|
date.setDate(date.getDate() - 1);
|
||||||
|
let error;
|
||||||
|
it('should throw an error when trying "in" direction twice', async() => {
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
date.setHours(8, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date.setHours(10, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`Dirección incorrecta`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when trying "in" direction after insert "in" and "middle"', async() => {
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
date.setHours(8, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
date.setHours(9, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'middle'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date.setHours(10, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`Dirección incorrecta`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should throw an error when trying "out" before closing a "middle" couple', async() => {
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
date.setHours(8, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
date.setHours(9, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'middle'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date.setHours(10, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'out'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`Dirección incorrecta`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when trying "middle" after "out"', async() => {
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
date.setHours(8, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
date.setHours(9, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'out'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date.setHours(10, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'middle'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`Dirección incorrecta`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when trying "out" direction twice', async() => {
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
date.setHours(8, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
date.setHours(9, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'out'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date.setHours(10, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'out'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`Dirección incorrecta`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('12h rest', () => {
|
||||||
|
activeCtx.accessToken.userId = salesBossId;
|
||||||
|
const workerId = hankPymId;
|
||||||
|
it('should throw an error when the 12h rest is not fulfilled yet', async() => {
|
||||||
|
let date = Date.vnNew();
|
||||||
|
date.setDate(date.getDate() - 2);
|
||||||
|
date = weekDay(date, monday);
|
||||||
|
let error;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
date.setHours(8, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
date.setHours(16, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'out'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date = weekDay(date, tuesday);
|
||||||
|
date.setHours(4, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`Descanso diario`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fail as the 12h rest is fulfilled', async() => {
|
||||||
|
let date = Date.vnNew();
|
||||||
|
date.setDate(date.getDate() - 2);
|
||||||
|
date = weekDay(date, monday);
|
||||||
|
let error;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
date.setHours(8, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
date.setHours(16, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'out'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date = weekDay(date, tuesday);
|
||||||
|
date.setHours(4, 1, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeDefined;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('for 3500kg drivers with enforced 9h rest', () => {
|
||||||
|
activeCtx.accessToken.userId = salesBossId;
|
||||||
|
const workerId = jessicaJonesId;
|
||||||
|
it('should throw an error when the 9h enforced rest is not fulfilled', async() => {
|
||||||
|
let date = Date.vnNew();
|
||||||
|
date.setDate(date.getDate() - 2);
|
||||||
|
date = weekDay(date, monday);
|
||||||
|
let error;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
date.setHours(8, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
date.setHours(16, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'out'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date = weekDay(date, tuesday);
|
||||||
|
date.setHours(1, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`Descanso diario`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fail when the 9h enforced rest is fulfilled', async() => {
|
||||||
|
let date = Date.vnNew();
|
||||||
|
date.setDate(date.getDate() - 2);
|
||||||
|
date = weekDay(date, monday);
|
||||||
|
let error;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
date.setHours(8, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
date.setHours(16, 0, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'out'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date = weekDay(date, tuesday);
|
||||||
|
date.setHours(1, 1, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeDefined;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('for 72h weekly rest', () => {
|
||||||
|
|
||||||
|
it('should throw an error when work 11 consecutive days', async() => {
|
||||||
|
let date = Date.vnNew();
|
||||||
|
date.setMonth(date.getMonth() - 1);
|
||||||
|
date.setDate(1);
|
||||||
|
let error;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
await populateWeek(date, monday, sunday, ctx, workerId, options);
|
||||||
|
date = nextWeek(date);
|
||||||
|
await populateWeek(date, monday, thursday, ctx, workerId, options);
|
||||||
|
try {
|
||||||
|
date = weekDay(date, friday);
|
||||||
|
date.setHours(10, 0, 1);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`Descanso semanal`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when the 72h weekly rest is not fulfilled', async() => {
|
||||||
|
|
||||||
|
let date = Date.vnNew();
|
||||||
|
date.setMonth(date.getMonth() - 1);
|
||||||
|
date.setDate(1);
|
||||||
|
let error;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
await populateWeek(date, monday, sunday, ctx, workerId, options);
|
||||||
|
date = nextWeek(date);
|
||||||
|
await populateWeek(date, monday, thursday, ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date = weekDay(date, sunday);
|
||||||
|
date.setHours(17, 59, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe(`Descanso semanal`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when the 72h weekly rest is fulfilled', async() => {
|
||||||
|
|
||||||
|
let date = Date.vnNew();
|
||||||
|
date.setMonth(date.getMonth() - 1);
|
||||||
|
date.setDate(1);
|
||||||
|
let error;
|
||||||
|
|
||||||
|
const tx = await models.WorkerTimeControl.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
await populateWeek(date, monday, sunday, ctx, workerId, options);
|
||||||
|
date = nextWeek(date);
|
||||||
|
await populateWeek(date, monday, thursday, ctx, workerId, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
date = weekDay(date, sunday);
|
||||||
|
date.setHours(18, 00, 0);
|
||||||
|
ctx.args = {timed: date, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.toBeDefined;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function weekDay(date, dayToSet) {
|
||||||
|
const currentDay = date.getDay();
|
||||||
|
const distance = dayToSet - currentDay;
|
||||||
|
|
||||||
|
date.setDate(date.getDate() + distance);
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextWeek(date) {
|
||||||
|
const sunday = 7;
|
||||||
|
const currentDay = date.getDay();
|
||||||
|
let newDate = date;
|
||||||
|
if (currentDay != 0)
|
||||||
|
newDate = weekDay(date, sunday);
|
||||||
|
|
||||||
|
newDate.setDate(newDate.getDate() + 1);
|
||||||
|
return newDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function populateWeek(date, dayStart, dayEnd, ctx, workerId, options) {
|
||||||
|
const dateStart = new Date(weekDay(date, dayStart));
|
||||||
|
const dateEnd = new Date(dateStart);
|
||||||
|
dateEnd.setDate(dateStart.getDate() + dayEnd);
|
||||||
|
|
||||||
|
for (let i = dayStart; i <= dayEnd; i++) {
|
||||||
|
dateStart.setHours(10, 0, 0);
|
||||||
|
ctx.args = {timed: dateStart, direction: 'in'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
dateStart.setHours(18, 0, 0);
|
||||||
|
ctx.args = {timed: dateStart, direction: 'out'};
|
||||||
|
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||||
|
dateStart.setDate(dateStart.getDate() + 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
|
describe('workerTimeControl getClockIn()', () => {
|
||||||
|
it('should correctly get the timetable of a worker', async() => {
|
||||||
|
const response = await models.WorkerTimeControl.getClockIn(1106, {});
|
||||||
|
|
||||||
|
expect(response.length).toEqual(4);
|
||||||
|
const [inHrs, middleOutHrs, middleInHrs, outHrs] = response;
|
||||||
|
|
||||||
|
expect(inHrs['0daysAgo']).toEqual('07:00');
|
||||||
|
expect(middleOutHrs['0daysAgo']).toEqual('10:00');
|
||||||
|
expect(middleInHrs['0daysAgo']).toEqual('10:20');
|
||||||
|
expect(outHrs['0daysAgo']).toEqual('14:50');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
const LoopBackContext = require('loopback-context');
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
|
describe('workerTimeControl login()', () => {
|
||||||
|
let ctx;
|
||||||
jorgep marked this conversation as resolved
Outdated
alexm
commented
No hace falta pasar el objeto No hace falta pasar el objeto
|
|||||||
|
beforeAll(async() => {
|
||||||
|
ctx = {
|
||||||
|
accessToken: {userId: 9},
|
||||||
|
req: {
|
||||||
|
headers: {origin: 'http://localhost'},
|
||||||
|
__: key => key
|
||||||
|
}
|
||||||
|
};
|
||||||
|
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||||
|
active: ctx
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly login', async() => {
|
||||||
|
const response = await models.WorkerTimeControl.login(ctx, 9);
|
||||||
|
|
||||||
|
expect(response.name).toBe('developer');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw UserError if pin is not provided', async() => {
|
||||||
|
try {
|
||||||
|
await models.WorkerTimeControl.login(ctx);
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(UserError);
|
||||||
|
expect(error.message).toBe('Incorrect pin');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -3,18 +3,10 @@ const models = require('vn-loopback/server/server').models;
|
||||||
const LoopBackContext = require('loopback-context');
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
describe('workerTimeControl add/delete timeEntry()', () => {
|
describe('workerTimeControl add/delete timeEntry()', () => {
|
||||||
const HHRRId = 37;
|
|
||||||
const teamBossId = 13;
|
|
||||||
const employeeId = 1;
|
const employeeId = 1;
|
||||||
const salesPersonId = 1106;
|
|
||||||
const salesBossId = 19;
|
const salesBossId = 19;
|
||||||
const hankPymId = 1107;
|
const hankPymId = 1107;
|
||||||
const jessicaJonesId = 1110;
|
|
||||||
const monday = 1;
|
const monday = 1;
|
||||||
const tuesday = 2;
|
|
||||||
const thursday = 4;
|
|
||||||
const friday = 5;
|
|
||||||
const sunday = 7;
|
|
||||||
const activeCtx = {
|
const activeCtx = {
|
||||||
accessToken: {userId: 50},
|
accessToken: {userId: 50},
|
||||||
};
|
};
|
||||||
|
@ -61,559 +53,10 @@ describe('workerTimeControl add/delete timeEntry()', () => {
|
||||||
expect(error.statusCode).toBe(400);
|
expect(error.statusCode).toBe(400);
|
||||||
expect(error.message).toBe(`You don't have enough privileges`);
|
expect(error.message).toBe(`You don't have enough privileges`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add if the current user is team boss and the target user is himself', async() => {
|
|
||||||
activeCtx.accessToken.userId = teamBossId;
|
|
||||||
const workerId = teamBossId;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
try {
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
const todayAtOne = Date.vnNew();
|
|
||||||
todayAtOne.setHours(1, 0, 0, 0);
|
|
||||||
|
|
||||||
ctx.args = {timed: todayAtOne, direction: 'in'};
|
|
||||||
const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
expect(createdTimeEntry.id).toBeDefined();
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should try but fail to delete his own time entry', async() => {
|
|
||||||
activeCtx.accessToken.userId = salesBossId;
|
|
||||||
const workerId = salesBossId;
|
|
||||||
|
|
||||||
let error;
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
try {
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
const todayAtOne = Date.vnNew();
|
|
||||||
todayAtOne.setHours(1, 0, 0, 0);
|
|
||||||
|
|
||||||
ctx.args = {timed: todayAtOne, direction: 'in'};
|
|
||||||
const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
activeCtx.accessToken.userId = salesPersonId;
|
|
||||||
await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
error = e;
|
|
||||||
await tx.rollback();
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error).toBeDefined();
|
|
||||||
expect(error.statusCode).toBe(400);
|
|
||||||
expect(error.message).toBe(`You don't have enough privileges`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete the created time entry for the team boss as himself', async() => {
|
|
||||||
activeCtx.accessToken.userId = teamBossId;
|
|
||||||
const workerId = teamBossId;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
try {
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
const todayAtOne = Date.vnNew();
|
|
||||||
todayAtOne.setHours(1, 0, 0, 0);
|
|
||||||
|
|
||||||
ctx.args = {timed: todayAtOne, direction: 'in'};
|
|
||||||
const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
expect(createdTimeEntry.id).toBeDefined();
|
|
||||||
|
|
||||||
await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options);
|
|
||||||
|
|
||||||
const deletedTimeEntry = await models.WorkerTimeControl.findById(createdTimeEntry.id, null, options);
|
|
||||||
|
|
||||||
expect(deletedTimeEntry).toBeNull();
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete the created time entry for the team boss as HHRR', async() => {
|
|
||||||
activeCtx.accessToken.userId = HHRRId;
|
|
||||||
const workerId = teamBossId;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
try {
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
const todayAtOne = Date.vnNew();
|
|
||||||
todayAtOne.setHours(1, 0, 0, 0);
|
|
||||||
|
|
||||||
ctx.args = {timed: todayAtOne, direction: 'in'};
|
|
||||||
const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
expect(createdTimeEntry.id).toBeDefined();
|
|
||||||
|
|
||||||
await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options);
|
|
||||||
|
|
||||||
const deletedTimeEntry = await models.WorkerTimeControl.findById(createdTimeEntry.id, null, options);
|
|
||||||
|
|
||||||
expect(deletedTimeEntry).toBeNull();
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should edit the created time entry for the team boss as HHRR', async() => {
|
|
||||||
activeCtx.accessToken.userId = HHRRId;
|
|
||||||
const workerId = teamBossId;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
try {
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
const todayAtOne = Date.vnNew();
|
|
||||||
todayAtOne.setHours(1, 0, 0, 0);
|
|
||||||
|
|
||||||
ctx.args = {timed: todayAtOne, direction: 'in'};
|
|
||||||
const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
expect(createdTimeEntry.id).toBeDefined();
|
|
||||||
|
|
||||||
ctx.args = {direction: 'out'};
|
|
||||||
const updatedTimeEntry = await models.WorkerTimeControl.updateTimeEntry(ctx, createdTimeEntry.id, options);
|
|
||||||
|
|
||||||
expect(updatedTimeEntry.direction).toEqual('out');
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('WorkerTimeControl_clockIn calls', () => {
|
describe('WorkerTimeControl_clockIn calls', () => {
|
||||||
let workerId;
|
beforeEach(() => activeCtx.accessToken.userId = salesBossId);
|
||||||
beforeEach(() => {
|
|
||||||
activeCtx.accessToken.userId = salesBossId;
|
|
||||||
workerId = hankPymId;
|
|
||||||
});
|
|
||||||
it('should fail to add a time entry if the target user has an absence that day', async() => {
|
|
||||||
const date = Date.vnNew();
|
|
||||||
date.setHours(8, 0, 0);
|
|
||||||
date.setDate(date.getDate() - 16);
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
try {
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`No está permitido trabajar`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fail to add a time entry for a worker without an existing contract', async() => {
|
|
||||||
const date = Date.vnNew();
|
|
||||||
date.setFullYear(date.getFullYear() - 2);
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
try {
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`No hay un contrato en vigor`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fail to add a time entry for a worker without an existing contract', async() => {
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setDate(date.getDate() - 2);
|
|
||||||
let error;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
date.setHours(0, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date.setHours(20,0, 1);
|
|
||||||
ctx.args = {timed: date, direction: 'out'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`Superado el tiempo máximo entre entrada y salida`);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('direction errors', () => {
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setDate(date.getDate() - 1);
|
|
||||||
let error;
|
|
||||||
it('should throw an error when trying "in" direction twice', async() => {
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
date.setHours(8, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date.setHours(10, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`Dirección incorrecta`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error when trying "in" direction after insert "in" and "middle"', async() => {
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
date.setHours(8, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
date.setHours(9, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'middle'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date.setHours(10, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`Dirección incorrecta`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should throw an error when trying "out" before closing a "middle" couple', async() => {
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
date.setHours(8, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
date.setHours(9, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'middle'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date.setHours(10, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'out'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`Dirección incorrecta`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error when trying "middle" after "out"', async() => {
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
date.setHours(8, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
date.setHours(9, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'out'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date.setHours(10, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'middle'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`Dirección incorrecta`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error when trying "out" direction twice', async() => {
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
date.setHours(8, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
date.setHours(9, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'out'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date.setHours(10, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'out'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`Dirección incorrecta`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('12h rest', () => {
|
|
||||||
activeCtx.accessToken.userId = salesBossId;
|
|
||||||
const workerId = hankPymId;
|
|
||||||
it('should throw an error when the 12h rest is not fulfilled yet', async() => {
|
|
||||||
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setDate(date.getDate() - 2);
|
|
||||||
date = weekDay(date, monday);
|
|
||||||
let error;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
date.setHours(8, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
date.setHours(16, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'out'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date = weekDay(date, tuesday);
|
|
||||||
date.setHours(4, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`Descanso diario`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not fail as the 12h rest is fulfilled', async() => {
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setDate(date.getDate() - 2);
|
|
||||||
date = weekDay(date, monday);
|
|
||||||
let error;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
date.setHours(8, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
date.setHours(16, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'out'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date = weekDay(date, tuesday);
|
|
||||||
date.setHours(4, 1, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error).not.toBeDefined;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('for 3500kg drivers with enforced 9h rest', () => {
|
|
||||||
activeCtx.accessToken.userId = salesBossId;
|
|
||||||
const workerId = jessicaJonesId;
|
|
||||||
it('should throw an error when the 9h enforced rest is not fulfilled', async() => {
|
|
||||||
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setDate(date.getDate() - 2);
|
|
||||||
date = weekDay(date, monday);
|
|
||||||
let error;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
date.setHours(8, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
date.setHours(16, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'out'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date = weekDay(date, tuesday);
|
|
||||||
date.setHours(1, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`Descanso diario`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not fail when the 9h enforced rest is fulfilled', async() => {
|
|
||||||
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setDate(date.getDate() - 2);
|
|
||||||
date = weekDay(date, monday);
|
|
||||||
let error;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
date.setHours(8, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
date.setHours(16, 0, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'out'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date = weekDay(date, tuesday);
|
|
||||||
date.setHours(1, 1, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error).not.toBeDefined;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('for 72h weekly rest', () => {
|
|
||||||
|
|
||||||
it('should throw an error when work 11 consecutive days', async() => {
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setMonth(date.getMonth() - 1);
|
|
||||||
date.setDate(1);
|
|
||||||
let error;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
await populateWeek(date, monday, sunday, ctx, workerId, options);
|
|
||||||
date = nextWeek(date);
|
|
||||||
await populateWeek(date, monday, thursday, ctx, workerId, options);
|
|
||||||
try {
|
|
||||||
date = weekDay(date, friday);
|
|
||||||
date.setHours(10, 0, 1);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`Descanso semanal`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error when the 72h weekly rest is not fulfilled', async() => {
|
|
||||||
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setMonth(date.getMonth() - 1);
|
|
||||||
date.setDate(1);
|
|
||||||
let error;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
await populateWeek(date, monday, sunday, ctx, workerId, options);
|
|
||||||
date = nextWeek(date);
|
|
||||||
await populateWeek(date, monday, thursday, ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date = weekDay(date, sunday);
|
|
||||||
date.setHours(17, 59, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error.message).toBe(`Descanso semanal`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error when the 72h weekly rest is fulfilled', async() => {
|
|
||||||
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setMonth(date.getMonth() - 1);
|
|
||||||
date.setDate(1);
|
|
||||||
let error;
|
|
||||||
|
|
||||||
const tx = await models.WorkerTimeControl.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
await populateWeek(date, monday, sunday, ctx, workerId, options);
|
|
||||||
date = nextWeek(date);
|
|
||||||
await populateWeek(date, monday, thursday, ctx, workerId, options);
|
|
||||||
|
|
||||||
try {
|
|
||||||
date = weekDay(date, sunday);
|
|
||||||
date.setHours(18, 00, 0);
|
|
||||||
ctx.args = {timed: date, direction: 'in'};
|
|
||||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error).not.toBeDefined;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('WorkerTimeControl_calculate calls', () => {
|
describe('WorkerTimeControl_calculate calls', () => {
|
||||||
let dated = Date.vnNew();
|
let dated = Date.vnNew();
|
||||||
|
@ -836,25 +279,6 @@ function weekDay(date, dayToSet) {
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextWeek(date) {
|
|
||||||
const sunday = 7;
|
|
||||||
const currentDay = date.getDay();
|
|
||||||
let newDate = date;
|
|
||||||
if (currentDay != 0)
|
|
||||||
newDate = weekDay(date, sunday);
|
|
||||||
|
|
||||||
newDate.setDate(newDate.getDate() + 1);
|
|
||||||
return newDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
function lastWeek(date) {
|
|
||||||
const monday = 1;
|
|
||||||
newDate = weekDay(date, monday);
|
|
||||||
|
|
||||||
newDate.setDate(newDate.getDate() - 1);
|
|
||||||
return newDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function populateWeek(date, dayStart, dayEnd, ctx, workerId, options) {
|
async function populateWeek(date, dayStart, dayEnd, ctx, workerId, options) {
|
||||||
const dateStart = new Date(weekDay(date, dayStart));
|
const dateStart = new Date(weekDay(date, dayStart));
|
||||||
const dateEnd = new Date(dateStart);
|
const dateEnd = new Date(dateStart);
|
||||||
|
|
|
@ -10,6 +10,9 @@ module.exports = Self => {
|
||||||
require('../methods/worker-time-control/weeklyHourRecordEmail')(Self);
|
require('../methods/worker-time-control/weeklyHourRecordEmail')(Self);
|
||||||
require('../methods/worker-time-control/getMailStates')(Self);
|
require('../methods/worker-time-control/getMailStates')(Self);
|
||||||
require('../methods/worker-time-control/resendWeeklyHourEmail')(Self);
|
require('../methods/worker-time-control/resendWeeklyHourEmail')(Self);
|
||||||
|
require('../methods/worker-time-control/login')(Self);
|
||||||
|
require('../methods/worker-time-control/getClockIn')(Self);
|
||||||
|
require('../methods/worker-time-control/clockIn')(Self);
|
||||||
|
|
||||||
Self.rewriteDbError(function(err) {
|
Self.rewriteDbError(function(err) {
|
||||||
if (err.code === 'ER_DUP_ENTRY')
|
if (err.code === 'ER_DUP_ENTRY')
|
||||||
|
|
Loading…
Reference in New Issue
el acl sobre renewToken ya debería estar definido para $owner, si no es asi definirlo
@juan podemos mirarlo?