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á
|
||||
* fichada a la tabla vn.workerTimeControl
|
||||
*/
|
||||
|
||||
DECLARE vLastIn DATETIME;
|
||||
DECLARE vLastOut DATETIME;
|
||||
DECLARE vNextIn DATETIME;
|
||||
|
@ -40,6 +39,7 @@ BEGIN
|
|||
DECLARE vIsManual BOOLEAN DEFAULT TRUE;
|
||||
DECLARE vMaxWorkShortCycle INT;
|
||||
DECLARE vMaxWorkLongCycle INT;
|
||||
DECLARE vReentryWaitTime TIME DEFAULT NULL;
|
||||
|
||||
DECLARE EXIT HANDLER FOR SQLSTATE '45000'
|
||||
BEGIN
|
||||
|
@ -59,7 +59,7 @@ BEGIN
|
|||
SET vErrorMessage = 'Error sin definir';
|
||||
END IF;
|
||||
|
||||
SELECT vErrorMessage `error`;
|
||||
SELECT CONCAT(vErrorMessage, IFNULL(DATE_FORMAT(vReentryWaitTime, '%i:%s'), '')) `error`;
|
||||
SELECT CONCAT(vUserName,
|
||||
' no ha podido fichar por el siguiente problema: ',
|
||||
vErrorMessage)
|
||||
|
@ -124,6 +124,16 @@ BEGIN
|
|||
|
||||
-- DIRECCION CORRECTA
|
||||
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((IF(option1 IN ('inMiddle', 'outMiddle'),
|
||||
'middle',
|
||||
|
@ -204,8 +214,6 @@ BEGIN
|
|||
CALL util.throw(vErrorCode);
|
||||
END IF;
|
||||
|
||||
|
||||
|
||||
IF (vDirection IN('in', 'out')) THEN
|
||||
-- VERIFICA MAXIMO TIEMPO DESDE ENTRADA HASTA LA SALIDA
|
||||
|
||||
|
@ -291,5 +299,6 @@ BEGIN
|
|||
|
||||
SELECT LAST_INSERT_ID() id;
|
||||
|
||||
END$$
|
||||
END
|
||||
$$
|
||||
DELIMITER ;
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
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
|
||||
/**
|
||||
* 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
|
||||
* @return (option1, option2)
|
||||
* Los valores posibles de retorno son ('in', 'inMiddle', 'outMiddle', 'out')
|
||||
* @return tmp.workerTimeControlDirection(option1, option2, reentryWaitTime)
|
||||
* Valores posibles options('in', 'inMiddle', 'outMiddle', 'out')
|
||||
*/
|
||||
DECLARE vLastIn DATETIME;
|
||||
DECLARE vLastMiddleIn DATETIME;
|
||||
DECLARE vIsMiddleOdd BOOLEAN;
|
||||
DECLARE vMailTo VARCHAR(50) DEFAULT NULL;
|
||||
DECLARE vUserName VARCHAR(50) DEFAULT NULL;
|
||||
DECLARE vReentryWaitTime TIME;
|
||||
|
||||
IF (vTimed IS NULL) THEN
|
||||
SET vTimed = util.VN_NOW();
|
||||
|
@ -33,7 +38,8 @@ BEGIN
|
|||
DROP TEMPORARY TABLE IF EXISTS tmp.workerTimeControlDirection;
|
||||
CREATE TEMPORARY TABLE tmp.workerTimeControlDirection
|
||||
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,
|
||||
CASE WHEN w.direction ='in' THEN 'inMiddle'
|
||||
WHEN w.direction = 'out' THEN 'in'
|
||||
|
@ -59,6 +65,26 @@ BEGIN
|
|||
VALUES('in', NULL);
|
||||
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
|
||||
SELECT CONCAT(u.name, '@verdnatura.es'), CONCAT(w.firstName, ' ', w.lastName)
|
||||
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;
|
||||
});
|
||||
|
||||
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 {
|
||||
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);
|
||||
dated.setHours(15, 14, 0);
|
||||
dated.setHours(05, 14, 0);
|
||||
await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
|
||||
|
||||
const start = new Date(dated - 1);
|
||||
|
@ -124,9 +124,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
|
|||
|
||||
try {
|
||||
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);
|
||||
dated.setHours(15, 15, 0);
|
||||
dated.setHours(05, 15, 0);
|
||||
await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
|
||||
|
||||
const start = new Date(dated - 1);
|
||||
|
@ -153,9 +153,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
|
|||
|
||||
try {
|
||||
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);
|
||||
dated.setHours(15, 24, 0);
|
||||
dated.setHours(05, 24, 0);
|
||||
await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
|
||||
|
||||
const start = new Date(dated - 1);
|
||||
|
@ -182,9 +182,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
|
|||
|
||||
try {
|
||||
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);
|
||||
dated.setHours(15, 25, 0);
|
||||
dated.setHours(05, 25, 0);
|
||||
await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
|
||||
|
||||
const start = new Date(dated - 1);
|
||||
|
@ -211,9 +211,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
|
|||
|
||||
try {
|
||||
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);
|
||||
dated.setHours(15, 59, 0);
|
||||
dated.setHours(05, 59, 0);
|
||||
await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
|
||||
|
||||
const start = new Date(dated - 1);
|
||||
|
@ -240,9 +240,9 @@ describe('workerTimeControl add/delete timeEntry()', () => {
|
|||
|
||||
try {
|
||||
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);
|
||||
dated.setHours(16, 0, 0);
|
||||
dated.setHours(06, 0, 0);
|
||||
await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
|
||||
|
||||
const start = new Date(dated - 1);
|
||||
|
@ -286,10 +286,10 @@ async function populateWeek(date, dayStart, dayEnd, ctx, workerId, options) {
|
|||
dateEnd.setDate(dateStart.getDate() + dayEnd);
|
||||
|
||||
for (let i = dayStart; i <= dayEnd; i++) {
|
||||
dateStart.setHours(10, 0, 0);
|
||||
dateStart.setHours(00, 0, 0);
|
||||
ctx.args = {timed: dateStart, direction: 'in'};
|
||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||
dateStart.setHours(18, 0, 0);
|
||||
dateStart.setHours(08, 0, 0);
|
||||
ctx.args = {timed: dateStart, direction: 'out'};
|
||||
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
|
||||
dateStart.setDate(dateStart.getDate() + 1);
|
||||
|
|
Loading…
Reference in New Issue