Merge branch 'dev' into 7912-wasteCost
gitea/salix/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Guillermo Bonet 2025-03-03 06:09:36 +00:00
commit 3871c9c505
5 changed files with 188 additions and 77 deletions

View File

@ -18,14 +18,13 @@ BEGIN
* Solo retorna el primer problema, en caso de no ocurrir ningún error se añadirá * Solo retorna el primer problema, en caso de no ocurrir ningún error se añadirá
* fichada a la tabla vn.workerTimeControl * fichada a la tabla vn.workerTimeControl
*/ */
DECLARE vLastIn DATETIME; DECLARE vLastIn DATETIME;
DECLARE vLastOut DATETIME; DECLARE vLastOut DATETIME;
DECLARE vNextIn DATETIME; DECLARE vNextIn DATETIME;
DECLARE vNextOut DATETIME; DECLARE vNextOut DATETIME;
DECLARE vNextDirection ENUM('in', 'out'); DECLARE vNextDirection ENUM('in', 'out');
DECLARE vLastDirection ENUM('in', 'out'); DECLARE vLastDirection ENUM('in', 'out');
DECLARE vDayMaxTime INTEGER; DECLARE vDayMaxTime INTEGER;
DECLARE vDayBreak INT; DECLARE vDayBreak INT;
DECLARE vShortWeekBreak INT; DECLARE vShortWeekBreak INT;
DECLARE vLongWeekBreak INT; DECLARE vLongWeekBreak INT;
@ -40,6 +39,7 @@ BEGIN
DECLARE vIsManual BOOLEAN DEFAULT TRUE; DECLARE vIsManual BOOLEAN DEFAULT TRUE;
DECLARE vMaxWorkShortCycle INT; DECLARE vMaxWorkShortCycle INT;
DECLARE vMaxWorkLongCycle INT; DECLARE vMaxWorkLongCycle INT;
DECLARE vReentryWaitTime TIME DEFAULT NULL;
DECLARE EXIT HANDLER FOR SQLSTATE '45000' DECLARE EXIT HANDLER FOR SQLSTATE '45000'
BEGIN BEGIN
@ -52,19 +52,19 @@ BEGIN
WHERE w.id = vWorkerFk; WHERE w.id = vWorkerFk;
SELECT `description` INTO vErrorMessage SELECT `description` INTO vErrorMessage
FROM workerTimeControlError FROM workerTimeControlError
WHERE `code` = vErrorCode; WHERE `code` = vErrorCode;
IF vErrorMessage IS NULL THEN IF vErrorMessage IS NULL THEN
SET vErrorMessage = 'Error sin definir'; SET vErrorMessage = 'Error sin definir';
END IF; END IF;
SELECT vErrorMessage `error`; SELECT CONCAT(vErrorMessage, IFNULL(DATE_FORMAT(vReentryWaitTime, '%i:%s'), '')) `error`;
SELECT CONCAT(vUserName, SELECT CONCAT(vUserName,
' no ha podido fichar por el siguiente problema: ', ' no ha podido fichar por el siguiente problema: ',
vErrorMessage) vErrorMessage)
INTO vErrorMessage; INTO vErrorMessage;
CALL mail_insert( vMailTo, vMailTo, 'Error al fichar', vErrorMessage); CALL mail_insert( vMailTo, vMailTo, 'Error al fichar', vErrorMessage);
END; END;
@ -97,19 +97,19 @@ BEGIN
JOIN workerTimeControlConfig wc JOIN workerTimeControlConfig wc
WHERE b.workerFk = vWorkerFk WHERE b.workerFk = vWorkerFk
AND vDated BETWEEN b.started AND IFNULL(b.ended, vDated); AND vDated BETWEEN b.started AND IFNULL(b.ended, vDated);
-- CONTRATO EN VIGOR -- CONTRATO EN VIGOR
IF vDayBreak IS NULL THEN IF vDayBreak IS NULL THEN
SET vErrorCode = 'INACTIVE_BUSINESS'; SET vErrorCode = 'INACTIVE_BUSINESS';
CALL util.throw(vErrorCode); CALL util.throw(vErrorCode);
END IF; END IF;
-- FICHADAS A FUTURO -- FICHADAS A FUTURO
IF vTimed > util.VN_NOW() + INTERVAL 1 MINUTE THEN IF vTimed > util.VN_NOW() + INTERVAL 1 MINUTE THEN
SET vErrorCode = 'IS_NOT_ALLOWED_FUTURE'; SET vErrorCode = 'IS_NOT_ALLOWED_FUTURE';
CALL util.throw(vErrorCode); CALL util.throw(vErrorCode);
END IF; END IF;
-- VERIFICAR SI ESTÁ PERMITIDO TRABAJAR -- VERIFICAR SI ESTÁ PERMITIDO TRABAJAR
CALL timeBusiness_calculateByWorker(vWorkerFk, vDated, vDated); CALL timeBusiness_calculateByWorker(vWorkerFk, vDated, vDated);
SELECT isAllowedToWork INTO vIsAllowedToWork SELECT isAllowedToWork INTO vIsAllowedToWork
@ -124,6 +124,16 @@ BEGIN
-- DIRECCION CORRECTA -- DIRECCION CORRECTA
CALL workerTimeControl_direction(vWorkerFk, vTimed); CALL workerTimeControl_direction(vWorkerFk, vTimed);
SELECT reentryWaitTime INTO vReentryWaitTime
FROM tmp.workerTimeControlDirection
LIMIT 1;
IF vReentryWaitTime IS NOT NULL THEN
SET vErrorCode = 'WAIT_TIME';
CALL util.throw(vErrorCode);
END IF;
IF (SELECT IF (SELECT
IF((IF(option1 IN ('inMiddle', 'outMiddle'), IF((IF(option1 IN ('inMiddle', 'outMiddle'),
'middle', 'middle',
@ -138,13 +148,13 @@ BEGIN
) THEN ) THEN
SET vIsError = TRUE; SET vIsError = TRUE;
END IF; END IF;
IF vIsError THEN IF vIsError THEN
SET vErrorCode = 'WRONG_DIRECTION'; SET vErrorCode = 'WRONG_DIRECTION';
IF(SELECT option1 IS NULL AND option2 IS NULL IF(SELECT option1 IS NULL AND option2 IS NULL
FROM tmp.workerTimeControlDirection) THEN FROM tmp.workerTimeControlDirection) THEN
SET vErrorCode = 'DAY_MAX_TIME'; SET vErrorCode = 'DAY_MAX_TIME';
END IF; END IF;
CALL util.throw(vErrorCode); CALL util.throw(vErrorCode);
@ -158,7 +168,7 @@ BEGIN
AND timed < vTimed AND timed < vTimed
ORDER BY timed DESC ORDER BY timed DESC
LIMIT 1; LIMIT 1;
IF (SELECT IF(vDirection = 'in', IF (SELECT IF(vDirection = 'in',
MOD(COUNT(*), 2) , MOD(COUNT(*), 2) ,
IF (vDirection = 'out', NOT MOD(COUNT(*), 2), FALSE)) IF (vDirection = 'out', NOT MOD(COUNT(*), 2), FALSE))
@ -169,7 +179,7 @@ BEGIN
SET vErrorCode = 'ODD_WORKERTIMECONTROL'; SET vErrorCode = 'ODD_WORKERTIMECONTROL';
CALL util.throw(vErrorCode); CALL util.throw(vErrorCode);
END IF; END IF;
-- DESCANSO DIARIO -- DESCANSO DIARIO
SELECT timed INTO vLastOut SELECT timed INTO vLastOut
FROM workerTimeControl FROM workerTimeControl
@ -178,7 +188,7 @@ BEGIN
AND timed < vTimed AND timed < vTimed
ORDER BY timed DESC ORDER BY timed DESC
LIMIT 1; LIMIT 1;
SELECT timed INTO vNextIn SELECT timed INTO vNextIn
FROM workerTimeControl FROM workerTimeControl
WHERE userFk = vWorkerFk WHERE userFk = vWorkerFk
@ -186,7 +196,7 @@ BEGIN
AND timed > vTimed AND timed > vTimed
ORDER BY timed ASC ORDER BY timed ASC
LIMIT 1; LIMIT 1;
CASE vDirection CASE vDirection
WHEN 'in' THEN WHEN 'in' THEN
IF UNIX_TIMESTAMP(vTimed) - UNIX_TIMESTAMP(vLastOut) <= vDayBreak THEN IF UNIX_TIMESTAMP(vTimed) - UNIX_TIMESTAMP(vLastOut) <= vDayBreak THEN
@ -204,11 +214,9 @@ BEGIN
CALL util.throw(vErrorCode); CALL util.throw(vErrorCode);
END IF; END IF;
IF (vDirection IN('in', 'out')) THEN IF (vDirection IN('in', 'out')) THEN
-- VERIFICA MAXIMO TIEMPO DESDE ENTRADA HASTA LA SALIDA -- VERIFICA MAXIMO TIEMPO DESDE ENTRADA HASTA LA SALIDA
SELECT timed INTO vNextOut SELECT timed INTO vNextOut
FROM workerTimeControl FROM workerTimeControl
WHERE userFk = vWorkerFk WHERE userFk = vWorkerFk
@ -216,7 +224,7 @@ BEGIN
AND timed > vTimed AND timed > vTimed
ORDER BY timed ASC ORDER BY timed ASC
LIMIT 1; LIMIT 1;
SELECT direction INTO vNextDirection SELECT direction INTO vNextDirection
FROM workerTimeControl FROM workerTimeControl
WHERE userFk = vWorkerFk WHERE userFk = vWorkerFk
@ -224,7 +232,7 @@ BEGIN
AND timed > vTimed AND timed > vTimed
ORDER BY timed ASC ORDER BY timed ASC
LIMIT 1; LIMIT 1;
SELECT direction INTO vLastDirection SELECT direction INTO vLastDirection
FROM workerTimeControl FROM workerTimeControl
WHERE userFk = vWorkerFk WHERE userFk = vWorkerFk
@ -232,34 +240,34 @@ BEGIN
AND timed < vTimed AND timed < vTimed
ORDER BY timed ASC ORDER BY timed ASC
LIMIT 1; LIMIT 1;
IF (vDirection ='in' IF (vDirection ='in'
AND vNextDirection = 'out' AND vNextDirection = 'out'
AND UNIX_TIMESTAMP(vNextOut) - UNIX_TIMESTAMP(vTimed) > vDayMaxTime) OR AND UNIX_TIMESTAMP(vNextOut) - UNIX_TIMESTAMP(vTimed) > vDayMaxTime) OR
(vDirection ='out' (vDirection ='out'
AND vLastDirection = 'in' AND vLastDirection = 'in'
AND UNIX_TIMESTAMP(vTimed) -UNIX_TIMESTAMP(vLastIn) > vDayMaxTime) THEN AND UNIX_TIMESTAMP(vTimed) - UNIX_TIMESTAMP(vLastIn) > vDayMaxTime) THEN
SET vErrorCode = 'DAY_MAX_TIME'; SET vErrorCode = 'DAY_MAX_TIME';
CALL util.throw(vErrorCode); CALL util.throw(vErrorCode);
END IF; END IF;
-- VERIFICA DESCANSO SEMANAL -- VERIFICA DESCANSO SEMANAL
WITH wtc AS( WITH wtc AS(
(SELECT timed (SELECT timed
FROM vn.workerTimeControl FROM vn.workerTimeControl
WHERE userFk = vWorkerFk WHERE userFk = vWorkerFk
AND direction IN ('in', 'out') AND direction IN ('in', 'out')
AND timed BETWEEN vTimed - INTERVAL (vWeekScope * 2) SECOND AND timed BETWEEN vTimed - INTERVAL (vWeekScope * 2) SECOND
AND vTimed + INTERVAL (vWeekScope * 2) SECOND ) AND vTimed + INTERVAL (vWeekScope * 2) SECOND )
UNION UNION
(SELECT vTimed) (SELECT vTimed)
), wtcGap AS( ), wtcGap AS(
SELECT timed, SELECT timed,
TIMESTAMPDIFF(SECOND, LAG(timed) OVER (ORDER BY timed), timed) gap TIMESTAMPDIFF(SECOND, LAG(timed) OVER (ORDER BY timed), timed) gap
FROM wtc FROM wtc
ORDER BY timed ORDER BY timed
), wtcBreak AS( ), wtcBreak AS(
SELECT timed, SELECT timed,
IF(IFNULL(gap, 0) > vShortWeekBreak, TRUE, FALSE) hasShortBreak, IF(IFNULL(gap, 0) > vShortWeekBreak, TRUE, FALSE) hasShortBreak,
IF(IFNULL(gap, 0) > vLongWeekBreak, TRUE, FALSE) hasLongBreak IF(IFNULL(gap, 0) > vLongWeekBreak, TRUE, FALSE) hasLongBreak
@ -270,8 +278,8 @@ BEGIN
SUM(hasShortBreak) OVER (ORDER BY timed) breakCounter , SUM(hasShortBreak) OVER (ORDER BY timed) breakCounter ,
LEAD(hasLongBreak) OVER (ORDER BY timed) nextHasLongBreak LEAD(hasLongBreak) OVER (ORDER BY timed) nextHasLongBreak
FROM wtcBreak FROM wtcBreak
)SELECT TIMESTAMPDIFF(SECOND, MIN(timed), MAX(timed)) > vMaxWorkLongCycle OR )SELECT TIMESTAMPDIFF(SECOND, MIN(timed), MAX(timed)) > vMaxWorkLongCycle OR
(TIMESTAMPDIFF(SECOND, MIN(timed), MAX(timed))> vMaxWorkShortCycle (TIMESTAMPDIFF(SECOND, MIN(timed), MAX(timed))> vMaxWorkShortCycle
AND NOT SUM(IFNULL(nextHasLongBreak, 1))) AND NOT SUM(IFNULL(nextHasLongBreak, 1)))
hasError INTO vIsError hasError INTO vIsError
FROM wtcBreakCounter FROM wtcBreakCounter
@ -291,5 +299,6 @@ BEGIN
SELECT LAST_INSERT_ID() id; SELECT LAST_INSERT_ID() id;
END$$ END
$$
DELIMITER ; DELIMITER ;

View File

@ -1,39 +1,45 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`workerTimeControl_direction`(vWorkerFk VARCHAR(10), vTimed DATETIME) CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`workerTimeControl_direction`(
vWorkerFk VARCHAR(10),
vTimed DATETIME
)
BEGIN BEGIN
/** /**
* Devuelve que direcciones de fichadas son lógicas a partir de la anterior fichada * Devuelve que direcciones de fichadas son lógicas a partir de la anterior fichada,
* @param vWorkerFk Identificador del trabajador * @param vWorkerFk Identificador del trabajador
* @return (option1, option2) * @return tmp.workerTimeControlDirection(option1, option2, reentryWaitTime)
* Los valores posibles de retorno son ('in', 'inMiddle', 'outMiddle', 'out') * Valores posibles options('in', 'inMiddle', 'outMiddle', 'out')
*/ */
DECLARE vLastIn DATETIME ; DECLARE vLastIn DATETIME;
DECLARE vIsMiddleOdd BOOLEAN ; DECLARE vLastMiddleIn DATETIME;
DECLARE vIsMiddleOdd BOOLEAN;
DECLARE vMailTo VARCHAR(50) DEFAULT NULL; DECLARE vMailTo VARCHAR(50) DEFAULT NULL;
DECLARE vUserName VARCHAR(50) DEFAULT NULL; DECLARE vUserName VARCHAR(50) DEFAULT NULL;
DECLARE vReentryWaitTime TIME;
IF (vTimed IS NULL) THEN IF (vTimed IS NULL) THEN
SET vTimed = util.VN_NOW(); SET vTimed = util.VN_NOW();
END IF; END IF;
SELECT timed INTO vLastIn SELECT timed INTO vLastIn
FROM workerTimeControl FROM workerTimeControl
WHERE userFk = vWorkerFk WHERE userFk = vWorkerFk
AND direction = 'in' AND direction = 'in'
AND timed < vTimed AND timed < vTimed
ORDER BY timed DESC ORDER BY timed DESC
LIMIT 1; LIMIT 1;
SELECT (COUNT(*)mod 2 = 1) INTO vIsMiddleOdd SELECT (COUNT(*)mod 2 = 1) INTO vIsMiddleOdd
FROM workerTimeControl FROM workerTimeControl
WHERE userFk = vWorkerFk WHERE userFk = vWorkerFk
AND direction = 'middle' AND direction = 'middle'
AND timed BETWEEN vLastIn AND vTimed; AND timed BETWEEN vLastIn AND vTimed;
DROP TEMPORARY TABLE IF EXISTS tmp.workerTimeControlDirection; DROP TEMPORARY TABLE IF EXISTS tmp.workerTimeControlDirection;
CREATE TEMPORARY TABLE tmp.workerTimeControlDirection CREATE TEMPORARY TABLE tmp.workerTimeControlDirection
SELECT IF(isCorrect, option1, NULL) option1, SELECT IF(isCorrect, option1, NULL) option1,
IF(isCorrect, option2, NULL) option2 IF(isCorrect, option2, NULL) option2,
CAST(NULL AS TIME) reentryWaitTime
FROM( SELECT IF(w.direction <> 'out' AND (UNIX_TIMESTAMP(vTimed) - UNIX_TIMESTAMP(w.timed) > wc.dayBreak), FALSE, TRUE) isCorrect, FROM( SELECT IF(w.direction <> 'out' AND (UNIX_TIMESTAMP(vTimed) - UNIX_TIMESTAMP(w.timed) > wc.dayBreak), FALSE, TRUE) isCorrect,
CASE WHEN w.direction ='in' THEN 'inMiddle' CASE WHEN w.direction ='in' THEN 'inMiddle'
WHEN w.direction = 'out' THEN 'in' WHEN w.direction = 'out' THEN 'in'
@ -59,6 +65,26 @@ BEGIN
VALUES('in', NULL); VALUES('in', NULL);
END IF; END IF;
IF (SELECT option1 ='outMiddle' AND option2 IS NULL FROM tmp.workerTimeControlDirection) THEN
SELECT timed INTO vLastMiddleIn
FROM workerTimeControl
WHERE userFk = vWorkerFk
AND timed < vTimed
ORDER BY timed DESC
LIMIT 1;
SELECT TIMEDIFF(vLastMiddleIn + INTERVAL wtc.maxTimeToBreak SECOND, vTimed) INTO vReentryWaitTime
FROM tmp.workerTimeControlDirection wt
JOIN workerTimeControlConfig wtc
WHERE TIME(vLastMiddleIn) BETWEEN wtc.mandatoryBreakFrom AND wtc.mandatoryBreakTo
AND TIMESTAMPDIFF(SECOND, vLastMiddleIn, vTimed) < wtc.maxTimeToBreak;
IF vReentryWaitTime THEN
UPDATE tmp.workerTimeControlDirection
SET reentryWaitTime = vReentryWaitTime;
END IF;
END IF;
IF (SELECT option1 IS NULL AND option2 IS NULL FROM tmp.workerTimeControlDirection) THEN IF (SELECT option1 IS NULL AND option2 IS NULL FROM tmp.workerTimeControlDirection) THEN
SELECT CONCAT(u.name, '@verdnatura.es'), CONCAT(w.firstName, ' ', w.lastName) SELECT CONCAT(u.name, '@verdnatura.es'), CONCAT(w.firstName, ' ', w.lastName)
INTO vMailTo, vUserName INTO vMailTo, vUserName
@ -66,10 +92,10 @@ BEGIN
JOIN worker w ON w.bossFk = u.id JOIN worker w ON w.bossFk = u.id
WHERE w.id = vWorkerFk; WHERE w.id = vWorkerFk;
CALL mail_insert( CALL mail_insert(
vMailTo, vMailTo,
vMailTo, vMailTo,
'Error al fichar', 'Error al fichar',
CONCAT(vUserName, ' tiene problemas para fichar')); CONCAT(vUserName, ' tiene problemas para fichar'));
END IF; END IF;
END$$ END$$

View File

@ -0,0 +1,8 @@
ALTER TABLE vn.workerTimeControlConfig
ADD COLUMN `mandatoryBreakFrom` time DEFAULT '12:00:00'
COMMENT 'Tiempo desde el que se obligará a realizar un descanso para jornada partida';
ALTER TABLE vn.workerTimeControlConfig
ADD COLUMN `mandatoryBreakTo` time DEFAULT '15:00:00';
INSERT INTO vn.workerTimeControlError (`code`, `description`)
VALUES ('WAIT_TIME', 'El descanso terminará en ');

View File

@ -45,7 +45,7 @@ describe('workerTimeControl clockIn()', () => {
throw e; throw e;
} }
}); });
it('should throw an error trying to change a middle hour to out not resting 12h', async() => { it('should throw an error trying to change a middle hour to out not resting 12h', async() => {
activeCtx.accessToken.userId = HHRRId; activeCtx.accessToken.userId = HHRRId;
const workerId = teamBossId; const workerId = teamBossId;
@ -61,7 +61,7 @@ describe('workerTimeControl clockIn()', () => {
const middleTime ="2000-12-26T11:00:00.000Z"; const middleTime ="2000-12-26T11:00:00.000Z";
ctx.args = {timed: middleTime, direction: 'middle'}; ctx.args = {timed: middleTime, direction: 'middle'};
const middleEntryTime = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); const middleEntryTime = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
const direction = 'out'; const direction = 'out';
await models.WorkerTimeControl.updateTimeEntry(ctx, middleEntryTime.id, direction, options); await models.WorkerTimeControl.updateTimeEntry(ctx, middleEntryTime.id, direction, options);
await tx.rollback(); await tx.rollback();
@ -87,7 +87,7 @@ describe('workerTimeControl clockIn()', () => {
ctx.args = {timed: middleTime, direction: 'middle'}; ctx.args = {timed: middleTime, direction: 'middle'};
const middleEntryTime = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); const middleEntryTime = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
middleEntryTime.updateAttribute('manual', false); middleEntryTime.updateAttribute('manual', false);
const direction = 'out'; const direction = 'out';
const outTimeEntryId = await models.WorkerTimeControl.updateTimeEntry(ctx, middleEntryTime.id, direction, options); const outTimeEntryId = await models.WorkerTimeControl.updateTimeEntry(ctx, middleEntryTime.id, direction, options);
@ -111,10 +111,10 @@ describe('workerTimeControl clockIn()', () => {
ctx.args = {timed: "2000-12-25T22:00:00.000Z", direction: 'middle'}; ctx.args = {timed: "2000-12-25T22:00:00.000Z", direction: 'middle'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
ctx.args = {timed: "2000-12-25T22:30:00.000Z", direction: 'middle'}; ctx.args = {timed: "2000-12-25T22:30:00.000Z", direction: 'middle'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
ctx.args = {timed: "2000-12-26T01:00:00.000Z", direction: 'in'}; ctx.args = {timed: "2000-12-26T01:00:00.000Z", direction: 'in'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
@ -196,7 +196,7 @@ describe('workerTimeControl clockIn()', () => {
todayAtTwo.setHours(2, 0, 0, 0); todayAtTwo.setHours(2, 0, 0, 0);
ctx.args = {timed: todayAtTwo, direction: 'middle'}; ctx.args = {timed: todayAtTwo, direction: 'middle'};
const middleTime = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); const middleTime = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
const direction = 'out'; const direction = 'out';
const outTimeEntryId = await models.WorkerTimeControl.updateTimeEntry( const outTimeEntryId = await models.WorkerTimeControl.updateTimeEntry(
ctx, middleTime.id, direction, options ctx, middleTime.id, direction, options
@ -204,7 +204,7 @@ describe('workerTimeControl clockIn()', () => {
const {direction: updatedDirection} = await models.WorkerTimeControl.findById(outTimeEntryId,{fields:['direction']},options); const {direction: updatedDirection} = await models.WorkerTimeControl.findById(outTimeEntryId,{fields:['direction']},options);
expect(updatedDirection).toEqual('out'); expect(updatedDirection).toEqual('out');
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
await tx.rollback(); await tx.rollback();
@ -544,7 +544,7 @@ describe('workerTimeControl clockIn()', () => {
}); });
describe('for 72h weekly rest', () => { describe('for 72h weekly rest', () => {
it('should throw an error when work 11 consecutive days', async() => { it('should throw an error when work 11 consecutive days', async() => {
let date = Date.vnNew(); let date = Date.vnNew();
date.setMonth(date.getMonth() - 1); date.setMonth(date.getMonth() - 1);
@ -598,7 +598,7 @@ describe('workerTimeControl clockIn()', () => {
expect(error.message).toBe(`Descanso semanal`); expect(error.message).toBe(`Descanso semanal`);
}); });
it('should throw an error when the 72h weekly rest is fulfilled', async() => { it('should throw an error when the 72h weekly rest is fulfilled', async() => {
let date = Date.vnNew(); let date = Date.vnNew();
@ -626,6 +626,74 @@ describe('workerTimeControl clockIn()', () => {
expect(error).not.toBeDefined; expect(error).not.toBeDefined;
}); });
it('should enforce a 1-hour break if the break starts between 12:00 and 15:00', 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};
try {
date.setHours(11, 0, 0);
ctx.args = {timed: date, direction: 'in'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
date.setHours(13, 30, 0);
ctx.args = {timed: date, direction: 'middle'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
date.setHours(14, 0, 0);
ctx.args = {timed: date, direction: 'middle'};
let error;
try {
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(error.statusCode).toBe(400);
expect(error.message).toMatch(/El descanso terminará en \d{2}:\d{2}/);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should allow resuming work after a full 1-hour break', 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};
try {
date.setHours(11, 0, 0);
ctx.args = {timed: date, direction: 'in'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
date.setHours(14, 00, 0);
ctx.args = {timed: date, direction: 'middle'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
date.setHours(15, 00, 0);
ctx.args = {timed: date, direction: 'middle'};
let error;
try {
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
} catch (e) {
error = e;
}
expect(error).toBeUndefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
}); });
}); });
}); });

View File

@ -95,9 +95,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
try { try {
await populateWeek(dated, monday, monday, ctx, hankPymId, options); await populateWeek(dated, monday, monday, ctx, hankPymId, options);
dated.setHours(14, 59, 0); dated.setHours(04, 59, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
dated.setHours(15, 14, 0); dated.setHours(05, 14, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
const start = new Date(dated - 1); const start = new Date(dated - 1);
@ -124,9 +124,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
try { try {
await populateWeek(dated, monday, monday, ctx, hankPymId, options); await populateWeek(dated, monday, monday, ctx, hankPymId, options);
dated.setHours(15, 0, 0); dated.setHours(05, 0, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
dated.setHours(15, 15, 0); dated.setHours(05, 15, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
const start = new Date(dated - 1); const start = new Date(dated - 1);
@ -153,9 +153,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
try { try {
await populateWeek(dated, monday, monday, ctx, hankPymId, options); await populateWeek(dated, monday, monday, ctx, hankPymId, options);
dated.setHours(14, 59, 0); dated.setHours(04, 59, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
dated.setHours(15, 24, 0); dated.setHours(05, 24, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
const start = new Date(dated - 1); const start = new Date(dated - 1);
@ -182,9 +182,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
try { try {
await populateWeek(dated, monday, monday, ctx, hankPymId, options); await populateWeek(dated, monday, monday, ctx, hankPymId, options);
dated.setHours(15, 0, 0); dated.setHours(05, 0, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
dated.setHours(15, 25, 0); dated.setHours(05, 25, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
const start = new Date(dated - 1); const start = new Date(dated - 1);
@ -211,9 +211,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
try { try {
await populateWeek(dated, monday, monday, ctx, hankPymId, options); await populateWeek(dated, monday, monday, ctx, hankPymId, options);
dated.setHours(14, 59, 0); dated.setHours(04, 59, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
dated.setHours(15, 59, 0); dated.setHours(05, 59, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
const start = new Date(dated - 1); const start = new Date(dated - 1);
@ -240,9 +240,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
try { try {
await populateWeek(dated, monday, monday, ctx, hankPymId, options); await populateWeek(dated, monday, monday, ctx, hankPymId, options);
dated.setHours(15, 0, 0); dated.setHours(05, 0, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
dated.setHours(16, 0, 0); dated.setHours(06, 0, 0);
await addTimeEntry(ctx, dated, 'middle', hankPymId, options); await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
const start = new Date(dated - 1); const start = new Date(dated - 1);
@ -286,10 +286,10 @@ async function populateWeek(date, dayStart, dayEnd, ctx, workerId, options) {
dateEnd.setDate(dateStart.getDate() + dayEnd); dateEnd.setDate(dateStart.getDate() + dayEnd);
for (let i = dayStart; i <= dayEnd; i++) { for (let i = dayStart; i <= dayEnd; i++) {
dateStart.setHours(10, 0, 0); dateStart.setHours(00, 0, 0);
ctx.args = {timed: dateStart, direction: 'in'}; ctx.args = {timed: dateStart, direction: 'in'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
dateStart.setHours(18, 0, 0); dateStart.setHours(08, 0, 0);
ctx.args = {timed: dateStart, direction: 'out'}; ctx.args = {timed: dateStart, direction: 'out'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
dateStart.setDate(dateStart.getDate() + 1); dateStart.setDate(dateStart.getDate() + 1);