diff --git a/CHANGELOG.md b/CHANGELOG.md
index cd6ed4522..29d270a3e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,21 +11,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
### Fixed
+
## [2342.01] - 2023-11-02
-### Added
-### Changed
-### Fixed
-
-## [2340.01] - 2023-10-05
-
### Added
- (Usuarios -> Foto) Se muestra la foto del trabajador
-
-### Changed
### Fixed
- (Usuarios -> Historial) Abre el descriptor del usuario correctamente
+
+## [2340.01] - 2023-10-05
+
## [2338.01] - 2023-09-21
### Added
@@ -35,17 +31,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- (Trabajadores -> Calendario) Icono de check arreglado cuando pulsas un tipo de dia
-### Fixed
-
## [2336.01] - 2023-09-07
-### Added
-
-### Changed
-
-### Fixed
-
-
## [2334.01] - 2023-08-24
### Added
diff --git a/db/changes/234004/.gitkeep b/db/changes/234004/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/db/changes/234004/00-workerTimeControl.sql b/db/changes/234004/00-workerTimeControl.sql
new file mode 100644
index 000000000..8f6263533
--- /dev/null
+++ b/db/changes/234004/00-workerTimeControl.sql
@@ -0,0 +1,41 @@
+UPDATE `vn`.`workerTimeControlConfig`
+ SET `timeToBreakTime` = 18000;
+
+ALTER TABLE `vn`.`workerTimeControlConfig`
+ DROP COLUMN IF EXISTS `maxTimeToBreak`;
+ALTER TABLE `vn`.`workerTimeControlConfig`
+ ADD COLUMN maxTimeToBreak INT DEFAULT 3600 NULL;
+
+ALTER TABLE `vn`.`workerTimeControlConfig`
+ DROP COLUMN IF EXISTS `maxWorkShortCycle`;
+
+ALTER TABLE `vn`.`workerTimeControlConfig`
+ ADD COLUMN `maxWorkShortCycle` INT(10) UNSIGNED DEFAULT 561600
+ COMMENT 'Máximo tiempo que un trabajador puede estar trabajando con el que adquirirá el derecho a un descanso semanal corto';
+
+ALTER TABLE `vn`.`workerTimeControlConfig`
+ DROP COLUMN IF EXISTS `maxWorkLongCycle`;
+
+ALTER TABLE `vn`.`workerTimeControlConfig`
+ ADD COLUMN `maxWorkLongCycle` INT(10) UNSIGNED DEFAULT 950400
+ COMMENT 'Máximo tiempo que un trabajador puede estar trabajando con el que adquirirá el derecho a un descanso semanal largo';
+
+CREATE TABLE IF NOT EXISTS `vn`.`workerTimeControlError` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `code` char(35) NOT NULL,
+ `description` varchar(255) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `code` (`code`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+
+INSERT IGNORE INTO `vn`.`workerTimeControlError` (`code`, `description`)
+ VALUES
+ ('IS_NOT_ALLOWED_FUTURE', 'No se permite fichar a futuro'),
+ ('INACTIVE_BUSINESS', 'No hay un contrato en vigor'),
+ ('IS_NOT_ALLOWED_WORK', 'No está permitido trabajar'),
+ ('ODD_WORKERTIMECONTROL', 'Fichadas impares'),
+ ('DAY_MAX_TIME', 'Superado el tiempo máximo entre entrada y salida'),
+ ('BREAK_DAY', 'Descanso diario'),
+ ('BREAK_WEEK', 'Descanso semanal'),
+ ('WRONG_DIRECTION', 'Dirección incorrecta'),
+ ('UNDEFINED_ERROR', 'Error sin definir');
\ No newline at end of file
diff --git a/db/changes/234004/01-timeControl_calculate.sql b/db/changes/234004/01-timeControl_calculate.sql
new file mode 100644
index 000000000..93d88c047
--- /dev/null
+++ b/db/changes/234004/01-timeControl_calculate.sql
@@ -0,0 +1,194 @@
+DELIMITER $$
+CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`timeControl_calculate`(
+ vDatedFrom DATETIME,
+ vDatedTo DATETIME)
+BEGIN
+/*
+ * Agrupa por trabajador y día, el tiempo de trabajo y descanso retribuido(si tiene).
+ * Los registros horarios incorrectos (tmp.timeControlError) no se considerarán.
+ * Si un trabajador ha trabajado más de un cierto umbral de tiempo (vTimeToBreakTime)
+ * y no ha tenido descansos que superen un parámetro determinado(vMaxTimeToBreak),
+ * se le añadirá un tiempo de descanso (vBreakTime) a sus horas trabajadas.
+ * El tiempo de descanso solo se añade si el trabajador realmente disfrutó del descanso.
+ * Si disfrutó de menos tiempo de descanso, solo se añade el tiempo que disfrutó.
+ *
+ * @param vDatedFrom
+ * @param vDatedTo
+ *
+ * @return tmp.timeControlCalculate
+ * (workerFk, dated, timeWorkSeconds, timeWorkSexagesimal, timeWorkDecimal, timed)
+ */
+ DECLARE vHourSeconds INTEGER;
+ DECLARE vDatedFromYesterday DATETIME;
+ DECLARE vDatedToTomorrow DATETIME;
+ DECLARE vTimeToBreakTime INT;
+ DECLARE vBreakTime INT;
+ DECLARE vMaxTimeToBreak INT;
+
+ SELECT DATE_SUB(vDatedFrom, INTERVAL 1 DAY), DATE_ADD(vDatedTo, INTERVAL 1 DAY)
+ INTO vDatedFromYesterday, vDatedToTomorrow;
+
+ SELECT timeToBreakTime, breakTime, maxTimeToBreak, TIME_TO_SEC('01:00:00')
+ INTO vTimeToBreakTime, vBreakTime, vMaxTimeToBreak, vHourSeconds
+ FROM workerTimeControlConfig
+ LIMIT 1;
+
+ CALL timeControl_getError(vDatedFromYesterday, vDatedToTomorrow);
+
+ CREATE OR REPLACE TEMPORARY TABLE tmp.workerTimeControl
+ (INDEX(userFk, timed), INDEX(timed), INDEX(direction))
+ ENGINE = MEMORY
+ SELECT wtc.userFk,
+ wtc.timed,
+ DATE(wtc.timed) dated,
+ wtc.direction,
+ TRUE isReal
+ FROM workerTimeControl wtc
+ JOIN tmp.`user` u ON u.userFk = wtc.userFk
+ LEFT JOIN (
+ SELECT wtc.userFk, MIN(wtc.timed) firstIn
+ FROM workerTimeControl wtc
+ JOIN tmp.`user` u ON u.userFk = wtc.userFk
+ LEFT JOIN tmp.timeControlError tce ON tce.id = wtc.id
+ WHERE wtc.timed BETWEEN vDatedFromYesterday AND vDatedToTomorrow
+ AND wtc.direction = 'in'
+ AND tce.id IS NULL
+ GROUP BY userFk
+ ) fi ON wtc.userFk = fi.userFk
+ LEFT JOIN (
+ SELECT wtc.userFk, MAX(wtc.timed) lastOut
+ FROM workerTimeControl wtc
+ JOIN tmp.`user` u ON u.userFk = wtc.userFk
+ LEFT JOIN tmp.timeControlError tce ON tce.id = wtc.id
+ WHERE wtc.timed BETWEEN vDatedFromYesterday AND vDatedToTomorrow
+ AND wtc.direction = 'out'
+ AND tce.id IS NULL
+ GROUP BY userFk
+ ) lo ON wtc.userFk = lo.userFk
+ LEFT JOIN tmp.timeControlError tce ON tce.id = wtc.id
+ WHERE wtc.timed BETWEEN fi.firstIn AND lo.lastOut
+ AND tce.id IS NULL
+ ORDER BY wtc.userFk, wtc.timed;
+
+ CREATE OR REPLACE TEMPORARY TABLE tmp.wtcToinsert
+ (INDEX(timed))
+ ENGINE = MEMORY
+ WITH wtc AS(
+ SELECT timed,
+ userFk,
+ dated,
+ direction,
+ LEAD(dated) OVER
+ (PARTITION BY userFk, dated ORDER BY timed) nextDay,
+ LEAD(userFk) OVER
+ (PARTITION BY userFk ORDER BY timed) nextUserFk,
+ ROW_NUMBER() OVER (ORDER BY userFk, timed) MOD 2 isOdd
+ FROM tmp.workerTimeControl
+ WHERE timed BETWEEN vDatedFromYesterday AND vDatedToTomorrow
+ ORDER BY userFk, timed
+ ), wtcToinsert AS(
+ SELECT userFk,
+ dated,
+ IF(userFk = nextUserFk
+ AND nextDay IS NULL
+ AND isOdd
+ AND direction <> 'out', TRUE, FALSE) outNextDay,
+ IF(userFk = nextUserFk
+ AND nextDay IS NULL
+ AND NOT isOdd
+ AND direction <> 'out', TRUE, FALSE) outNextDayWhitBreak
+ FROM wtc
+ HAVING outNextDay OR outNextDayWhitBreak
+ )SELECT userFk, util.dayEnd(dated) timed, 'out' direction
+ FROM wtcToinsert
+ WHERE outNextDay
+ UNION ALL
+ SELECT userFk, dated + INTERVAL 1 DAY, 'in'
+ FROM wtcToinsert
+ WHERE outNextDay
+ UNION ALL
+ SELECT userFk, util.dayEnd(dated) - INTERVAL 1 SECOND, 'middle'
+ FROM wtcToinsert
+ WHERE outNextDayWhitBreak
+ UNION ALL
+ SELECT userFk, util.dayEnd(dated), 'out'
+ FROM wtcToinsert
+ WHERE outNextDayWhitBreak
+ UNION ALL
+ SELECT userFk, dated + INTERVAL 1 DAY, 'in'
+ FROM wtcToinsert
+ WHERE outNextDayWhitBreak
+ UNION ALL
+ SELECT userFk, dated + INTERVAL 1 DAY + INTERVAL 1 SECOND, 'middle'
+ FROM wtcToinsert
+ WHERE outNextDayWhitBreak;
+
+ INSERT INTO tmp.workerTimeControl (userFk, timed, dated, direction, isReal)
+ SELECT userFk, timed, DATE(timed), direction, FALSE
+ FROM tmp.wtcToinsert;
+
+ SET @accumulatedForBreakTime = 0;
+ SET @oldrealDay = NULL;
+ CREATE OR REPLACE TEMPORARY TABLE tmp.timeControlCalculate
+ WITH workerTimed AS (
+ SELECT
+ userFk,
+ dated,
+ timed,
+ (direction ='in' AND isReal) breakPoint,
+ SUM(CASE WHEN (direction ='in' AND isReal) THEN TRUE ELSE FALSE END)
+ OVER (ORDER BY userFk, timed) AS realDay,
+ TIMESTAMPDIFF(SECOND, LAG(timed)
+ OVER (PARTITION BY userFk, dated ORDER BY timed), timed) gapTime,
+ ROW_NUMBER()
+ OVER (PARTITION BY userFk, dated ORDER BY timed) MOD 2 isOdd
+ FROM tmp.workerTimeControl
+ WHERE timed BETWEEN vDatedFromYesterday AND vDatedToTomorrow
+ ), accumulated AS (
+ SELECT SUM(IF(isOdd, 0, gapTime))
+ OVER (PARTITION BY userFk,dated ORDER BY userFk,timed) accumulatedWorkTime,
+ SUM(IF(NOT isOdd OR breakPoint, 0, IFNULL(gapTime, 0)))
+ OVER (PARTITION BY realDay ORDER BY realDay,timed) accumulatedBreakTime,
+ IF(realDay <> @oldrealDay OR (isOdd AND gapTime >= vMaxTimeToBreak),
+ @accumulatedForBreakTime := 0,
+ @accumulatedForBreakTime := @accumulatedForBreakTime +
+ IF(isOdd, 0, gapTime )) accumulatedForBreakTime,
+ @oldrealDay := realDay,
+ userFk,
+ dated,
+ realDay
+ FROM workerTimed
+ ), totalWorked AS (
+ SELECT userFk,
+ dated,
+ MAX(accumulatedWorkTime) +
+ IF(MAX(accumulatedForBreakTime) >= vTimeToBreakTime,
+ LEAST(vBreakTime, MAX(accumulatedBreakTime)),
+ 0) timeWorkSeconds
+ FROM accumulated
+ GROUP BY userFk, dated
+ )SELECT tw.userFk,
+ tw.dated,
+ timeWorkSeconds,
+ SEC_TO_TIME(timeWorkSeconds) timeWorkSexagesimal,
+ timeWorkSeconds / vHourSeconds timeWorkDecimal,
+ sub.tableTimed
+ FROM totalWorked tw
+ JOIN (
+ SELECT userFk,
+ dated,
+ GROUP_CONCAT(DATE_FORMAT(timed, "%H:%i") ORDER BY timed ASC
+ SEPARATOR ' - ')tableTimed
+ FROM tmp.workerTimeControl
+ WHERE timed BETWEEN vDatedFromYesterday AND vDatedToTomorrow
+ AND isReal
+ GROUP BY userFk, dated
+ )sub ON sub.dated = tw.dated
+ AND sub.userFk = tw.userFk
+ WHERE tw.dated BETWEEN vDatedFrom AND vDatedTo;
+
+ DROP TEMPORARY TABLE tmp.timeControlError;
+ DROP TEMPORARY TABLE tmp.wtcToinsert;
+ DROP TEMPORARY TABLE tmp.workerTimeControl;
+END$$
+DELIMITER ;
\ No newline at end of file
diff --git a/db/changes/234004/02-workerTimeControl_clockIn.sql b/db/changes/234004/02-workerTimeControl_clockIn.sql
new file mode 100644
index 000000000..69091e51c
--- /dev/null
+++ b/db/changes/234004/02-workerTimeControl_clockIn.sql
@@ -0,0 +1,286 @@
+DELIMITER $$
+CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`workerTimeControl_clockIn`(
+ vWorkerFk INT,
+ vTimed DATETIME,
+ vDirection VARCHAR(10)
+)
+BEGIN
+/**
+ * Verifica si el empleado puede fichar
+ * @param vWorkerFk Identificador del trabajador
+ * @param vTimed valor de la fichada, IF vTimed IS NULL vTimed = NOW
+ * @param vDirection solo se pueden pasa los valores del campo
+ * workerTimeControl.direction ENUM('in', 'out', 'middle')
+ * @return Si todo es correcto, retorna el número de id la tabla workerTimeControl.
+ * Si hay algún problema, devuelve el mesaje que se debe mostrar al usuario
+ * 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;
+ DECLARE vNextOut DATETIME;
+ DECLARE vNextDirection ENUM('in', 'out');
+ DECLARE vLastDirection ENUM('in', 'out');
+ DECLARE vDayMaxTime INTEGER;
+ DECLARE vDayBreak INT;
+ DECLARE vShortWeekBreak INT;
+ DECLARE vLongWeekBreak INT;
+ DECLARE vWeekScope INT;
+ DECLARE vMailTo VARCHAR(50) DEFAULT NULL;
+ DECLARE vUserName VARCHAR(50) DEFAULT NULL;
+ DECLARE vIsError BOOLEAN DEFAULT FALSE;
+ DECLARE vErrorMessage VARCHAR(255) DEFAULT NULL;
+ DECLARE vErrorCode VARCHAR(50);
+ DECLARE vDated DATE;
+ DECLARE vIsAllowedToWork VARCHAR(50);
+ DECLARE vIsManual BOOLEAN DEFAULT TRUE;
+ DECLARE vMaxWorkShortCycle INT;
+ DECLARE vMaxWorkLongCycle INT;
+
+ DECLARE EXIT HANDLER FOR SQLSTATE '45000'
+ BEGIN
+
+ SELECT CONCAT(u.name, '@verdnatura.es'),
+ CONCAT(w.firstName, ' ', w.lastName)
+ INTO vMailTo, vUserName
+ FROM account.user u
+ JOIN worker w ON w.bossFk = u.id
+ WHERE w.id = vWorkerFk;
+
+ SELECT `description` INTO vErrorMessage
+ FROM workerTimeControlError
+ WHERE `code` = vErrorCode;
+
+ IF vErrorMessage IS NULL THEN
+ SET vErrorMessage = 'Error sin definir';
+ END IF;
+
+ SELECT vErrorMessage `error`;
+ SELECT CONCAT(vUserName,
+ ' no ha podido fichar por el siguiente problema: ',
+ vErrorMessage)
+ INTO vErrorMessage;
+
+ CALL mail_insert( vMailTo, vMailTo, 'Error al fichar', vErrorMessage);
+ END;
+
+ IF (vTimed IS NULL) THEN
+ SET vTimed = util.VN_NOW();
+ SET vIsManual = FALSE;
+ END IF;
+
+ SET vDated = DATE(vTimed);
+
+ SELECT IF(pc.name = 'Conductor +3500kg',
+ wc.dayBreakDriver,
+ wc.dayBreak),
+ wc.shortWeekBreak,
+ wc.longWeekBreak,
+ wc.weekScope,
+ wc.dayMaxTime,
+ wc.maxWorkShortCycle,
+ wc.maxWorkLongCycle
+ INTO vDayBreak,
+ vShortWeekBreak,
+ vLongWeekBreak,
+ vWeekScope,
+ vDayMaxTime,
+ vMaxWorkShortCycle,
+ vMaxWorkLongCycle
+ FROM business b
+ JOIN professionalCategory pc
+ ON pc.id = b.workerBusinessProfessionalCategoryFk
+ JOIN workerTimeControlConfig wc
+ WHERE b.workerFk = vWorkerFk
+ AND vDated BETWEEN b.started AND IFNULL(b.ended, vDated);
+
+ -- CONTRATO EN VIGOR
+ IF vDayBreak IS NULL THEN
+ SET vErrorCode = 'INACTIVE_BUSINESS';
+ CALL util.throw(vErrorCode);
+ END IF;
+
+ -- FICHADAS A FUTURO
+ IF vTimed > util.VN_NOW() + INTERVAL 1 MINUTE THEN
+ SET vErrorCode = 'IS_NOT_ALLOWED_FUTURE';
+ CALL util.throw(vErrorCode);
+ END IF;
+
+ -- VERIFICAR SI ESTÁ PERMITIDO TRABAJAR
+ CALL timeBusiness_calculateByWorker(vWorkerFk, vDated, vDated);
+ SELECT isAllowedToWork INTO vIsAllowedToWork
+ FROM tmp.timeBusinessCalculate;
+ DROP TEMPORARY TABLE tmp.timeBusinessCalculate;
+
+ IF NOT vIsAllowedToWork THEN
+ SET vErrorCode = 'IS_NOT_ALLOWED_WORK';
+ CALL util.throw(vErrorCode);
+ END IF;
+
+ -- DIRECCION CORRECTA
+ CALL workerTimeControl_direction(vWorkerFk, vTimed);
+ IF (SELECT
+ IF(IF(option1 IN ('inMiddle', 'outMiddle'),
+ 'middle',
+ option1) <> vDirection
+ AND IF(option2 IN ('inMiddle', 'outMiddle'),
+ 'middle',
+ IFNULL(option2, '')) <> vDirection,
+ TRUE ,
+ FALSE)
+ FROM tmp.workerTimeControlDirection
+ ) THEN
+ SET vIsError = TRUE;
+ END IF;
+
+ DROP TEMPORARY TABLE tmp.workerTimeControlDirection;
+ IF vIsError THEN
+ SET vErrorCode = 'WRONG_DIRECTION';
+ CALL util.throw(vErrorCode);
+ END IF;
+
+ -- FICHADAS IMPARES
+ SELECT timed INTO vLastIn
+ FROM workerTimeControl
+ WHERE userFk = vWorkerFk
+ AND direction = 'in'
+ AND timed < vTimed
+ ORDER BY timed DESC
+ LIMIT 1;
+
+ IF (SELECT IF(vDirection = 'in',
+ MOD(COUNT(*), 2) ,
+ IF (vDirection = 'out', NOT MOD(COUNT(*), 2), FALSE))
+ FROM workerTimeControl
+ WHERE userFk = vWorkerFk
+ AND timed BETWEEN vLastIn AND vTimed
+ ) THEN
+ SET vErrorCode = 'ODD_WORKERTIMECONTROL';
+ CALL util.throw(vErrorCode);
+ END IF;
+
+ -- DESCANSO DIARIO
+ SELECT timed INTO vLastOut
+ FROM workerTimeControl
+ WHERE userFk = vWorkerFk
+ AND direction = 'out'
+ AND timed < vTimed
+ ORDER BY timed DESC
+ LIMIT 1;
+
+ SELECT timed INTO vNextIn
+ FROM workerTimeControl
+ WHERE userFk = vWorkerFk
+ AND direction = 'in'
+ AND timed > vTimed
+ ORDER BY timed ASC
+ LIMIT 1;
+
+ CASE vDirection
+ WHEN 'in' THEN
+ IF UNIX_TIMESTAMP(vTimed) - UNIX_TIMESTAMP(vLastOut) <= vDayBreak THEN
+ SET vIsError = TRUE;
+ END IF;
+ WHEN 'out' THEN
+ IF UNIX_TIMESTAMP(vNextIn) - UNIX_TIMESTAMP(vTimed) <= vDayBreak THEN
+ SET vIsError = TRUE;
+ END IF;
+ ELSE BEGIN END;
+ END CASE;
+
+ IF vIsError THEN
+ SET vErrorCode = 'BREAK_DAY';
+ CALL util.throw(vErrorCode);
+ END IF;
+
+
+
+ IF (vDirection IN('in', 'out')) THEN
+ -- VERIFICA MAXIMO TIEMPO DESDE ENTRADA HASTA LA SALIDA
+
+ SELECT timed INTO vNextOut
+ FROM workerTimeControl
+ WHERE userFk = vWorkerFk
+ AND direction = 'out'
+ AND timed > vTimed
+ ORDER BY timed ASC
+ LIMIT 1;
+
+ SELECT direction INTO vNextDirection
+ FROM workerTimeControl
+ WHERE userFk = vWorkerFk
+ AND direction IN('in','out')
+ AND timed > vTimed
+ ORDER BY timed ASC
+ LIMIT 1;
+
+ SELECT direction INTO vLastDirection
+ FROM workerTimeControl
+ WHERE userFk = vWorkerFk
+ AND direction IN('in', 'out')
+ AND timed < vTimed
+ ORDER BY timed ASC
+ LIMIT 1;
+
+ IF (vDirection ='in'
+ AND vNextDirection = 'out'
+ AND UNIX_TIMESTAMP(vNextOut) - UNIX_TIMESTAMP(vTimed) > vDayMaxTime) OR
+ (vDirection ='out'
+ AND vLastDirection = 'in'
+ AND UNIX_TIMESTAMP(vTimed) -UNIX_TIMESTAMP(vLastIn) > vDayMaxTime) THEN
+ SET vErrorCode = 'DAY_MAX_TIME';
+ CALL util.throw(vErrorCode);
+ END IF;
+
+ -- VERIFICA DESCANSO SEMANAL
+
+ WITH wtc AS(
+ (SELECT timed
+ FROM vn.workerTimeControl
+ WHERE userFk = vWorkerFk
+ AND direction IN ('in', 'out')
+ AND timed BETWEEN vTimed - INTERVAL (vWeekScope * 2) SECOND
+ AND vTimed + INTERVAL (vWeekScope * 2) SECOND )
+ UNION
+ (SELECT vTimed)
+ ), wtcGap AS(
+ SELECT timed,
+ TIMESTAMPDIFF(SECOND, LAG(timed) OVER (ORDER BY timed), timed) gap
+ FROM wtc
+ ORDER BY timed
+ ), wtcBreak AS(
+ SELECT timed,
+ IF(IFNULL(gap, 0) > vShortWeekBreak, TRUE, FALSE) hasShortBreak,
+ IF(IFNULL(gap, 0) > vLongWeekBreak, TRUE, FALSE) hasLongBreak
+ FROM wtcGap
+ ORDER BY timed
+ ), wtcBreakCounter AS(
+ SELECT timed,
+ SUM(hasShortBreak) OVER (ORDER BY timed) breakCounter ,
+ LEAD(hasLongBreak) OVER (ORDER BY timed) nextHasLongBreak
+ FROM wtcBreak
+ )SELECT TIMESTAMPDIFF(SECOND, MIN(timed), MAX(timed)) > vMaxWorkLongCycle OR
+ (TIMESTAMPDIFF(SECOND, MIN(timed), MAX(timed))> vMaxWorkShortCycle
+ AND NOT SUM(IFNULL(nextHasLongBreak, 1)))
+ hasError INTO vIsError
+ FROM wtcBreakCounter
+ GROUP BY breakCounter
+ HAVING hasError
+ LIMIT 1;
+
+ IF vIsError THEN
+ SET vErrorCode = 'BREAK_WEEK';
+ CALL util.throw(vErrorCode);
+ END IF;
+ END IF;
+
+ -- SE PERMITE FICHAR
+ INSERT INTO workerTimeControl(userFk, timed, direction, `manual`)
+ VALUES(vWorkerFk, vTimed, vDirection, vIsManual);
+
+ SELECT LAST_INSERT_ID() id;
+
+END$$
+DELIMITER ;
\ No newline at end of file
diff --git a/db/changes/234201/00-packagingFkviews.sql b/db/changes/234201/00-packagingFkviews.sql
index f355325f3..abc7dc004 100644
--- a/db/changes/234201/00-packagingFkviews.sql
+++ b/db/changes/234201/00-packagingFkviews.sql
@@ -1,3 +1,41 @@
+CREATE OR REPLACE DEFINER=`root`@`localhost`
+ SQL SECURITY DEFINER
+ VIEW `vn`.`awbVolume`
+AS SELECT `d`.`awbFk` AS `awbFk`,
+ `b`.`stickers` * `i`.`density` * IF(
+ `p`.`volume` > 0,
+ `p`.`volume`,
+ `p`.`width` * `p`.`depth` * IF(`p`.`height` = 0, `i`.`size` + 10, `p`.`height`)
+ ) / (`vc`.`aerealVolumetricDensity` * 1000) AS `volume`,
+ `b`.`id` AS `buyFk`
+FROM (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ `vn`.`buy` `b`
+ JOIN `vn`.`item` `i` ON(`b`.`itemFk` = `i`.`id`)
+ )
+ JOIN `vn`.`itemType` `it` ON(`i`.`typeFk` = `it`.`id`)
+ )
+ JOIN `vn`.`packaging` `p` ON(`p`.`id` = `b`.`packagingFk`)
+ )
+ JOIN `vn`.`entry` `e` ON(`b`.`entryFk` = `e`.`id`)
+ )
+ JOIN `vn`.`travel` `t` ON(`t`.`id` = `e`.`travelFk`)
+ )
+ JOIN `vn`.`duaEntry` `de` ON(`de`.`entryFk` = `e`.`id`)
+ )
+ JOIN `vn`.`dua` `d` ON(`d`.`id` = `de`.`duaFk`)
+ )
+ JOIN `vn`.`volumeConfig` `vc`
+ )
+WHERE `t`.`shipped` > makedate(year(`util`.`VN_CURDATE`()) - 1, 1);
+
+
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`Compres`
@@ -108,39 +146,3 @@ FROM (
LEFT JOIN `edi`.`supplier` `s` ON(`e`.`pro` = `s`.`supplier_id`)
);
-CREATE OR REPLACE DEFINER=`root`@`localhost`
- SQL SECURITY DEFINER
- VIEW `vn`.`awbVolume`
-AS SELECT `d`.`awbFk` AS `awbFk`,
- `b`.`stickers` * `i`.`density` * IF(
- `p`.`volume` > 0,
- `p`.`volume`,
- `p`.`width` * `p`.`depth` * IF(`p`.`height` = 0, `i`.`size` + 10, `p`.`height`)
- ) / (`vc`.`aerealVolumetricDensity` * 1000) AS `volume`,
- `b`.`id` AS `buyFk`
-FROM (
- (
- (
- (
- (
- (
- (
- (
- `vn`.`buy` `b`
- JOIN `vn`.`item` `i` ON(`b`.`itemFk` = `i`.`id`)
- )
- JOIN `vn`.`itemType` `it` ON(`i`.`typeFk` = `it`.`id`)
- )
- JOIN `vn`.`packaging` `p` ON(`p`.`id` = `b`.`packagingFk`)
- )
- JOIN `vn`.`entry` `e` ON(`b`.`entryFk` = `e`.`id`)
- )
- JOIN `vn`.`travel` `t` ON(`t`.`id` = `e`.`travelFk`)
- )
- JOIN `vn`.`duaEntry` `de` ON(`de`.`entryFk` = `e`.`id`)
- )
- JOIN `vn`.`dua` `d` ON(`d`.`id` = `de`.`duaFk`)
- )
- JOIN `vn`.`volumeConfig` `vc`
- )
-WHERE `t`.`shipped` > makedate(year(`util`.`VN_CURDATE`()) - 1, 1);
\ No newline at end of file
diff --git a/db/changes/234601/00-ACLticketTrackingState.sql b/db/changes/234601/00-ACLticketTrackingState.sql
new file mode 100644
index 000000000..0f7bd4f44
--- /dev/null
+++ b/db/changes/234601/00-ACLticketTrackingState.sql
@@ -0,0 +1,12 @@
+UPDATE `salix`.`ACL`
+ SET `property` = 'state',
+ `model` = 'Ticket'
+ WHERE `property` = 'changeState';
+
+REVOKE INSERT, UPDATE, DELETE ON `vn`.`ticketTracking` FROM 'productionboss'@;
+REVOKE INSERT, UPDATE, DELETE ON `vn`.`ticketTracking` FROM 'productionAssi'@;
+REVOKE INSERT, UPDATE, DELETE ON `vn`.`ticketTracking` FROM 'hr'@;
+REVOKE INSERT, UPDATE, DELETE ON `vn`.`ticketTracking` FROM 'salesPerson'@;
+REVOKE INSERT, UPDATE, DELETE ON `vn`.`ticketTracking` FROM 'deliveryPerson'@;
+REVOKE INSERT, UPDATE, DELETE ON `vn`.`ticketTracking` FROM 'employee'@;
+REVOKE EXECUTE ON `vn`.`ticket_setState` FROM 'employee'@;
diff --git a/db/changes/234601/00-ticketSetStateRefactor.sql b/db/changes/234601/00-ticketSetStateRefactor.sql
new file mode 100644
index 000000000..9078ffb0e
--- /dev/null
+++ b/db/changes/234601/00-ticketSetStateRefactor.sql
@@ -0,0 +1,55 @@
+DELIMITER $$
+CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_setState`(
+ vSelf INT,
+ vStateCode VARCHAR(255) COLLATE utf8_general_ci
+)
+BEGIN
+/**
+ * Modifica el estado de un ticket si se cumplen las condiciones necesarias.
+ *
+ * @param vSelf el id del ticket
+ * @param vStateCode estado a modificar del ticket
+ */
+ DECLARE vticketAlertLevel INT;
+ DECLARE vTicketStateCode VARCHAR(255);
+ DECLARE vCanChangeState BOOL;
+ DECLARE vPackedAlertLevel INT;
+ DECLARE vZoneFk INT;
+
+ SELECT s.alertLevel, s.`code`, t.zoneFk
+ INTO vticketAlertLevel, vTicketStateCode, vZoneFk
+ FROM state s
+ JOIN ticketTracking tt ON tt.stateFk = s.id
+ JOIN ticket t ON t.id = tt.ticketFk
+ WHERE tt.ticketFk = vSelf
+ ORDER BY tt.created DESC
+ LIMIT 1;
+
+ SELECT id INTO vPackedAlertLevel FROM alertLevel WHERE code = 'PACKED';
+
+ IF vStateCode = 'OK' AND vZoneFk IS NULL THEN
+ CALL util.throw('ASSIGN_ZONE_FIRST');
+ END IF;
+
+ SET vCanChangeState = (
+ vStateCode <> 'ON_CHECKING' OR
+ vticketAlertLevel < vPackedAlertLevel
+ )AND NOT (
+ vTicketStateCode IN ('CHECKED', 'CHECKING')
+ AND vStateCode IN ('PREPARED', 'ON_PREPARATION')
+ );
+
+ IF vCanChangeState THEN
+ INSERT INTO ticketTracking (stateFk, ticketFk, workerFk)
+ SELECT id, vSelf, account.myUser_getId()
+ FROM state
+ WHERE `code` = vStateCode COLLATE utf8_unicode_ci;
+
+ IF vStateCode = 'PACKED' THEN
+ CALL ticket_doCmr(vSelf);
+ END IF;
+ ELSE
+ CALL util.throw('INCORRECT_TICKET_STATE');
+ END IF;
+END$$
+DELIMITER ;
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 1dd8a7bd8..d0afa8d81 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -2004,6 +2004,10 @@ UPDATE `vn`.`business` b
SET b.`departmentFk` = 43
WHERE b.id IN(18, 19);
+UPDATE `vn`.`business` b
+ SET b.`started` = b.`started` - INTERVAL 100 DAY
+ WHERE b.id = 1107;
+
INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
VALUES
('1', '27.5', YEAR(util.VN_CURDATE())),
@@ -2052,22 +2056,22 @@ INSERT INTO `vn`.`absenceType` (`id`, `name`, `rgb`, `code`, `holidayEntitlement
INSERT INTO `vn`.`calendar` (`businessFk`, `dayOffTypeFk`, `dated`)
VALUES
- (1, 6, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
- (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
- (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -11 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 11 DAY))),
- (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -12 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 12 DAY))),
- (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -20 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 20 DAY))),
- (1106, 2, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, DATE_ADD(util.VN_CURDATE(), INTERVAL -13 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 8 DAY))),
- (1106, 1, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, DATE_ADD(util.VN_CURDATE(), INTERVAL -14 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 9 DAY))),
- (1106, 2, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, DATE_ADD(util.VN_CURDATE(), INTERVAL -15 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 7 DAY))),
- (1107, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 10 DAY))),
- (1107, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -11 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 11 DAY))),
- (1107, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -12 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 12 DAY))),
- (1107, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -20 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 20 DAY))),
- (1107, 2, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, DATE_ADD(util.VN_CURDATE(), INTERVAL -13 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 8 DAY))),
- (1107, 1, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, DATE_ADD(util.VN_CURDATE(), INTERVAL -14 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 9 DAY))),
- (1107, 2, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, DATE_ADD(util.VN_CURDATE(), INTERVAL -15 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL 7 DAY))),
- (1107, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL - 16 DAY));
+ (1, 6, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, util.VN_CURDATE() - INTERVAL 10 DAY, util.VN_CURDATE() + INTERVAL 10 DAY)),
+ (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, util.VN_CURDATE() - INTERVAL 10 DAY, util.VN_CURDATE() + INTERVAL 10 DAY)),
+ (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, util.VN_CURDATE() - INTERVAL 11 DAY, util.VN_CURDATE() + INTERVAL 11 DAY)),
+ (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, util.VN_CURDATE() - INTERVAL 12 DAY, util.VN_CURDATE() + INTERVAL 12 DAY)),
+ (1106, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, util.VN_CURDATE() - INTERVAL 20 DAY, util.VN_CURDATE() + INTERVAL 20 DAY)),
+ (1106, 2, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, util.VN_CURDATE() - INTERVAL 13 DAY, util.VN_CURDATE() + INTERVAL 8 DAY)),
+ (1106, 1, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, util.VN_CURDATE() - INTERVAL 14 DAY, util.VN_CURDATE() + INTERVAL 9 DAY)),
+ (1106, 2, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, util.VN_CURDATE() - INTERVAL 15 DAY, util.VN_CURDATE() + INTERVAL 7 DAY)),
+ (1107, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, util.VN_CURDATE() - INTERVAL 10 DAY, util.VN_CURDATE() + INTERVAL 10 DAY)),
+ (1107, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, util.VN_CURDATE() - INTERVAL 11 DAY, util.VN_CURDATE() + INTERVAL 11 DAY)),
+ (1107, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, util.VN_CURDATE() - INTERVAL 12 DAY, util.VN_CURDATE() + INTERVAL 12 DAY)),
+ (1107, 1, IF(MONTH(util.VN_CURDATE()) = 12 AND DAY(util.VN_CURDATE()) > 10, util.VN_CURDATE() - INTERVAL 20 DAY, util.VN_CURDATE() + INTERVAL 20 DAY)),
+ (1107, 2, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, util.VN_CURDATE() - INTERVAL 13 DAY, util.VN_CURDATE() + INTERVAL 8 DAY)),
+ (1107, 1, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, util.VN_CURDATE() - INTERVAL 14 DAY, util.VN_CURDATE() + INTERVAL 9 DAY)),
+ (1107, 2, IF(MONTH(util.VN_CURDATE()) >= 1 AND DAY(util.VN_CURDATE()) > 20, util.VN_CURDATE() - INTERVAL 15 DAY, util.VN_CURDATE() + INTERVAL 7 DAY)),
+ (1107, 2, util.VN_CURDATE() - INTERVAL 16 DAY);
INSERT INTO `vn`.`smsConfig` (`id`, `uri`, `title`, `apiKey`)
VALUES
@@ -2755,9 +2759,9 @@ INSERT INTO `vn`.`sectorCollectionSaleGroup` (`sectorCollectionFk`, `saleGroupFk
VALUES
(1, 1);
-INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, `shortWeekBreak`, `longWeekBreak`, `weekScope`, `mailPass`, `mailHost`, `mailSuccessFolder`, `mailErrorFolder`, `mailUser`, `minHoursToBreak`, `breakHours`, `hoursCompleteWeek`, `startNightlyHours`, `endNightlyHours`, `maxTimePerDay`, `breakTime`, `timeToBreakTime`, `dayMaxTime`, `shortWeekDays`, `longWeekDays`, `teleworkingStart`, `teleworkingStartBreakTime`)
+INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, `shortWeekBreak`, `longWeekBreak`, `weekScope`, `mailPass`, `mailHost`, `mailSuccessFolder`, `mailErrorFolder`, `mailUser`, `minHoursToBreak`, `breakHours`, `hoursCompleteWeek`, `startNightlyHours`, `endNightlyHours`, `maxTimePerDay`, `breakTime`, `timeToBreakTime`, `dayMaxTime`, `shortWeekDays`, `longWeekDays`, `teleworkingStart`, `teleworkingStartBreakTime`, `maxTimeToBreak`, `maxWorkShortCycle`, `maxWorkLongCycle`)
VALUES
- (1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13, 28800, 32400);
+ (1, 43200, 32400, 129600, 259200, 1080000, '', 'imap.verdnatura.es', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.00, 0.33, 40, '22:00:00', '06:00:00', 72000, 1200, 18000, 72000, 6, 13, 28800, 32400, 3600, 561600, 950400);
INSERT INTO `vn`.`host` (`id`, `code`, `description`, `warehouseFk`, `bankFk`)
VALUES
diff --git a/db/tests/vn/timeControl_calculateByUser.spec.js b/db/tests/vn/timeControl_calculateByUser.spec.js
deleted file mode 100644
index 0b385d2c9..000000000
--- a/db/tests/vn/timeControl_calculateByUser.spec.js
+++ /dev/null
@@ -1,91 +0,0 @@
-const app = require('vn-loopback/server/server');
-const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
-
-describe('timeControl_calculateByUser()', () => {
- it(`should return today's worked hours`, async() => {
- let start = Date.vnNew();
- start.setHours(0, 0, 0, 0);
- start.setDate(start.getDate() - 1);
-
- let end = Date.vnNew();
- end.setHours(0, 0, 0, 0);
- end.setDate(end.getDate() + 1);
-
- let stmts = [];
- let stmt;
-
- let params = {
- workerID: 1106,
- start: start,
- end: end
- };
-
- stmt = new ParameterizedSQL('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
- params.workerID,
- params.start,
- params.end
- ]);
- stmts.push(stmt);
-
- let tableIndex = stmts.push('SELECT * FROM tmp.timeControlCalculate') - 1;
-
- let sql = ParameterizedSQL.join(stmts, ';');
- let result = await app.models.Ticket.rawStmt(sql);
-
- let [timeControlCalculateTable] = result[tableIndex];
-
- expect(timeControlCalculateTable.timeWorkSeconds).toEqual(28200);
- });
- // #2261
- xit(`should return the worked hours between last sunday and monday`, async() => {
- let lastSunday = Date.vnNew();
- let daysSinceSunday = lastSunday.getDay();
- if (daysSinceSunday === 0) // this means today is sunday but you need the previous sunday :)
- daysSinceSunday = 7;
- lastSunday.setHours(23, 0, 0, 0);
- lastSunday.setDate(lastSunday.getDate() - daysSinceSunday);
-
- let monday = Date.vnNew();
- let daysSinceMonday = daysSinceSunday - 1; // aiming for monday (today could be monday)
- monday.setHours(7, 0, 0, 0);
- monday.setDate(monday.getDate() - daysSinceMonday);
-
- let stmts = [];
- let stmt;
-
- stmts.push('START TRANSACTION');
-
- const workerID = 1108;
-
- stmt = new ParameterizedSQL(`
- INSERT INTO vn.workerTimeControl(userFk, timed, manual, direction)
- VALUES
- (?, ?, 1, 'in'),
- (?, ?, 1, 'out')
- `, [
- workerID,
- lastSunday,
- workerID,
- monday
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
- workerID,
- lastSunday,
- monday
- ]);
- stmts.push(stmt);
-
- let tableIndex = stmts.push('SELECT * FROM tmp.timeControlCalculate') - 1;
-
- stmts.push('ROLLBACK');
-
- let sql = ParameterizedSQL.join(stmts, ';');
- let result = await app.models.Ticket.rawStmt(sql);
-
- let [timeControlCalculateTable] = result[tableIndex];
-
- expect(timeControlCalculateTable.timeWorkSeconds).toEqual(30000);
- });
-});
diff --git a/db/tests/vn/workerTimeControlCheck.spec.js b/db/tests/vn/workerTimeControlCheck.spec.js
deleted file mode 100644
index 0ca1429d4..000000000
--- a/db/tests/vn/workerTimeControlCheck.spec.js
+++ /dev/null
@@ -1,580 +0,0 @@
-const app = require('vn-loopback/server/server');
-const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
-
-// #2261 xdescribe dbtest workerTimeControl_check()
-xdescribe('worker workerTimeControl_check()', () => {
- it(`should throw an error if the worker can't sign on that tablet`, async() => {
- let stmts = [];
- let stmt;
- const workerId = 1110;
- const tabletId = 2;
- let err;
- stmts.push('START TRANSACTION');
- try {
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
-
- stmts.push('ROLLBACK');
-
- let sql = ParameterizedSQL.join(stmts, ';');
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- err = e;
- }
-
- expect(err.sqlMessage).toEqual('No perteneces a este departamento.');
- });
-
- it('should check that the worker can sign on that tablet', async() => {
- let stmts = [];
- let stmt;
- const workerId = 1110;
- const tabletId = 1;
- let err;
- stmts.push('START TRANSACTION');
- try {
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
-
- stmts.push('ROLLBACK');
-
- let sql = ParameterizedSQL.join(stmts, ';');
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- err = e;
- }
-
- expect(err).not.toBeDefined();
- });
-
- it('should throw an error if the worker with a special category has not finished the 9h break', async() => {
- const workerId = 1110;
- const tabletId = 1;
- let stmts = [];
- let stmt;
- let sql;
- let error;
-
- stmts.push('START TRANSACTION');
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-17,NOW()),0,"in"),
- (?,TIMESTAMPADD(SECOND,-32399,NOW()),0,"out")`, [
- workerId,
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
- stmts.push('ROLLBACK');
- sql = ParameterizedSQL.join(stmts, ';');
-
- try {
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- await app.models.Worker.rawSql('ROLLBACK');
- error = e;
- }
-
- expect(error.sqlMessage).toEqual('Descansos 9 h');
- });
-
- it('should check f the worker with a special category has finished the 9h break', async() => {
- const workerId = 1110;
- const tabletId = 1;
- let stmts = [];
- let stmt;
- let err;
- stmts.push('START TRANSACTION');
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-17,NOW()),0,"in"),
- (?,TIMESTAMPADD(SECOND,-32401,NOW()),0,"out")`, [
- workerId,
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
- stmts.push('ROLLBACK');
-
- let sql = ParameterizedSQL.join(stmts, ';');
-
- try {
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- await app.models.Worker.rawSql('ROLLBACK');
- err = e;
- }
-
- expect(err).not.toBeDefined();
- });
-
- it('should throw an error if the worker has not finished the 12h break', async() => {
- const workerId = 1109;
- const tabletId = 1;
- let stmts = [];
- let stmt;
- let sql;
- let error;
-
- stmts.push('START TRANSACTION');
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-20,NOW()),0,"in"),
- (?,TIMESTAMPADD(SECOND,-43199,NOW()),0,"out")`, [
- workerId,
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
- stmts.push('ROLLBACK');
- sql = ParameterizedSQL.join(stmts, ';');
-
- try {
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- await app.models.Worker.rawSql('ROLLBACK');
- error = e;
- }
-
- expect(error.sqlMessage).toEqual('Descansos 12 h');
- });
-
- it('should throw an error if the worker has finished the 12h break', async() => {
- const workerId = 1109;
- const tabletId = 1;
- let stmts = [];
- let stmt;
- let err;
- stmts.push('START TRANSACTION');
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-20,NOW()),0,"in"),
- (?,TIMESTAMPADD(SECOND,-43201,NOW()),0,"out")`, [
- workerId,
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
- stmts.push('ROLLBACK');
-
- let sql = ParameterizedSQL.join(stmts, ';');
-
- try {
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- await app.models.Worker.rawSql('ROLLBACK');
- err = e;
- }
-
- expect(err).not.toBeDefined();
- });
-
- it('should throw an error if the worker has odd entry records', async() => {
- const workerId = 1109;
- const tabletId = 1;
- let stmts = [];
- let stmt;
- let err;
- stmts.push('START TRANSACTION');
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-24,NOW()),0,"in")`, [
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
- stmts.push('ROLLBACK');
-
- let sql = ParameterizedSQL.join(stmts, ';');
-
- try {
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- await app.models.Worker.rawSql('ROLLBACK');
- err = e;
- }
-
- expect(err.sqlMessage).toEqual('Dias con fichadas impares');
- });
-
- it('should throw an error if the worker try to sign on a holiday day', async() => {
- const workerId = 1109;
- const tabletId = 1;
- let stmts = [];
- let stmt;
- let err;
-
- stmts.push('START TRANSACTION');
-
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-24,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-20,NOW()),0,"out")`, [
- workerId,
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
- stmts.push('ROLLBACK');
-
- let sql = ParameterizedSQL.join(stmts, ';');
-
- try {
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- await app.models.Worker.rawSql('ROLLBACK');
- err = e;
- }
-
- expect(err.sqlMessage).toEqual('Holidays');
- });
-
- it('should throw an error if the worker try to sign with your contract ended', async() => {
- const workerId = 1109;
- const tabletId = 1;
- let stmts = [];
- let stmt;
- let err;
-
- stmts.push('START TRANSACTION');
-
- stmt = new ParameterizedSQL(`UPDATE vn.business SET ended = DATE_ADD(CURDATE(), INTERVAL -1 DAY) WHERE id = ?`, [
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-24,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-20,NOW()),0,"out")`, [
- workerId,
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
- stmts.push('ROLLBACK');
-
- let sql = ParameterizedSQL.join(stmts, ';');
-
- try {
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- await app.models.Worker.rawSql('ROLLBACK');
- err = e;
- }
-
- expect(err.sqlMessage).toEqual('No hay un contrato en vigor');
- });
-
- it('should throw an error if the worker has not finished the 36h weekly break', async() => {
- const workerId = 1109;
- const tabletId = 1;
- let stmts = [];
- let stmt;
-
- stmts.push('SET @warn := NULL');
-
- stmts.push('START TRANSACTION');
-
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-24,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-16,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-48,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-40,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-72,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-64,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-96,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-88,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-120,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-112,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-144,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-136,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-168,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-160,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-192,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-184,NOW()),0,"out")`, [
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
-
- let warningMessageIndex = stmts.push('SELECT @warn AS warning') - 1;
- stmts.push('ROLLBACK');
- let sql = ParameterizedSQL.join(stmts, ';');
- let result = await app.models.Worker.rawStmt(sql);
-
- expect(result[warningMessageIndex][0].warning).toEqual('Descansos 36 h');
- });
-
- it('should check if the worker has finished the 36h weekly break', async() => {
- const workerId = 1109;
- const tabletId = 1;
- let stmts = [];
- let stmt;
-
- stmts.push('SET @warn := NULL');
-
- stmts.push('START TRANSACTION');
-
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-24,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-16,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-48,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-40,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-72,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-64,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-96,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-88,NOW()),0,"out")`, [
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
- stmts.push('ROLLBACK');
-
- let warningMessageIndex = stmts.push('SELECT @warn AS warning') - 1;
-
- let sql = ParameterizedSQL.join(stmts, ';');
- let result = await app.models.Worker.rawStmt(sql);
-
- expect(result[warningMessageIndex][0].warning).toBe(null);
- });
-
- it('should throw an error if the worker has not finished the 72h biweekly break', async() => {
- const workerId = 1109;
- const tabletId = 1;
- let stmts = [];
- let stmt;
- let err;
- stmts.push('START TRANSACTION');
-
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-24,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-16,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-48,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-40,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-72,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-64,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-96,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-88,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-120,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-112,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-144,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-136,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-168,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-160,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-192,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-184,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-216,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-208,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-240,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-232,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-264,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-256,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-289,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-280,NOW()),0,"out")`, [
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
- stmts.push('ROLLBACK');
-
- stmts.push('SELECT @warn AS warning') - 1;
-
- let sql = ParameterizedSQL.join(stmts, ';');
-
- try {
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- await app.models.Worker.rawSql('ROLLBACK');
- err = e;
- }
-
- expect(err.sqlMessage).toEqual('Descansos 72 h');
- });
-
- it('should check if the worker has finished the 72h biweekly break', async() => {
- const workerId = 1109;
- const tabletId = 1;
- let stmts = [];
- let stmt;
- let err;
- stmts.push('START TRANSACTION');
-
- stmt = new ParameterizedSQL(`INSERT INTO vn.workerTimeControl(userFk,timed,manual,direction)
- VALUES
- (?,TIMESTAMPADD(HOUR,-24,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-16,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-48,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-40,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-72,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-64,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-96,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-88,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-120,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-112,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-144,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-136,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-168,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-160,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-192,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-184,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-216,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-208,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-240,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-232,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-264,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-256,NOW()),0,"out"),
- (?,TIMESTAMPADD(HOUR,-288,NOW()),0,"in"),
- (?,TIMESTAMPADD(HOUR,-280,NOW()),0,"out")`, [
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId,
- workerId
- ]);
- stmts.push(stmt);
-
- stmt = new ParameterizedSQL('CALL vn.workerTimeControl_check(?, ?, NULL)', [
- workerId,
- tabletId
- ]);
- stmts.push(stmt);
- stmts.push('ROLLBACK');
-
- stmts.push('SELECT @warn AS warning') - 1;
-
- let sql = ParameterizedSQL.join(stmts, ';');
-
- try {
- await app.models.Worker.rawStmt(sql);
- } catch (e) {
- await app.models.Worker.rawSql('ROLLBACK');
- err = e;
- }
-
- expect(err).not.toBeDefined();
- });
-});
diff --git a/modules/ticket/back/locale/sale-group/en.yml b/modules/ticket/back/locale/sale-group/en.yml
new file mode 100644
index 000000000..d88231647
--- /dev/null
+++ b/modules/ticket/back/locale/sale-group/en.yml
@@ -0,0 +1,10 @@
+name: saleGroup
+columns:
+ id: id
+ created: created
+ userFk: user
+ parkingFk: parking
+ sectorFk: sector
+ ticketFk: ticket
+ editorFk: editor
+
diff --git a/modules/ticket/back/locale/sale-group/es.yml b/modules/ticket/back/locale/sale-group/es.yml
new file mode 100644
index 000000000..9efbe7148
--- /dev/null
+++ b/modules/ticket/back/locale/sale-group/es.yml
@@ -0,0 +1,10 @@
+name: saleGroup
+columns:
+ id: id
+ created: creado
+ userFk: usuario
+ parkingFk: parking
+ sectorFk: sector
+ ticketFk: ticket
+ editorFk: editor
+
diff --git a/modules/ticket/back/methods/ticket-tracking/setDelivered.js b/modules/ticket/back/methods/ticket-tracking/setDelivered.js
index df482fd01..d3cdb192f 100644
--- a/modules/ticket/back/methods/ticket-tracking/setDelivered.js
+++ b/modules/ticket/back/methods/ticket-tracking/setDelivered.js
@@ -47,7 +47,7 @@ module.exports = Self => {
const promises = [];
for (const id of ticketIds) {
- const promise = models.TicketTracking.changeState(ctx, {
+ const promise = await models.Ticket.state(ctx, {
stateFk: state.id,
workerFk: worker.id,
ticketFk: id
diff --git a/modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js b/modules/ticket/back/methods/ticket/specs/state.spec.js
similarity index 87%
rename from modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js
rename to modules/ticket/back/methods/ticket/specs/state.spec.js
index 175bc4e4b..9b5e80165 100644
--- a/modules/ticket/back/methods/ticket-tracking/specs/changeState.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/state.spec.js
@@ -1,7 +1,7 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
-describe('ticket changeState()', () => {
+describe('ticket state()', () => {
const salesPersonId = 18;
const employeeId = 1;
const productionId = 49;
@@ -47,7 +47,7 @@ describe('ticket changeState()', () => {
activeCtx.accessToken.userId = salesPersonId;
const params = {ticketFk: 2, stateFk: 3};
- await models.TicketTracking.changeState(ctx, params, options);
+ await models.Ticket.state(ctx, params, options);
await tx.rollback();
} catch (e) {
@@ -69,7 +69,7 @@ describe('ticket changeState()', () => {
activeCtx.accessToken.userId = employeeId;
const params = {ticketFk: 11, stateFk: 13};
- await models.TicketTracking.changeState(ctx, params, options);
+ await models.Ticket.state(ctx, params, options);
await tx.rollback();
} catch (e) {
@@ -80,7 +80,8 @@ describe('ticket changeState()', () => {
expect(error.code).toBe('ACCESS_DENIED');
});
- it('should be able to create a ticket tracking line for a not editable ticket if the user has the production role', async() => {
+ it('should be able to create a ticket tracking line for a not' +
+ ' editable ticket if the user has the production role', async() => {
const tx = await models.TicketTracking.beginTransaction({});
try {
@@ -91,7 +92,7 @@ describe('ticket changeState()', () => {
activeCtx.accessToken.userId = productionId;
const params = {ticketFk: ticket.id, stateFk: 3};
- const ticketTracking = await models.TicketTracking.changeState(ctx, params, options);
+ const ticketTracking = await models.Ticket.state(ctx, params, options);
expect(ticketTracking.__data.ticketFk).toBe(params.ticketFk);
expect(ticketTracking.__data.stateFk).toBe(params.stateFk);
@@ -105,7 +106,8 @@ describe('ticket changeState()', () => {
}
});
- it('should update the ticket tracking line when the user is salesperson, uses the state assigned and a valid worker id', async() => {
+ it('should update the ticket tracking line when the user is salesperson,' +
+ ' uses the state assigned and a valid worker id', async() => {
const tx = await models.TicketTracking.beginTransaction({});
try {
@@ -115,7 +117,7 @@ describe('ticket changeState()', () => {
const ctx = {req: {accessToken: {userId: 18}}};
const assignedState = await models.State.findOne({where: {code: 'PICKER_DESIGNED'}}, options);
const params = {ticketFk: ticket.id, stateFk: assignedState.id, workerFk: 1};
- const res = await models.TicketTracking.changeState(ctx, params, options);
+ const res = await models.Ticket.state(ctx, params, options);
expect(res.__data.ticketFk).toBe(params.ticketFk);
expect(res.__data.stateFk).toBe(params.stateFk);
diff --git a/modules/ticket/back/methods/ticket-tracking/changeState.js b/modules/ticket/back/methods/ticket/state.js
similarity index 94%
rename from modules/ticket/back/methods/ticket-tracking/changeState.js
rename to modules/ticket/back/methods/ticket/state.js
index dbef8762e..01bfbba20 100644
--- a/modules/ticket/back/methods/ticket-tracking/changeState.js
+++ b/modules/ticket/back/methods/ticket/state.js
@@ -1,7 +1,7 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
- Self.remoteMethodCtx('changeState', {
+ Self.remoteMethodCtx('state', {
description: 'Change the state of a ticket',
accessType: 'WRITE',
accepts: [
@@ -18,12 +18,12 @@ module.exports = Self => {
root: true
},
http: {
- path: `/changeState`,
+ path: `/state`,
verb: 'POST'
}
});
- Self.changeState = async(ctx, params, options) => {
+ Self.state = async(ctx, params, options) => {
const models = Self.app.models;
const myOptions = {};
let tx;
diff --git a/modules/ticket/back/models/ticket-tracking.js b/modules/ticket/back/models/ticket-tracking.js
index 2e6d3403e..92e046d3e 100644
--- a/modules/ticket/back/models/ticket-tracking.js
+++ b/modules/ticket/back/models/ticket-tracking.js
@@ -1,5 +1,4 @@
module.exports = function(Self) {
- require('../methods/ticket-tracking/changeState')(Self);
require('../methods/ticket-tracking/setDelivered')(Self);
Self.validatesPresenceOf('stateFk', {message: 'State cannot be blank'});
diff --git a/modules/ticket/back/models/ticket.js b/modules/ticket/back/models/ticket.js
index ea068ef8a..1930765fb 100644
--- a/modules/ticket/back/models/ticket.js
+++ b/modules/ticket/back/models/ticket.js
@@ -1,4 +1,4 @@
module.exports = Self => {
- // Methods
require('./ticket-methods')(Self);
+ require('../methods/ticket/state')(Self);
};
diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html
index 729822764..262395d16 100644
--- a/modules/ticket/front/sale/index.html
+++ b/modules/ticket/front/sale/index.html
@@ -15,7 +15,7 @@
+ on-change="$ctrl.state(value)">
{
+ return this.$http.post('Tickets/state', params).then(() => {
this.vnApp.showSuccess(this.$t('Data saved!'));
this.card.reload();
}).finally(() => this.resetChanges());
diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js
index b36e78893..70781eb58 100644
--- a/modules/ticket/front/sale/index.spec.js
+++ b/modules/ticket/front/sale/index.spec.js
@@ -228,15 +228,16 @@ describe('Ticket', () => {
});
});
- describe('changeState()', () => {
- it('should make an HTTP post query, then call the showSuccess(), reload() and resetChanges() methods', () => {
+ describe('state()', () => {
+ it('should make an HTTP post query, then call the showSuccess(),' +
+ ' reload() and resetChanges() methods', () => {
jest.spyOn(controller.card, 'reload').mockReturnThis();
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
jest.spyOn(controller, 'resetChanges').mockReturnThis();
const expectedParams = {ticketFk: 1, code: 'OK'};
- $httpBackend.expect('POST', `TicketTrackings/changeState`, expectedParams).respond(200);
- controller.changeState('OK');
+ $httpBackend.expect('POST', `Tickets/state`, expectedParams).respond(200);
+ controller.state('OK');
$httpBackend.flush();
expect(controller.card.reload).toHaveBeenCalledWith();
@@ -246,7 +247,8 @@ describe('Ticket', () => {
});
describe('removeSales()', () => {
- it('should make an HTTP post query, then call the showSuccess(), removeSelectedSales() and resetChanges() methods', () => {
+ it('should make an HTTP post query, then call the showSuccess(),' +
+ ' removeSelectedSales() and resetChanges() methods', () => {
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
jest.spyOn(controller, 'removeSelectedSales').mockReturnThis();
jest.spyOn(controller, 'resetChanges').mockReturnThis();
@@ -352,7 +354,8 @@ describe('Ticket', () => {
});
describe('updatePrice()', () => {
- it('should make an HTTP POST query, update the sale price and then call to the resetChanges() method', () => {
+ it('should make an HTTP POST query, update the sale price ' +
+ 'and then call to the resetChanges() method', () => {
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
jest.spyOn(controller, 'resetChanges').mockReturnThis();
@@ -418,7 +421,8 @@ describe('Ticket', () => {
expect(controller.$.editDiscount.hide).toHaveBeenCalledWith();
});
- it('should not call to the updateDiscount() method and then to the editDiscountDialog hide() method', () => {
+ it('should not call to the updateDiscount() method and then' +
+ ' to the editDiscountDialog hide() method', () => {
jest.spyOn(controller, 'updateDiscount').mockReturnThis();
const firstSelectedSale = controller.sales[0];
@@ -444,7 +448,8 @@ describe('Ticket', () => {
});
describe('updateDiscount()', () => {
- it('should make an HTTP POST query, update the sales discount and then call to the resetChanges() method', () => {
+ it('should make an HTTP POST query, update the sales discount ' +
+ 'and then call to the resetChanges() method', () => {
jest.spyOn(controller, 'resetChanges').mockReturnThis();
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
diff --git a/modules/ticket/front/summary/index.html b/modules/ticket/front/summary/index.html
index 4cf7ed11d..025078d36 100644
--- a/modules/ticket/front/summary/index.html
+++ b/modules/ticket/front/summary/index.html
@@ -18,7 +18,7 @@
value-field="code"
fields="['id', 'name', 'alertLevel', 'code']"
url="States/editableStates"
- on-change="$ctrl.changeState(value)">
+ on-change="$ctrl.state(value)">
{
if ('id' in this.$params) this.reload();
})
diff --git a/modules/ticket/front/summary/index.spec.js b/modules/ticket/front/summary/index.spec.js
index 599da73ae..6837bfd54 100644
--- a/modules/ticket/front/summary/index.spec.js
+++ b/modules/ticket/front/summary/index.spec.js
@@ -43,15 +43,15 @@ describe('Ticket', () => {
});
});
- describe('changeState()', () => {
+ describe('state()', () => {
it('should change the state', () => {
jest.spyOn(controller.vnApp, 'showSuccess');
const value = 'myTicketState';
let res = {id: 1, nickname: 'myNickname'};
$httpBackend.when('GET', `Tickets/1/summary`).respond(200, res);
- $httpBackend.expectPOST(`TicketTrackings/changeState`).respond(200, 'ok');
- controller.changeState(value);
+ $httpBackend.expectPOST(`Tickets/state`).respond(200, 'ok');
+ controller.state(value);
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
diff --git a/modules/ticket/front/tracking/edit/index.html b/modules/ticket/front/tracking/edit/index.html
index bff8e71b1..47f367007 100644
--- a/modules/ticket/front/tracking/edit/index.html
+++ b/modules/ticket/front/tracking/edit/index.html
@@ -1,4 +1,4 @@
-
+
{
+ this.$http.post(`Tickets/state`, this.params).then(() => {
this.$.watcher.updateOriginalData();
this.card.reload();
this.vnApp.showSuccess(this.$t('Data saved!'));
diff --git a/modules/ticket/front/tracking/edit/index.spec.js b/modules/ticket/front/tracking/edit/index.spec.js
index 1ba5912b5..9d9aa7983 100644
--- a/modules/ticket/front/tracking/edit/index.spec.js
+++ b/modules/ticket/front/tracking/edit/index.spec.js
@@ -61,7 +61,7 @@ describe('Ticket', () => {
jest.spyOn(controller.vnApp, 'showSuccess');
jest.spyOn(controller.$state, 'go');
- $httpBackend.expectPOST(`TicketTrackings/changeState`, controller.params).respond({});
+ $httpBackend.expectPOST(`Tickets/state`, controller.params).respond({});
controller.onSubmit();
$httpBackend.flush();
diff --git a/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js b/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js
index e90c849b7..42ec6290a 100644
--- a/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js
+++ b/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js
@@ -14,7 +14,6 @@ describe('workerTimeControl add/delete timeEntry()', () => {
const tuesday = 2;
const thursday = 4;
const friday = 5;
- const saturday = 6;
const sunday = 7;
const activeCtx = {
accessToken: {userId: 50},
@@ -200,15 +199,15 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
describe('WorkerTimeControl_clockIn calls', () => {
- it('should fail to add a time entry if the target user has an absence that day', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
+ let workerId;
+ beforeEach(() => {
activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
+ 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.setDate(date.getDate() - 16);
date.setHours(8, 0, 0);
- let error;
-
+ date.setDate(date.getDate() - 16);
const tx = await models.WorkerTimeControl.beginTransaction({});
const options = {transaction: tx};
try {
@@ -225,15 +224,12 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('should fail to add a time entry for a worker without an existing contract', async() => {
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
const date = Date.vnNew();
date.setFullYear(date.getFullYear() - 2);
- let error;
const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
try {
- const options = {transaction: tx};
ctx.args = {timed: date, direction: 'in'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
@@ -246,19 +242,39 @@ describe('workerTimeControl add/delete timeEntry()', () => {
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() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
-
- let date = Date.vnNew();
- date.setDate(date.getDate() - 21);
- 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);
@@ -278,21 +294,13 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('should throw an error when trying "in" direction after insert "in" and "middle"', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
-
- let date = Date.vnNew();
- date.setDate(date.getDate() - 21);
- 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(9, 0, 0);
ctx.args = {timed: date, direction: 'middle'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
@@ -312,15 +320,6 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('Should throw an error when trying "out" before closing a "middle" couple', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
-
- let date = Date.vnNew();
- date.setDate(date.getDate() - 21);
- date = weekDay(date, monday);
- let error;
-
const tx = await models.WorkerTimeControl.beginTransaction({});
const options = {transaction: tx};
@@ -346,15 +345,6 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('should throw an error when trying "middle" after "out"', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
-
- let date = Date.vnNew();
- date.setDate(date.getDate() - 21);
- date = weekDay(date, monday);
- let error;
-
const tx = await models.WorkerTimeControl.beginTransaction({});
const options = {transaction: tx};
@@ -380,15 +370,6 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('should throw an error when trying "out" direction twice', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
-
- let date = Date.vnNew();
- date.setDate(date.getDate() - 21);
- date = weekDay(date, monday);
- let error;
-
const tx = await models.WorkerTimeControl.beginTransaction({});
const options = {transaction: tx};
@@ -415,14 +396,12 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
describe('12h rest', () => {
+ activeCtx.accessToken.userId = salesBossId;
+ const workerId = hankPymId;
it('should throw an error when the 12h rest is not fulfilled yet', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
-
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
let date = Date.vnNew();
- date.setDate(date.getDate() - 21);
+ date.setDate(date.getDate() - 2);
date = weekDay(date, monday);
let error;
@@ -448,16 +427,12 @@ describe('workerTimeControl add/delete timeEntry()', () => {
error = e;
}
- expect(error.message).toBe(`Descanso diario 12h.`);
+ expect(error.message).toBe(`Descanso diario`);
});
it('should not fail as the 12h rest is fulfilled', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
-
let date = Date.vnNew();
- date.setDate(date.getDate() - 21);
+ date.setDate(date.getDate() - 2);
date = weekDay(date, monday);
let error;
@@ -488,13 +463,12 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
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() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = jessicaJonesId;
let date = Date.vnNew();
- date.setDate(date.getDate() - 21);
+ date.setDate(date.getDate() - 2);
date = weekDay(date, monday);
let error;
@@ -520,16 +494,13 @@ describe('workerTimeControl add/delete timeEntry()', () => {
error = e;
}
- expect(error.message).toBe(`Descanso diario 9h.`);
+ expect(error.message).toBe(`Descanso diario`);
});
it('should not fail when the 9h enforced rest is fulfilled', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = jessicaJonesId;
-
+
let date = Date.vnNew();
- date.setDate(date.getDate() - 21);
+ date.setDate(date.getDate() - 2);
date = weekDay(date, monday);
let error;
@@ -559,14 +530,11 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
});
- describe('for 36h weekly rest', () => {
- it('should throw an error when the 36h weekly rest is not fulfilled', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
-
+ describe('for 72h weekly rest', () => {
+
+ it('should throw an error when work 11 consecutive days', async() => {
let date = Date.vnNew();
- date.setMonth(date.getMonth() - 2);
+ date.setMonth(date.getMonth() - 1);
date.setDate(1);
let error;
@@ -576,66 +544,24 @@ describe('workerTimeControl add/delete timeEntry()', () => {
await populateWeek(date, monday, sunday, ctx, workerId, options);
date = nextWeek(date);
await populateWeek(date, monday, thursday, ctx, workerId, options);
- date = weekDay(date, friday);
- date.setHours(7, 59, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
try {
- date.setHours(8, 1, 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(`Descanso semanal 36h. / 72h.`);
- });
-
- it('should throw an error when the 36h weekly rest is not fulfilled again', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
-
- let date = Date.vnNew();
- date.setMonth(date.getMonth() - 2);
- 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, saturday);
- date.setHours(3, 59, 0);
+ 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 36h. / 72h.`);
+ expect(error.message).toBe(`Descanso semanal`);
});
- });
- describe('for 72h weekly rest', () => {
- it('should throw when the 72h weekly rest is not fulfilled yet', async() => {
- pending('https://redmine.verdnatura.es/issues/4707');
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
+ it('should throw an error when the 72h weekly rest is not fulfilled', async() => {
let date = Date.vnNew();
- date.setMonth(date.getMonth() - 2);
+ date.setMonth(date.getMonth() - 1);
date.setDate(1);
let error;
@@ -645,32 +571,263 @@ describe('workerTimeControl add/delete timeEntry()', () => {
await populateWeek(date, monday, sunday, ctx, workerId, options);
date = nextWeek(date);
await populateWeek(date, monday, thursday, ctx, workerId, options);
- date = nextWeek(date);
- await populateWeek(date, monday, friday, ctx, workerId, options);
- date = nextWeek(date);
- await populateWeek(date, monday, saturday, ctx, workerId, options);
- date = nextWeek(date);
- await populateWeek(date, monday, saturday, ctx, workerId, options);
- date = lastWeek(date);
try {
date = weekDay(date, sunday);
- date.setHours(8, 0, 0);
+ 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 36h. / 72h.`);
+ 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', () => {
+ let dated = Date.vnNew();
+ dated.setDate(dated.getDate() - 7);
+ dated = new Date(weekDay(dated, monday));
+ const end = new Date(dated);
+ end.setDate(end.getDate() + 1);
+
+ it(`should return today's worked 8 hours without break`, async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ try {
+ await populateWeek(dated, monday, monday, ctx, hankPymId, options);
+ const start = new Date(dated - 1);
+ start.setHours(0, 0, 0);
+ await models.WorkerTimeControl.rawSql('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
+ hankPymId,
+ start,
+ end
+ ], options);
+
+ let [timeControlCalculateTable] = await models.WorkerTimeControl.rawSql('SELECT * FROM tmp.timeControlCalculate', null, options);
+
+ expect(timeControlCalculateTable.timeWorkSeconds).toEqual(28800);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it(`should return today's worked hours with 15min break and work time consecutive less than 5h`, async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ try {
+ await populateWeek(dated, monday, monday, ctx, hankPymId, options);
+ dated.setHours(14, 59, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+ dated.setHours(15, 14, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+
+ const start = new Date(dated - 1);
+ start.setHours(0, 0, 0);
+ await models.WorkerTimeControl.rawSql('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
+ hankPymId,
+ start,
+ end
+ ], options);
+
+ let [timeControlCalculateTable] = await models.WorkerTimeControl.rawSql('SELECT * FROM tmp.timeControlCalculate', null, options);
+
+ expect(timeControlCalculateTable.timeWorkSeconds).toEqual(28800);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it(`should return today's worked hours with 15min break and work time consecutive greater than 5h`, async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ try {
+ await populateWeek(dated, monday, monday, ctx, hankPymId, options);
+ dated.setHours(15, 0, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+ dated.setHours(15, 15, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+
+ const start = new Date(dated - 1);
+ start.setHours(0, 0, 0);
+ await models.WorkerTimeControl.rawSql('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
+ hankPymId,
+ start,
+ end
+ ], options);
+
+ let [timeControlCalculateTable] = await models.WorkerTimeControl.rawSql('SELECT * FROM tmp.timeControlCalculate', null, options);
+
+ expect(timeControlCalculateTable.timeWorkSeconds).toEqual(28800);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it(`should return today's worked hours with 25min break and work time consecutive less than 5h`, async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ try {
+ await populateWeek(dated, monday, monday, ctx, hankPymId, options);
+ dated.setHours(14, 59, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+ dated.setHours(15, 24, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+
+ const start = new Date(dated - 1);
+ start.setHours(0, 0, 0);
+ await models.WorkerTimeControl.rawSql('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
+ hankPymId,
+ start,
+ end
+ ], options);
+
+ let [timeControlCalculateTable] = await models.WorkerTimeControl.rawSql('SELECT * FROM tmp.timeControlCalculate', null, options);
+
+ expect(timeControlCalculateTable.timeWorkSeconds).toEqual(28500);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it(`should return today's worked hours with 25min break and work time consecutive greater than 5h`, async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ try {
+ await populateWeek(dated, monday, monday, ctx, hankPymId, options);
+ dated.setHours(15, 0, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+ dated.setHours(15, 25, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+
+ const start = new Date(dated - 1);
+ start.setHours(0, 0, 0);
+ await models.WorkerTimeControl.rawSql('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
+ hankPymId,
+ start,
+ end
+ ], options);
+
+ let [timeControlCalculateTable] = await models.WorkerTimeControl.rawSql('SELECT * FROM tmp.timeControlCalculate', null, options);
+
+ expect(timeControlCalculateTable.timeWorkSeconds).toEqual(28500);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it(`should return today's worked hours with 60min break and work time consecutive less than 5h`, async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ try {
+ await populateWeek(dated, monday, monday, ctx, hankPymId, options);
+ dated.setHours(14, 59, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+ dated.setHours(15, 59, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+
+ const start = new Date(dated - 1);
+ start.setHours(0, 0, 0);
+ await models.WorkerTimeControl.rawSql('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
+ hankPymId,
+ start,
+ end
+ ], options);
+
+ let [timeControlCalculateTable] = await models.WorkerTimeControl.rawSql('SELECT * FROM tmp.timeControlCalculate', null, options);
+
+ expect(timeControlCalculateTable.timeWorkSeconds).toEqual(25200);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it(`should return today's worked hours with 60min break and work time consecutive greater than 5h`, async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ try {
+ await populateWeek(dated, monday, monday, ctx, hankPymId, options);
+ dated.setHours(15, 0, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+ dated.setHours(16, 0, 0);
+ await addTimeEntry(ctx, dated, 'middle', hankPymId, options);
+
+ const start = new Date(dated - 1);
+ start.setHours(0, 0, 0);
+ await models.WorkerTimeControl.rawSql('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
+ hankPymId,
+ start,
+ end
+ ], options);
+
+ let [timeControlCalculateTable] = await models.WorkerTimeControl.rawSql('SELECT * FROM tmp.timeControlCalculate', null, options);
+
+ expect(timeControlCalculateTable.timeWorkSeconds).toEqual(26400);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
});
});
});
});
+async function addTimeEntry(ctx, dated, direction, userId, option) {
+ ctx.args = {timed: dated, direction};
+ await models.WorkerTimeControl.addTimeEntry(ctx, userId, option);
+}
+
function weekDay(date, dayToSet) {
const currentDay = date.getDay();
const distance = dayToSet - currentDay;
@@ -704,10 +861,10 @@ async function populateWeek(date, dayStart, dayEnd, ctx, workerId, options) {
dateEnd.setDate(dateStart.getDate() + dayEnd);
for (let i = dayStart; i <= dayEnd; i++) {
- dateStart.setHours(8, 0, 0);
+ dateStart.setHours(10, 0, 0);
ctx.args = {timed: dateStart, direction: 'in'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- dateStart.setHours(16, 0, 0);
+ dateStart.setHours(18, 0, 0);
ctx.args = {timed: dateStart, direction: 'out'};
await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
dateStart.setDate(dateStart.getDate() + 1);
diff --git a/modules/worker/front/time-control/index.js b/modules/worker/front/time-control/index.js
index 9137d7839..0a955c586 100644
--- a/modules/worker/front/time-control/index.js
+++ b/modules/worker/front/time-control/index.js
@@ -111,9 +111,10 @@ class Controller extends Section {
dayIndex.setDate(dayIndex.getDate() + 1);
}
- if (!this.weekTotalHours) this.fetchHours();
- if (this.worker)
+ if (this.worker) {
+ this.fetchHours();
this.getWeekData();
+ }
}
set weekTotalHours(totalHours) {
@@ -403,7 +404,7 @@ class Controller extends Section {
});
}
- changeState(state, reason) {
+ state(state, reason) {
this.state = state;
this.reason = reason;
this.repaint();