3979-abonarTicketsSinAlmacen #1910
|
@ -17,10 +17,6 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
"path": {
|
|
||||||
"type": "string",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"code": {
|
"code": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": true
|
"required": true
|
||||||
|
|
|
@ -258,18 +258,20 @@ module.exports = function(Self) {
|
||||||
|
|
||||||
class Mailer {
|
class Mailer {
|
||||||
async send(verifyOptions, cb) {
|
async send(verifyOptions, cb) {
|
||||||
const url = new URL(verifyOptions.verifyHref);
|
try {
|
||||||
if (process.env.NODE_ENV) url.port = '';
|
const url = new URL(verifyOptions.verifyHref);
|
||||||
|
if (process.env.NODE_ENV) url.port = '';
|
||||||
|
|
||||||
const params = {
|
const email = new Email('email-verify', {
|
||||||
url: url.href,
|
url: url.href,
|
||||||
recipient: verifyOptions.to
|
recipient: verifyOptions.to
|
||||||
};
|
});
|
||||||
|
await email.send();
|
||||||
|
|
||||||
const email = new Email('email-verify', params);
|
cb(null, verifyOptions.to);
|
||||||
email.send();
|
} catch (err) {
|
||||||
|
cb(err);
|
||||||
cb(null, verifyOptions.to);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,8 +59,8 @@ async function test() {
|
||||||
const JunitReporter = require('jasmine-reporters');
|
const JunitReporter = require('jasmine-reporters');
|
||||||
jasmine.addReporter(new JunitReporter.JUnitXmlReporter());
|
jasmine.addReporter(new JunitReporter.JUnitXmlReporter());
|
||||||
|
|
||||||
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 90000;
|
|
||||||
jasmine.exitOnCompletion = true;
|
jasmine.exitOnCompletion = true;
|
||||||
|
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 900000;
|
||||||
}
|
}
|
||||||
|
|
||||||
const backSpecs = [
|
const backSpecs = [
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM mariadb:10.7.7
|
FROM mariadb:10.11.6
|
||||||
|
|
||||||
ENV MYSQL_ROOT_PASSWORD root
|
ENV MYSQL_ROOT_PASSWORD root
|
||||||
ENV TZ Europe/Madrid
|
ENV TZ Europe/Madrid
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
ALTER TABLE `vn`.`clientSms` ADD `ticketFk` int(11) NULL;
|
||||||
|
ALTER TABLE `vn`.`clientSms` ADD CONSTRAINT `clientSms_FK_2` FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
INSERT INTO`vn`.`clientSms` (`clientFk`, `smsFk`, `ticketFk`)
|
||||||
|
SELECT `t`.`clientFk`, `s`.`smsFk`, `s`.`ticketFk`
|
||||||
|
FROM `vn`.`clientSms` `s`
|
||||||
|
JOIN `vn`.`ticket` `t` ON `t`.`id` = `s`.`ticketFk`;
|
||||||
|
|
||||||
|
RENAME TABLE `vn`.`ticketSms` TO `vn`.`ticketSms__`;
|
|
@ -0,0 +1,81 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn`.`ticketPositionInPath`(vTicketId INT)
|
||||||
|
RETURNS varchar(10) CHARSET utf8mb3 COLLATE utf8mb3_general_ci
|
||||||
|
DETERMINISTIC
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
DECLARE vRestTicketsMaxOrder INT;
|
||||||
|
DECLARE vRestTicketsMinOrder INT;
|
||||||
|
DECLARE vRestTicketsPacking INT;
|
||||||
|
DECLARE vMyProductionOrder INT;
|
||||||
|
DECLARE vPosition VARCHAR(10) DEFAULT 'MID';
|
||||||
|
DECLARE vMyPath INT;
|
||||||
|
DECLARE vMyWarehouse INT;
|
||||||
|
DECLARE PACKING_ORDER INT;
|
||||||
|
DECLARE vExpeditionsCount INT;
|
||||||
|
DECLARE vIsValenciaPath BOOLEAN DEFAULT FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SELECT `order`
|
||||||
|
INTO PACKING_ORDER
|
||||||
|
FROM state
|
||||||
|
WHERE code = 'PACKING';
|
||||||
|
|
||||||
|
SELECT t.routeFk, t.warehouseFk, IFNULL(ts.productionOrder,0)
|
||||||
|
INTO vMyPath, vMyWarehouse, vMyProductionOrder
|
||||||
|
FROM ticket t
|
||||||
|
LEFT JOIN ticketState ts on ts.ticketFk = t.id
|
||||||
|
WHERE t.id = vTicketId;
|
||||||
|
|
||||||
|
SELECT (ag.`name` = 'VN_VALENCIA')
|
||||||
|
INTO vIsValenciaPath
|
||||||
|
FROM vn2008.Rutas r
|
||||||
|
JOIN vn2008.Agencias a on a.Id_Agencia = r.Id_Agencia
|
||||||
|
JOIN vn2008.agency ag on ag.agency_id = a.agency_id
|
||||||
|
WHERE r.Id_Ruta = vMyPath;
|
||||||
|
|
||||||
|
IF vIsValenciaPath THEN -- Rutas Valencia
|
||||||
|
|
||||||
|
SELECT COUNT(*)
|
||||||
|
INTO vExpeditionsCount
|
||||||
|
FROM expedition e
|
||||||
|
JOIN ticket t ON t.id = e.ticketFk
|
||||||
|
WHERE t.routeFk = vMyPath;
|
||||||
|
|
||||||
|
SELECT MAX(ts.productionOrder), MIN(ts.productionOrder)
|
||||||
|
INTO vRestTicketsMaxOrder, vRestTicketsMinOrder
|
||||||
|
FROM ticket t
|
||||||
|
LEFT JOIN ticketState ts on t.id = ts.ticketFk
|
||||||
|
WHERE t.routeFk = vMyPath
|
||||||
|
AND t.warehouseFk = vMyWarehouse
|
||||||
|
AND t.id != vTicketid;
|
||||||
|
|
||||||
|
SELECT COUNT(*)
|
||||||
|
INTO vRestTicketsPacking
|
||||||
|
FROM ticket t
|
||||||
|
LEFT JOIN ticketState ts on t.id = ts.ticketFk
|
||||||
|
WHERE ts.productionOrder = PACKING_ORDER
|
||||||
|
AND t.routeFk = vMyPath
|
||||||
|
AND t.warehouseFk = vMyWarehouse
|
||||||
|
AND t.id != vTicketid;
|
||||||
|
|
||||||
|
IF vExpeditionsCount = 1 THEN
|
||||||
|
SET vPosition = 'FIRST';
|
||||||
|
ELSEIF vRestTicketsMinOrder > PACKING_ORDER THEN
|
||||||
|
SET vPosition = 'LAST';
|
||||||
|
ELSEIF vRestTicketsPacking THEN
|
||||||
|
SET vPosition = 'SHARED';
|
||||||
|
ELSE
|
||||||
|
SET vPosition = 'MID';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
ELSE
|
||||||
|
SET vPosition = 'MID';
|
||||||
|
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN vPosition;
|
||||||
|
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`expedition_beforeInsert`
|
||||||
|
BEFORE INSERT ON `expedition`
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
DECLARE intcounter INT;
|
||||||
|
DECLARE vShipFk INT;
|
||||||
|
|
||||||
|
SET NEW.editorFk = account.myUser_getId();
|
||||||
|
|
||||||
|
IF NEW.freightItemFk IS NOT NULL THEN
|
||||||
|
|
||||||
|
UPDATE ticket SET packages = nz(packages) + 1 WHERE id = NEW.ticketFk;
|
||||||
|
|
||||||
|
SELECT IFNULL(MAX(counter),0) +1 INTO intcounter
|
||||||
|
FROM expedition e
|
||||||
|
INNER JOIN ticket t1 ON e.ticketFk = t1.id
|
||||||
|
LEFT JOIN ticketState ts ON ts.ticketFk = t1.id
|
||||||
|
INNER JOIN ticket t2 ON t2.addressFk = t1.addressFk AND DATE(t2.shipped) = DATE(t1.shipped)
|
||||||
|
AND t1.warehouseFk = t2.warehouseFk
|
||||||
|
WHERE t2.id = NEW.ticketFk AND ts.alertLevel < 3 AND t1.companyFk = t2.companyFk
|
||||||
|
AND t1.agencyModeFk = t2.agencyModeFk;
|
||||||
|
|
||||||
|
SET NEW.`counter` = intcounter;
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,58 @@
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost`
|
||||||
|
SQL SECURITY DEFINER
|
||||||
|
VIEW `vn`.`expeditionRoute_freeTickets` AS
|
||||||
|
SELECT
|
||||||
|
`t`.`routeFk` AS `routeFk`,
|
||||||
|
`tss`.`ticketFk` AS `ticket`,
|
||||||
|
`s`.`name` AS `code`,
|
||||||
|
`w`.`name` AS `almacen`,
|
||||||
|
`tss`.`updated` AS `updated`,
|
||||||
|
`p`.`code` AS `parkingCode`
|
||||||
|
FROM `vn`.`ticketState` `tss`
|
||||||
|
JOIN `vn`.`ticket` `t` ON `t`.`id` = `tss`.`ticketFk`
|
||||||
|
JOIN `vn`.`warehouse` `w` ON `w`.`id` = `t`.`warehouseFk`
|
||||||
|
JOIN `vn`.`state` `s` ON `s`.`id` = `tss`.`state`
|
||||||
|
LEFT JOIN `vn`.`ticketParking` `tp` ON `tp`.`ticketFk` = `t`.`id`
|
||||||
|
LEFT JOIN `vn`.`parking` `p` ON `p`.`id` = `tp`.`parkingFk`
|
||||||
|
WHERE IFNULL(`t`.`packages`, 0) = 0;
|
||||||
|
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost`
|
||||||
|
SQL SECURITY DEFINER
|
||||||
|
VIEW `vn`.`ticketState`
|
||||||
|
AS SELECT `tt`.`created` AS `updated`,
|
||||||
|
`tt`.`stateFk` AS `stateFk`,
|
||||||
|
`tt`.`userFk` AS `userFk`,
|
||||||
|
`tls`.`ticketFk` AS `ticketFk`,
|
||||||
|
`s`.`id` AS `state`,
|
||||||
|
`s`.`order` AS `productionOrder`,
|
||||||
|
`s`.`alertLevel` AS `alertLevel`,
|
||||||
|
`s`.`code` AS `code`,
|
||||||
|
`s`.`isPreviousPreparable` AS `isPreviousPreparable`,
|
||||||
|
`s`.`isPicked` AS `isPicked`
|
||||||
|
FROM (
|
||||||
|
(
|
||||||
|
`vn`.`ticketLastState` `tls`
|
||||||
|
JOIN `vn`.`ticketTracking` `tt` ON(`tt`.`id` = `tls`.`ticketTrackingFk`)
|
||||||
|
)
|
||||||
|
JOIN `vn`.`state` `s` ON(`s`.`id` = `tt`.`stateFk`)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost`
|
||||||
|
SQL SECURITY DEFINER
|
||||||
|
VIEW `vn`.`ticketStateToday`
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
`ts`.`ticketFk` AS `ticket`,
|
||||||
|
`ts`.`state` AS `state`,
|
||||||
|
`ts`.`productionOrder` AS `productionOrder`,
|
||||||
|
`ts`.`alertLevel` AS `alertLevel`,
|
||||||
|
`ts`.`userFk` AS `worker`,
|
||||||
|
`ts`.`code` AS `code`,
|
||||||
|
`ts`.`updated` AS `updated`,
|
||||||
|
`ts`.`isPicked` AS `isPicked`
|
||||||
|
FROM
|
||||||
|
`vn`.`ticketState` `ts`
|
||||||
|
JOIN `vn`.`ticket` `t` ON `t`.`id` = `ts`.`ticketFk`
|
||||||
|
WHERE
|
||||||
|
`t`.`shipped` BETWEEN `util`.`VN_CURDATE`() AND `util`.`VN_CURDATE`() + INTERVAL 1 DAY;
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`invoiceOut_beforeInsert`
|
||||||
|
BEFORE INSERT ON `invoiceOut`
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Reference format:
|
||||||
|
* - 0: Serial [A-Z]
|
||||||
|
* - 1: Sage company id
|
||||||
|
* - 2-3: Last two digits of issued year
|
||||||
|
* - 4-8: Autoincrement identifier
|
||||||
|
**/
|
||||||
|
DECLARE vNewRef INT DEFAULT 0;
|
||||||
|
DECLARE vCompanyCode INT;
|
||||||
|
DECLARE vLastRef VARCHAR(255);
|
||||||
|
DECLARE vRefStr VARCHAR(255);
|
||||||
|
DECLARE vRefLen INT DEFAULT 5;
|
||||||
|
DECLARE vYearLen INT DEFAULT 2;
|
||||||
|
DECLARE vPrefixLen INT;
|
||||||
|
|
||||||
|
SELECT companyCode INTO vCompanyCode
|
||||||
|
FROM company
|
||||||
|
WHERE id = NEW.companyFk;
|
||||||
|
|
||||||
|
IF vCompanyCode IS NULL THEN
|
||||||
|
CALL util.throw('sageCompanyNotDefined');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT MAX(i.ref) INTO vLastRef
|
||||||
|
FROM invoiceOut i
|
||||||
|
WHERE i.serial = NEW.serial
|
||||||
|
AND i.issued BETWEEN util.firstDayOfYear(NEW.issued) AND util.dayEnd(util.lastDayOfYear(NEW.issued))
|
||||||
|
AND i.companyFk = NEW.companyFk;
|
||||||
|
|
||||||
|
IF vLastRef IS NOT NULL THEN
|
||||||
|
SET vPrefixLen = LENGTH(NEW.serial) + LENGTH(vCompanyCode) + vYearLen;
|
||||||
|
SET vRefLen = LENGTH(vLastRef) - vPrefixLen;
|
||||||
|
SET vRefStr = SUBSTRING(vLastRef, vPrefixLen + 1);
|
||||||
|
SET vNewRef = vRefStr + 1;
|
||||||
|
|
||||||
|
IF LENGTH(vNewRef) > vRefLen THEN
|
||||||
|
CALL util.throw('refLenExceeded');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SET NEW.ref = CONCAT(
|
||||||
|
SUBSTRING(vLastRef, 1, vPrefixLen),
|
||||||
|
LPAD(vNewRef, LENGTH(vRefStr), '0')
|
||||||
|
);
|
||||||
|
ELSE
|
||||||
|
SET NEW.ref = CONCAT(
|
||||||
|
NEW.serial,
|
||||||
|
vCompanyCode,
|
||||||
|
RIGHT(YEAR(NEW.issued), vYearLen),
|
||||||
|
LPAD(1, vRefLen, '0')
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -3010,6 +3010,15 @@ INSERT INTO `vn`.`invoiceCorrectionType` (`id`, `description`)
|
||||||
(2, 'Error in sales details'),
|
(2, 'Error in sales details'),
|
||||||
(3, 'Error in customer data');
|
(3, 'Error in customer data');
|
||||||
|
|
||||||
|
UPDATE `vn`.`client`
|
||||||
|
SET fi='65004204V'
|
||||||
|
WHERE id=1;
|
||||||
|
|
||||||
|
UPDATE `vn`.`worker`
|
||||||
|
SET fi='59328808D'
|
||||||
|
WHERE id=1106;
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO `account`.`mailAliasAcl` (`mailAliasFk`, `roleFk`)
|
INSERT INTO `account`.`mailAliasAcl` (`mailAliasFk`, `roleFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1),
|
(1, 1),
|
||||||
|
@ -3020,3 +3029,17 @@ INSERT INTO `vn`.`docuwareTablet` (`tablet`,`description`)
|
||||||
VALUES
|
VALUES
|
||||||
('Tablet1','Jarvis tablet'),
|
('Tablet1','Jarvis tablet'),
|
||||||
('Tablet2','Avengers tablet');
|
('Tablet2','Avengers tablet');
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`sms` (`id`, `senderFk`, `sender`, `destination`, `message`, `statusCode`, `status`, `created`)
|
||||||
|
VALUES (1, 66, '111111111', '0001111111111', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 0, 'OK', util.VN_CURDATE()),
|
||||||
|
(2, 66, '222222222', '0002222222222', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 0, 'PENDING', util.VN_CURDATE()),
|
||||||
|
(3, 66, '333333333', '0003333333333', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 0, 'ERROR', util.VN_CURDATE()),
|
||||||
|
(4, 66, '444444444', '0004444444444', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 0, 'OK', util.VN_CURDATE());
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`clientSms` (`id`, `clientFk`, `smsFk`, `ticketFk`)
|
||||||
|
VALUES(1, 1103, 1, NULL),
|
||||||
|
(2, 1103, 2, NULL),
|
||||||
|
(3, 1103, 3, 32),
|
||||||
|
(4, 1103, 4, 32),
|
||||||
|
(13, 1101, 1, NULL),
|
||||||
|
(14, 1101, 4, 27);
|
||||||
|
|
|
@ -1,123 +0,0 @@
|
||||||
const app = require('vn-loopback/server/server');
|
|
||||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
|
||||||
|
|
||||||
// 2277 solucionar problema al testear procedimiento con start transaction / rollback
|
|
||||||
xdescribe('ticket_componentMakeUpdate()', () => {
|
|
||||||
it('should recalculate the ticket components without make modifications', async() => {
|
|
||||||
let stmts = [];
|
|
||||||
let stmt;
|
|
||||||
|
|
||||||
let params = {
|
|
||||||
ticketId: 11,
|
|
||||||
clientId: 1102,
|
|
||||||
agencyModeId: 2,
|
|
||||||
addressId: 122,
|
|
||||||
zoneId: 3,
|
|
||||||
warehouseId: 1,
|
|
||||||
companyId: 442,
|
|
||||||
isDeleted: 0,
|
|
||||||
hasToBeUnrouted: 0,
|
|
||||||
componentOption: 1
|
|
||||||
};
|
|
||||||
|
|
||||||
stmts.push('START TRANSACTION');
|
|
||||||
|
|
||||||
stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [
|
|
||||||
params.ticketId
|
|
||||||
]);
|
|
||||||
stmts.push(stmt);
|
|
||||||
|
|
||||||
let originalTicketIndex = stmts.push(stmt) - 1;
|
|
||||||
|
|
||||||
stmt = new ParameterizedSQL('CALL vn.ticket_componentMakeUpdate(?, ?, ?, ?, ?, ?, ?, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), ?, ?, ?)', [
|
|
||||||
params.ticketId,
|
|
||||||
params.clientId,
|
|
||||||
params.agencyModeId,
|
|
||||||
params.addressId,
|
|
||||||
params.zoneId,
|
|
||||||
params.warehouseId,
|
|
||||||
params.companyId,
|
|
||||||
params.isDeleted,
|
|
||||||
params.hasToBeUnrouted,
|
|
||||||
params.componentOption
|
|
||||||
]);
|
|
||||||
stmts.push(stmt);
|
|
||||||
|
|
||||||
stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [
|
|
||||||
params.ticketId
|
|
||||||
]);
|
|
||||||
stmts.push(stmt);
|
|
||||||
|
|
||||||
let updatedTicketIndex = stmts.push(stmt) - 1;
|
|
||||||
|
|
||||||
stmts.push('ROLLBACK');
|
|
||||||
|
|
||||||
let sql = ParameterizedSQL.join(stmts, ';');
|
|
||||||
let result = await app.models.Ticket.rawStmt(sql);
|
|
||||||
|
|
||||||
let originalTicketData = result[originalTicketIndex];
|
|
||||||
let updatedTicketData = result[updatedTicketIndex];
|
|
||||||
|
|
||||||
expect(originalTicketData[0].isDeleted).toEqual(updatedTicketData[0].isDeleted);
|
|
||||||
expect(originalTicketData[0].routeFk).toEqual(updatedTicketData[0].routeFk);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete and unroute a ticket and recalculate the components', async() => {
|
|
||||||
let stmts = [];
|
|
||||||
let stmt;
|
|
||||||
|
|
||||||
let params = {
|
|
||||||
ticketId: 11,
|
|
||||||
clientId: 1102,
|
|
||||||
agencyModeId: 2,
|
|
||||||
addressId: 122,
|
|
||||||
zoneId: 3,
|
|
||||||
warehouseId: 1,
|
|
||||||
companyId: 442,
|
|
||||||
isDeleted: 1,
|
|
||||||
hasToBeUnrouted: 1,
|
|
||||||
componentOption: 1
|
|
||||||
};
|
|
||||||
|
|
||||||
stmts.push('START TRANSACTION');
|
|
||||||
|
|
||||||
stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [
|
|
||||||
params.ticketId
|
|
||||||
]);
|
|
||||||
stmts.push(stmt);
|
|
||||||
|
|
||||||
let originalTicketIndex = stmts.push(stmt) - 1;
|
|
||||||
|
|
||||||
stmt = new ParameterizedSQL('CALL vn.ticket_componentMakeUpdate(?, ?, ?, ?, ?, ?, ?, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), ?, ?, ?)', [
|
|
||||||
params.ticketId,
|
|
||||||
params.clientId,
|
|
||||||
params.agencyModeId,
|
|
||||||
params.addressId,
|
|
||||||
params.zoneId,
|
|
||||||
params.warehouseId,
|
|
||||||
params.companyId,
|
|
||||||
params.isDeleted,
|
|
||||||
params.hasToBeUnrouted,
|
|
||||||
params.componentOption
|
|
||||||
]);
|
|
||||||
stmts.push(stmt);
|
|
||||||
|
|
||||||
stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [
|
|
||||||
params.ticketId
|
|
||||||
]);
|
|
||||||
stmts.push(stmt);
|
|
||||||
|
|
||||||
let updatedTicketIndex = stmts.push(stmt) - 1;
|
|
||||||
|
|
||||||
stmts.push('ROLLBACK');
|
|
||||||
|
|
||||||
let sql = ParameterizedSQL.join(stmts, ';');
|
|
||||||
let result = await app.models.Ticket.rawStmt(sql);
|
|
||||||
|
|
||||||
let originalTicketData = result[originalTicketIndex];
|
|
||||||
let updatedTicketData = result[updatedTicketIndex];
|
|
||||||
|
|
||||||
expect(originalTicketData[0].isDeleted).not.toEqual(updatedTicketData[0].isDeleted);
|
|
||||||
expect(originalTicketData[0].routeFk).not.toEqual(updatedTicketData[0].routeFk);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -56,63 +56,6 @@ describe('Worker time control path', () => {
|
||||||
expect(result).toContain(month);
|
expect(result).toContain(month);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should return error when insert 'out' of first entry`, async() => {
|
|
||||||
pending('https://redmine.verdnatura.es/issues/4707');
|
|
||||||
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
|
|
||||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, eightAm);
|
|
||||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
|
|
||||||
await page.respondToDialog('accept');
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should insert 'in' monday`, async() => {
|
|
||||||
pending('https://redmine.verdnatura.es/issues/4707');
|
|
||||||
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
|
|
||||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, eightAm);
|
|
||||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'in');
|
|
||||||
await page.respondToDialog('accept');
|
|
||||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfMonday, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual(eightAm);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should insert 'out' monday`, async() => {
|
|
||||||
pending('https://redmine.verdnatura.es/issues/4707');
|
|
||||||
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
|
|
||||||
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, fourPm);
|
|
||||||
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
|
|
||||||
await page.respondToDialog('accept');
|
|
||||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.secondEntryOfMonday, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual(fourPm);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should check Hank Pym worked 8:20 hours`, async() => {
|
|
||||||
pending('https://redmine.verdnatura.es/issues/4707');
|
|
||||||
await page.waitForTextInElement(selectors.workerTimeControl.mondayWorkedHours, '08:20 h.');
|
|
||||||
await page.waitForTextInElement(selectors.workerTimeControl.weekWorkedHours, '08:20 h.');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should remove first entry of monday', async() => {
|
|
||||||
pending('https://redmine.verdnatura.es/issues/4707');
|
|
||||||
await page.waitForTextInElement(selectors.workerTimeControl.firstEntryOfMonday, eightAm);
|
|
||||||
await page.waitForTextInElement(selectors.workerTimeControl.secondEntryOfMonday, fourPm);
|
|
||||||
await page.waitToClick(selectors.workerTimeControl.firstEntryOfMondayDelete);
|
|
||||||
await page.respondToDialog('accept');
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Entry removed');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should be the 'out' the first entry of monday`, async() => {
|
|
||||||
pending('https://redmine.verdnatura.es/issues/4707');
|
|
||||||
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfMonday, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual(fourPm);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should change week of month', async() => {
|
it('should change week of month', async() => {
|
||||||
await page.click(selectors.workerTimeControl.thrirdWeekDay);
|
await page.click(selectors.workerTimeControl.thrirdWeekDay);
|
||||||
const result = await page.getProperty(selectors.workerTimeControl.mondayWorkedHours, 'innerText');
|
const result = await page.getProperty(selectors.workerTimeControl.mondayWorkedHours, 'innerText');
|
||||||
|
|
|
@ -188,17 +188,6 @@ describe('Ticket Edit sale path', () => {
|
||||||
expect(result).toContain('22.50');
|
expect(result).toContain('22.50');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should check in the history that logs has been added', async() => {
|
|
||||||
pending('https://redmine.verdnatura.es/issues/5455');
|
|
||||||
await page.reload({waitUntil: ['networkidle0', 'domcontentloaded']});
|
|
||||||
await page.waitToClick(selectors.ticketSales.firstSaleHistoryButton);
|
|
||||||
await page.waitForSelector(selectors.ticketSales.firstSaleHistory);
|
|
||||||
const result = await page.countElement(selectors.ticketSales.firstSaleHistory);
|
|
||||||
|
|
||||||
expect(result).toBeGreaterThan(0);
|
|
||||||
await page.waitToClick(selectors.ticketSales.closeHistory);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should recalculate price of sales', async() => {
|
it('should recalculate price of sales', async() => {
|
||||||
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
|
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
|
||||||
await page.waitToClick(selectors.ticketSales.secondSaleCheckbox);
|
await page.waitToClick(selectors.ticketSales.secondSaleCheckbox);
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
// #2221 Local MySQL8 crashes when rest method Items/getBalance is called
|
|
||||||
xdescribe('Ticket diary path', () => {
|
|
||||||
let page;
|
|
||||||
|
|
||||||
beforeAll(async() => {
|
|
||||||
page = (await getBrowser()).page;
|
|
||||||
await page.loginAndModule('employee', 'ticket');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await page.browser().close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should navigate to item diary from ticket sale and check the lines`, async() => {
|
|
||||||
await page.accessToSearchResult('1');
|
|
||||||
await page.waitToClick(selectors.ticketSummary.firstSaleItemId);
|
|
||||||
await page.waitToClick(selectors.ticketSummary.popoverDiaryButton);
|
|
||||||
await page.waitForState('item.card.diary');
|
|
||||||
|
|
||||||
const secondIdClass = await page.getClassName(selectors.itemDiary.secondTicketId);
|
|
||||||
const fourthBalanceClass = await page.getClassName(selectors.itemDiary.fourthBalance);
|
|
||||||
const firstBalanceClass = await page.getClassName(selectors.itemDiary.firstBalance);
|
|
||||||
|
|
||||||
expect(secondIdClass).toContain('message');
|
|
||||||
expect(fourthBalanceClass).toContain('message');
|
|
||||||
expect(firstBalanceClass).toContain('balance');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,114 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer.js';
|
|
||||||
|
|
||||||
// #1528 e2e claim/detail
|
|
||||||
xdescribe('Claim detail', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('salesPerson', 'claim');
|
|
||||||
await page.accessToSearchResult('1');
|
|
||||||
await page.accessToSection('claim.card.detail');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add the first claimable item from ticket to the claim', async() => {
|
|
||||||
await page.waitToClick(selectors.claimDetail.addItemButton);
|
|
||||||
await page.waitToClick(selectors.claimDetail.firstClaimableSaleFromTicket);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the claim contains now two items', async() => {
|
|
||||||
const result = await page.countElement(selectors.claimDetail.claimDetailLine);
|
|
||||||
|
|
||||||
expect(result).toEqual(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should edit de first item claimed quantity', async() => {
|
|
||||||
await page.clearInput(selectors.claimDetail.firstItemQuantityInput); // selector deleted, find new upon fixes
|
|
||||||
await page.write(selectors.claimDetail.firstItemQuantityInput, '4'); // selector deleted, find new upon fixes
|
|
||||||
await page.keyboard.press('Enter');
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the first item quantity, and the claimed total were correctly edited', async() => {
|
|
||||||
const claimedQuantity = page
|
|
||||||
.waitToGetProperty(selectors.claimDetail.firstItemQuantityInput, 'value'); // selector deleted, find new upon fixes
|
|
||||||
|
|
||||||
const totalClaimed = page
|
|
||||||
.waitToGetProperty(selectors.claimDetail.totalClaimed, 'innerText');
|
|
||||||
|
|
||||||
expect(claimedQuantity).toEqual('4');
|
|
||||||
expect(totalClaimed).toContain('€47.62');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should login as salesAssistant and navigate to the claim.detail section', async() => {
|
|
||||||
await page.loginAndModule('salesAssistant', 'claim');
|
|
||||||
await page.accessToSearchResult('1');
|
|
||||||
await page.accessToSection('claim.card.detail');
|
|
||||||
let url = await page.expectURL('/detail'); // replace with waitForState
|
|
||||||
|
|
||||||
expect(url).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should edit de second item claimed discount', async() => {
|
|
||||||
await page.waitToClick(selectors.claimDetail.secondItemDiscount);
|
|
||||||
await page.write(selectors.claimDetail.discount, '100');
|
|
||||||
await page.keyboard.press('Enter');
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the mana is the expected one', async() => {
|
|
||||||
await page.waitToClick(selectors.claimDetail.secondItemDiscount);
|
|
||||||
const result = await page.waitToGetProperty(selectors.claimDetail.discoutPopoverMana, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain('MANÁ: €106');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete the second item from the claim', async() => {
|
|
||||||
await page.waitToClick(selectors.claimDetail.secondItemDeleteButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the claim contains now one item', async() => {
|
|
||||||
const result = await page.countElement(selectors.claimDetail.claimDetailLine);
|
|
||||||
|
|
||||||
expect(result).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add the deleted ticket from to the claim', async() => {
|
|
||||||
await page.waitToClick(selectors.claimDetail.addItemButton);
|
|
||||||
await page.waitToClick(selectors.claimDetail.firstClaimableSaleFromTicket);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should have been redirected to the next section in claims`, async() => {
|
|
||||||
let url = await page.expectURL('development'); // replace with waitForState
|
|
||||||
|
|
||||||
expect(url).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should navigate back to claim.detail to confirm the claim contains now two items', async() => {
|
|
||||||
await page.accessToSection('claim.card.detail');
|
|
||||||
await page.waitForSelector(selectors.claimDetail.claimDetailLine);
|
|
||||||
const result = await page.countElement(selectors.claimDetail.claimDetailLine);
|
|
||||||
|
|
||||||
expect(result).toEqual(2);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -105,17 +105,4 @@ describe('Travel basic data path', () => {
|
||||||
it(`should check the received checkbox was saved even tho it doesn't make sense`, async() => {
|
it(`should check the received checkbox was saved even tho it doesn't make sense`, async() => {
|
||||||
await page.waitForClassPresent(selectors.travelBasicData.received, 'checked');
|
await page.waitForClassPresent(selectors.travelBasicData.received, 'checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate to the travel logs', async() => {
|
|
||||||
pending('https://redmine.verdnatura.es/issues/5455');
|
|
||||||
await page.accessToSection('travel.card.log');
|
|
||||||
await page.waitForState('travel.card.log');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the 1st log contains details from the changes made', async() => {
|
|
||||||
pending('https://redmine.verdnatura.es/issues/5455');
|
|
||||||
const result = await page.waitToGetProperty(selectors.travelLog.firstLogFirstTD, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain('new reference!');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -33,18 +33,6 @@ describe('Component vnTreeview', () => {
|
||||||
$element.remove();
|
$element.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
// See how to test DOM element in Jest
|
|
||||||
xdescribe('undrop()', () => {
|
|
||||||
it(`should reset all drop events and properties`, () => {
|
|
||||||
controller.dropping = angular.element(`<vn-treeview-child class="dropping"></vn-treeview-child>`);
|
|
||||||
jest.spyOn(controller.dropping.classList, 'remove');
|
|
||||||
|
|
||||||
controller.undrop();
|
|
||||||
|
|
||||||
expect(controller.dropping).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('dragOver()', () => {
|
describe('dragOver()', () => {
|
||||||
it(`should set the dragClientY property`, () => {
|
it(`should set the dragClientY property`, () => {
|
||||||
const event = new Event('dragover');
|
const event = new Event('dragover');
|
||||||
|
|
|
@ -69,8 +69,7 @@
|
||||||
"Sent units from ticket": "I sent *{{quantity}}* units of [{{concept}} ({{itemId}})]({{{itemUrl}}}) to *\"{{nickname}}\"* coming from ticket id [{{ticketId}}]({{{ticketUrl}}})",
|
"Sent units from ticket": "I sent *{{quantity}}* units of [{{concept}} ({{itemId}})]({{{itemUrl}}}) to *\"{{nickname}}\"* coming from ticket id [{{ticketId}}]({{{ticketUrl}}})",
|
||||||
"Change quantity": "{{concept}} change of {{oldQuantity}} to {{newQuantity}}",
|
"Change quantity": "{{concept}} change of {{oldQuantity}} to {{newQuantity}}",
|
||||||
"Claim will be picked": "The product from the claim [({{claimId}})]({{{claimUrl}}}) from the client *{{clientName}}* will be picked",
|
"Claim will be picked": "The product from the claim [({{claimId}})]({{{claimUrl}}}) from the client *{{clientName}}* will be picked",
|
||||||
"Claim state has changed to incomplete": "The state of the claim [({{claimId}})]({{{claimUrl}}}) from client *{{clientName}}* has changed to *incomplete*",
|
"Claim state has changed to": "The state of the claim [({{claimId}})]({{{claimUrl}}}) from client *{{clientName}}* has changed to *{{newState}}*",
|
||||||
"Claim state has changed to canceled": "The state of the claim [({{claimId}})]({{{claimUrl}}}) from client *{{clientName}}* has changed to *canceled*",
|
|
||||||
"Customs agent is required for a non UEE member": "Customs agent is required for a non UEE member",
|
"Customs agent is required for a non UEE member": "Customs agent is required for a non UEE member",
|
||||||
"Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member",
|
"Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member",
|
||||||
"Client checked as validated despite of duplication": "Client checked as validated despite of duplication from client id {{clientId}}",
|
"Client checked as validated despite of duplication": "Client checked as validated despite of duplication from client id {{clientId}}",
|
||||||
|
|
|
@ -136,8 +136,7 @@
|
||||||
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})",
|
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})",
|
||||||
"Change quantity": "{{concept}} cambia de {{oldQuantity}} a {{newQuantity}}",
|
"Change quantity": "{{concept}} cambia de {{oldQuantity}} a {{newQuantity}}",
|
||||||
"Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*",
|
"Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*",
|
||||||
"Claim state has changed to incomplete": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *incompleta*",
|
"Claim state has changed to": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *{{newState}}*",
|
||||||
"Claim state has changed to canceled": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *anulado*",
|
|
||||||
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
|
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
|
||||||
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
|
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
|
||||||
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
|
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
|
||||||
|
@ -332,6 +331,7 @@
|
||||||
"quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima",
|
"quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima",
|
||||||
"Cannot past travels with entries": "No se pueden pasar envíos con entradas",
|
"Cannot past travels with entries": "No se pueden pasar envíos con entradas",
|
||||||
"It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}",
|
"It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}",
|
||||||
|
"This claim has been updated": "La reclamación con Id: {{claimId}}, ha sido actualizada",
|
||||||
"This user does not have an assigned tablet": "Este usuario no tiene tablet asignada",
|
"This user does not have an assigned tablet": "Este usuario no tiene tablet asignada",
|
||||||
"Incorrect pin": "Pin incorrecto.",
|
"Incorrect pin": "Pin incorrecto.",
|
||||||
"You already have the mailAlias": "Ya tienes este alias de correo",
|
"You already have the mailAlias": "Ya tienes este alias de correo",
|
||||||
|
|
|
@ -7,7 +7,8 @@ const execFile = require('child_process').execFile;
|
||||||
* https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties
|
* https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties
|
||||||
*/
|
*/
|
||||||
const UserAccountControlFlags = {
|
const UserAccountControlFlags = {
|
||||||
ACCOUNTDISABLE: 2
|
ACCOUNTDISABLE: 0x2,
|
||||||
|
DONT_EXPIRE_PASSWD: 0x10000
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
|
@ -118,7 +119,8 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = {
|
entry = {
|
||||||
userAccountControl: sambaUser.userAccountControl
|
userAccountControl: (sambaUser.userAccountControl
|
||||||
|
| UserAccountControlFlags.DONT_EXPIRE_PASSWD)
|
||||||
& ~UserAccountControlFlags.ACCOUNTDISABLE,
|
& ~UserAccountControlFlags.ACCOUNTDISABLE,
|
||||||
uidNumber: info.uidNumber,
|
uidNumber: info.uidNumber,
|
||||||
accountExpires: 0,
|
accountExpires: 0,
|
||||||
|
|
|
@ -120,7 +120,7 @@ module.exports = Self => {
|
||||||
observationTypeFk: obsevationType.id
|
observationTypeFk: obsevationType.id
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
await models.TicketTracking.create({
|
await models.Ticket.state(ctx, {
|
||||||
ticketFk: newRefundTicket.id,
|
ticketFk: newRefundTicket.id,
|
||||||
stateFk: state.id,
|
stateFk: state.id,
|
||||||
userFk: worker.id
|
userFk: worker.id
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
const LoopBackContext = require('loopback-context');
|
const LoopBackContext = require('loopback-context');
|
||||||
|
const i18n = require('i18n');
|
||||||
describe('Update Claim', () => {
|
describe('Update Claim', () => {
|
||||||
let url;
|
let url;
|
||||||
|
let claimStatesMap = {};
|
||||||
beforeAll(async() => {
|
beforeAll(async() => {
|
||||||
url = await app.models.Url.getUrl();
|
url = await app.models.Url.getUrl();
|
||||||
const activeCtx = {
|
const activeCtx = {
|
||||||
|
@ -16,6 +17,8 @@ describe('Update Claim', () => {
|
||||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||||
active: activeCtx
|
active: activeCtx
|
||||||
});
|
});
|
||||||
|
const claimStates = await app.models.ClaimState.find();
|
||||||
|
claimStatesMap = claimStates.reduce((acc, state) => ({...acc, [state.code]: state.id}), {});
|
||||||
});
|
});
|
||||||
const newDate = Date.vnNew();
|
const newDate = Date.vnNew();
|
||||||
const originalData = {
|
const originalData = {
|
||||||
|
@ -62,6 +65,123 @@ describe('Update Claim', () => {
|
||||||
expect(error.message).toEqual(`You don't have enough privileges to change that field`);
|
expect(error.message).toEqual(`You don't have enough privileges to change that field`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`should success to update the claimState to 'pending' and send a rocket message`, async() => {
|
||||||
|
const tx = await app.models.Claim.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const newClaim = await app.models.Claim.create(originalData, options);
|
||||||
|
|
||||||
|
const chatModel = app.models.Chat;
|
||||||
|
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
||||||
|
|
||||||
|
const pendingState = claimStatesMap.pending;
|
||||||
|
const claimManagerId = 72;
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
accessToken: {userId: claimManagerId},
|
||||||
|
headers: {origin: url}
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
observation: 'valid observation',
|
||||||
|
claimStateFk: pendingState,
|
||||||
|
hasToPickUp: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ctx.req.__ = i18n.__;
|
||||||
|
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
|
||||||
|
|
||||||
|
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
|
||||||
|
|
||||||
|
expect(updatedClaim.observation).toEqual(ctx.args.observation);
|
||||||
|
expect(chatModel.sendCheckingPresence).toHaveBeenCalled();
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should success to update the claimState to 'managed' and send a rocket message`, async() => {
|
||||||
|
const tx = await app.models.Claim.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const newClaim = await app.models.Claim.create(originalData, options);
|
||||||
|
|
||||||
|
const chatModel = app.models.Chat;
|
||||||
|
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
||||||
|
|
||||||
|
const managedState = claimStatesMap.managed;
|
||||||
|
const claimManagerId = 72;
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
accessToken: {userId: claimManagerId},
|
||||||
|
headers: {origin: url}
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
observation: 'valid observation',
|
||||||
|
claimStateFk: managedState,
|
||||||
|
hasToPickUp: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ctx.req.__ = i18n.__;
|
||||||
|
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
|
||||||
|
|
||||||
|
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
|
||||||
|
|
||||||
|
expect(updatedClaim.observation).toEqual(ctx.args.observation);
|
||||||
|
expect(chatModel.sendCheckingPresence).toHaveBeenCalled();
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should success to update the claimState to 'resolved' and send a rocket message`, async() => {
|
||||||
|
const tx = await app.models.Claim.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const newClaim = await app.models.Claim.create(originalData, options);
|
||||||
|
|
||||||
|
const chatModel = app.models.Chat;
|
||||||
|
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
||||||
|
|
||||||
|
const resolvedState = claimStatesMap.resolved;
|
||||||
|
const claimManagerId = 72;
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
accessToken: {userId: claimManagerId},
|
||||||
|
headers: {origin: url}
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
observation: 'valid observation',
|
||||||
|
claimStateFk: resolvedState,
|
||||||
|
hasToPickUp: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ctx.req.__ = i18n.__;
|
||||||
|
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
|
||||||
|
|
||||||
|
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
|
||||||
|
|
||||||
|
expect(updatedClaim.observation).toEqual(ctx.args.observation);
|
||||||
|
expect(chatModel.sendCheckingPresence).toHaveBeenCalled();
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it(`should success to update the claimState to 'canceled' and send a rocket message`, async() => {
|
it(`should success to update the claimState to 'canceled' and send a rocket message`, async() => {
|
||||||
const tx = await app.models.Claim.beginTransaction({});
|
const tx = await app.models.Claim.beginTransaction({});
|
||||||
|
|
||||||
|
@ -73,7 +193,7 @@ describe('Update Claim', () => {
|
||||||
const chatModel = app.models.Chat;
|
const chatModel = app.models.Chat;
|
||||||
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
||||||
|
|
||||||
const canceledState = 4;
|
const canceledState = claimStatesMap.canceled;
|
||||||
const claimManagerId = 72;
|
const claimManagerId = 72;
|
||||||
const ctx = {
|
const ctx = {
|
||||||
req: {
|
req: {
|
||||||
|
@ -86,9 +206,7 @@ describe('Update Claim', () => {
|
||||||
hasToPickUp: false
|
hasToPickUp: false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ctx.req.__ = (value, params) => {
|
ctx.req.__ = i18n.__;
|
||||||
return params.nickname;
|
|
||||||
};
|
|
||||||
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
|
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
|
||||||
|
|
||||||
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
|
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
|
||||||
|
@ -127,9 +245,7 @@ describe('Update Claim', () => {
|
||||||
hasToPickUp: false
|
hasToPickUp: false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ctx.req.__ = (value, params) => {
|
ctx.req.__ = i18n.__;
|
||||||
return params.nickname;
|
|
||||||
};
|
|
||||||
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
|
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
|
||||||
|
|
||||||
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
|
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
|
||||||
|
@ -168,9 +284,7 @@ describe('Update Claim', () => {
|
||||||
hasToPickUp: true
|
hasToPickUp: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ctx.req.__ = (value, params) => {
|
ctx.req.__ = i18n.__;
|
||||||
return params.nickname;
|
|
||||||
};
|
|
||||||
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
|
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
|
||||||
|
|
||||||
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
|
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
|
||||||
|
|
|
@ -96,12 +96,9 @@ module.exports = Self => {
|
||||||
// When claimState has been changed
|
// When claimState has been changed
|
||||||
if (args.claimStateFk) {
|
if (args.claimStateFk) {
|
||||||
const newState = await models.ClaimState.findById(args.claimStateFk, null, myOptions);
|
const newState = await models.ClaimState.findById(args.claimStateFk, null, myOptions);
|
||||||
if (newState.hasToNotify) {
|
await notifyStateChange(ctx, salesPerson.id, claim, newState.code);
|
||||||
if (newState.code == 'incomplete')
|
if (newState.code == 'canceled')
|
||||||
await notifyStateChange(ctx, salesPerson.id, claim, newState.code);
|
await notifyStateChange(ctx, claim.workerFk, claim, newState.code);
|
||||||
if (newState.code == 'canceled')
|
|
||||||
await notifyStateChange(ctx, claim.workerFk, claim, newState.code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
@ -113,15 +110,16 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function notifyStateChange(ctx, workerId, claim, state) {
|
async function notifyStateChange(ctx, workerId, claim, newState) {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const url = await models.Url.getUrl();
|
const url = await models.Url.getUrl();
|
||||||
const $t = ctx.req.__; // $translate
|
const $t = ctx.req.__; // $translate
|
||||||
|
|
||||||
const message = $t(`Claim state has changed to ${state}`, {
|
const message = $t(`Claim state has changed to`, {
|
||||||
claimId: claim.id,
|
claimId: claim.id,
|
||||||
clientName: claim.client().name,
|
clientName: claim.client().name,
|
||||||
claimUrl: `${url}claim/${claim.id}/summary`
|
claimUrl: `${url}claim/${claim.id}/summary`,
|
||||||
|
newState
|
||||||
});
|
});
|
||||||
await models.Chat.sendCheckingPresence(ctx, workerId, message);
|
await models.Chat.sendCheckingPresence(ctx, workerId, message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,9 +113,6 @@
|
||||||
"SageTransactionType": {
|
"SageTransactionType": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
"TicketSms": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"TpvError": {
|
"TpvError": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,6 +21,11 @@
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "Sms",
|
"model": "Sms",
|
||||||
"foreignKey": "smsFk"
|
"foreignKey": "smsFk"
|
||||||
|
},
|
||||||
|
"ticket": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Ticket",
|
||||||
|
"foreignKey": "ticketFk"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
{
|
|
||||||
"name": "TicketSms",
|
|
||||||
"base": "VnModel",
|
|
||||||
"options": {
|
|
||||||
"mysql": {
|
|
||||||
"table": "ticketSms"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"properties": {
|
|
||||||
"smsFk": {
|
|
||||||
"type": "number",
|
|
||||||
"id": true,
|
|
||||||
"description": "Identifier"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"relations": {
|
|
||||||
"ticket": {
|
|
||||||
"type": "belongsTo",
|
|
||||||
"model": "Ticket",
|
|
||||||
"foreignKey": "ticketFk"
|
|
||||||
},
|
|
||||||
"sms": {
|
|
||||||
"type": "belongsTo",
|
|
||||||
"model": "Sms",
|
|
||||||
"foreignKey": "smsFk"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +1,2 @@
|
||||||
<vn-crud-model
|
<vn-card>
|
||||||
vn-id="model"
|
</vn-card>
|
||||||
url="ClientSms"
|
|
||||||
link="{clientFk: $ctrl.$params.id}"
|
|
||||||
filter="::$ctrl.filter"
|
|
||||||
data="clientSmsList"
|
|
||||||
limit="20"
|
|
||||||
auto-load="true">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-data-viewer model="model">
|
|
||||||
<vn-card class="vn-w-lg">
|
|
||||||
<vn-table model="model" auto-load="false">
|
|
||||||
<vn-thead>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-th field="senderFk">Sender</vn-th>
|
|
||||||
<vn-th field="destination" number>Destination</vn-th>
|
|
||||||
<vn-th field="message">Message</vn-th>
|
|
||||||
<vn-th field="status">Status</vn-th>
|
|
||||||
<vn-th field="created" expand>Created</vn-th>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-thead>
|
|
||||||
<vn-tbody>
|
|
||||||
<vn-tr ng-repeat="clientSms in clientSmsList">
|
|
||||||
<vn-td>
|
|
||||||
<span class="link" ng-click="workerDescriptor.show($event, clientSms.sms.senderFk)">
|
|
||||||
{{::clientSms.sms.sender.name}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td number expand>{{::clientSms.sms.destination}}</vn-td>
|
|
||||||
<vn-td expand vn-tooltip="{{::clientSms.sms.message}}">{{::clientSms.sms.message}}</vn-td>
|
|
||||||
<vn-td>{{::clientSms.sms.status}}</vn-td>
|
|
||||||
<vn-td shrink-datetime>{{::clientSms.sms.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-tbody>
|
|
||||||
</vn-table>
|
|
||||||
</vn-card>
|
|
||||||
</vn-data-viewer>
|
|
||||||
<vn-worker-descriptor-popover
|
|
||||||
vn-id="worker-descriptor">
|
|
||||||
</vn-worker-descriptor-popover>
|
|
||||||
|
|
|
@ -1,32 +1,14 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import Section from 'salix/components/section';
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
export default class Controller extends Section {
|
class Controller extends Section {
|
||||||
constructor($element, $) {
|
constructor($element, $) {
|
||||||
super($element, $);
|
super($element, $);
|
||||||
|
}
|
||||||
|
|
||||||
this.filter = {
|
async $onInit() {
|
||||||
fields: ['id', 'smsFk'],
|
this.$state.go('client.card.summary', {id: this.$params.id});
|
||||||
include: {
|
window.location.href = await this.vnApp.getUrl(`Customer/${this.$params.id}/sms`);
|
||||||
relation: 'sms',
|
|
||||||
scope: {
|
|
||||||
fields: [
|
|
||||||
'senderFk',
|
|
||||||
'sender',
|
|
||||||
'destination',
|
|
||||||
'message',
|
|
||||||
'statusCode',
|
|
||||||
'status',
|
|
||||||
'created'],
|
|
||||||
include: {
|
|
||||||
relation: 'sender',
|
|
||||||
scope: {
|
|
||||||
fields: ['name']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
const models = require('vn-loopback/server/server').models;
|
|
||||||
const https = require('https');
|
|
||||||
|
|
||||||
xdescribe('boxing getVideo()', () => {
|
|
||||||
it('should return data', async() => {
|
|
||||||
const tx = await models.PackingSiteConfig.beginTransaction({});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
const id = 1;
|
|
||||||
const video = 'video.mp4';
|
|
||||||
|
|
||||||
const response = {
|
|
||||||
pipe: () => {},
|
|
||||||
on: () => {},
|
|
||||||
end: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
const req = {
|
|
||||||
headers: 'apiHeader',
|
|
||||||
data: {
|
|
||||||
pipe: () => {},
|
|
||||||
on: () => {},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(https, 'request').and.returnValue(response);
|
|
||||||
|
|
||||||
const result = await models.Boxing.getVideo(id, video, req, null, options);
|
|
||||||
|
|
||||||
expect(result[0]).toEqual(response.data.videos[0].filename);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -49,7 +49,7 @@ module.exports = Self => {
|
||||||
for (const id of ticketIds) {
|
for (const id of ticketIds) {
|
||||||
const promise = await models.Ticket.state(ctx, {
|
const promise = await models.Ticket.state(ctx, {
|
||||||
stateFk: state.id,
|
stateFk: state.id,
|
||||||
workerFk: worker.id,
|
userFk: worker.id,
|
||||||
ticketFk: id
|
ticketFk: id
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
promises.push(promise);
|
promises.push(promise);
|
||||||
|
|
|
@ -130,7 +130,17 @@ module.exports = Self => {
|
||||||
await models.TicketDms.create({ticketFk: ticketId, dmsFk: dms[0].id}, myOptions);
|
await models.TicketDms.create({ticketFk: ticketId, dmsFk: dms[0].id}, myOptions);
|
||||||
const ticket = await models.Ticket.findById(ticketId, null, myOptions);
|
const ticket = await models.Ticket.findById(ticketId, null, myOptions);
|
||||||
await ticket.updateAttribute('isSigned', true, myOptions);
|
await ticket.updateAttribute('isSigned', true, myOptions);
|
||||||
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [ticketId, 'DELIVERED'], myOptions);
|
|
||||||
|
const deliveryState = await models.State.find({
|
||||||
|
where: {
|
||||||
|
code: 'DELIVERED'
|
||||||
|
}
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
await models.Ticket.state(ctx, {
|
||||||
|
ticketFk: ticketId,
|
||||||
|
stateFk: deliveryState.id
|
||||||
|
}, myOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
|
@ -33,7 +33,9 @@ module.exports = Self => {
|
||||||
Self.sendSms = async(ctx, id, destination, message) => {
|
Self.sendSms = async(ctx, id, destination, message) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const sms = await models.Sms.send(ctx, destination, message);
|
const sms = await models.Sms.send(ctx, destination, message);
|
||||||
await models.TicketSms.create({
|
const {clientFk} = await models.Ticket.findById(id);
|
||||||
|
await models.ClientSms.create({
|
||||||
|
clientFk,
|
||||||
ticketFk: id,
|
ticketFk: id,
|
||||||
smsFk: sms.id
|
smsFk: sms.id
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,12 +14,12 @@ describe('ticket sendSms()', () => {
|
||||||
|
|
||||||
await models.Ticket.sendSms(ctx, id, destination, message, options);
|
await models.Ticket.sendSms(ctx, id, destination, message, options);
|
||||||
|
|
||||||
const filter = {
|
const clientSms = await models.ClientSms.findOne(
|
||||||
ticketFk: id
|
{where: {ticketFk: id}},
|
||||||
};
|
options
|
||||||
const ticketSms = await models.TicketSms.findOne(filter, options);
|
);
|
||||||
|
|
||||||
expect(ticketSms.ticketFk).toEqual(id);
|
expect(clientSms.ticketFk).toEqual(id);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -45,9 +45,8 @@ describe('ticket state()', () => {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
activeCtx.accessToken.userId = salesPersonId;
|
activeCtx.accessToken.userId = salesPersonId;
|
||||||
const params = {ticketFk: 2, stateFk: 3};
|
|
||||||
|
|
||||||
await models.Ticket.state(ctx, params, options);
|
await models.Ticket.state(ctx, {ticketFk: 2, stateFk: 3}, options);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -67,9 +66,8 @@ describe('ticket state()', () => {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
activeCtx.accessToken.userId = employeeId;
|
activeCtx.accessToken.userId = employeeId;
|
||||||
const params = {ticketFk: 11, stateFk: 13};
|
|
||||||
|
|
||||||
await models.Ticket.state(ctx, params, options);
|
await models.Ticket.state(ctx, {ticketFk: 11, stateFk: 13}, options);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -7,7 +7,6 @@ module.exports = Self => {
|
||||||
accepts: [
|
accepts: [
|
||||||
{
|
{
|
||||||
arg: 'data',
|
arg: 'data',
|
||||||
description: 'Model instance data',
|
|
||||||
type: 'Object',
|
type: 'Object',
|
||||||
required: true,
|
required: true,
|
||||||
http: {source: 'body'}
|
http: {source: 'body'}
|
||||||
|
@ -37,25 +36,21 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
|
|
||||||
if (!params.stateFk && !params.code)
|
if (!params.stateFk && !params.code)
|
||||||
throw new UserError('State cannot be blank');
|
throw new UserError('State cannot be blank');
|
||||||
|
|
||||||
if (params.code) {
|
if (params.stateFk) {
|
||||||
const state = await models.State.findOne({
|
const {code} = await models.State.findById(params.stateFk, {fields: ['code']}, myOptions);
|
||||||
where: {code: params.code},
|
params.code = code;
|
||||||
fields: ['id']
|
} else {
|
||||||
}, myOptions);
|
const {id} = await models.State.findOne({where: {code: params.code}}, myOptions);
|
||||||
|
params.stateFk = id;
|
||||||
params.stateFk = state.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params.userFk) {
|
if (!params.userFk) {
|
||||||
const worker = await models.Worker.findOne({
|
const worker = await models.Worker.findOne({
|
||||||
where: {id: userId}
|
where: {id: ctx.req.accessToken.userId}
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
params.userFk = worker.id;
|
params.userFk = worker.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,17 +58,21 @@ module.exports = Self => {
|
||||||
fields: ['stateFk']
|
fields: ['stateFk']
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
let oldStateAllowed;
|
const oldStateAllowed = ticketState && await models.State.isEditable(ctx, ticketState.stateFk, myOptions);
|
||||||
if (ticketState)
|
|
||||||
oldStateAllowed = await models.State.isEditable(ctx, ticketState.stateFk, myOptions);
|
|
||||||
const newStateAllowed = await models.State.isEditable(ctx, params.stateFk, myOptions);
|
const newStateAllowed = await models.State.isEditable(ctx, params.stateFk, myOptions);
|
||||||
|
|
||||||
const isAllowed = (!ticketState || oldStateAllowed == true) && newStateAllowed == true;
|
if ((ticketState && !oldStateAllowed) || !newStateAllowed)
|
||||||
|
|
||||||
if (!isAllowed)
|
|
||||||
throw new UserError(`You don't have enough privileges`, 'ACCESS_DENIED');
|
throw new UserError(`You don't have enough privileges`, 'ACCESS_DENIED');
|
||||||
|
|
||||||
const ticketTracking = await models.TicketTracking.create(params, myOptions);
|
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [params.ticketFk, params.code], myOptions);
|
||||||
|
|
||||||
|
const ticketTracking = await models.TicketTracking.findOne({
|
||||||
|
where: {ticketFk: params.ticketFk},
|
||||||
|
order: 'id DESC',
|
||||||
|
limit: 1
|
||||||
|
}, myOptions);
|
||||||
|
|
||||||
|
await ticketTracking.updateAttribute('userFk', params.userFk, myOptions);
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
"user": {
|
"user": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "VnUser",
|
"model": "VnUser",
|
||||||
"foreignKey": "workerFk"
|
"foreignKey": "userFk"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
<vn-tr ng-repeat="tracking in trackings">
|
<vn-tr ng-repeat="tracking in trackings">
|
||||||
<vn-td>{{::tracking.state.name}}</vn-td>
|
<vn-td>{{::tracking.state.name}}</vn-td>
|
||||||
<vn-td expand>
|
<vn-td expand>
|
||||||
<span
|
<span
|
||||||
ng-class="{'link': tracking.user.id}"
|
ng-class="{'link': tracking.user.worker}"
|
||||||
ng-click="workerDescriptor.show($event, tracking.user.id)">
|
ng-click="tracking.user.worker && workerDescriptor.show($event, tracking.user.worker.id)">
|
||||||
{{::tracking.user.name || 'System' | translate}}
|
{{::tracking.user.name || 'System' | translate}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
|
|
|
@ -9,7 +9,13 @@ class Controller extends Section {
|
||||||
{
|
{
|
||||||
relation: 'user',
|
relation: 'user',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['name']
|
fields: ['id', 'name'],
|
||||||
|
include: {
|
||||||
|
relation: 'worker',
|
||||||
|
scope: {
|
||||||
|
fields: ['id']
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
relation: 'state',
|
relation: 'state',
|
||||||
|
|
|
@ -5,7 +5,7 @@ module.exports = Self => {
|
||||||
accepts: [
|
accepts: [
|
||||||
{
|
{
|
||||||
arg: 'workerFk',
|
arg: 'workerFk',
|
||||||
type: 'int',
|
type: 'number',
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
|
const validateTin = require('vn-loopback/util/validateTin');
|
||||||
require('../methods/worker/filter')(Self);
|
require('../methods/worker/filter')(Self);
|
||||||
require('../methods/worker/mySubordinates')(Self);
|
require('../methods/worker/mySubordinates')(Self);
|
||||||
require('../methods/worker/isSubordinate')(Self);
|
require('../methods/worker/isSubordinate')(Self);
|
||||||
|
@ -23,4 +24,21 @@ module.exports = Self => {
|
||||||
Self.validatesUniquenessOf('locker', {
|
Self.validatesUniquenessOf('locker', {
|
||||||
message: 'This locker has already been assigned'
|
message: 'This locker has already been assigned'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Self.validateAsync('fi', tinIsValid, {
|
||||||
|
message: 'Invalid TIN'
|
||||||
|
});
|
||||||
|
|
||||||
|
async function tinIsValid(err, done) {
|
||||||
|
const filter = {
|
||||||
|
fields: ['code'],
|
||||||
|
where: {id: this.countryFk}
|
||||||
|
};
|
||||||
|
const country = await Self.app.models.Country.findOne(filter);
|
||||||
|
const code = country ? country.code.toLowerCase() : null;
|
||||||
|
|
||||||
|
if (!this.fi || !validateTin(this.fi, code))
|
||||||
|
err();
|
||||||
|
done();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,7 +61,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
for (ticket of ticketList) {
|
for (ticket of ticketList) {
|
||||||
if (ticket.ticketState().alertLevel == 0) {
|
if (ticket.ticketState().alertLevel == 0) {
|
||||||
promises.push(models.TicketTracking.create({
|
promises.push(models.Ticket.state(ctx, {
|
||||||
ticketFk: ticket.id,
|
ticketFk: ticket.id,
|
||||||
stateFk: fixingState.id,
|
stateFk: fixingState.id,
|
||||||
userFk: worker.id
|
userFk: worker.id
|
||||||
|
|
Loading…
Reference in New Issue