Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 4774-traductions
This commit is contained in:
commit
b3472ca5db
|
@ -19,8 +19,15 @@ module.exports = Self => {
|
||||||
|
|
||||||
if (typeof options == 'object')
|
if (typeof options == 'object')
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
const [info, info2, [{'@vCollectionFk': collectionFk}]] = await Self.rawSql(
|
|
||||||
'CALL vn.collection_getAssigned(?, @vCollectionFk);SELECT @vCollectionFk', [userId], myOptions);
|
const randStr = Math.random().toString(36).substring(3);
|
||||||
|
const result = await Self.rawSql(`
|
||||||
|
CALL vn.collection_getAssigned(?, @vCollectionFk);
|
||||||
|
SELECT @vCollectionFk ?
|
||||||
|
`, [userId, randStr], myOptions);
|
||||||
|
|
||||||
|
const collectionFk = result.find(item => item[0]?.[randStr] !== undefined)?.[0]?.[randStr];
|
||||||
|
|
||||||
if (!collectionFk) throw new UserError('There are not picking tickets');
|
if (!collectionFk) throw new UserError('There are not picking tickets');
|
||||||
await Self.rawSql('CALL vn.collection_printSticker(?, NULL)', [collectionFk], myOptions);
|
await Self.rawSql('CALL vn.collection_printSticker(?, NULL)', [collectionFk], myOptions);
|
||||||
|
|
||||||
|
|
|
@ -72,9 +72,9 @@ describe('Renew Token', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
const query = 'SELECT * FROM util.debug';
|
|
||||||
|
|
||||||
const debugLog = await models.Application.rawSql(query, null);
|
const query = 'SELECT * FROM util.debug WHERE variable = "renewToken"';
|
||||||
|
const debugLog = await models.Application.rawSql(query);
|
||||||
|
|
||||||
expect(debugLog.length).toEqual(1);
|
expect(debugLog.length).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
|
@ -175,6 +175,9 @@
|
||||||
"PrintConfig": {
|
"PrintConfig": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"QueueMember": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"ViaexpressConfig": {
|
"ViaexpressConfig": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"name": "QueueMember",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "pbx.queueMember"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true
|
||||||
|
},
|
||||||
|
"queue": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"extension": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"queueRelation": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Queue",
|
||||||
|
"foreignKey": "queue",
|
||||||
|
"primaryKey": "name"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"property": "*",
|
||||||
|
"accessType": "READ",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "employee",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -546,7 +546,8 @@ INSERT INTO `vn`.`observationType`(`id`,`description`, `code`)
|
||||||
(6, 'Weight', 'weight'),
|
(6, 'Weight', 'weight'),
|
||||||
(7, 'InvoiceOut', 'invoiceOut'),
|
(7, 'InvoiceOut', 'invoiceOut'),
|
||||||
(8, 'DropOff', 'dropOff'),
|
(8, 'DropOff', 'dropOff'),
|
||||||
(9, 'Sustitución', 'substitution');
|
(9, 'Sustitución', 'substitution'),
|
||||||
|
(10, 'Finance', 'finance');
|
||||||
|
|
||||||
INSERT INTO `vn`.`addressObservation`(`id`,`addressFk`,`observationTypeFk`,`description`)
|
INSERT INTO `vn`.`addressObservation`(`id`,`addressFk`,`observationTypeFk`,`description`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -3988,3 +3989,25 @@ VALUES
|
||||||
INSERT IGNORE INTO ormConfig
|
INSERT IGNORE INTO ormConfig
|
||||||
SET id =1,
|
SET id =1,
|
||||||
selectLimit = 1000;
|
selectLimit = 1000;
|
||||||
|
|
||||||
|
INSERT INTO pbx.queueMultiConfig
|
||||||
|
SET id = 'ring',
|
||||||
|
strategy = 20,
|
||||||
|
timeout = 2,
|
||||||
|
retry = 0,
|
||||||
|
weight = 0,
|
||||||
|
maxLen = 0,
|
||||||
|
ringInUse = 0;
|
||||||
|
|
||||||
|
INSERT INTO pbx.queue (description, name, config)
|
||||||
|
VALUES ('X-men', '1000', 1),
|
||||||
|
('Avengers', '2000', 1);
|
||||||
|
|
||||||
|
INSERT IGNORE INTO pbx.queueMember
|
||||||
|
SET queue = '1000',
|
||||||
|
extension = '1010';
|
||||||
|
|
||||||
|
UPDATE vn.department SET pbxQueue = '1000' WHERE name = "CAMARA";
|
||||||
|
UPDATE vn.department SET pbxQueue = '2000' WHERE name = "VENTAS";
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,52 +1,52 @@
|
||||||
DELIMITER $$
|
DELIMITER $$
|
||||||
CREATE OR REPLACE DEFINER=`vn`@`localhost`
|
CREATE OR REPLACE DEFINER=`vn`@`localhost`
|
||||||
PROCEDURE `hedera`.`orderRow_updateOverstocking`(vOrderFk INT)
|
PROCEDURE `hedera`.`orderRow_updateOverstocking`(vOrderFk INT)
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Set amount = 0 to avoid overbooking sales
|
* Set amount = 0 to avoid overbooking sales
|
||||||
*
|
*
|
||||||
* @param vOrderFk hedera.order.id
|
* @param vOrderFk hedera.order.id
|
||||||
*/
|
*/
|
||||||
DECLARE vCalcFk INT;
|
DECLARE vCalcFk INT;
|
||||||
DECLARE vDone BOOL;
|
DECLARE vDone BOOL;
|
||||||
DECLARE vWarehouseFk INT;
|
DECLARE vWarehouseFk INT;
|
||||||
|
|
||||||
DECLARE cWarehouses CURSOR FOR
|
DECLARE cWarehouses CURSOR FOR
|
||||||
SELECT DISTINCT warehouseFk
|
SELECT DISTINCT warehouseFk
|
||||||
FROM orderRow
|
FROM orderRow
|
||||||
WHERE orderFk = vOrderFk
|
WHERE orderFk = vOrderFk
|
||||||
AND shipment = util.VN_CURDATE();
|
AND shipment = util.VN_CURDATE();
|
||||||
|
|
||||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||||
|
|
||||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||||
BEGIN
|
BEGIN
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
RESIGNAL;
|
RESIGNAL;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
OPEN cWarehouses;
|
OPEN cWarehouses;
|
||||||
checking: LOOP
|
checking: LOOP
|
||||||
SET vDone = FALSE;
|
SET vDone = FALSE;
|
||||||
|
|
||||||
FETCH cWarehouses INTO vWarehouseFk;
|
FETCH cWarehouses INTO vWarehouseFk;
|
||||||
|
|
||||||
IF vDone THEN
|
IF vDone THEN
|
||||||
LEAVE checking;
|
LEAVE checking;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
CALL cache.available_refresh(vCalcFk, FALSE, vWarehouseFk, util.VN_CURDATE());
|
CALL cache.available_refresh(vCalcFk, FALSE, vWarehouseFk, util.VN_CURDATE());
|
||||||
|
|
||||||
UPDATE orderRow r
|
UPDATE orderRow r
|
||||||
JOIN `order` o ON o.id = r.orderFk
|
JOIN `order` o ON o.id = r.orderFk
|
||||||
JOIN orderConfig oc
|
JOIN orderConfig oc
|
||||||
JOIN cache.available a ON a.calc_id = vCalcFk AND a.item_id = r.itemFk
|
JOIN cache.available a ON a.calc_id = vCalcFk AND a.item_id = r.itemFk
|
||||||
SET r.amount = 0
|
SET r.amount = 0
|
||||||
WHERE ADDTIME(o.rowUpdated, oc.reserveTime) < util.VN_NOW()
|
WHERE ADDTIME(o.rowUpdated, oc.reserveTime) < util.VN_NOW()
|
||||||
AND a.available <= 0
|
AND a.available <= 0
|
||||||
AND r.warehouseFk = vWarehouseFk
|
AND r.warehouseFk = vWarehouseFk
|
||||||
AND r.orderFk = vOrderFk;
|
AND r.orderFk = vOrderFk;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
CLOSE cWarehouses;
|
CLOSE cWarehouses;
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -22,7 +22,6 @@ BEGIN
|
||||||
DECLARE vItemFk INT;
|
DECLARE vItemFk INT;
|
||||||
DECLARE vConcept VARCHAR(30);
|
DECLARE vConcept VARCHAR(30);
|
||||||
DECLARE vAmount INT;
|
DECLARE vAmount INT;
|
||||||
DECLARE vAvailable INT;
|
|
||||||
DECLARE vPrice DECIMAL(10,2);
|
DECLARE vPrice DECIMAL(10,2);
|
||||||
DECLARE vSaleFk INT;
|
DECLARE vSaleFk INT;
|
||||||
DECLARE vRowFk INT;
|
DECLARE vRowFk INT;
|
||||||
|
@ -32,7 +31,6 @@ BEGIN
|
||||||
DECLARE vClientFk INT;
|
DECLARE vClientFk INT;
|
||||||
DECLARE vCompanyFk INT;
|
DECLARE vCompanyFk INT;
|
||||||
DECLARE vAgencyModeFk INT;
|
DECLARE vAgencyModeFk INT;
|
||||||
DECLARE vCalcFk INT;
|
|
||||||
DECLARE vIsTaxDataChecked BOOL;
|
DECLARE vIsTaxDataChecked BOOL;
|
||||||
|
|
||||||
DECLARE vDates CURSOR FOR
|
DECLARE vDates CURSOR FOR
|
||||||
|
@ -109,9 +107,9 @@ BEGIN
|
||||||
) INTO vHas0Amount;
|
) INTO vHas0Amount;
|
||||||
|
|
||||||
IF vHas0Amount THEN
|
IF vHas0Amount THEN
|
||||||
CALL util.throw('Remove lines with quantity = 0 before confirming');
|
CALL util.throw('Hay líneas vacías. Por favor, elimínelas');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
START TRANSACTION;
|
START TRANSACTION;
|
||||||
|
|
||||||
CALL order_checkEditable(vSelf);
|
CALL order_checkEditable(vSelf);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
DELIMITER $$
|
DELIMITER $$
|
||||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `hedera`.`orderRow_afterInsert`
|
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `hedera`.`orderRow_afterInsert`
|
||||||
AFTER INSERT ON `orderRow`
|
AFTER INSERT ON `orderRow`
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
BEGIN
|
BEGIN
|
||||||
UPDATE `order`
|
UPDATE `order`
|
||||||
SET rowUpdated = NOW()
|
SET rowUpdated = util.VN_NOW()
|
||||||
WHERE id = NEW.orderFk;
|
WHERE id = NEW.orderFk;
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -5,100 +5,139 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`collection_getAssigne
|
||||||
)
|
)
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Comprueba si existen colecciones libres que se ajustan al perfil del usuario
|
* Comprueba si existen colecciones libres que se ajustan
|
||||||
* y le asigna la más antigua.
|
* al perfil del usuario y le asigna la más antigua.
|
||||||
* Añade un registro al semillero de colecciones y hace la reserva para la colección
|
* Añade un registro al semillero de colecciones.
|
||||||
*
|
*
|
||||||
* @param vUserFk Id de usuario
|
* @param vUserFk Id de usuario
|
||||||
* @param vCollectionFk Id de colección
|
* @param vCollectionFk Id de colección
|
||||||
*/
|
*/
|
||||||
DECLARE vHasTooMuchCollections BOOL;
|
DECLARE vHasTooMuchCollections BOOL;
|
||||||
DECLARE vItemPackingTypeFk VARCHAR(1);
|
DECLARE vDone BOOL DEFAULT FALSE;
|
||||||
DECLARE vWarehouseFk INT;
|
DECLARE vCollectionWorker INT;
|
||||||
DECLARE vLockName VARCHAR(215);
|
DECLARE vMaxNotAssignedCollectionLifeTime TIME;
|
||||||
DECLARE vLockTime INT DEFAULT 30;
|
|
||||||
|
DECLARE vCollections CURSOR FOR
|
||||||
|
WITH collections AS (
|
||||||
|
SELECT tc.collectionFk,
|
||||||
|
SUM(sv.volume) volume,
|
||||||
|
c.saleTotalCount,
|
||||||
|
c.itemPackingTypeFk,
|
||||||
|
c.trainFk,
|
||||||
|
c.warehouseFk,
|
||||||
|
c.wagons
|
||||||
|
FROM vn.ticketCollection tc
|
||||||
|
JOIN vn.collection c ON c.id = tc.collectionFk
|
||||||
|
JOIN vn.saleVolume sv ON sv.ticketFk = tc.ticketFk
|
||||||
|
WHERE c.workerFk IS NULL
|
||||||
|
AND sv.shipped >= util.VN_CURDATE()
|
||||||
|
GROUP BY tc.collectionFk
|
||||||
|
) SELECT c.collectionFk
|
||||||
|
FROM collections c
|
||||||
|
JOIN vn.operator o
|
||||||
|
WHERE o.workerFk = vUserFk
|
||||||
|
AND (c.saleTotalCount <= o.linesLimit OR o.linesLimit IS NULL)
|
||||||
|
AND (c.itemPackingTypeFk = o.itemPackingTypeFk OR o.itemPackingTypeFk IS NULL)
|
||||||
|
AND o.numberOfWagons = c.wagons
|
||||||
|
AND o.trainFk = c.trainFk
|
||||||
|
AND o.warehouseFk = c.warehouseFk;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||||
|
-- Si hay colecciones sin terminar, sale del proceso
|
||||||
|
|
||||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||||
BEGIN
|
BEGIN
|
||||||
IF vLockName IS NOT NULL THEN
|
ROLLBACK;
|
||||||
DO RELEASE_LOCK(vLockName);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RESIGNAL;
|
RESIGNAL;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
-- Si hay colecciones sin terminar, sale del proceso
|
|
||||||
CALL collection_get(vUserFk);
|
CALL collection_get(vUserFk);
|
||||||
|
|
||||||
SELECT (pc.maxNotReadyCollections - COUNT(*)) <= 0,
|
SELECT (pc.maxNotReadyCollections - COUNT(*)) <= 0, pc.maxNotAssignedCollectionLifeTime
|
||||||
pc.collection_assign_lockname
|
INTO vHasTooMuchCollections, vMaxNotAssignedCollectionLifeTime
|
||||||
INTO vHasTooMuchCollections,
|
FROM productionConfig pc
|
||||||
vLockName
|
LEFT JOIN tmp.collection ON TRUE;
|
||||||
FROM tmp.collection c
|
|
||||||
JOIN productionConfig pc;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE tmp.collection;
|
DROP TEMPORARY TABLE tmp.collection;
|
||||||
|
|
||||||
IF vHasTooMuchCollections THEN
|
IF vHasTooMuchCollections THEN
|
||||||
CALL util.throw('There are pending collections');
|
CALL util.throw('Hay colecciones pendientes');
|
||||||
END IF;
|
|
||||||
|
|
||||||
SELECT warehouseFk, itemPackingTypeFk
|
|
||||||
INTO vWarehouseFk, vItemPackingTypeFk
|
|
||||||
FROM operator
|
|
||||||
WHERE workerFk = vUserFk;
|
|
||||||
|
|
||||||
SET vLockName = CONCAT_WS('/',
|
|
||||||
vLockName,
|
|
||||||
vWarehouseFk,
|
|
||||||
vItemPackingTypeFk
|
|
||||||
);
|
|
||||||
|
|
||||||
IF NOT GET_LOCK(vLockName, vLockTime) THEN
|
|
||||||
CALL util.throw(CONCAT('Cannot get lock: ', vLockName));
|
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- Se eliminan las colecciones sin asignar que estan obsoletas
|
-- Se eliminan las colecciones sin asignar que estan obsoletas
|
||||||
INSERT INTO ticketTracking(stateFk, ticketFk)
|
|
||||||
SELECT s.id, tc.ticketFk
|
|
||||||
FROM collection c
|
|
||||||
JOIN ticketCollection tc ON tc.collectionFk = c.id
|
|
||||||
JOIN state s ON s.code = 'PRINTED_AUTO'
|
|
||||||
JOIN productionConfig pc
|
|
||||||
WHERE c.workerFk IS NULL
|
|
||||||
AND TIMEDIFF(util.VN_NOW(), c.created) > pc.maxNotAssignedCollectionLifeTime;
|
|
||||||
|
|
||||||
DELETE c
|
INSERT INTO ticketTracking(stateFk, ticketFk)
|
||||||
FROM collection c
|
SELECT s.id, tc.ticketFk
|
||||||
JOIN productionConfig pc
|
FROM `collection` c
|
||||||
WHERE c.workerFk IS NULL
|
JOIN ticketCollection tc ON tc.collectionFk = c.id
|
||||||
AND TIMEDIFF(util.VN_NOW(), c.created) > pc.maxNotAssignedCollectionLifeTime;
|
JOIN `state` s ON s.code = 'PRINTED_AUTO'
|
||||||
|
WHERE c.workerFk IS NULL
|
||||||
|
AND TIMEDIFF(util.VN_NOW(), c.created) > vMaxNotAssignedCollectionLifeTime;
|
||||||
|
|
||||||
|
DELETE FROM `collection`
|
||||||
|
WHERE workerFk IS NULL
|
||||||
|
AND TIMEDIFF(util.VN_NOW(), created) > vMaxNotAssignedCollectionLifeTime;
|
||||||
|
|
||||||
-- Se añade registro al semillero
|
-- Se añade registro al semillero
|
||||||
INSERT INTO collectionHotbed
|
|
||||||
SET userFk = vUserFk;
|
INSERT INTO collectionHotbed(userFk) VALUES(vUserFk);
|
||||||
|
|
||||||
-- Comprueba si hay colecciones disponibles que se ajustan a su configuracion
|
-- Comprueba si hay colecciones disponibles que se ajustan a su configuracion
|
||||||
SELECT MIN(c.id) INTO vCollectionFk
|
|
||||||
FROM collection c
|
OPEN vCollections;
|
||||||
JOIN operator o ON (o.itemPackingTypeFk = c.itemPackingTypeFk
|
l: LOOP
|
||||||
OR c.itemPackingTypeFk IS NULL)
|
SET vDone = FALSE;
|
||||||
AND o.numberOfWagons = c.wagons
|
FETCH vCollections INTO vCollectionFk;
|
||||||
AND o.trainFk = c.trainFk
|
|
||||||
AND o.warehouseFk = c.warehouseFk
|
IF vDone THEN
|
||||||
AND c.workerFk IS NULL
|
LEAVE l;
|
||||||
WHERE o.workerFk = vUserFk;
|
END IF;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||||
|
BEGIN
|
||||||
|
ROLLBACK;
|
||||||
|
SET vCollectionFk = NULL;
|
||||||
|
RESIGNAL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
SELECT workerFk INTO vCollectionWorker
|
||||||
|
FROM `collection`
|
||||||
|
WHERE id = vCollectionFk FOR UPDATE;
|
||||||
|
|
||||||
|
IF vCollectionWorker IS NULL THEN
|
||||||
|
UPDATE `collection`
|
||||||
|
SET workerFk = vUserFk
|
||||||
|
WHERE id = vCollectionFk;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
LEAVE l;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
ROLLBACK;
|
||||||
|
END;
|
||||||
|
END LOOP;
|
||||||
|
CLOSE vCollections;
|
||||||
|
|
||||||
IF vCollectionFk IS NULL THEN
|
IF vCollectionFk IS NULL THEN
|
||||||
CALL collection_new(vUserFk, vCollectionFk);
|
CALL collection_new(vUserFk, vCollectionFk);
|
||||||
|
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
SELECT workerFk INTO vCollectionWorker
|
||||||
|
FROM `collection`
|
||||||
|
WHERE id = vCollectionFk FOR UPDATE;
|
||||||
|
|
||||||
|
IF vCollectionWorker IS NULL THEN
|
||||||
|
UPDATE `collection`
|
||||||
|
SET workerFk = vUserFk
|
||||||
|
WHERE id = vCollectionFk;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
UPDATE collection
|
|
||||||
SET workerFk = vUserFk
|
|
||||||
WHERE id = vCollectionFk;
|
|
||||||
|
|
||||||
CALL itemShelvingSale_addByCollection(vCollectionFk);
|
CALL itemShelvingSale_addByCollection(vCollectionFk);
|
||||||
|
|
||||||
DO RELEASE_LOCK(vLockName);
|
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
|
@ -45,7 +45,7 @@ BEGIN
|
||||||
LEFT JOIN observation ob ON ob.ticketFk = t.id
|
LEFT JOIN observation ob ON ob.ticketFk = t.id
|
||||||
WHERE t.id = vParamFk
|
WHERE t.id = vParamFk
|
||||||
AND t.shipped >= vYesterday
|
AND t.shipped >= vYesterday
|
||||||
UNION ALL
|
UNION
|
||||||
SELECT t.id ticketFk,
|
SELECT t.id ticketFk,
|
||||||
IF(NOT(vItemPackingTypeFk <=> 'V'), cc.code, CONCAT(SUBSTRING('ABCDEFGH', tc.wagon, 1), '-', tc.`level`)) `level`,
|
IF(NOT(vItemPackingTypeFk <=> 'V'), cc.code, CONCAT(SUBSTRING('ABCDEFGH', tc.wagon, 1), '-', tc.`level`)) `level`,
|
||||||
am.name agencyName,
|
am.name agencyName,
|
||||||
|
@ -66,7 +66,7 @@ BEGIN
|
||||||
LEFT JOIN vn.worker w ON w.id = c.salesPersonFk
|
LEFT JOIN vn.worker w ON w.id = c.salesPersonFk
|
||||||
LEFT JOIN observation ob ON ob.ticketFk = t.id
|
LEFT JOIN observation ob ON ob.ticketFk = t.id
|
||||||
WHERE tc.collectionFk = vParamFk
|
WHERE tc.collectionFk = vParamFk
|
||||||
UNION ALL
|
UNION
|
||||||
SELECT sg.ticketFk,
|
SELECT sg.ticketFk,
|
||||||
NULL `level`,
|
NULL `level`,
|
||||||
am.name agencyName,
|
am.name agencyName,
|
||||||
|
@ -83,6 +83,7 @@ BEGIN
|
||||||
LEFT JOIN observation ob ON ob.ticketFk = t.id
|
LEFT JOIN observation ob ON ob.ticketFk = t.id
|
||||||
LEFT JOIN vn.client c ON c.id = t.clientFk
|
LEFT JOIN vn.client c ON c.id = t.clientFk
|
||||||
WHERE sc.id = vParamFk
|
WHERE sc.id = vParamFk
|
||||||
AND t.shipped >= vYesterday;
|
AND t.shipped >= vYesterday
|
||||||
|
GROUP BY ticketFk;
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`itemShelvingSale_deleteAdded`(
|
||||||
|
vSelf INT(11)
|
||||||
|
)
|
||||||
|
proc: BEGIN
|
||||||
|
/**
|
||||||
|
* Borra una reservea devolviendo la cantidad al itemShelving
|
||||||
|
*
|
||||||
|
* @param vSelf Identificador del itemShelvingSale
|
||||||
|
*/
|
||||||
|
DECLARE vSaleFk INT;
|
||||||
|
DECLARE vHasSalesPicked BOOL;
|
||||||
|
|
||||||
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||||
|
BEGIN
|
||||||
|
ROLLBACK;
|
||||||
|
RESIGNAL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
SELECT iss.saleFk INTO vSaleFk
|
||||||
|
FROM itemShelvingSale iss
|
||||||
|
JOIN sale s ON s.id = iss.saleFk
|
||||||
|
WHERE iss.id = vSelf AND s.isAdded
|
||||||
|
FOR UPDATE;
|
||||||
|
|
||||||
|
IF vSaleFk IS NULL THEN
|
||||||
|
CALL util.throw('The sale can not be deleted');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT COUNT(*) INTO vHasSalesPicked
|
||||||
|
FROM itemShelvingSale
|
||||||
|
WHERE saleFk = vSaleFk AND isPicked;
|
||||||
|
|
||||||
|
IF vHasSalesPicked THEN
|
||||||
|
CALL util.throw('A sale with picked sales cannot be deleted');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
UPDATE itemShelvingSale iss
|
||||||
|
JOIN itemShelving ish ON ish.id = iss.itemShelvingFk
|
||||||
|
SET ish.available = ish.available + iss.quantity
|
||||||
|
WHERE iss.saleFk = vSaleFk;
|
||||||
|
|
||||||
|
DELETE FROM sale WHERE id = vSaleFk;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,29 @@
|
||||||
|
DELIMITER $$
|
||||||
|
|
||||||
|
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`queueMember_updateQueue`(
|
||||||
|
vBusinessFk INT
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Elimina la entrada de la cola anterior y luego inserta la nueva para un trabajador.
|
||||||
|
*
|
||||||
|
* @param vBusinessFk ID del negocio
|
||||||
|
*/
|
||||||
|
DECLARE vNewQueue VARCHAR(10);
|
||||||
|
DECLARE vExtension VARCHAR(10);
|
||||||
|
DECLARE exit handler FOR SQLEXCEPTION
|
||||||
|
|
||||||
|
SELECT d.pbxQueue, s.extension
|
||||||
|
INTO vNewQueue, vExtension
|
||||||
|
FROM business b
|
||||||
|
JOIN department d ON d.id = b.departmentFk
|
||||||
|
JOIN pbx.sip s ON s.user_id = b.workerFk
|
||||||
|
WHERE b.id = vBusinessFk;
|
||||||
|
|
||||||
|
DELETE FROM pbx.queueMember
|
||||||
|
WHERE extension = vExtension COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO pbx.queueMember (queue, extension)
|
||||||
|
VALUES (vNewQueue, vExtension);
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -21,6 +21,8 @@ BEGIN
|
||||||
SET businessFk = vNewBusinessFk
|
SET businessFk = vNewBusinessFk
|
||||||
WHERE id = vSelf;
|
WHERE id = vSelf;
|
||||||
|
|
||||||
|
CALL queueMember_updateQueue(vNewBusinessFk);
|
||||||
|
|
||||||
IF vOldBusinessFk IS NULL THEN
|
IF vOldBusinessFk IS NULL THEN
|
||||||
CALL account.account_enable(vSelf);
|
CALL account.account_enable(vSelf);
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,20 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` TRIGGER `vn`.`business_afterUpdate`
|
||||||
AFTER UPDATE ON `business`
|
AFTER UPDATE ON `business`
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
BEGIN
|
BEGIN
|
||||||
|
DECLARE vIsActive BOOL;
|
||||||
|
DECLARE vExtension VARCHAR(10);
|
||||||
|
|
||||||
CALL worker_updateBusiness(NEW.workerFk);
|
CALL worker_updateBusiness(NEW.workerFk);
|
||||||
|
|
||||||
IF NOT (OLD.workerFk <=> NEW.workerFk) THEN
|
IF NOT (OLD.workerFk <=> NEW.workerFk) THEN
|
||||||
CALL worker_updateBusiness(OLD.workerFk);
|
CALL worker_updateBusiness(OLD.workerFk);
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
|
IF NOT (OLD.departmentFk <=> NEW.departmentFk) THEN
|
||||||
|
SELECT COUNT(*) INTO vIsActive FROM worker WHERE businessFk = NEW.id;
|
||||||
|
IF vIsActive THEN
|
||||||
|
CALL queueMember_updateQueue(NEW.id);
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -9,5 +9,8 @@ BEGIN
|
||||||
SET NEW.userFk = account.myUser_getId();
|
SET NEW.userFk = account.myUser_getId();
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
|
IF NEW.shelvingFk <> OLD.shelvingFk THEN
|
||||||
|
SET NEW.movingState = NULL;
|
||||||
|
END IF;
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE vn.clientObservation DROP COLUMN IF EXISTS observationTypeFk;
|
||||||
|
ALTER TABLE vn.clientObservation ADD COLUMN IF NOT EXISTS observationTypeFk TINYINT(3) UNSIGNED NULL;
|
||||||
|
ALTER TABLE vn.clientObservation ADD CONSTRAINT clientObservationTypeFk FOREIGN KEY IF NOT EXISTS (observationTypeFk) REFERENCES vn.observationType(id);
|
|
@ -0,0 +1,3 @@
|
||||||
|
INSERT IGNORE INTO vn.observationType
|
||||||
|
SET description = 'Finance',
|
||||||
|
code = 'finance';
|
|
@ -0,0 +1,3 @@
|
||||||
|
DELETE FROM salix.ACL
|
||||||
|
WHERE model = 'WorkerLog'
|
||||||
|
AND property = '*';
|
|
@ -0,0 +1,3 @@
|
||||||
|
UPDATE vn.sale
|
||||||
|
SET originalQuantity = quantity
|
||||||
|
WHERE originalQuantity IS NULL
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE vn.sale MODIFY COLUMN originalQuantity decimal(10,2) DEFAULT 0.00 NOT NULL COMMENT 'Se utiliza para notificar a través de rocket los cambios de quantity';
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- Place your SQL code here
|
||||||
|
ALTER TABLE vn.itemShelving ADD IF NOT EXISTS isMoving BOOL DEFAULT FALSE NOT NULL COMMENT 'Indica que se ha marcado este registro para transferirlo a otro sector';
|
|
@ -0,0 +1,3 @@
|
||||||
|
-- Place your SQL code here
|
||||||
|
ALTER TABLE vn.itemShelving DROP COLUMN IF EXISTS isMoving;
|
||||||
|
ALTER TABLE vn.itemShelving ADD IF NOT EXISTS movingState ENUM('selected','printed') NULL;
|
|
@ -0,0 +1,3 @@
|
||||||
|
-- Place your SQL code here
|
||||||
|
ALTER TABLE hedera.`order` ADD IF NOT EXISTS rowUpdated DATETIME NULL
|
||||||
|
COMMENT 'Timestamp for last updated record in orderRow table';
|
|
@ -0,0 +1,3 @@
|
||||||
|
-- Place your SQL code here
|
||||||
|
ALTER TABLE hedera.`order` ADD IF NOT EXISTS rowUpdated DATETIME NULL
|
||||||
|
COMMENT 'Timestamp for last updated record in orderRow table';
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
ALTER TABLE vn.sector ADD isOnReservationMode tinyint(1) DEFAULT FALSE NULL;
|
|
@ -0,0 +1,3 @@
|
||||||
|
-- Place your SQL code here
|
||||||
|
ALTER TABLE vn.itemShelving DROP COLUMN IF EXISTS isMoving;
|
||||||
|
ALTER TABLE vn.itemShelving ADD IF NOT EXISTS movingState ENUM('selected','printed') NULL;
|
|
@ -0,0 +1,3 @@
|
||||||
|
-- Place your SQL code here
|
||||||
|
ALTER TABLE vn.itemShelving DROP COLUMN IF EXISTS isMoving;
|
||||||
|
ALTER TABLE vn.itemShelving ADD IF NOT EXISTS movingState ENUM('selected','printed') NULL;
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE `vn`.`ticketConfig`
|
||||||
|
ADD COLUMN `closureDaysAgo` int(11) NOT NULL DEFAULT 2 COMMENT 'Number of days to look back for ticket closure',
|
||||||
|
ADD CONSTRAINT `closureDaysAgo_check` CHECK (`closureDaysAgo` > 0);
|
|
@ -1,42 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Client Add notes path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('employee', 'client');
|
|
||||||
await page.accessToSearchResult('Bruce Banner');
|
|
||||||
await page.accessToSection('client.card.note.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should reach the notes index`, async() => {
|
|
||||||
await page.waitForState('client.card.note.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should click on the add note button`, async() => {
|
|
||||||
await page.waitToClick(selectors.clientNotes.addNoteFloatButton);
|
|
||||||
await page.waitForState('client.card.note.create');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should create a note`, async() => {
|
|
||||||
await page.waitForSelector(selectors.clientNotes.note);
|
|
||||||
await page.type(`${selectors.clientNotes.note} textarea`, 'Meeting with Black Widow 21st 9am');
|
|
||||||
await page.waitToClick(selectors.clientNotes.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the note was created', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.clientNotes.firstNoteText, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual('Meeting with Black Widow 21st 9am');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -28,12 +28,12 @@ describe('Client defaulter path', () => {
|
||||||
const salesPersonName =
|
const salesPersonName =
|
||||||
await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText');
|
await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText');
|
||||||
|
|
||||||
expect(clientName).toEqual('Bruce Banner');
|
expect(clientName).toEqual('Ororo Munroe');
|
||||||
expect(salesPersonName).toEqual('developer');
|
expect(salesPersonName).toEqual('salesperson');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should first observation not changed', async() => {
|
it('should first observation not changed', async() => {
|
||||||
const expectedObservation = 'Meeting with Black Widow 21st 9am';
|
const expectedObservation = 'Madness, as you know, is like gravity, all it takes is a little push';
|
||||||
const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value');
|
const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value');
|
||||||
|
|
||||||
expect(result).toContain(expectedObservation);
|
expect(result).toContain(expectedObservation);
|
||||||
|
@ -62,13 +62,4 @@ describe('Client defaulter path', () => {
|
||||||
await page.write(selectors.clientDefaulter.observation, 'My new observation');
|
await page.write(selectors.clientDefaulter.observation, 'My new observation');
|
||||||
await page.waitToClick(selectors.clientDefaulter.saveButton);
|
await page.waitToClick(selectors.clientDefaulter.saveButton);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should first observation changed', async() => {
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
await page.waitForSelector(selectors.clientDefaulter.firstObservation);
|
|
||||||
const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value');
|
|
||||||
|
|
||||||
expect(message.text).toContain('Observation saved!');
|
|
||||||
expect(result).toContain('My new observation');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -381,5 +381,6 @@
|
||||||
"The entry does not have stickers": "La entrada no tiene etiquetas",
|
"The entry does not have stickers": "La entrada no tiene etiquetas",
|
||||||
"This buyer has already made a reservation for this date": "Este comprador ya ha hecho una reserva para esta fecha",
|
"This buyer has already made a reservation for this date": "Este comprador ya ha hecho una reserva para esta fecha",
|
||||||
"No valid travel thermograph found": "No se encontró un termógrafo válido",
|
"No valid travel thermograph found": "No se encontró un termógrafo válido",
|
||||||
"The quantity claimed cannot be greater than the quantity of the line": "La cantidad reclamada no puede ser mayor que la cantidad de la línea"
|
"The quantity claimed cannot be greater than the quantity of the line": "La cantidad reclamada no puede ser mayor que la cantidad de la línea",
|
||||||
}
|
"type cannot be blank": "Se debe rellenar el tipo"
|
||||||
|
}
|
|
@ -25,7 +25,12 @@
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "VnUser",
|
"model": "VnUser",
|
||||||
"foreignKey": "user_id"
|
"foreignKey": "user_id"
|
||||||
|
},
|
||||||
|
"queueMember": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "QueueMember",
|
||||||
|
"foreignKey": "extension",
|
||||||
|
"primaryKey": "extension"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
module.exports = function(Self) {
|
module.exports = function(Self) {
|
||||||
Self.validate('text', isEnabled, {message: 'Description cannot be blank'});
|
Self.validate('text', function(err) {
|
||||||
function isEnabled(err) {
|
|
||||||
if (!this.text) err();
|
if (!this.text) err();
|
||||||
}
|
}, {message: 'Description cannot be blank'});
|
||||||
|
|
||||||
|
Self.validate('observationTypeFk', function(err) {
|
||||||
|
if (!this.observationTypeFk) err();
|
||||||
|
}, {message: 'type cannot be blank'});
|
||||||
|
|
||||||
Self.observe('before save', function(ctx, next) {
|
Self.observe('before save', function(ctx, next) {
|
||||||
ctx.instance.created = Date();
|
ctx.instance.created = Date();
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"name": "ClientObservation",
|
"name": "ClientObservation",
|
||||||
"description": "Client notes",
|
"description": "Client notes",
|
||||||
"base": "VnModel",
|
"base": "VnModel",
|
||||||
"mixins": {
|
"mixins": {
|
||||||
"Loggable": true
|
"Loggable": true
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "clientObservation"
|
"table": "clientObservation"
|
||||||
|
@ -26,6 +26,10 @@
|
||||||
"created": {
|
"created": {
|
||||||
"type": "date",
|
"type": "date",
|
||||||
"description": "Creation date and time"
|
"description": "Creation date and time"
|
||||||
|
},
|
||||||
|
"observationTypeFk": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Type of observation"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
@ -44,14 +48,18 @@
|
||||||
"include": {
|
"include": {
|
||||||
"relation": "worker",
|
"relation": "worker",
|
||||||
"scope": {
|
"scope": {
|
||||||
"fields": ["id"],
|
"fields": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
"include": {
|
"include": {
|
||||||
"relation": "user",
|
"relation": "user",
|
||||||
"scope": {
|
"scope": {
|
||||||
"fields": ["nickname"]
|
"fields": [
|
||||||
|
"nickname"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
url="clientObservations"
|
|
||||||
filter="$ctrl.filter"
|
|
||||||
link="{clientFk: $ctrl.$params.id}"
|
|
||||||
data="notes"
|
|
||||||
auto-load="true">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-data-viewer
|
|
||||||
model="model"
|
|
||||||
class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-md">
|
|
||||||
<div
|
|
||||||
ng-repeat="note in notes"
|
|
||||||
class="note vn-pa-sm border-solid border-radius vn-mb-md">
|
|
||||||
<vn-horizontal class="vn-mb-sm" style="color: #666">
|
|
||||||
<vn-one>{{::note.worker.user.nickname}}</vn-one>
|
|
||||||
<vn-auto>{{::note.created | date:'dd/MM/yyyy HH:mm'}}</vn-auto>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal class="text">
|
|
||||||
{{::note.text}}
|
|
||||||
</vn-horizontal>
|
|
||||||
</div>
|
|
||||||
</vn-card>
|
|
||||||
</vn-data-viewer>
|
|
||||||
<a vn-tooltip="New note"
|
|
||||||
ui-sref="client.card.note.create({id: $ctrl.$params.id})"
|
|
||||||
vn-bind="+"
|
|
||||||
fixed-bottom-right>
|
|
||||||
<vn-float-button icon="add"></vn-float-button>
|
|
||||||
</a>
|
|
|
@ -5,9 +5,10 @@ import './style.scss';
|
||||||
export default class Controller extends Section {
|
export default class Controller extends Section {
|
||||||
constructor($element, $) {
|
constructor($element, $) {
|
||||||
super($element, $);
|
super($element, $);
|
||||||
this.filter = {
|
}
|
||||||
order: 'created DESC',
|
async $onInit() {
|
||||||
};
|
this.$state.go('home');
|
||||||
|
window.location.href = await this.vnApp.getUrl(`customer/${this.$params.id}/notes`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
Tickets monitor: Monitor de tickets
|
||||||
|
Clients on website: Clientes activos en la web
|
||||||
|
Recent order actions: Acciones recientes en pedidos
|
||||||
|
Search tickets: Buscar tickets
|
||||||
|
Delete selected elements: Eliminar los elementos seleccionados
|
||||||
|
All the selected elements will be deleted. Are you sure you want to continue?: Todos los elementos seleccionados serán eliminados. ¿Seguro que quieres continuar?
|
||||||
|
Component lack: Faltan componentes
|
||||||
|
Ticket too little: Ticket demasiado pequeño
|
||||||
|
Minimize/Maximize: Minimizar/Maximizar
|
||||||
|
Problems: Problemas
|
||||||
|
Theoretical: Teórica
|
||||||
|
Practical: Práctica
|
||||||
|
Preparation: Preparación
|
||||||
|
Auto-refresh: Auto-refresco
|
||||||
|
Toggle auto-refresh every 2 minutes: Conmuta el refresco automático cada 2 minutos
|
||||||
|
Is fragile: Es frágil
|
|
@ -59,6 +59,9 @@
|
||||||
"isReserve": {
|
"isReserve": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
"isOnReservationMode": {
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('getWithPackaging', {
|
||||||
|
description: 'Returns the list of suppliers with an entry of type packaging',
|
||||||
|
accessType: 'READ',
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/getWithPackaging`,
|
||||||
|
verb: 'GET'
|
||||||
|
},
|
||||||
|
nolimit: true
|
||||||
|
});
|
||||||
|
Self.getWithPackaging = async options => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const myOptions = {};
|
||||||
|
const oneYearAgo = new Date();
|
||||||
|
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
const entries = await models.Entry.find({
|
||||||
|
where: {
|
||||||
|
typeFk: 'packaging',
|
||||||
|
created: {gte: oneYearAgo}
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
relation: 'supplier',
|
||||||
|
scope: {
|
||||||
|
fields: ['id', 'name']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fields: {supplierFk: true}
|
||||||
|
}, myOptions);
|
||||||
|
|
||||||
|
const result = entries.map(item => ({
|
||||||
|
id: item.supplier().id,
|
||||||
|
name: item.supplier().name
|
||||||
|
}));
|
||||||
|
return Array.from(new Map(result.map(entry => [entry.id, entry])).values());
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
const {models} = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('Supplier getWithPackaging()', () => {
|
||||||
|
it('should return a list of suppliers with an entry of type packaging', async() => {
|
||||||
|
const typeFk = 'packaging';
|
||||||
|
|
||||||
|
const tx = await models.Supplier.beginTransaction({});
|
||||||
|
const myOptions = {transaction: tx};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const entry = await models.Entry.findOne(
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
id: 1
|
||||||
|
},
|
||||||
|
myOptions
|
||||||
|
});
|
||||||
|
|
||||||
|
await entry.updateAttributes({
|
||||||
|
typeFk: typeFk,
|
||||||
|
created: new Date()
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await models.Supplier.getWithPackaging(myOptions);
|
||||||
|
|
||||||
|
expect(result.length).toEqual(1);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -12,6 +12,7 @@ module.exports = Self => {
|
||||||
require('../methods/supplier/campaignMetricsEmail')(Self);
|
require('../methods/supplier/campaignMetricsEmail')(Self);
|
||||||
require('../methods/supplier/newSupplier')(Self);
|
require('../methods/supplier/newSupplier')(Self);
|
||||||
require('../methods/supplier/getItemsPackaging')(Self);
|
require('../methods/supplier/getItemsPackaging')(Self);
|
||||||
|
require('../methods/supplier/getWithPackaging')(Self);
|
||||||
|
|
||||||
Self.validatesPresenceOf('name', {
|
Self.validatesPresenceOf('name', {
|
||||||
message: 'The social name cannot be empty'
|
message: 'The social name cannot be empty'
|
||||||
|
|
|
@ -53,8 +53,9 @@ module.exports = Self => {
|
||||||
JOIN province p ON p.id = c.provinceFk
|
JOIN province p ON p.id = c.provinceFk
|
||||||
JOIN country co ON co.id = p.countryFk
|
JOIN country co ON co.id = p.countryFk
|
||||||
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||||
|
JOIN ticketConfig tc ON TRUE
|
||||||
WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered'))
|
WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered'))
|
||||||
AND DATE(t.shipped) BETWEEN ? - INTERVAL 2 DAY AND util.dayEnd(?)
|
AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
|
||||||
AND t.refFk IS NULL
|
AND t.refFk IS NULL
|
||||||
GROUP BY t.id
|
GROUP BY t.id
|
||||||
`, [toDate, toDate]);
|
`, [toDate, toDate]);
|
||||||
|
@ -108,6 +109,7 @@ module.exports = Self => {
|
||||||
JOIN alertLevel al ON al.id = ts.alertLevel
|
JOIN alertLevel al ON al.id = ts.alertLevel
|
||||||
JOIN client c ON c.id = t.clientFk
|
JOIN client c ON c.id = t.clientFk
|
||||||
JOIN province p ON p.id = c.provinceFk
|
JOIN province p ON p.id = c.provinceFk
|
||||||
|
JOIN ticketConfig tc ON TRUE
|
||||||
LEFT JOIN autonomy a ON a.id = p.autonomyFk
|
LEFT JOIN autonomy a ON a.id = p.autonomyFk
|
||||||
JOIN country co ON co.id = p.countryFk
|
JOIN country co ON co.id = p.countryFk
|
||||||
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||||
|
@ -116,7 +118,7 @@ module.exports = Self => {
|
||||||
LEFT JOIN vn.invoiceOutSerial ios ON ios.taxAreaFk = 'WORLD'
|
LEFT JOIN vn.invoiceOutSerial ios ON ios.taxAreaFk = 'WORLD'
|
||||||
AND ios.code = invoiceSerial(t.clientFk, t.companyFk, 'multiple')
|
AND ios.code = invoiceSerial(t.clientFk, t.companyFk, 'multiple')
|
||||||
WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered'))
|
WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered'))
|
||||||
AND DATE(t.shipped) BETWEEN ? - INTERVAL 2 DAY AND util.dayEnd(?)
|
AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
|
||||||
AND t.refFk IS NULL
|
AND t.refFk IS NULL
|
||||||
AND IFNULL(a.hasDailyInvoice, co.hasDailyInvoice)
|
AND IFNULL(a.hasDailyInvoice, co.hasDailyInvoice)
|
||||||
GROUP BY ticketFk
|
GROUP BY ticketFk
|
||||||
|
@ -141,9 +143,10 @@ module.exports = Self => {
|
||||||
JOIN alertLevel al ON al.id = ts.alertLevel
|
JOIN alertLevel al ON al.id = ts.alertLevel
|
||||||
JOIN agencyMode am ON am.id = t.agencyModeFk
|
JOIN agencyMode am ON am.id = t.agencyModeFk
|
||||||
JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
|
JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
|
||||||
|
JOIN ticketConfig tc ON TRUE
|
||||||
LEFT JOIN ticketObservation tob ON tob.ticketFk = t.id
|
LEFT JOIN ticketObservation tob ON tob.ticketFk = t.id
|
||||||
SET t.routeFk = NULL
|
SET t.routeFk = NULL
|
||||||
WHERE DATE(t.shipped) BETWEEN ? - INTERVAL 2 DAY AND util.dayEnd(?)
|
WHERE t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
|
||||||
AND al.code NOT IN ('DELIVERED', 'PACKED')
|
AND al.code NOT IN ('DELIVERED', 'PACKED')
|
||||||
AND NOT t.packages
|
AND NOT t.packages
|
||||||
AND tob.id IS NULL
|
AND tob.id IS NULL
|
||||||
|
|
|
@ -12,16 +12,15 @@ module.exports = async function(ctx, Self, tickets, options) {
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
let tx;
|
let tx;
|
||||||
if (!myOptions.transaction) {
|
// IMPORTANT: Due to its high cost in production, wrapping this process in a transaction may cause timeouts.
|
||||||
tx = await Self.beginTransaction({});
|
|
||||||
myOptions.transaction = tx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tickets.length == 0) return;
|
if (tickets.length == 0) return;
|
||||||
|
|
||||||
const failedtickets = [];
|
const failedtickets = [];
|
||||||
for (const ticket of tickets) {
|
for (const ticket of tickets) {
|
||||||
try {
|
try {
|
||||||
|
await Self.rawSql(`CALL util.debugAdd('invoicingTicket', ?)`, [ticket.id], {userId});
|
||||||
|
|
||||||
await Self.app.models.InvoiceOut.getSerial(ticket.clientFk, ticket.companyFk, ticket.addressFk, 'quick');
|
await Self.app.models.InvoiceOut.getSerial(ticket.clientFk, ticket.companyFk, ticket.addressFk, 'quick');
|
||||||
await Self.rawSql(
|
await Self.rawSql(
|
||||||
`CALL vn.ticket_closeByTicket(?)`,
|
`CALL vn.ticket_closeByTicket(?)`,
|
||||||
|
@ -149,6 +148,11 @@ module.exports = async function(ctx, Self, tickets, options) {
|
||||||
myOptions);
|
myOptions);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
await Self.rawSql(`
|
||||||
|
INSERT INTO util.debug (variable, value)
|
||||||
|
VALUES ('invoicingTicketError', ?)
|
||||||
|
`, [ticket.id + ' - ' + error]);
|
||||||
|
|
||||||
if (error.responseCode == 450) {
|
if (error.responseCode == 450) {
|
||||||
await invalidEmail(ticket);
|
await invalidEmail(ticket);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -50,9 +50,9 @@ describe('Ticket closure functionality', () => {
|
||||||
|
|
||||||
expect(ticketStateBefore.code).not.toBe(ticketStateAfter.code);
|
expect(ticketStateBefore.code).not.toBe(ticketStateAfter.code);
|
||||||
|
|
||||||
const ticketAfter = await models.TicketState.findById(ticketId, null, options);
|
const ticketAfter = await models.Ticket.findById(ticketId, null, options);
|
||||||
|
|
||||||
expect(ticketAfter.refFk).toBeUndefined();
|
expect(ticketAfter.refFk).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send Incoterms authorization email on first order', async() => {
|
it('should send Incoterms authorization email on first order', async() => {
|
||||||
|
|
|
@ -87,7 +87,7 @@ module.exports = Self => {
|
||||||
{
|
{
|
||||||
relation: 'sector',
|
relation: 'sector',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['warehouseFk', 'description'],
|
fields: ['warehouseFk', 'description', 'isOnReservationMode'],
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
relation: 'printer',
|
relation: 'printer',
|
||||||
|
|
|
@ -67,6 +67,12 @@ module.exports = Self => {
|
||||||
type: 'String',
|
type: 'String',
|
||||||
description: 'The worker user name',
|
description: 'The worker user name',
|
||||||
http: {source: 'query'}
|
http: {source: 'query'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'email',
|
||||||
|
type: 'String',
|
||||||
|
description: 'The user email',
|
||||||
|
http: {source: 'query'}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
returns: {
|
returns: {
|
||||||
|
@ -99,6 +105,8 @@ module.exports = Self => {
|
||||||
return {'w.firstName': {like: `%${value}%`}};
|
return {'w.firstName': {like: `%${value}%`}};
|
||||||
case 'lastName':
|
case 'lastName':
|
||||||
return {'w.lastName': {like: `%${value}%`}};
|
return {'w.lastName': {like: `%${value}%`}};
|
||||||
|
case 'nickname':
|
||||||
|
return {'u.nickname': {like: `%${value}%`}};
|
||||||
case 'extension':
|
case 'extension':
|
||||||
return {'p.extension': value};
|
return {'p.extension': value};
|
||||||
case 'fi':
|
case 'fi':
|
||||||
|
@ -107,6 +115,8 @@ module.exports = Self => {
|
||||||
return {'d.id': value};
|
return {'d.id': value};
|
||||||
case 'userName':
|
case 'userName':
|
||||||
return {'u.name': {like: `%${value}%`}};
|
return {'u.name': {like: `%${value}%`}};
|
||||||
|
case 'email':
|
||||||
|
return {'eu.email': {like: `%${value}%`}};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -116,15 +126,23 @@ module.exports = Self => {
|
||||||
let stmt;
|
let stmt;
|
||||||
|
|
||||||
stmt = new ParameterizedSQL(
|
stmt = new ParameterizedSQL(
|
||||||
`SELECT w.id, u.email, p.extension, u.name as userName,
|
`SELECT w.id,
|
||||||
d.name AS department, w.lastName, u.nickname, mu.email
|
w.lastName,
|
||||||
|
w.firstName,
|
||||||
|
u.email,
|
||||||
|
u.nickname,
|
||||||
|
p.extension,
|
||||||
|
u.name as userName,
|
||||||
|
d.name AS department,
|
||||||
|
eu.email,
|
||||||
|
c.fi
|
||||||
FROM worker w
|
FROM worker w
|
||||||
LEFT JOIN workerDepartment wd ON wd.workerFk = w.id
|
LEFT JOIN workerDepartment wd ON wd.workerFk = w.id
|
||||||
LEFT JOIN department d ON d.id = wd.departmentFk
|
LEFT JOIN department d ON d.id = wd.departmentFk
|
||||||
LEFT JOIN client c ON c.id = w.id
|
LEFT JOIN client c ON c.id = w.id
|
||||||
LEFT JOIN account.user u ON u.id = w.id
|
LEFT JOIN account.user u ON u.id = w.id
|
||||||
LEFT JOIN pbx.sip p ON p.user_id = u.id
|
LEFT JOIN pbx.sip p ON p.user_id = u.id
|
||||||
LEFT JOIN account.emailUser mu ON mu.userFk = u.id`
|
LEFT JOIN account.emailUser eu ON eu.userFk = u.id`
|
||||||
);
|
);
|
||||||
|
|
||||||
stmt.merge(conn.makeSuffix(filter));
|
stmt.merge(conn.makeSuffix(filter));
|
||||||
|
|
|
@ -217,6 +217,7 @@ module.exports = Self => {
|
||||||
const code = e.code;
|
const code = e.code;
|
||||||
const message = e.sqlMessage;
|
const message = e.sqlMessage;
|
||||||
|
|
||||||
|
if (e.message && e.message.includes('Invalid email')) throw new UserError('Invalid email');
|
||||||
if (e.message && e.message.includes(`Email already exists`)) throw new UserError(`This personal mail already exists`);
|
if (e.message && e.message.includes(`Email already exists`)) throw new UserError(`This personal mail already exists`);
|
||||||
if (code === 'ER_DUP_ENTRY' && message.includes(`CodigoTrabajador_UNIQUE`)) throw new UserError(`This worker code already exists`);
|
if (code === 'ER_DUP_ENTRY' && message.includes(`CodigoTrabajador_UNIQUE`)) throw new UserError(`This worker code already exists`);
|
||||||
if (code === 'ER_DUP_ENTRY' && message.includes(`PRIMARY`)) throw new UserError(`This worker already exists`);
|
if (code === 'ER_DUP_ENTRY' && message.includes(`PRIMARY`)) throw new UserError(`This worker already exists`);
|
||||||
|
|
|
@ -253,7 +253,18 @@
|
||||||
"relation": "client"
|
"relation": "client"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"relation": "sip"
|
"relation": "sip",
|
||||||
|
"scope": {
|
||||||
|
"include": {
|
||||||
|
"relation": "queueMember",
|
||||||
|
"scope": {
|
||||||
|
"fields": [
|
||||||
|
"queue",
|
||||||
|
"extension"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "salix-back",
|
"name": "salix-back",
|
||||||
"version": "24.42.0",
|
"version": "24.44.0",
|
||||||
"author": "Verdnatura Levante SL",
|
"author": "Verdnatura Levante SL",
|
||||||
"description": "Salix backend",
|
"description": "Salix backend",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
|
|
Loading…
Reference in New Issue