Merge branch 'test' into 5900-removeDuplicatedLogs
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
bc4058512a
|
@ -18,11 +18,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- (Entradas -> Correo) Al cambiar el tipo de cambio enviará un correo a las personas designadas
|
- (Entradas -> Correo) Al cambiar el tipo de cambio enviará un correo a las personas designadas
|
||||||
|
- (General -> Históricos) Botón para ver el estado del registro en cada punto
|
||||||
|
- (General -> Históricos) Al filtar por registro se muestra todo el histórial desde que fue creado
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- (General -> Históricos) Los registros se muestran agrupados por usuario y entidad
|
||||||
|
- (Facturas -> Facturación global) Optimizada, generación de PDFs y notificaciones en paralelo
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
-
|
- (General -> Históricos) Duplicidades eliminadas
|
||||||
|
- (Facturas -> Facturación global) Solucionados fallos que paran el proceso
|
||||||
|
|
||||||
## [2324.01] - 2023-06-15
|
## [2324.01] - 2023-06-15
|
||||||
|
|
||||||
|
|
|
@ -17,23 +17,22 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.renewToken = async function(ctx) {
|
Self.renewToken = async function(ctx) {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const userId = ctx.req.accessToken.userId;
|
const token = ctx.req.accessToken;
|
||||||
const created = ctx.req.accessToken.created;
|
|
||||||
const tokenId = ctx.req.accessToken.id;
|
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const differenceMilliseconds = now - created;
|
const differenceMilliseconds = now - token.created;
|
||||||
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
|
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
|
||||||
|
|
||||||
const accessTokenConfig = await models.AccessTokenConfig.findOne({fields: ['renewPeriod']});
|
const fields = ['renewPeriod', 'courtesyTime'];
|
||||||
|
const accessTokenConfig = await models.AccessTokenConfig.findOne({fields});
|
||||||
|
|
||||||
if (differenceSeconds <= accessTokenConfig.renewPeriod)
|
if (differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime)
|
||||||
throw new UserError(`The renew period has not been exceeded`);
|
throw new UserError(`The renew period has not been exceeded`, 'periodNotExceeded');
|
||||||
|
|
||||||
await Self.logout(tokenId);
|
await Self.logout(token.id);
|
||||||
const user = await Self.findById(userId);
|
const user = await Self.findById(token.userId);
|
||||||
const accessToken = await user.createAccessToken();
|
const accessToken = await user.createAccessToken();
|
||||||
|
|
||||||
return {token: accessToken.id, created: accessToken.created};
|
return {id: accessToken.id, ttl: accessToken.ttl};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -76,6 +76,6 @@ module.exports = Self => {
|
||||||
|
|
||||||
let loginInfo = Object.assign({password}, userInfo);
|
let loginInfo = Object.assign({password}, userInfo);
|
||||||
token = await Self.login(loginInfo, 'user');
|
token = await Self.login(loginInfo, 'user');
|
||||||
return {token: token.id, created: token.created};
|
return {token: token.id, ttl: token.ttl};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
|
"courtesyTime": {
|
||||||
|
"type": "number",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
"renewInterval": {
|
"renewInterval": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"required": true
|
"required": true
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
CREATE TABLE `vn`.`travelConfig` (
|
||||||
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`warehouseInFk` smallint(6) unsigned NOT NULL DEFAULT 8 COMMENT 'Warehouse de origen',
|
||||||
|
`warehouseOutFk` smallint(6) unsigned NOT NULL DEFAULT 60 COMMENT 'Warehouse destino',
|
||||||
|
`agencyFk` int(11) NOT NULL DEFAULT 1378 COMMENT 'Agencia por defecto',
|
||||||
|
`companyFk` int(10) unsigned NOT NULL DEFAULT 442 COMMENT 'Compañía por defecto',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `travelConfig_FK` (`warehouseInFk`),
|
||||||
|
KEY `travelConfig_FK_1` (`warehouseOutFk`),
|
||||||
|
KEY `travelConfig_FK_2` (`agencyFk`),
|
||||||
|
KEY `travelConfig_FK_3` (`companyFk`),
|
||||||
|
CONSTRAINT `travelConfig_FK` FOREIGN KEY (`warehouseInFk`) REFERENCES `warehouse` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `travelConfig_FK_1` FOREIGN KEY (`warehouseOutFk`) REFERENCES `warehouse` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `travelConfig_FK_2` FOREIGN KEY (`agencyFk`) REFERENCES `agencyMode` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `travelConfig_FK_3` FOREIGN KEY (`companyFk`) REFERENCES `company` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||||
|
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('Entry', 'addFromPackaging', 'WRITE', 'ALLOW', 'ROLE', 'production'),
|
||||||
|
('Entry', 'addFromBuy', 'WRITE', 'ALLOW', 'ROLE', 'production'),
|
||||||
|
('Supplier', 'getItemsPackaging', 'READ', 'ALLOW', 'ROLE', 'production');
|
|
@ -1,10 +1,11 @@
|
||||||
CREATE TABLE `salix`.`accessTokenConfig` (
|
CREATE TABLE `salix`.`accessTokenConfig` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`renewPeriod` int(10) unsigned DEFAULT NULL,
|
`renewPeriod` int(10) unsigned DEFAULT NULL,
|
||||||
|
`courtesyTime` int(10) unsigned DEFAULT NULL,
|
||||||
`renewInterval` int(10) unsigned DEFAULT NULL,
|
`renewInterval` int(10) unsigned DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||||
|
|
||||||
INSERT IGNORE INTO `salix`.`accessTokenConfig` (`id`, `renewPeriod`, `renewInterval`)
|
INSERT IGNORE INTO `salix`.`accessTokenConfig` (`id`, `renewPeriod`, `courtesyTime`, `renewInterval`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 21600, 300);
|
(1, 21600, 5, 300);
|
||||||
|
|
|
@ -699,12 +699,12 @@ INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agen
|
||||||
|
|
||||||
INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `zoneFk`, `zonePrice`, `zoneBonus`, `created`)
|
INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `zoneFk`, `zonePrice`, `zoneBonus`, `created`)
|
||||||
VALUES
|
VALUES
|
||||||
(1 , 3, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Bat cave', 121, 'T1111111', 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH)),
|
(1 , 3, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Bat cave', 121, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH)),
|
||||||
(2 , 1, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, 'T1111111', 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH)),
|
(2 , 1, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH)),
|
||||||
(3 , 1, 7, 1, 6, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, 'T2222222', 0, 3, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH)),
|
(3 , 1, 7, 1, 6, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH)),
|
||||||
(4 , 3, 2, 1, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, 'T3333333', 0, 9, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH)),
|
(4 , 3, 2, 1, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 9, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH)),
|
||||||
(5 , 3, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, 'T4444444', 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH)),
|
(5 , 3, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH)),
|
||||||
(6 , 1, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Mountain Drive Gotham', 1, 'A1111111', 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH)),
|
(6 , 1, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Mountain Drive Gotham', 1, NULL, 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH)),
|
||||||
(7 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1101, 'Mountain Drive Gotham', 1, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
|
(7 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1101, 'Mountain Drive Gotham', 1, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
|
||||||
(8 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1101, 'Bat cave', 121, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
|
(8 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1101, 'Bat cave', 121, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
|
||||||
(9 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
|
(9 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
|
||||||
|
@ -2572,6 +2572,26 @@ INSERT INTO `vn`.`ticketRecalc`(`ticketFk`)
|
||||||
|
|
||||||
CALL `vn`.`ticket_doRecalc`();
|
CALL `vn`.`ticket_doRecalc`();
|
||||||
|
|
||||||
|
UPDATE `vn`.`ticket`
|
||||||
|
SET refFk = 'T1111111'
|
||||||
|
WHERE id IN (1,2);
|
||||||
|
|
||||||
|
UPDATE `vn`.`ticket`
|
||||||
|
SET refFk = 'T2222222'
|
||||||
|
WHERE id = 3;
|
||||||
|
|
||||||
|
UPDATE `vn`.`ticket`
|
||||||
|
SET refFk = 'T3333333'
|
||||||
|
WHERE id = 4;
|
||||||
|
|
||||||
|
UPDATE `vn`.`ticket`
|
||||||
|
SET refFk = 'T4444444'
|
||||||
|
WHERE id = 5;
|
||||||
|
|
||||||
|
UPDATE `vn`.`ticket`
|
||||||
|
SET refFk = 'A1111111'
|
||||||
|
WHERE id = 6;
|
||||||
|
|
||||||
INSERT INTO `vn`.`zoneAgencyMode`(`id`, `agencyModeFk`, `zoneFk`)
|
INSERT INTO `vn`.`zoneAgencyMode`(`id`, `agencyModeFk`, `zoneFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1, 1),
|
(1, 1, 1),
|
||||||
|
|
|
@ -12605,7 +12605,7 @@ BEGIN
|
||||||
FROM myTicket t
|
FROM myTicket t
|
||||||
WHERE shipped BETWEEN TIMESTAMP(vFrom) AND TIMESTAMP(vTo, '23:59:59');
|
WHERE shipped BETWEEN TIMESTAMP(vFrom) AND TIMESTAMP(vTo, '23:59:59');
|
||||||
|
|
||||||
CALL vn.ticketGetTotal;
|
CALL vn.ticketGetTotal(NULL);
|
||||||
|
|
||||||
SELECT v.id, IFNULL(v.landed, v.shipped) landed,
|
SELECT v.id, IFNULL(v.landed, v.shipped) landed,
|
||||||
v.shipped, v.companyFk, v.nickname,
|
v.shipped, v.companyFk, v.nickname,
|
||||||
|
@ -47167,7 +47167,7 @@ BEGIN
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT vTicketId ticketFk;
|
SELECT vTicketId ticketFk;
|
||||||
|
|
||||||
CALL ticketGetTotal;
|
CALL ticketGetTotal(NULL);
|
||||||
|
|
||||||
SELECT total INTO vTotal FROM tmp.ticketTotal;
|
SELECT total INTO vTotal FROM tmp.ticketTotal;
|
||||||
|
|
||||||
|
@ -58494,6 +58494,13 @@ BEGIN
|
||||||
DECLARE vIsCEESerial BOOL DEFAULT FALSE;
|
DECLARE vIsCEESerial BOOL DEFAULT FALSE;
|
||||||
DECLARE vIsCorrectInvoiceDate BOOL;
|
DECLARE vIsCorrectInvoiceDate BOOL;
|
||||||
DECLARE vMaxShipped DATE;
|
DECLARE vMaxShipped DATE;
|
||||||
|
DECLARE vDone BOOL;
|
||||||
|
DECLARE vTicketFk INT;
|
||||||
|
DECLARE vCursor CURSOR FOR
|
||||||
|
SELECT id
|
||||||
|
FROM ticketToInvoice;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||||
|
|
||||||
SET vInvoiceDate = IFNULL(vInvoiceDate, util.VN_CURDATE());
|
SET vInvoiceDate = IFNULL(vInvoiceDate, util.VN_CURDATE());
|
||||||
|
|
||||||
|
@ -58579,6 +58586,20 @@ BEGIN
|
||||||
FROM invoiceOut
|
FROM invoiceOut
|
||||||
WHERE id = vNewInvoiceId;
|
WHERE id = vNewInvoiceId;
|
||||||
|
|
||||||
|
OPEN vCursor;
|
||||||
|
l: LOOP
|
||||||
|
SET vDone = FALSE;
|
||||||
|
FETCH vCursor INTO vTicketFk;
|
||||||
|
|
||||||
|
IF vDone THEN
|
||||||
|
LEAVE l;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
CALL ticket_recalc(vTicketFk, vTaxArea);
|
||||||
|
|
||||||
|
END LOOP;
|
||||||
|
CLOSE vCursor;
|
||||||
|
|
||||||
UPDATE ticket t
|
UPDATE ticket t
|
||||||
JOIN tmp.ticketToInvoice ti ON ti.id = t.id
|
JOIN tmp.ticketToInvoice ti ON ti.id = t.id
|
||||||
SET t.refFk = vNewRef;
|
SET t.refFk = vNewRef;
|
||||||
|
@ -58594,10 +58615,6 @@ BEGIN
|
||||||
INSERT INTO ticketTracking(stateFk,ticketFk,workerFk)
|
INSERT INTO ticketTracking(stateFk,ticketFk,workerFk)
|
||||||
SELECT * FROM tmp.updateInter;
|
SELECT * FROM tmp.updateInter;
|
||||||
|
|
||||||
INSERT INTO ticketLog (action, userFk, originFk, description)
|
|
||||||
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
|
||||||
FROM tmp.ticketToInvoice ti;
|
|
||||||
|
|
||||||
CALL invoiceExpenceMake(vNewInvoiceId);
|
CALL invoiceExpenceMake(vNewInvoiceId);
|
||||||
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
||||||
|
|
||||||
|
@ -69870,7 +69887,7 @@ DELIMITER ;
|
||||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||||
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
||||||
DELIMITER ;;
|
DELIMITER ;;
|
||||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `ticketGetTotal`()
|
CREATE DEFINER=`root`@`localhost` PROCEDURE `ticketGetTotal`(vTaxArea VARCHAR(25))
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Calcula el total con IVA para un conjunto de tickets.
|
* Calcula el total con IVA para un conjunto de tickets.
|
||||||
|
@ -69878,7 +69895,7 @@ BEGIN
|
||||||
* @table tmp.ticket(ticketFk) Identificadores de los tickets a calcular
|
* @table tmp.ticket(ticketFk) Identificadores de los tickets a calcular
|
||||||
* @return tmp.ticketTotal Total para cada ticket
|
* @return tmp.ticketTotal Total para cada ticket
|
||||||
*/
|
*/
|
||||||
CALL ticket_getTax(NULL);
|
CALL ticket_getTax(vTaxArea);
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketTotal;
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketTotal;
|
||||||
CREATE TEMPORARY TABLE tmp.ticketTotal
|
CREATE TEMPORARY TABLE tmp.ticketTotal
|
||||||
|
@ -70029,7 +70046,7 @@ BEGIN
|
||||||
AND clientFk = vClientFk
|
AND clientFk = vClientFk
|
||||||
AND shipped > '2001-01-01';
|
AND shipped > '2001-01-01';
|
||||||
|
|
||||||
CALL vn.ticketGetTotal;
|
CALL vn.ticketGetTotal(NULL);
|
||||||
|
|
||||||
SELECT c.id,
|
SELECT c.id,
|
||||||
c.name as Cliente,
|
c.name as Cliente,
|
||||||
|
@ -71878,7 +71895,7 @@ proc: BEGIN
|
||||||
LEAVE myLoop;
|
LEAVE myLoop;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
CALL ticket_recalc(vTicketFk);
|
CALL ticket_recalc(vTicketFk, NULL);
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
CLOSE cCur;
|
CLOSE cCur;
|
||||||
|
@ -72333,15 +72350,15 @@ BEGIN
|
||||||
JOIN ticket t ON t.id = tmpTicket.ticketFk;
|
JOIN ticket t ON t.id = tmpTicket.ticketFk;
|
||||||
|
|
||||||
CALL addressTaxArea ();
|
CALL addressTaxArea ();
|
||||||
|
|
||||||
IF vTaxArea > '' THEN
|
IF vTaxArea IS NOT NULL THEN
|
||||||
UPDATE tmp.addressTaxArea
|
UPDATE tmp.addressTaxArea
|
||||||
SET areaFk = vTaxArea;
|
SET areaFk = vTaxArea;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
/* Solo se calcula la base imponible (taxableBase) y el impuesto se calculará posteriormente
|
/* Solo se calcula la base imponible (taxableBase) y el impuesto se calculará posteriormente
|
||||||
* No se debería cambiar el sistema por problemas con los decimales
|
* No se debería cambiar el sistema por problemas con los decimales
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketTax;
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketTax;
|
||||||
CREATE TEMPORARY TABLE tmp.ticketTax
|
CREATE TEMPORARY TABLE tmp.ticketTax
|
||||||
(PRIMARY KEY (ticketFk, code, rate))
|
(PRIMARY KEY (ticketFk, code, rate))
|
||||||
|
@ -72349,7 +72366,7 @@ BEGIN
|
||||||
SELECT * FROM (
|
SELECT * FROM (
|
||||||
SELECT tmpTicket.ticketFk,
|
SELECT tmpTicket.ticketFk,
|
||||||
bp.pgcFk,
|
bp.pgcFk,
|
||||||
SUM(s.quantity * s.price * (100 - s.discount)/100 ) AS taxableBase,
|
SUM(s.quantity * s.price * (100 - s.discount)/100 ) taxableBase,
|
||||||
pgc.rate,
|
pgc.rate,
|
||||||
tc.code,
|
tc.code,
|
||||||
bp.priority
|
bp.priority
|
||||||
|
@ -72369,7 +72386,7 @@ BEGIN
|
||||||
JOIN pgc ON pgc.code = bp.pgcFk
|
JOIN pgc ON pgc.code = bp.pgcFk
|
||||||
JOIN taxClass tc ON tc.id = bp.taxClassFk
|
JOIN taxClass tc ON tc.id = bp.taxClassFk
|
||||||
GROUP BY tmpTicket.ticketFk, pgc.code, pgc.rate
|
GROUP BY tmpTicket.ticketFk, pgc.code, pgc.rate
|
||||||
HAVING taxableBase != 0) t3
|
HAVING taxableBase <> 0) t3
|
||||||
ORDER BY priority;
|
ORDER BY priority;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketServiceTax;
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketServiceTax;
|
||||||
|
@ -72378,7 +72395,7 @@ BEGIN
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT tt.ticketFk,
|
SELECT tt.ticketFk,
|
||||||
pgc.code pgcFk,
|
pgc.code pgcFk,
|
||||||
SUM(ts.quantity * ts.price) AS taxableBase,
|
SUM(ts.quantity * ts.price) taxableBase,
|
||||||
pgc.rate,
|
pgc.rate,
|
||||||
tc.code
|
tc.code
|
||||||
FROM tmp.ticket tt
|
FROM tmp.ticket tt
|
||||||
|
@ -72394,7 +72411,7 @@ BEGIN
|
||||||
JOIN pgc ON pgc.code = bp.pgcFk
|
JOIN pgc ON pgc.code = bp.pgcFk
|
||||||
JOIN taxClass tc ON tc.id = bp.taxClassFk
|
JOIN taxClass tc ON tc.id = bp.taxClassFk
|
||||||
GROUP BY tt.ticketFk, pgc.code
|
GROUP BY tt.ticketFk, pgc.code
|
||||||
HAVING taxableBase != 0;
|
HAVING taxableBase <> 0;
|
||||||
|
|
||||||
INSERT INTO tmp.ticketTax (ticketFk, pgcFk, taxableBase, rate, code)
|
INSERT INTO tmp.ticketTax (ticketFk, pgcFk, taxableBase, rate, code)
|
||||||
SELECT ts.ticketFk, ts.pgcFk, ts.taxableBase, ts.rate, ts.code
|
SELECT ts.ticketFk, ts.pgcFk, ts.taxableBase, ts.rate, ts.code
|
||||||
|
@ -72405,8 +72422,8 @@ BEGIN
|
||||||
CREATE TEMPORARY TABLE tmp.ticketAmount
|
CREATE TEMPORARY TABLE tmp.ticketAmount
|
||||||
(INDEX (ticketFk))
|
(INDEX (ticketFk))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT ticketFk,
|
SELECT ticketFk,
|
||||||
taxableBase,
|
taxableBase,
|
||||||
SUM(CAST(taxableBase * rate / 100 AS DECIMAL(10, 2))) tax,
|
SUM(CAST(taxableBase * rate / 100 AS DECIMAL(10, 2))) tax,
|
||||||
code
|
code
|
||||||
FROM tmp.ticketTax
|
FROM tmp.ticketTax
|
||||||
|
@ -72725,20 +72742,31 @@ DELIMITER ;
|
||||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||||
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
||||||
DELIMITER ;;
|
DELIMITER ;;
|
||||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `ticket_recalc`(vTicketId INT)
|
CREATE DEFINER=`root`@`localhost` PROCEDURE `ticket_recalc`(vSelf INT, vTaxArea VARCHAR(25))
|
||||||
BEGIN
|
proc:BEGIN
|
||||||
/**
|
/**
|
||||||
* Calcula y guarda el total con/sin IVA en un ticket.
|
* Calcula y guarda el total con/sin IVA en un ticket.
|
||||||
*
|
*
|
||||||
* @param vTicketId Identificador del ticket
|
* @param vTicketId Identificador del ticket
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
DECLARE hasInvoice BOOL;
|
||||||
|
|
||||||
|
SELECT COUNT(*) INTO hasInvoice
|
||||||
|
FROM ticket
|
||||||
|
WHERE id = vSelf
|
||||||
|
AND refFk IS NOT NULL;
|
||||||
|
|
||||||
|
IF hasInvoice THEN
|
||||||
|
LEAVE proc;
|
||||||
|
END IF;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticket;
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticket;
|
||||||
CREATE TEMPORARY TABLE tmp.ticket
|
CREATE TEMPORARY TABLE tmp.ticket
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT vTicketId ticketFk;
|
SELECT vSelf ticketFk;
|
||||||
|
|
||||||
CALL ticketGetTotal;
|
CALL ticketGetTotal(vTaxArea);
|
||||||
|
|
||||||
UPDATE ticket t
|
UPDATE ticket t
|
||||||
JOIN tmp.ticketTotal tt ON tt.ticketFk = t.id
|
JOIN tmp.ticketTotal tt ON tt.ticketFk = t.id
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe('Travel descriptor path', () => {
|
||||||
browser = await getBrowser();
|
browser = await getBrowser();
|
||||||
page = browser.page;
|
page = browser.page;
|
||||||
await page.loginAndModule('buyer', 'travel');
|
await page.loginAndModule('buyer', 'travel');
|
||||||
await page.write(selectors.travelIndex.generalSearchFilter, '1');
|
await page.write(selectors.travelIndex.generalSearchFilter, '3');
|
||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
await page.waitForState('travel.card.summary');
|
await page.waitForState('travel.card.summary');
|
||||||
});
|
});
|
||||||
|
@ -23,7 +23,7 @@ describe('Travel descriptor path', () => {
|
||||||
await page.waitForState('travel.index');
|
await page.waitForState('travel.index');
|
||||||
const result = await page.countElement(selectors.travelIndex.anySearchResult);
|
const result = await page.countElement(selectors.travelIndex.anySearchResult);
|
||||||
|
|
||||||
expect(result).toBeGreaterThanOrEqual(7);
|
expect(result).toBeGreaterThanOrEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate to the first search result', async() => {
|
it('should navigate to the first search result', async() => {
|
||||||
|
|
|
@ -59,12 +59,13 @@ export default class Auth {
|
||||||
password: password || undefined
|
password: password || undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
return this.$http.post('VnUsers/signIn', params)
|
return this.$http.post('VnUsers/signIn', params)
|
||||||
.then(json => this.onLoginOk(json, remember));
|
.then(json => this.onLoginOk(json, now, remember));
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoginOk(json, remember) {
|
onLoginOk(json, now, remember) {
|
||||||
this.vnToken.set(json.data.token, json.data.created, remember);
|
this.vnToken.set(json.data.token, now, json.data.ttl, remember);
|
||||||
|
|
||||||
return this.loadAcls().then(() => {
|
return this.loadAcls().then(() => {
|
||||||
let continueHash = this.$state.params.continue;
|
let continueHash = this.$state.params.continue;
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import HttpError from 'core/lib/http-error';
|
import HttpError from 'core/lib/http-error';
|
||||||
|
|
||||||
interceptor.$inject = ['$q', 'vnApp', 'vnToken', '$translate'];
|
interceptor.$inject = ['$q', 'vnApp', '$translate'];
|
||||||
function interceptor($q, vnApp, vnToken, $translate) {
|
function interceptor($q, vnApp, $translate) {
|
||||||
let apiPath = 'api/';
|
let apiPath = 'api/';
|
||||||
|
let token = sessionStorage.getItem('vnToken')
|
||||||
|
?? localStorage.getItem('vnToken');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
setToken(newToken) {
|
||||||
|
token = newToken;
|
||||||
|
},
|
||||||
setApiPath(path) {
|
setApiPath(path) {
|
||||||
apiPath = path;
|
apiPath = path;
|
||||||
},
|
},
|
||||||
|
@ -14,8 +19,8 @@ function interceptor($q, vnApp, vnToken, $translate) {
|
||||||
|
|
||||||
if (config.url.charAt(0) !== '/' && apiPath)
|
if (config.url.charAt(0) !== '/' && apiPath)
|
||||||
config.url = `${apiPath}${config.url}`;
|
config.url = `${apiPath}${config.url}`;
|
||||||
if (vnToken.token)
|
if (token)
|
||||||
config.headers.Authorization = vnToken.token;
|
config.headers.Authorization = token;
|
||||||
if ($translate.use())
|
if ($translate.use())
|
||||||
config.headers['Accept-Language'] = $translate.use();
|
config.headers['Accept-Language'] = $translate.use();
|
||||||
if (config.filter) {
|
if (config.filter) {
|
||||||
|
|
|
@ -6,37 +6,118 @@ import ngModule from '../module';
|
||||||
* @property {String} token The current login token or %null
|
* @property {String} token The current login token or %null
|
||||||
*/
|
*/
|
||||||
export default class Token {
|
export default class Token {
|
||||||
constructor() {
|
constructor(vnInterceptor, $http, $rootScope) {
|
||||||
try {
|
Object.assign(this, {
|
||||||
this.token = sessionStorage.getItem('vnToken');
|
vnInterceptor,
|
||||||
this.created = sessionStorage.getItem('vnTokenCreated');
|
$http,
|
||||||
if (!this.token) {
|
$rootScope
|
||||||
this.token = localStorage.getItem('vnToken');
|
});
|
||||||
this.created = localStorage.getItem('vnTokenCreated');
|
|
||||||
}
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
set(token, created, remember) {
|
|
||||||
this.unset();
|
|
||||||
try {
|
|
||||||
if (remember) {
|
|
||||||
localStorage.setItem('vnToken', token);
|
|
||||||
localStorage.setItem('vnTokenCreated', created);
|
|
||||||
} else {
|
|
||||||
sessionStorage.setItem('vnToken', token);
|
|
||||||
sessionStorage.setItem('vnTokenCreated', created);
|
|
||||||
}
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
this.token = token;
|
try {
|
||||||
this.created = created;
|
this.getStorage(sessionStorage);
|
||||||
|
this.remember = true;
|
||||||
|
|
||||||
|
if (!this.token) {
|
||||||
|
this.getStorage(localStorage);
|
||||||
|
this.remember = false;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set(token, created, ttl, remember) {
|
||||||
|
this.unset();
|
||||||
|
|
||||||
|
Object.assign(this, {
|
||||||
|
token,
|
||||||
|
created,
|
||||||
|
ttl,
|
||||||
|
remember
|
||||||
|
});
|
||||||
|
this.vnInterceptor.setToken(token);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (remember)
|
||||||
|
this.setStorage(localStorage, token, created, ttl);
|
||||||
|
else
|
||||||
|
this.setStorage(sessionStorage, token, created, ttl);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unset() {
|
unset() {
|
||||||
localStorage.removeItem('vnToken');
|
|
||||||
sessionStorage.removeItem('vnToken');
|
|
||||||
this.token = null;
|
this.token = null;
|
||||||
this.created = null;
|
this.created = null;
|
||||||
|
this.ttl = null;
|
||||||
|
this.remember = null;
|
||||||
|
this.vnInterceptor.setToken(null);
|
||||||
|
|
||||||
|
this.removeStorage(localStorage);
|
||||||
|
this.removeStorage(sessionStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
getStorage(storage) {
|
||||||
|
this.token = storage.getItem('vnToken');
|
||||||
|
if (!this.token) return;
|
||||||
|
const created = storage.getItem('vnTokenCreated');
|
||||||
|
this.created = created && new Date(created);
|
||||||
|
this.renewPeriod = storage.getItem('vnTokenRenewPeriod');
|
||||||
|
}
|
||||||
|
|
||||||
|
setStorage(storage, token, created, ttl) {
|
||||||
|
storage.setItem('vnToken', token);
|
||||||
|
storage.setItem('vnTokenCreated', created.toJSON());
|
||||||
|
storage.setItem('vnTokenTtl', ttl);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeStorage(storage) {
|
||||||
|
storage.removeItem('vnToken');
|
||||||
|
storage.removeItem('vnTokenCreated');
|
||||||
|
storage.removeItem('vnTokenTtl');
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchConfig() {
|
||||||
|
const filter = {fields: ['renewInterval', 'renewPeriod']};
|
||||||
|
this.$http.get('AccessTokenConfigs/findOne', {filter}).then(res => {
|
||||||
|
const data = res.data;
|
||||||
|
if (!data) return;
|
||||||
|
this.renewPeriod = data.renewPeriod;
|
||||||
|
this.stopRenewer();
|
||||||
|
this.inservalId = setInterval(() => this.checkValidity(), data.renewInterval * 1000);
|
||||||
|
this.checkValidity();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
checkValidity() {
|
||||||
|
if (this.checking || !this.created) return;
|
||||||
|
this.checking = true;
|
||||||
|
const renewPeriod = Math.min(this.ttl, this.renewPeriod) * 1000;
|
||||||
|
const maxDate = this.created.getTime() + renewPeriod;
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
if (now.getTime() <= maxDate) {
|
||||||
|
this.checking = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$http.post('VnUsers/renewToken')
|
||||||
|
.then(res => {
|
||||||
|
const token = res.data;
|
||||||
|
this.set(token.id, now, token.ttl, this.remember);
|
||||||
|
})
|
||||||
|
.catch(res => {
|
||||||
|
if (res.data?.error?.code !== 'periodNotExceeded')
|
||||||
|
throw res;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.checking = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stopRenewer() {
|
||||||
|
clearInterval(this.inservalId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Token.$inject = ['vnInterceptor', '$http', '$rootScope'];
|
||||||
|
|
||||||
ngModule.service('vnToken', Token);
|
ngModule.service('vnToken', Token);
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<button class="buttonAccount">
|
<button class="buttonAccount">
|
||||||
<img
|
<img
|
||||||
id="user"
|
id="user"
|
||||||
ng-src="{{$ctrl.getImageUrl()}}"
|
ng-src="{{::$ctrl.getImageUrl()}}"
|
||||||
ng-click="userPopover.show($event)"
|
ng-click="userPopover.show($event)"
|
||||||
translate-attr="{title: 'Account'}"
|
translate-attr="{title: 'Account'}"
|
||||||
on-error-src/>
|
on-error-src/>
|
||||||
|
@ -93,4 +93,4 @@
|
||||||
</vn-list>
|
</vn-list>
|
||||||
</vn-portal>
|
</vn-portal>
|
||||||
<ui-view class="main-view"></ui-view>
|
<ui-view class="main-view"></ui-view>
|
||||||
<vn-scroll-up></vn-scroll-up>
|
<vn-scroll-up></vn-scroll-up>
|
||||||
|
|
|
@ -3,14 +3,13 @@ import Component from 'core/lib/component';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
export class Layout extends Component {
|
export class Layout extends Component {
|
||||||
constructor($element, $, vnModules, vnToken) {
|
constructor($element, $, vnModules) {
|
||||||
super($element, $);
|
super($element, $);
|
||||||
this.modules = vnModules.get();
|
this.modules = vnModules.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
$onInit() {
|
$onInit() {
|
||||||
this.getUserData();
|
this.getUserData();
|
||||||
this.getAccessTokenConfig();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserData() {
|
getUserData() {
|
||||||
|
@ -32,41 +31,11 @@ export class Layout extends Component {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccessTokenConfig() {
|
|
||||||
this.$http.get('AccessTokenConfigs').then(json => {
|
|
||||||
const firtsResult = json.data[0];
|
|
||||||
if (!firtsResult) return;
|
|
||||||
this.renewPeriod = firtsResult.renewPeriod;
|
|
||||||
this.renewInterval = firtsResult.renewInterval;
|
|
||||||
|
|
||||||
const intervalMilliseconds = firtsResult.renewInterval * 1000;
|
|
||||||
this.inservalId = setInterval(this.checkTokenValidity.bind(this), intervalMilliseconds);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
checkTokenValidity() {
|
|
||||||
const now = new Date();
|
|
||||||
const differenceMilliseconds = now - new Date(this.vnToken.created);
|
|
||||||
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
|
|
||||||
|
|
||||||
if (differenceSeconds > this.renewPeriod) {
|
|
||||||
this.$http.post('VnUsers/renewToken')
|
|
||||||
.then(json => {
|
|
||||||
if (json.data.token) {
|
|
||||||
let remember = true;
|
|
||||||
if (window.sessionStorage.vnToken) remember = false;
|
|
||||||
|
|
||||||
this.vnToken.set(json.data.token, json.data.created, remember);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$onDestroy() {
|
$onDestroy() {
|
||||||
clearInterval(this.inservalId);
|
this.vnToken.stopRenewer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Layout.$inject = ['$element', '$scope', 'vnModules', 'vnToken'];
|
Layout.$inject = ['$element', '$scope', 'vnModules'];
|
||||||
|
|
||||||
ngModule.vnComponent('vnLayout', {
|
ngModule.vnComponent('vnLayout', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
|
|
|
@ -37,49 +37,4 @@ describe('Component vnLayout', () => {
|
||||||
expect(url).not.toBeDefined();
|
expect(url).not.toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getAccessTokenConfig()', () => {
|
|
||||||
it(`should set the renewPeriod and renewInterval properties in localStorage`, () => {
|
|
||||||
const response = [{
|
|
||||||
renewPeriod: 100,
|
|
||||||
renewInterval: 5
|
|
||||||
}];
|
|
||||||
|
|
||||||
$httpBackend.expect('GET', `AccessTokenConfigs`).respond(response);
|
|
||||||
controller.getAccessTokenConfig();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.renewPeriod).toBe(100);
|
|
||||||
expect(controller.renewInterval).toBe(5);
|
|
||||||
expect(controller.inservalId).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('checkTokenValidity()', () => {
|
|
||||||
it(`should not call renewToken and not set vnToken in the controller`, () => {
|
|
||||||
controller.renewPeriod = 100;
|
|
||||||
controller.vnToken.created = new Date();
|
|
||||||
|
|
||||||
controller.checkTokenValidity();
|
|
||||||
|
|
||||||
expect(controller.vnToken.token).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should call renewToken and set vnToken properties in the controller`, () => {
|
|
||||||
const response = {
|
|
||||||
token: 999,
|
|
||||||
created: new Date()
|
|
||||||
};
|
|
||||||
controller.renewPeriod = 100;
|
|
||||||
const oneHourBefore = new Date(Date.now() - (60 * 60 * 1000));
|
|
||||||
controller.vnToken.created = oneHourBefore;
|
|
||||||
|
|
||||||
$httpBackend.expect('POST', `VnUsers/renewToken`).respond(response);
|
|
||||||
controller.checkTokenValidity();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.vnToken.token).toBe(999);
|
|
||||||
expect(controller.vnToken.created).toEqual(response.created);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
url="{{$ctrl.url}}"
|
url="{{$ctrl.url}}"
|
||||||
filter="$ctrl.filter"
|
filter="$ctrl.filter"
|
||||||
data="$ctrl.logs"
|
data="$ctrl.logs"
|
||||||
order="creationDate DESC, originFk DESC, id DESC"
|
order="creationDate DESC, id DESC"
|
||||||
limit="20">
|
limit="20">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<vn-crud-model
|
<vn-crud-model
|
||||||
|
@ -24,7 +24,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="user-log vn-mb-sm" ng-repeat="userLog in ::originLog.logs">
|
<div class="user-log vn-mb-sm" ng-repeat="userLog in ::originLog.logs">
|
||||||
<div class="timeline">
|
<div class="timeline">
|
||||||
<vn-avatar
|
<div class="user-avatar">
|
||||||
|
<vn-avatar
|
||||||
ng-class="::{system: !userLog.user}"
|
ng-class="::{system: !userLog.user}"
|
||||||
val="{{::userLog.user ? userLog.user.nickname : $ctrl.$t('System')}}"
|
val="{{::userLog.user ? userLog.user.nickname : $ctrl.$t('System')}}"
|
||||||
ng-click="$ctrl.showWorkerDescriptor($event, userLog)">
|
ng-click="$ctrl.showWorkerDescriptor($event, userLog)">
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
ng-src="/api/Images/user/160x160/{{::userLog.userFk}}/download?access_token={{::$ctrl.vnToken.token}}">
|
ng-src="/api/Images/user/160x160/{{::userLog.userFk}}/download?access_token={{::$ctrl.vnToken.token}}">
|
||||||
</img>
|
</img>
|
||||||
</vn-avatar>
|
</vn-avatar>
|
||||||
|
</div>
|
||||||
<div class="arrow bg-panel" ng-if="::$ctrl.byRecord"></div>
|
<div class="arrow bg-panel" ng-if="::$ctrl.byRecord"></div>
|
||||||
<div class="line"></div>
|
<div class="line"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -228,9 +230,6 @@
|
||||||
</vn-date-picker>
|
</vn-date-picker>
|
||||||
</form>
|
</form>
|
||||||
</vn-side-menu>
|
</vn-side-menu>
|
||||||
<vn-worker-descriptor-popover
|
|
||||||
vn-id="worker-descriptor">
|
|
||||||
</vn-worker-descriptor-popover>
|
|
||||||
<vn-popover vn-id="instance-popover">
|
<vn-popover vn-id="instance-popover">
|
||||||
<tpl-body class="vn-log-instance">
|
<tpl-body class="vn-log-instance">
|
||||||
<vn-spinner
|
<vn-spinner
|
||||||
|
@ -240,9 +239,9 @@
|
||||||
</vn-spinner>
|
</vn-spinner>
|
||||||
<div
|
<div
|
||||||
ng-if="!$ctrl.instance.canceler" class="instance">
|
ng-if="!$ctrl.instance.canceler" class="instance">
|
||||||
<div class="header vn-pa-sm">
|
<h6 class="header vn-pa-sm">
|
||||||
{{$ctrl.instance.modelLog.modelI18n}} #{{$ctrl.instance.modelLog.id}}
|
{{$ctrl.instance.modelLog.modelI18n}} #{{$ctrl.instance.modelLog.id}}
|
||||||
</div>
|
</h6>
|
||||||
<div class="change-detail vn-pa-sm">
|
<div class="change-detail vn-pa-sm">
|
||||||
<div ng-if="$ctrl.instance.props"
|
<div ng-if="$ctrl.instance.props"
|
||||||
ng-repeat="prop in $ctrl.instance.props">
|
ng-repeat="prop in $ctrl.instance.props">
|
||||||
|
@ -258,3 +257,6 @@
|
||||||
</div>
|
</div>
|
||||||
</tpl-body>
|
</tpl-body>
|
||||||
</vn-popover>
|
</vn-popover>
|
||||||
|
<vn-worker-descriptor-popover
|
||||||
|
vn-id="worker-descriptor">
|
||||||
|
</vn-worker-descriptor-popover>
|
||||||
|
|
|
@ -67,7 +67,7 @@ export default class Controller extends Section {
|
||||||
|
|
||||||
$onInit() {
|
$onInit() {
|
||||||
const match = this.url?.match(/(.*)Logs$/);
|
const match = this.url?.match(/(.*)Logs$/);
|
||||||
this.modelI18n = this.translateModel(match && match[1]);
|
this.modelI18n = match && this.translateModel(match[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$postLink() {
|
$postLink() {
|
||||||
|
@ -115,23 +115,21 @@ export default class Controller extends Section {
|
||||||
// User
|
// User
|
||||||
|
|
||||||
const userChanged = originChanged
|
const userChanged = originChanged
|
||||||
|| log.userFk != prevLog.userFk
|
|| log.userFk != prevLog.userFk;
|
||||||
|| nLogs >= 6;
|
|
||||||
if (userChanged) {
|
if (userChanged) {
|
||||||
originLog.logs.push(userLog = {
|
originLog.logs.push(userLog = {
|
||||||
user: log.user,
|
user: log.user,
|
||||||
userFk: log.userFk,
|
userFk: log.userFk,
|
||||||
logs: []
|
logs: []
|
||||||
});
|
});
|
||||||
nLogs = 0;
|
|
||||||
}
|
}
|
||||||
nLogs++;
|
|
||||||
|
|
||||||
// Model
|
// Model
|
||||||
|
|
||||||
const modelChanged = userChanged
|
const modelChanged = userChanged
|
||||||
|| log.changedModel != prevLog.changedModel
|
|| log.changedModel != prevLog.changedModel
|
||||||
|| log.changedModelId != prevLog.changedModelId;
|
|| log.changedModelId != prevLog.changedModelId
|
||||||
|
|| nLogs >= 6;
|
||||||
if (modelChanged) {
|
if (modelChanged) {
|
||||||
userLog.logs.push(modelLog = {
|
userLog.logs.push(modelLog = {
|
||||||
model: log.changedModel,
|
model: log.changedModel,
|
||||||
|
@ -140,7 +138,9 @@ export default class Controller extends Section {
|
||||||
showValue: log.changedModelValue,
|
showValue: log.changedModelValue,
|
||||||
logs: []
|
logs: []
|
||||||
});
|
});
|
||||||
|
nLogs = 0;
|
||||||
}
|
}
|
||||||
|
nLogs++;
|
||||||
|
|
||||||
modelLog.logs.push(log);
|
modelLog.logs.push(log);
|
||||||
|
|
||||||
|
@ -181,8 +181,8 @@ export default class Controller extends Section {
|
||||||
props.push({
|
props.push({
|
||||||
name: prop,
|
name: prop,
|
||||||
nameI18n: firstUpper(locale.columns?.[prop]) || prop,
|
nameI18n: firstUpper(locale.columns?.[prop]) || prop,
|
||||||
old: getVal(olds, prop),
|
val: getVal(vals, prop),
|
||||||
val: getVal(vals, prop)
|
old: olds && getVal(olds, prop)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
props.sort(
|
props.sort(
|
||||||
|
@ -220,7 +220,7 @@ export default class Controller extends Section {
|
||||||
const instance = res.data;
|
const instance = res.data;
|
||||||
const propNames = Object.keys(instance);
|
const propNames = Object.keys(instance);
|
||||||
const locale = window.validations[modelLog.model]?.locale || {};
|
const locale = window.validations[modelLog.model]?.locale || {};
|
||||||
this.instance.props = this.parseProps(propNames, locale, instance, {});
|
this.instance.props = this.parseProps(propNames, locale, instance);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.instance.canceler = null;
|
this.instance.canceler = null;
|
||||||
|
|
|
@ -44,11 +44,20 @@ vn-log {
|
||||||
right: -4px;
|
right: -4px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
& > vn-avatar {
|
& > .user-avatar {
|
||||||
cursor: pointer;
|
background-color: $color-bg;
|
||||||
|
padding: $spacing-sm 0;
|
||||||
|
margin-top: -$spacing-sm;
|
||||||
|
position: sticky;
|
||||||
|
top: 64px;
|
||||||
|
|
||||||
&.system {
|
& > vn-avatar {
|
||||||
background-color: $color-main !important;
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
&.system {
|
||||||
|
background-color: $color-main !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
& > .line {
|
& > .line {
|
||||||
|
@ -57,8 +66,8 @@ vn-log {
|
||||||
width: 2px;
|
width: 2px;
|
||||||
left: 18px;
|
left: 18px;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
top: 44px;
|
top: 0;
|
||||||
bottom: -2px;
|
bottom: -$spacing-sm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:last-child > .timeline > .line {
|
&:last-child > .timeline > .line {
|
||||||
|
@ -228,6 +237,7 @@ vn-log {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
& > .change-detail {
|
& > .change-detail {
|
||||||
color: $color-font-light;
|
color: $color-font-light;
|
||||||
|
|
|
@ -11,7 +11,8 @@ function config($stateProvider, $urlRouterProvider) {
|
||||||
abstract: true,
|
abstract: true,
|
||||||
template: '<vn-layout></vn-layout>',
|
template: '<vn-layout></vn-layout>',
|
||||||
resolve: {
|
resolve: {
|
||||||
config: ['vnConfig', vnConfig => vnConfig.initialize()]
|
config: ['vnConfig', vnConfig => vnConfig.initialize()],
|
||||||
|
token: ['vnToken', vnToken => vnToken.fetchConfig()]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.state('outLayout', {
|
.state('outLayout', {
|
||||||
|
|
|
@ -37,37 +37,52 @@ module.exports = Self => {
|
||||||
changedModelId: log.changedModelId
|
changedModelId: log.changedModelId
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Fetch creation and all update logs for record up to requested log
|
||||||
|
|
||||||
const createdWhere = {
|
const createdWhere = {
|
||||||
action: 'insert',
|
action: 'insert',
|
||||||
creationDate: {lte: log.creationDate}
|
creationDate: {lte: log.creationDate}
|
||||||
};
|
};
|
||||||
const createdLog = await Self.findOne({
|
const createdLog = await Self.findOne({
|
||||||
fields: ['id', 'creationDate'],
|
fields: ['id', 'creationDate', 'newInstance'],
|
||||||
where: Object.assign(createdWhere, where),
|
where: Object.assign(createdWhere, where),
|
||||||
order: 'creationDate DESC'
|
order: 'creationDate DESC, id DESC'
|
||||||
});
|
});
|
||||||
if (!createdLog)
|
|
||||||
throw new NotFoundError('Cannot find creation log');
|
|
||||||
|
|
||||||
const logsWhere = {
|
const instance = {};
|
||||||
id: {between: [
|
|
||||||
Math.min(id, createdLog.id),
|
let logsWhere = {
|
||||||
Math.max(id, createdLog.id)
|
action: 'update'
|
||||||
]},
|
|
||||||
creationDate: {between: [
|
|
||||||
createdLog.creationDate,
|
|
||||||
log.creationDate
|
|
||||||
]}
|
|
||||||
};
|
};
|
||||||
|
if (createdLog) {
|
||||||
|
Object.assign(instance, createdLog.newInstance);
|
||||||
|
Object.assign(logsWhere, {
|
||||||
|
creationDate: {between: [
|
||||||
|
createdLog.creationDate,
|
||||||
|
log.creationDate
|
||||||
|
]},
|
||||||
|
id: {between: [
|
||||||
|
Math.min(id, createdLog.id),
|
||||||
|
Math.max(id, createdLog.id)
|
||||||
|
]}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Object.assign(logsWhere, {
|
||||||
|
creationDate: {lte: log.creationDate},
|
||||||
|
id: {lte: id}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const logs = await Self.find({
|
const logs = await Self.find({
|
||||||
fields: ['newInstance'],
|
fields: ['newInstance'],
|
||||||
where: Object.assign(logsWhere, where),
|
where: Object.assign(logsWhere, where),
|
||||||
order: 'creationDate'
|
order: 'creationDate, id'
|
||||||
});
|
});
|
||||||
if (!logs.length)
|
if (!logs.length && !createdLog)
|
||||||
throw new NotFoundError('No logs found for record');
|
throw new NotFoundError('No logs found for record');
|
||||||
|
|
||||||
const instance = {};
|
// Merge all logs in order into one instance
|
||||||
|
|
||||||
for (const log of logs)
|
for (const log of logs)
|
||||||
Object.assign(instance, log.newInstance);
|
Object.assign(instance, log.newInstance);
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = `CALL vn.ticket_recalc(?)`;
|
const query = `CALL vn.ticket_recalc(?, NULL)`;
|
||||||
await Self.rawSql(query, [refundTicket.id], myOptions);
|
await Self.rawSql(query, [refundTicket.id], myOptions);
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
|
@ -96,7 +96,7 @@ module.exports = Self => {
|
||||||
await sale.updateAttributes({price: newPrice}, myOptions);
|
await sale.updateAttributes({price: newPrice}, myOptions);
|
||||||
|
|
||||||
await Self.rawSql('CALL vn.manaSpellersRequery(?)', [userId], myOptions);
|
await Self.rawSql('CALL vn.manaSpellersRequery(?)', [userId], myOptions);
|
||||||
await Self.rawSql('CALL vn.ticket_recalc(?)', [sale.ticketFk], myOptions);
|
await Self.rawSql('CALL vn.ticket_recalc(?, NULL)', [sale.ticketFk], myOptions);
|
||||||
|
|
||||||
const salesPerson = sale.ticket().client().salesPersonUser();
|
const salesPerson = sale.ticket().client().salesPersonUser();
|
||||||
if (salesPerson) {
|
if (salesPerson) {
|
||||||
|
|
|
@ -85,7 +85,7 @@ module.exports = Self => {
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
await Self.rawSql('CALL vn.sale_calculateComponent(?, NULL)', [newSale.id], myOptions);
|
await Self.rawSql('CALL vn.sale_calculateComponent(?, NULL)', [newSale.id], myOptions);
|
||||||
await Self.rawSql('CALL vn.ticket_recalc(?)', [id], myOptions);
|
await Self.rawSql('CALL vn.ticket_recalc(?, NULL)', [id], myOptions);
|
||||||
|
|
||||||
const sale = await models.Sale.findById(newSale.id, {
|
const sale = await models.Sale.findById(newSale.id, {
|
||||||
include: {
|
include: {
|
||||||
|
|
|
@ -81,17 +81,15 @@ module.exports = Self => {
|
||||||
throw new UserError('You must delete all the buy requests first');
|
throw new UserError('You must delete all the buy requests first');
|
||||||
|
|
||||||
// removes item shelvings
|
// removes item shelvings
|
||||||
if (hasItemShelvingSales && isSalesAssistant) {
|
const promises = [];
|
||||||
const promises = [];
|
for (let sale of sales) {
|
||||||
for (let sale of sales) {
|
if (sale.itemShelvingSale()) {
|
||||||
if (sale.itemShelvingSale()) {
|
const itemShelvingSale = sale.itemShelvingSale();
|
||||||
const itemShelvingSale = sale.itemShelvingSale();
|
const destroyedShelving = models.ItemShelvingSale.destroyById(itemShelvingSale.id, myOptions);
|
||||||
const destroyedShelving = models.ItemShelvingSale.destroyById(itemShelvingSale.id, myOptions);
|
promises.push(destroyedShelving);
|
||||||
promises.push(destroyedShelving);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
await Promise.all(promises);
|
|
||||||
}
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
// Remove ticket greuges
|
// Remove ticket greuges
|
||||||
const ticketGreuges = await models.Greuge.find({where: {ticketFk: id}}, myOptions);
|
const ticketGreuges = await models.Greuge.find({where: {ticketFk: id}}, myOptions);
|
||||||
|
|
|
@ -147,7 +147,7 @@ module.exports = Self => {
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
await Self.rawSql('CALL vn.manaSpellersRequery(?)', [userId], myOptions);
|
await Self.rawSql('CALL vn.manaSpellersRequery(?)', [userId], myOptions);
|
||||||
await Self.rawSql('CALL vn.ticket_recalc(?)', [id], myOptions);
|
await Self.rawSql('CALL vn.ticket_recalc(?, NULL)', [id], myOptions);
|
||||||
|
|
||||||
const ticket = await models.Ticket.findById(id, {
|
const ticket = await models.Ticket.findById(id, {
|
||||||
include: {
|
include: {
|
||||||
|
|
|
@ -156,7 +156,7 @@
|
||||||
icon="install_mobile"
|
icon="install_mobile"
|
||||||
ng-show="$ctrl.totalChecked > 0"
|
ng-show="$ctrl.totalChecked > 0"
|
||||||
ng-click="$ctrl.sendDocuware()"
|
ng-click="$ctrl.sendDocuware()"
|
||||||
vn-tooltip="Set as delivered and open delivery note(s)"
|
vn-tooltip="Set as delivered and send delivery note(s) to the tablet"
|
||||||
tooltip-position="left">
|
tooltip-position="left">
|
||||||
</vn-button>
|
</vn-button>
|
||||||
<vn-button class="round vn-mb-sm"
|
<vn-button class="round vn-mb-sm"
|
||||||
|
|
|
@ -3,7 +3,7 @@ Go to lines: Ir a lineas
|
||||||
Not available: No disponible
|
Not available: No disponible
|
||||||
Not visible: No visible
|
Not visible: No visible
|
||||||
Payment on account...: Pago a cuenta...
|
Payment on account...: Pago a cuenta...
|
||||||
Set as delivered and open delivery note(s): Marcar como servido/s y abrir albarán/es
|
Set as delivered and send delivery note(s) to the tablet: Marcar como servido/s y enviar albarán/es a la tablet
|
||||||
Closure: Cierre
|
Closure: Cierre
|
||||||
You cannot make a payment on account from multiple clients: No puedes realizar un pago a cuenta de clientes diferentes
|
You cannot make a payment on account from multiple clients: No puedes realizar un pago a cuenta de clientes diferentes
|
||||||
Filter by selection: Filtro por selección
|
Filter by selection: Filtro por selección
|
||||||
|
@ -17,4 +17,4 @@ Quick invoice: Factura rápida
|
||||||
Multiple invoice: Factura múltiple
|
Multiple invoice: Factura múltiple
|
||||||
Make invoice...: Crear factura...
|
Make invoice...: Crear factura...
|
||||||
Invoice selected tickets: Facturar tickets seleccionados
|
Invoice selected tickets: Facturar tickets seleccionados
|
||||||
Are you sure to invoice tickets: ¿Seguro que quieres facturar {{ticketsAmount}} tickets?
|
Are you sure to invoice tickets: ¿Seguro que quieres facturar {{ticketsAmount}} tickets?
|
||||||
|
|
|
@ -37,6 +37,16 @@ class Controller extends SearchPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
applyFilters(param) {
|
applyFilters(param) {
|
||||||
|
if (typeof this.filter.scopeDays === 'number') {
|
||||||
|
const shippedFrom = Date.vnNew();
|
||||||
|
shippedFrom.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const shippedTo = new Date(shippedFrom.getTime());
|
||||||
|
shippedTo.setDate(shippedTo.getDate() + this.filter.scopeDays);
|
||||||
|
shippedTo.setHours(23, 59, 59, 999);
|
||||||
|
Object.assign(this.filter, {shippedFrom, shippedTo});
|
||||||
|
}
|
||||||
|
|
||||||
this.model.applyFilter({}, this.filter)
|
this.model.applyFilter({}, this.filter)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (param && this.model._orgData.length === 1)
|
if (param && this.model._orgData.length === 1)
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td expand>{{entry.supplierName}}</vn-td>
|
<vn-td expand>{{entry.supplierName}}</vn-td>
|
||||||
<vn-td shrink>{{entry.ref}}</vn-td>
|
<vn-td shrink>{{entry.reference}}</vn-td>
|
||||||
<vn-td shrink>{{entry.hb}}</vn-td>
|
<vn-td shrink>{{entry.hb}}</vn-td>
|
||||||
<vn-td shrink>{{entry.freightValue | currency: 'EUR': 2}}</vn-td>
|
<vn-td shrink>{{entry.freightValue | currency: 'EUR': 2}}</vn-td>
|
||||||
<vn-td shrink>{{entry.packageValue | currency: 'EUR': 2}}</vn-td>
|
<vn-td shrink>{{entry.packageValue | currency: 'EUR': 2}}</vn-td>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
module.exports = function(Self) {
|
module.exports = function(Self) {
|
||||||
Self.observe('after save', async function(ctx) {
|
Self.observe('after save', async function(ctx) {
|
||||||
const instance = ctx.instance;
|
const instance = ctx.data || ctx.instance;
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const options = ctx.options;
|
const options = ctx.options;
|
||||||
|
|
||||||
if (!instance.sectorFk || !instance.labelerFk) return;
|
if (!instance?.sectorFk || !instance?.labelerFk) return;
|
||||||
|
|
||||||
const sector = await models.Sector.findById(instance.sectorFk, {
|
const sector = await models.Sector.findById(instance.sectorFk, {
|
||||||
fields: ['mainPrinterFk']
|
fields: ['mainPrinterFk']
|
||||||
|
|
|
@ -16,18 +16,12 @@
|
||||||
"type": "number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"trainFk": {
|
"trainFk": {
|
||||||
"type": "number",
|
"type": "number"
|
||||||
"required": true
|
|
||||||
},
|
},
|
||||||
"itemPackingTypeFk": {
|
"itemPackingTypeFk": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"required": true
|
|
||||||
},
|
},
|
||||||
"warehouseFk": {
|
"warehouseFk": {
|
||||||
"type": "number",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"sectorFk": {
|
|
||||||
"type": "number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"labelerFk": {
|
"labelerFk": {
|
||||||
|
|
Loading…
Reference in New Issue