Merge branch 'dev' into 7912-wasteCost
gitea/salix/pipeline/pr-dev This commit looks good
Details
gitea/salix/pipeline/pr-dev This commit looks good
Details
This commit is contained in:
commit
3871c9c505
|
@ -18,7 +18,6 @@ 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;
|
||||||
|
@ -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
|
||||||
|
@ -59,7 +59,7 @@ BEGIN
|
||||||
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)
|
||||||
|
@ -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',
|
||||||
|
@ -204,8 +214,6 @@ 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
|
||||||
|
|
||||||
|
@ -291,5 +299,6 @@ BEGIN
|
||||||
|
|
||||||
SELECT LAST_INSERT_ID() id;
|
SELECT LAST_INSERT_ID() id;
|
||||||
|
|
||||||
END$$
|
END
|
||||||
|
$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
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 vLastMiddleIn DATETIME;
|
||||||
DECLARE vIsMiddleOdd BOOLEAN;
|
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();
|
||||||
|
@ -33,7 +38,8 @@ BEGIN
|
||||||
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
|
||||||
|
|
|
@ -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 ');
|
|
@ -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;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue