4037-fix(multi-check) #973
|
@ -62,13 +62,13 @@ pipeline {
|
|||
}
|
||||
}
|
||||
}
|
||||
// stage('Backend') {
|
||||
// steps {
|
||||
// nodejs('node-v14') {
|
||||
// sh 'gulp launchBackTest --ci'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
stage('Backend') {
|
||||
steps {
|
||||
nodejs('node-v14') {
|
||||
sh 'npm run test:back:ci'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
|
|
|
@ -54,17 +54,17 @@ $ gulp docker
|
|||
|
||||
For client-side unit tests run from project's root.
|
||||
```
|
||||
$ jest
|
||||
$ npm run test:front
|
||||
```
|
||||
|
||||
For server-side unit tests run from project's root.
|
||||
```
|
||||
$ gulp backTest
|
||||
$ npm run test:back
|
||||
```
|
||||
|
||||
For end-to-end tests run from project's root.
|
||||
```
|
||||
$ gulp e2e
|
||||
$ npm run test:e2e
|
||||
```
|
||||
|
||||
## Visual Studio Code extensions
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('account changePassword()', () => {
|
||||
it('should throw an error when old password is wrong', async() => {
|
||||
let req = app.models.Account.changePassword(null, 1, 'wrongOldPass', 'newPass');
|
||||
let err;
|
||||
await models.Account.changePassword(1, 'wrongPassword', 'nightmare.9999')
|
||||
.catch(error => err = error.sqlMessage);
|
||||
|
||||
await expectAsync(req).toBeRejected();
|
||||
expect(err).toBeDefined();
|
||||
expect(err).toEqual('Invalid password');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
// #3400 analizar que hacer con rutas de back colletion
|
||||
xdescribe('newCollection()', () => {
|
||||
it('return a new collection', async() => {
|
||||
describe('newCollection()', () => {
|
||||
it('should return a new collection', async() => {
|
||||
pending('#3400 analizar que hacer con rutas de back collection');
|
||||
let ctx = {req: {accessToken: {userId: 1106}}};
|
||||
let response = await app.models.Collection.newCollection(ctx, 1, 1, 1);
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('deleteTrashFiles', {
|
||||
description: 'Deletes files that have trash type',
|
||||
accessType: 'WRITE',
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/deleteTrashFiles`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.deleteTrashFiles = async(options) => {
|
||||
const tx = await Self.beginTransaction({});
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction)
|
||||
myOptions.transaction = tx;
|
||||
|
||||
try {
|
||||
const models = Self.app.models;
|
||||
const DmsContainer = models.DmsContainer;
|
||||
|
||||
const trashDmsType = await models.DmsType.findOne({
|
||||
where: {code: 'trash'}
|
||||
}, myOptions);
|
||||
|
||||
const dmsToDelete = await models.Dms.find({
|
||||
where: {
|
||||
dmsTypeFk: trashDmsType.id
|
||||
}
|
||||
}, myOptions);
|
||||
|
||||
for (let dms of dmsToDelete) {
|
||||
const pathHash = DmsContainer.getHash(dms.id);
|
||||
const dmsContainer = await DmsContainer.container(pathHash);
|
||||
const dstFile = path.join(dmsContainer.client.root, pathHash, dms.file);
|
||||
await fs.unlink(dstFile);
|
||||
await dms.destroy(myOptions);
|
||||
}
|
||||
if (tx) await tx.commit();
|
||||
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -5,6 +5,7 @@ module.exports = Self => {
|
|||
require('../methods/dms/uploadFile')(Self);
|
||||
require('../methods/dms/removeFile')(Self);
|
||||
require('../methods/dms/updateFile')(Self);
|
||||
require('../methods/dms/deleteTrashFiles')(Self);
|
||||
|
||||
Self.checkRole = async function(ctx, id) {
|
||||
const models = Self.app.models;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"verbose": true,
|
||||
"watch": [
|
||||
"back/**/*.js",
|
||||
"modules/**/*.js"
|
||||
],
|
||||
"ignore": [
|
||||
"modules/account/front/**/*",
|
||||
"modules/claim/front/**/*",
|
||||
"modules/client/front/**/*",
|
||||
"modules/entry/front/**/*",
|
||||
"modules/invoiceIn/front/**/*",
|
||||
"modules/invoiceOut/front/**/*",
|
||||
"modules/item/front/**/*",
|
||||
"modules/monitor/front/**/*",
|
||||
"modules/order/front/**/*",
|
||||
"modules/route/front/**/*",
|
||||
"modules/supplier/front/**/*",
|
||||
"modules/ticket/front/**/*",
|
||||
"modules/travel/front/**/*",
|
||||
"modules/worker/front/**/*",
|
||||
"modules/zone/front/**/*"
|
||||
]
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
require('require-yaml');
|
||||
const Docker = require('../db/docker.js');
|
||||
let dataSources = require('../loopback/server/datasources.json');
|
||||
|
||||
process.on('warning', warning => {
|
||||
console.log(warning.name);
|
||||
|
@ -6,34 +7,64 @@ process.on('warning', warning => {
|
|||
console.log(warning.stack);
|
||||
});
|
||||
|
||||
let verbose = false;
|
||||
async function test() {
|
||||
let isCI = false;
|
||||
|
||||
if (process.argv[2] === '--v')
|
||||
verbose = true;
|
||||
if (process.argv[2] === 'ci')
|
||||
isCI = true;
|
||||
|
||||
let Jasmine = require('jasmine');
|
||||
let jasmine = new Jasmine();
|
||||
let SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
||||
const container = new Docker();
|
||||
|
||||
let serviceSpecs = [
|
||||
`${__dirname}/**/*[sS]pec.js`,
|
||||
`${__dirname}/../loopback/**/*[sS]pec.js`,
|
||||
`${__dirname}/../modules/*/back/**/*.[sS]pec.js`
|
||||
await container.run(isCI);
|
||||
dataSources = JSON.parse(JSON.stringify(dataSources));
|
||||
|
||||
Object.assign(dataSources.vn, {
|
||||
host: container.dbConf.host,
|
||||
port: container.dbConf.port
|
||||
});
|
||||
|
||||
const bootOptions = {dataSources};
|
||||
const app = require('vn-loopback/server/server');
|
||||
app.boot(bootOptions);
|
||||
|
||||
const Jasmine = require('jasmine');
|
||||
const jasmine = new Jasmine();
|
||||
|
||||
const SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
||||
jasmine.addReporter(new SpecReporter({
|
||||
spec: {
|
||||
displaySuccessful: isCI,
|
||||
displayPending: isCI
|
||||
},
|
||||
summary: {
|
||||
displayPending: false,
|
||||
}
|
||||
}));
|
||||
|
||||
if (isCI) {
|
||||
const JunitReporter = require('jasmine-reporters');
|
||||
jasmine.addReporter(new JunitReporter.JUnitXmlReporter());
|
||||
|
||||
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
|
||||
}
|
||||
|
||||
const backSpecs = [
|
||||
'./back/**/*[sS]pec.js',
|
||||
'./loopback/**/*[sS]pec.js',
|
||||
'./modules/*/back/**/*.[sS]pec.js'
|
||||
];
|
||||
|
||||
jasmine.loadConfig({
|
||||
spec_dir: '.',
|
||||
spec_files: serviceSpecs,
|
||||
helpers: []
|
||||
spec_files: backSpecs,
|
||||
helpers: [],
|
||||
});
|
||||
|
||||
jasmine.addReporter(new SpecReporter({
|
||||
spec: {
|
||||
// displayStacktrace: 'summary',
|
||||
displaySuccessful: verbose,
|
||||
displayFailedSpec: true,
|
||||
displaySpecDuration: true
|
||||
jasmine.exitOnCompletion = false;
|
||||
await jasmine.execute();
|
||||
if (app) await app.disconnect();
|
||||
if (container) await container.rm();
|
||||
console.log('app disconnected & container removed');
|
||||
}
|
||||
}));
|
||||
|
||||
jasmine.execute();
|
||||
test();
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
INSERT INTO `salix`.`ACL`(`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES('ExpeditionState', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,5 @@
|
|||
INSERT INTO `salix`.`ACL`(`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES('Expense', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||
|
||||
INSERT INTO `salix`.`ACL`(`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES('Expense', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative');
|
|
@ -0,0 +1,5 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES('SupplierActivity', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES('SupplierActivity', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative');
|
|
@ -0,0 +1,8 @@
|
|||
ALTER TABLE vn.propertyDms DROP FOREIGN KEY propertyDms_FK;
|
||||
ALTER TABLE vn.propertyDms ADD CONSTRAINT propertyDms_FK FOREIGN KEY (dmsFk) REFERENCES vn.dms(id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE vn.clientDms DROP FOREIGN KEY clientDms_ibfk_2;
|
||||
ALTER TABLE vn.clientDms ADD CONSTRAINT clientDms_ibfk_2 FOREIGN KEY (dmsFk) REFERENCES vn.dms(id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE vn.workerDocument DROP FOREIGN KEY workerDocument_ibfk_2;
|
||||
ALTER TABLE vn.workerDocument ADD CONSTRAINT workerDocument_ibfk_2 FOREIGN KEY (document) REFERENCES vn.dms(id) ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE vn.dmsType ADD monthToDelete INT UNSIGNED DEFAULT NULL NULL;
|
||||
ALTER TABLE vn.dmsType MODIFY COLUMN monthToDelete int(10) unsigned DEFAULT NULL NULL COMMENT 'Meses en el pasado para ir borrando registros, dejar a null para no borrarlos nunca';
|
||||
UPDATE vn.dmsType
|
||||
SET monthToDelete=6
|
||||
WHERE id=20;
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE TRIGGER dms_beforeDelete
|
||||
BEFORE DELETE
|
||||
ON dms FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE vCanNotBeDeleted INT;
|
||||
SELECT COUNT(*) INTO vCanNotBeDeleted
|
||||
FROM dmsType dt
|
||||
WHERE NOT (code <=> 'trash')
|
||||
AND dt.id = OLD.dmsTypeFk;
|
||||
|
||||
IF vCanNotBeDeleted THEN
|
||||
CALL util.throw('A dms can not be deleted');
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,175 @@
|
|||
DROP PROCEDURE IF EXISTS vn.clean;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`clean`()
|
||||
BEGIN
|
||||
DECLARE vDateShort DATETIME;
|
||||
DECLARE vOneYearAgo DATE;
|
||||
DECLARE vFourYearsAgo DATE;
|
||||
DECLARE v18Month DATE;
|
||||
DECLARE v26Month DATE;
|
||||
DECLARE v3Month DATE;
|
||||
DECLARE vTrashId varchar(15);
|
||||
|
||||
SET vDateShort = TIMESTAMPADD(MONTH, -2, CURDATE());
|
||||
SET vOneYearAgo = TIMESTAMPADD(YEAR,-1,CURDATE());
|
||||
SET vFourYearsAgo = TIMESTAMPADD(YEAR,-4,CURDATE());
|
||||
SET v18Month = TIMESTAMPADD(MONTH, -18,CURDATE());
|
||||
SET v26Month = TIMESTAMPADD(MONTH, -26,CURDATE());
|
||||
SET v3Month = TIMESTAMPADD(MONTH, -3, CURDATE());
|
||||
|
||||
DELETE FROM ticketParking WHERE created < vDateShort;
|
||||
DELETE FROM routesMonitor WHERE dated < vDateShort;
|
||||
DELETE FROM workerTimeControlLog WHERE created < vDateShort;
|
||||
DELETE FROM `message` WHERE sendDate < vDateShort;
|
||||
DELETE FROM messageInbox WHERE sendDate < vDateShort;
|
||||
DELETE FROM messageInbox WHERE sendDate < vDateShort;
|
||||
DELETE FROM workerTimeControl WHERE timed < vFourYearsAgo;
|
||||
DELETE FROM itemShelving WHERE created < CURDATE() AND visible = 0;
|
||||
DELETE FROM ticketDown WHERE created < TIMESTAMPADD(DAY,-1,CURDATE());
|
||||
DELETE FROM entryLog WHERE creationDate < vDateShort;
|
||||
DELETE IGNORE FROM expedition WHERE created < v26Month;
|
||||
DELETE FROM sms WHERE created < v18Month;
|
||||
DELETE FROM saleTracking WHERE created < vOneYearAgo;
|
||||
DELETE tobs FROM ticketObservation tobs
|
||||
JOIN ticket t ON tobs.ticketFk = t.id WHERE t.shipped < TIMESTAMPADD(YEAR,-2,CURDATE());
|
||||
DELETE sc.* FROM saleCloned sc JOIN sale s ON s.id = sc.saleClonedFk JOIN ticket t ON t.id = s.ticketFk WHERE t.shipped < vOneYearAgo;
|
||||
DELETE FROM sharingCart where ended < vDateShort;
|
||||
DELETE FROM sharingClient where ended < vDateShort;
|
||||
DELETE tw.* FROM ticketWeekly tw
|
||||
LEFT JOIN sale s ON s.ticketFk = tw.ticketFk WHERE s.itemFk IS NULL;
|
||||
DELETE FROM claim WHERE ticketCreated < vFourYearsAgo;
|
||||
DELETE FROM message WHERE sendDate < vDateShort;
|
||||
-- Robert ubicacion anterior de trevelLog comentario para debug
|
||||
DELETE sc FROM saleChecked sc
|
||||
JOIN sale s ON sc.saleFk = s.id WHERE s.created < vDateShort;
|
||||
DELETE FROM zoneEvent WHERE `type` = 'day' AND dated < v3Month;
|
||||
DELETE bm
|
||||
FROM buyMark bm
|
||||
JOIN buy b ON b.id = bm.id
|
||||
JOIN entry e ON e.id = b.entryFk
|
||||
JOIN travel t ON t.id = e.travelFk
|
||||
WHERE t.landed <= vDateShort;
|
||||
DELETE FROM stowaway WHERE created < v3Month;
|
||||
DELETE FROM vn.buy WHERE created < vDateShort AND entryFk = 9200;
|
||||
DELETE FROM vn.itemShelvingLog WHERE created < vDateShort;
|
||||
DELETE FROM vn.stockBuyed WHERE creationDate < vDateShort;
|
||||
|
||||
|
||||
-- Equipos duplicados
|
||||
DELETE w.*
|
||||
FROM workerTeam w
|
||||
JOIN (SELECT id, team, workerFk, COUNT(*) - 1 as duplicated
|
||||
FROM workerTeam
|
||||
GROUP BY team,workerFk
|
||||
HAVING duplicated
|
||||
) d ON d.team = w.team AND d.workerFk = w.workerFk AND d.id != w.id;
|
||||
|
||||
DELETE sc
|
||||
FROM saleComponent sc
|
||||
JOIN sale s ON s.id= sc.saleFk
|
||||
JOIN ticket t ON t.id= s.ticketFk
|
||||
WHERE t.shipped < v18Month;
|
||||
|
||||
DELETE c
|
||||
FROM vn.claim c
|
||||
JOIN vn.claimState cs ON cs.id = c.claimStateFk
|
||||
WHERE cs.description = "Anulado" AND
|
||||
c.created < vDateShort;
|
||||
DELETE
|
||||
FROM vn.expeditionTruck
|
||||
WHERE ETD < v3Month;
|
||||
|
||||
-- borrar travels sin entradas
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.thermographToDelete;
|
||||
CREATE TEMPORARY TABLE tmp.thermographToDelete
|
||||
SELECT th.id,th.dmsFk
|
||||
FROM vn.travel t
|
||||
LEFT JOIN vn.entry e ON e.travelFk = t.id
|
||||
JOIN vn.travelThermograph th ON th.travelFk = t.id
|
||||
WHERE t.shipped < TIMESTAMPADD(MONTH, -3, CURDATE()) AND e.travelFk IS NULL;
|
||||
|
||||
SELECT dt.id into vTrashId
|
||||
FROM vn.dmsType dt
|
||||
WHERE dt.code = 'trash';
|
||||
|
||||
UPDATE tmp.thermographToDelete th
|
||||
JOIN vn.dms d ON d.id = th.dmsFk
|
||||
SET d.dmsTypeFk = vTrashId;
|
||||
|
||||
DELETE th
|
||||
FROM tmp.thermographToDelete tmp
|
||||
JOIN vn.travelThermograph th ON th.id = tmp.id;
|
||||
|
||||
DELETE t
|
||||
FROM vn.travel t
|
||||
LEFT JOIN vn.entry e ON e.travelFk = t.id
|
||||
WHERE t.shipped < TIMESTAMPADD(MONTH, -3, CURDATE()) AND e.travelFk IS NULL;
|
||||
|
||||
UPDATE dms d
|
||||
JOIN dmsType dt ON dt.id = d.dmsTypeFk
|
||||
SET d.dmsTypeFk = vTrashId
|
||||
WHERE created < TIMESTAMPADD(MONTH, -dt.monthToDelete, CURDATE());
|
||||
|
||||
-- borrar entradas sin compras
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.entryToDelete;
|
||||
CREATE TEMPORARY TABLE tmp.entryToDelete
|
||||
SELECT e.*
|
||||
FROM vn.entry e
|
||||
LEFT JOIN vn.buy b ON b.entryFk = e.id
|
||||
JOIN vn.entryConfig ec ON e.id != ec.defaultEntry
|
||||
WHERE e.dated < TIMESTAMPADD(MONTH, -3, CURDATE()) AND b.entryFK IS NULL;
|
||||
|
||||
DELETE e
|
||||
FROM vn.entry e
|
||||
JOIN tmp.entryToDelete tmp ON tmp.id = e.id;
|
||||
|
||||
-- borrar de route registros menores a 4 años
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.routeToDelete;
|
||||
CREATE TEMPORARY TABLE tmp.routeToDelete
|
||||
SELECT *
|
||||
FROM vn.route r
|
||||
WHERE created < TIMESTAMPADD(YEAR,-4,CURDATE());
|
||||
|
||||
UPDATE tmp.routeToDelete tmp
|
||||
JOIN vn.dms d ON d.id = tmp.gestdocFk
|
||||
SET d.dmsTypeFk = vTrashId;
|
||||
|
||||
DELETE r
|
||||
FROM tmp.routeToDelete tmp
|
||||
JOIN vn.route r ON r.id = tmp.id;
|
||||
|
||||
-- borrar registros de dua y awb menores a 2 años
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.duaToDelete;
|
||||
CREATE TEMPORARY TABLE tmp.duaToDelete
|
||||
SELECT *
|
||||
FROM vn.dua
|
||||
WHERE operated < TIMESTAMPADD(YEAR,-2,CURDATE());
|
||||
|
||||
UPDATE tmp.duaToDelete tm
|
||||
JOIN vn.dms d ON d.id = tm.gestdocFk
|
||||
SET d.dmsTypeFk = vTrashId;
|
||||
|
||||
DELETE d
|
||||
FROM tmp.duaToDelete tmp
|
||||
JOIN vn.dua d ON d.id = tmp.id;
|
||||
|
||||
DELETE FROM vn.awb WHERE created < TIMESTAMPADD(YEAR,-2,CURDATE());
|
||||
|
||||
-- Borra los ficheros gestDoc
|
||||
INSERT INTO vn.printServerQueue(priorityFk, labelReportFk)VALUES(1,11);
|
||||
|
||||
-- Borra los registros de collection y ticketcollection
|
||||
DELETE FROM vn.collection WHERE created < vDateShort;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.thermographToDelete;
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.entryToDelete;
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.duaToDelete;
|
||||
|
||||
DELETE FROM travelLog WHERE creationDate < v3Month;
|
||||
|
||||
CALL shelving_clean;
|
||||
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,2 @@
|
|||
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
|
||||
VALUES ('Dms','deleteTrashFiles','WRITE','ALLOW','ROLE','employee')
|
|
@ -1 +0,0 @@
|
|||
Delete file
|
|
@ -24,7 +24,10 @@ module.exports = class Docker {
|
|||
let d = new Date();
|
||||
let pad = v => v < 10 ? '0' + v : v;
|
||||
let stamp = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
||||
|
||||
log('Building container image...');
|
||||
await this.execP(`docker build --build-arg STAMP=${stamp} -t salix-db ./db`);
|
||||
log('Image built.');
|
||||
|
||||
let dockerArgs;
|
||||
|
||||
|
@ -39,6 +42,7 @@ module.exports = class Docker {
|
|||
|
||||
let runChown = process.platform != 'linux';
|
||||
|
||||
log('Starting container...');
|
||||
const container = await this.execP(`docker run --env RUN_CHOWN=${runChown} -d ${dockerArgs} salix-db`);
|
||||
this.id = container.stdout.trim();
|
||||
|
||||
|
@ -158,6 +162,7 @@ module.exports = class Docker {
|
|||
return reject(new Error('Docker exited, please see the docker logs for more info'));
|
||||
|
||||
let conn = mysql.createConnection(myConf);
|
||||
|
||||
conn.on('error', () => {});
|
||||
conn.connect(err => {
|
||||
conn.destroy();
|
||||
|
|
|
@ -854,18 +854,35 @@ INSERT INTO `vn`.`packaging`(`id`, `volume`, `width`, `height`, `depth`, `isPack
|
|||
('cc', 1640038.00, 56.00, 220.00, 128.00, 1, CURDATE(), 15, 90.00),
|
||||
('pallet 100', 2745600.00, 100.00, 220.00, 120.00, 1, CURDATE(), 16, 0.00);
|
||||
|
||||
INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`, `externalId`, `packagingFk`)
|
||||
INSERT INTO `vn`.`expeditionStateType`(`id`, `description`, `code`)
|
||||
VALUES
|
||||
(1, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 15, 1, 1, 18, 'UR9000006041', 94),
|
||||
(2, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 16, 2, 1, 18, 'UR9000006041', 94),
|
||||
(3, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 3, 1, 18, 'UR9000006041', 94),
|
||||
(4, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 4, 1, 18, 'UR9000006041', 94),
|
||||
(5, 1, 2, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 1, 1, 18, NULL, 94),
|
||||
(6, 7, 3, 71, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), NULL, 1, 1, 18, NULL, 94),
|
||||
(7, 2, 4, 71, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), NULL, 1, 1, 18, NULL, 94),
|
||||
(8, 3, 5, 71, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), NULL, 1, 1, 18, NULL, 94),
|
||||
(9, 3, 6, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 1, 1, 18, NULL, 94),
|
||||
(10, 7, 7, 71, NOW(), NULL, 1, 1, 18, NULL, 94);
|
||||
(1, 'En reparto', 'ON DELIVERY'),
|
||||
(2, 'Entregada', 'DELIVERED'),
|
||||
(3, 'Perdida', 'LOST');
|
||||
|
||||
|
||||
INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`, `externalId`, `packagingFk`, `stateTypeFk`)
|
||||
VALUES
|
||||
(1, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 15, 1, 1, 18, 'UR9000006041', 94, 1),
|
||||
(2, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 16, 2, 1, 18, 'UR9000006041', 94, 1),
|
||||
(3, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 3, 1, 18, 'UR9000006041', 94, 2),
|
||||
(4, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 4, 1, 18, 'UR9000006041', 94, 2),
|
||||
(5, 1, 2, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 1, 1, 18, NULL, 94, 3),
|
||||
(6, 7, 3, 71, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), NULL, 1, 1, 18, NULL, 94, 3),
|
||||
(7, 2, 4, 71, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), NULL, 1, 1, 18, NULL, 94, NULL),
|
||||
(8, 3, 5, 71, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), NULL, 1, 1, 18, NULL, 94, 1),
|
||||
(9, 3, 6, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 1, 1, 18, NULL, 94, 2),
|
||||
(10, 7, 7, 71, NOW(), NULL, 1, 1, 18, NULL, 94, 3);
|
||||
|
||||
|
||||
INSERT INTO `vn`.`expeditionState`(`id`, `created`, `expeditionFk`, `typeFk`, `userFk`)
|
||||
VALUES
|
||||
(1, CURDATE(), 1, 1, 1),
|
||||
(2, CURDATE(), 2, 1, 1),
|
||||
(3, CURDATE(), 3, 1, 1),
|
||||
(4, CURDATE(), 3, 2, 1106),
|
||||
(5, CURDATE(), 5, 1, 1106),
|
||||
(6, CURDATE(), 5, 3, 1106);
|
||||
|
||||
INSERT INTO `vn`.`ticketPackaging`(`id`, `ticketFk`, `packagingFk`, `quantity`, `created`, `pvp`)
|
||||
VALUES
|
||||
|
@ -1296,11 +1313,11 @@ INSERT INTO `vn`.`supplierAddress`(`id`, `supplierFk`, `nickname`, `street`, `pr
|
|||
(5, 442, 'GCR building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'),
|
||||
(6, 442, 'The Gotham Tonight building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222');
|
||||
|
||||
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`, `commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`, `isPayMethodChecked`)
|
||||
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`, `commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`, `isPayMethodChecked`, `healthRegister`)
|
||||
VALUES
|
||||
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1),
|
||||
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1),
|
||||
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'flowerPlants', 1);
|
||||
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1, '400664487V'),
|
||||
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1, '400664487V'),
|
||||
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V');
|
||||
|
||||
INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`)
|
||||
VALUES
|
||||
|
|
|
@ -982,8 +982,8 @@ export default {
|
|||
save: 'vn-invoice-in-basic-data button[type=submit]'
|
||||
},
|
||||
invoiceInTax: {
|
||||
addTaxButton: 'vn-invoice-in-tax vn-icon-button[icon="add_circle"]',
|
||||
thirdExpence: 'vn-invoice-in-tax vn-horizontal:nth-child(3) > vn-autocomplete[ng-model="invoiceInTax.expenseFk"]',
|
||||
addTaxButton: 'vn-invoice-in-tax vn-icon-button[vn-tooltip="Add tax"]',
|
||||
thirdExpense: 'vn-invoice-in-tax vn-horizontal:nth-child(3) > vn-autocomplete[ng-model="invoiceInTax.expenseFk"]',
|
||||
thirdTaxableBase: 'vn-invoice-in-tax vn-horizontal:nth-child(3) > vn-input-number[ng-model="invoiceInTax.taxableBase"]',
|
||||
thirdTaxType: 'vn-invoice-in-tax vn-horizontal:nth-child(3) > vn-autocomplete[ng-model="invoiceInTax.taxTypeSageFk"]',
|
||||
thirdTransactionType: 'vn-invoice-in-tax vn-horizontal:nth-child(3) > vn-autocomplete[ng-model="invoiceInTax.transactionTypeSageFk"]',
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
require('@babel/register')({presets: ['@babel/env']});
|
||||
require('core-js/stable');
|
||||
require('regenerator-runtime/runtime');
|
||||
|
||||
const axios = require('axios');
|
||||
const Docker = require('../../db/docker.js');
|
||||
const e2eConfig = require('./config.js');
|
||||
const log = require('fancy-log');
|
||||
|
||||
process.on('warning', warning => {
|
||||
console.log(warning.name);
|
||||
console.log(warning.message);
|
||||
console.log(warning.stack);
|
||||
});
|
||||
|
||||
async function test() {
|
||||
if (process.argv[2] === 'show')
|
||||
process.env.E2E_SHOW = true;
|
||||
|
||||
const container = new Docker('salix-db');
|
||||
|
||||
await container.run();
|
||||
|
||||
const Jasmine = require('jasmine');
|
||||
const jasmine = new Jasmine();
|
||||
|
||||
const specFiles = [
|
||||
`./e2e/paths/01*/*[sS]pec.js`,
|
||||
`./e2e/paths/02*/*[sS]pec.js`,
|
||||
`./e2e/paths/03*/*[sS]pec.js`,
|
||||
`./e2e/paths/04*/*[sS]pec.js`,
|
||||
`./e2e/paths/05*/*[sS]pec.js`,
|
||||
`./e2e/paths/06*/*[sS]pec.js`,
|
||||
`./e2e/paths/07*/*[sS]pec.js`,
|
||||
`./e2e/paths/08*/*[sS]pec.js`,
|
||||
`./e2e/paths/09*/*[sS]pec.js`,
|
||||
`./e2e/paths/10*/*[sS]pec.js`,
|
||||
`./e2e/paths/11*/*[sS]pec.js`,
|
||||
`./e2e/paths/12*/*[sS]pec.js`,
|
||||
`./e2e/paths/13*/*[sS]pec.js`,
|
||||
`./e2e/paths/**/*[sS]pec.js`
|
||||
];
|
||||
|
||||
jasmine.loadConfig({
|
||||
spec_dir: '.',
|
||||
spec_files: specFiles,
|
||||
helpers: [],
|
||||
random: false,
|
||||
});
|
||||
|
||||
await backendStatus();
|
||||
|
||||
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
|
||||
await jasmine.execute();
|
||||
}
|
||||
|
||||
async function backendStatus() {
|
||||
log('Awaiting backend connection...');
|
||||
|
||||
const milliseconds = 1000;
|
||||
const maxAttempts = 10;
|
||||
|
||||
return new Promise(resolve => {
|
||||
let timer;
|
||||
let attempts = 1;
|
||||
timer = setInterval(async() => {
|
||||
try {
|
||||
attempts++;
|
||||
const url = `${e2eConfig.url}/api/Applications/status`;
|
||||
const {data} = await axios.get(url);
|
||||
|
||||
if (data == true) {
|
||||
clearInterval(timer);
|
||||
log('Backend connection stablished!');
|
||||
resolve(attempts);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error && attempts >= maxAttempts) {
|
||||
log('Could not connect to backend');
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
}, milliseconds);
|
||||
});
|
||||
}
|
||||
|
||||
test();
|
|
@ -19,7 +19,7 @@ describe('InvoiceIn tax path', () => {
|
|||
|
||||
it('should add a new tax', async() => {
|
||||
await page.waitToClick(selectors.invoiceInTax.addTaxButton);
|
||||
await page.autocompleteSearch(selectors.invoiceInTax.thirdExpence, '6210000567');
|
||||
await page.autocompleteSearch(selectors.invoiceInTax.thirdExpense, '6210000567');
|
||||
await page.write(selectors.invoiceInTax.thirdTaxableBase, '100');
|
||||
await page.autocompleteSearch(selectors.invoiceInTax.thirdTaxType, '6');
|
||||
await page.autocompleteSearch(selectors.invoiceInTax.thirdTransactionType, 'Operaciones exentas');
|
||||
|
@ -37,9 +37,9 @@ describe('InvoiceIn tax path', () => {
|
|||
expect(result).toEqual('Taxable base €1,323.16');
|
||||
});
|
||||
|
||||
it('should navigate back to the tax section and check the reciently added line contains the expected expense', async() => {
|
||||
it('should navigate back to tax section, check the reciently added line contains the expected expense', async() => {
|
||||
await page.accessToSection('invoiceIn.card.tax');
|
||||
const result = await page.waitToGetProperty(selectors.invoiceInTax.thirdExpence, 'value');
|
||||
const result = await page.waitToGetProperty(selectors.invoiceInTax.thirdExpense, 'value');
|
||||
|
||||
expect(result).toEqual('6210000567: Alquiler VNH');
|
||||
});
|
||||
|
|
189
gulpfile.js
189
gulpfile.js
|
@ -3,8 +3,6 @@ const gulp = require('gulp');
|
|||
const PluginError = require('plugin-error');
|
||||
const argv = require('minimist')(process.argv.slice(2));
|
||||
const log = require('fancy-log');
|
||||
const got = require('got');
|
||||
const e2eConfig = require('./e2e/helpers/config.js');
|
||||
const Docker = require('./db/docker.js');
|
||||
|
||||
// Configuration
|
||||
|
@ -67,187 +65,6 @@ back.description = `Starts backend and database service`;
|
|||
|
||||
const defaultTask = gulp.parallel(front, back);
|
||||
defaultTask.description = `Starts all application services`;
|
||||
|
||||
// Backend tests - Private method
|
||||
|
||||
async function launchBackTest(done) {
|
||||
let err;
|
||||
let dataSources = require('./loopback/server/datasources.json');
|
||||
|
||||
const container = new Docker();
|
||||
await container.run(argv.ci);
|
||||
|
||||
dataSources = JSON.parse(JSON.stringify(dataSources));
|
||||
|
||||
Object.assign(dataSources.vn, {
|
||||
host: container.dbConf.host,
|
||||
port: container.dbConf.port
|
||||
});
|
||||
|
||||
let bootOptions = {dataSources};
|
||||
|
||||
let app = require(`./loopback/server/server`);
|
||||
|
||||
try {
|
||||
app.boot(bootOptions);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const jasmine = require('gulp-jasmine');
|
||||
|
||||
const options = {
|
||||
verbose: false,
|
||||
includeStackTrace: false,
|
||||
errorOnFail: false,
|
||||
timeout: 5000,
|
||||
config: {}
|
||||
};
|
||||
|
||||
if (argv.ci) {
|
||||
const reporters = require('jasmine-reporters');
|
||||
options.reporter = new reporters.JUnitXmlReporter();
|
||||
}
|
||||
|
||||
let backSpecFiles = [
|
||||
'back/**/*.spec.js',
|
||||
'loopback/**/*.spec.js',
|
||||
'modules/*/back/**/*.spec.js'
|
||||
];
|
||||
|
||||
gulp.src(backSpecFiles)
|
||||
.pipe(jasmine(options))
|
||||
.on('end', resolve)
|
||||
.on('error', reject)
|
||||
.resume();
|
||||
});
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
await app.disconnect();
|
||||
await container.rm();
|
||||
done();
|
||||
if (err)
|
||||
throw err;
|
||||
}
|
||||
launchBackTest.description = `
|
||||
Runs the backend tests once using a random container, can receive --ci arg to save reports on a xml file`;
|
||||
|
||||
// Backend tests
|
||||
|
||||
function backTest(done) {
|
||||
const nodemon = require('gulp-nodemon');
|
||||
|
||||
nodemon({
|
||||
exec: ['node --tls-min-v1.0 ./node_modules/gulp/bin/gulp.js'],
|
||||
args: ['launchBackTest'],
|
||||
watch: backSources,
|
||||
done: done
|
||||
});
|
||||
}
|
||||
backTest.description = `Watches for changes in modules to execute backTest task`;
|
||||
|
||||
// End to end tests
|
||||
function e2eSingleRun() {
|
||||
require('@babel/register')({presets: ['@babel/env']});
|
||||
require('core-js/stable');
|
||||
require('regenerator-runtime/runtime');
|
||||
|
||||
const jasmine = require('gulp-jasmine');
|
||||
const SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
||||
|
||||
if (argv.show || argv.s)
|
||||
process.env.E2E_SHOW = true;
|
||||
|
||||
const specFiles = [
|
||||
`${__dirname}/e2e/paths/01*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/02*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/03*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/04*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/05*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/06*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/07*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/08*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/09*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/10*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/11*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/12*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/13*/*[sS]pec.js`,
|
||||
`${__dirname}/e2e/paths/**/*[sS]pec.js`
|
||||
];
|
||||
|
||||
return gulp.src(specFiles).pipe(jasmine({
|
||||
errorOnFail: false,
|
||||
timeout: 30000,
|
||||
config: {
|
||||
random: false,
|
||||
// TODO: Waiting for this option to be implemented
|
||||
// https://github.com/jasmine/jasmine/issues/1533
|
||||
stopSpecOnExpectationFailure: false
|
||||
},
|
||||
reporter: [
|
||||
new SpecReporter({
|
||||
spec: {
|
||||
displayStacktrace: 'none',
|
||||
displaySuccessful: true,
|
||||
displayFailedSpec: true,
|
||||
displaySpecDuration: true,
|
||||
},
|
||||
summary: {
|
||||
displayStacktrace: 'raw',
|
||||
displayPending: false
|
||||
},
|
||||
colors: {
|
||||
enabled: true,
|
||||
successful: 'brightGreen',
|
||||
failed: 'brightRed'
|
||||
},
|
||||
// stacktrace: {
|
||||
// filter: stacktrace => {
|
||||
// const lines = stacktrace.split('\n');
|
||||
// const filtered = [];
|
||||
// for (let i = 1; i < lines.length; i++) {
|
||||
// if (/e2e\/paths/.test(lines[i]))
|
||||
// filtered.push(lines[i]);
|
||||
// }
|
||||
// return filtered.join('\n');
|
||||
// }
|
||||
// }
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
|
||||
e2e = gulp.series(docker, async function isBackendReady() {
|
||||
const attempts = await backendStatus();
|
||||
log(`Backend ready after ${attempts} attempt(s)`);
|
||||
|
||||
return attempts;
|
||||
}, e2eSingleRun);
|
||||
e2e.description = `Restarts database and runs the e2e tests`;
|
||||
|
||||
async function backendStatus() {
|
||||
const milliseconds = 250;
|
||||
return new Promise(resolve => {
|
||||
let timer;
|
||||
let attempts = 1;
|
||||
timer = setInterval(async() => {
|
||||
try {
|
||||
const url = `${e2eConfig.url}/api/Applications/status`;
|
||||
const {body} = await got.get(url);
|
||||
|
||||
if (body == 'true') {
|
||||
clearInterval(timer);
|
||||
resolve(attempts);
|
||||
} else
|
||||
attempts++;
|
||||
} catch (error) {
|
||||
if (error || attempts > 100) // 250ms * 100 => 25s timeout
|
||||
throw new Error('Could not connect to backend');
|
||||
}
|
||||
}, milliseconds);
|
||||
});
|
||||
}
|
||||
backendStatus.description = `Performs a simple requests to check the backend status`;
|
||||
|
||||
function install() {
|
||||
const install = require('gulp-install');
|
||||
const print = require('gulp-print');
|
||||
|
@ -431,9 +248,6 @@ module.exports = {
|
|||
back,
|
||||
backOnly,
|
||||
backWatch,
|
||||
backTest,
|
||||
launchBackTest,
|
||||
e2e,
|
||||
i,
|
||||
install,
|
||||
build,
|
||||
|
@ -444,6 +258,5 @@ module.exports = {
|
|||
locales,
|
||||
localesRoutes,
|
||||
watch,
|
||||
docker,
|
||||
backendStatus,
|
||||
docker
|
||||
};
|
||||
|
|
|
@ -47,5 +47,6 @@ module.exports = {
|
|||
'^.+\\.js?$': 'babel-jest',
|
||||
'^.+\\.html$': 'html-loader-jest'
|
||||
},
|
||||
reporters: ['default', 'jest-junit']
|
||||
};
|
||||
|
||||
|
|
|
@ -12,11 +12,13 @@ describe('Client updatePortfolio', () => {
|
|||
|
||||
const expectedResult = 841.63;
|
||||
|
||||
await models.Client.rawSql(`UPDATE vn.client SET salesPersonFk = ${salesPersonId} WHERE id = ${clientId}; `);
|
||||
const clientQuery = `UPDATE vn.client SET salesPersonFk = ${salesPersonId} WHERE id = ${clientId}; `;
|
||||
await models.Client.rawSql(clientQuery);
|
||||
|
||||
await models.Client.updatePortfolio();
|
||||
|
||||
let [salesPerson] = await models.Client.rawSql(`SELECT portfolioWeight FROM bs.salesPerson WHERE workerFk = ${salesPersonId}; `, null, options);
|
||||
const portfolioQuery = `SELECT portfolioWeight FROM bs.salesPerson WHERE workerFk = ${salesPersonId}; `;
|
||||
const [salesPerson] = await models.Client.rawSql(portfolioQuery, null, options);
|
||||
|
||||
expect(salesPerson.portfolioWeight).toEqual(expectedResult);
|
||||
|
||||
|
@ -26,8 +28,9 @@ describe('Client updatePortfolio', () => {
|
|||
throw e;
|
||||
}
|
||||
});
|
||||
// task 3817
|
||||
xit('should keep the same portfolioWeight when a salesperson is unassigned of a client', async() => {
|
||||
|
||||
it('should keep the same portfolioWeight when a salesperson is unassigned of a client', async() => {
|
||||
pending('task 3817');
|
||||
const salesPersonId = 19;
|
||||
const tx = await models.Client.beginTransaction({});
|
||||
|
||||
|
@ -40,7 +43,8 @@ describe('Client updatePortfolio', () => {
|
|||
|
||||
await models.Client.updatePortfolio();
|
||||
|
||||
let [salesPerson] = await models.Client.rawSql(`SELECT portfolioWeight FROM bs.salesPerson WHERE workerFk = ${salesPersonId}; `, null, options);
|
||||
const portfolioQuery = `SELECT portfolioWeight FROM bs.salesPerson WHERE workerFk = ${salesPersonId}; `;
|
||||
const [salesPerson] = await models.Client.rawSql(portfolioQuery, null, options);
|
||||
|
||||
expect(salesPerson.portfolioWeight).toEqual(expectedResult);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ describe('loopback model address', () => {
|
|||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
beforeAll(() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
const activeCtx = {accessToken: {userId: 9}};
|
||||
|
||||
describe('entry importBuysPreview()', () => {
|
||||
const entryId = 1;
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
ng-model="invoiceInDueDay.bankFk"
|
||||
url="Banks"
|
||||
show-field="bank"
|
||||
select-fields="['id','bank']"
|
||||
order="id"
|
||||
search-function="$ctrl.bankSearchFunc($search)"
|
||||
rule>
|
||||
<tpl-item>{{id}}: {{bank}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
|
|
|
@ -17,6 +17,12 @@ class Controller extends Section {
|
|||
this.card.reload();
|
||||
});
|
||||
}
|
||||
|
||||
bankSearchFunc($search) {
|
||||
return /^\d+$/.test($search)
|
||||
? {id: $search}
|
||||
: {bank: {like: '%' + $search + '%'}};
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInDueDay', {
|
||||
|
|
|
@ -33,6 +33,13 @@
|
|||
show-field="id"
|
||||
rule>
|
||||
<tpl-item>{{id}}: {{name}}</tpl-item>
|
||||
<append>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Create expense"
|
||||
icon="add_circle"
|
||||
vn-click-stop="createExpense.show()">
|
||||
</vn-icon-button>
|
||||
</append>
|
||||
</vn-autocomplete>
|
||||
<vn-input-number vn-one
|
||||
disabled="$ctrl.invoiceIn.currency.code != 'EUR'"
|
||||
|
@ -97,3 +104,40 @@
|
|||
</vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
||||
|
||||
<!-- Dialog of create expense-->
|
||||
<vn-dialog
|
||||
vn-id="createExpense"
|
||||
on-accept="$ctrl.onResponse()">
|
||||
<tpl-body>
|
||||
<section>
|
||||
<h5 class="vn-py-sm">{{$ctrl.$t('New expense')}}</h5>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one
|
||||
vn-id="code"
|
||||
label="Code"
|
||||
ng-model="$ctrl.expense.code"
|
||||
required="true"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
<vn-check
|
||||
vn-one
|
||||
label="It's a withholding"
|
||||
ng-model="$ctrl.expense.isWithheld">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one
|
||||
vn-id="description"
|
||||
label="Description"
|
||||
ng-model="$ctrl.expense.description"
|
||||
required="true">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
</section>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||
<button response="accept" translate>Save</button>
|
||||
</tpl-buttons>
|
||||
</vn-dialog>
|
|
@ -1,7 +1,12 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
import UserError from 'core/lib/user-error';
|
||||
|
||||
class Controller extends Section {
|
||||
constructor($element, $, vnWeekDays) {
|
||||
super($element, $);
|
||||
this.expense = {};
|
||||
}
|
||||
taxRate(invoiceInTax, taxRateSelection) {
|
||||
const taxTypeSage = taxRateSelection && taxRateSelection.rate;
|
||||
const taxableBase = invoiceInTax && invoiceInTax.taxableBase;
|
||||
|
@ -26,6 +31,27 @@ class Controller extends Section {
|
|||
this.card.reload();
|
||||
});
|
||||
}
|
||||
|
||||
onResponse() {
|
||||
try {
|
||||
if (!this.expense.code)
|
||||
throw new Error(`The code can't be empty`);
|
||||
if (!this.expense.description)
|
||||
throw new UserError(`The description can't be empty`);
|
||||
|
||||
const data = [{
|
||||
id: this.expense.code,
|
||||
isWithheld: this.expense.isWithheld,
|
||||
name: this.expense.description
|
||||
}];
|
||||
|
||||
this.$http.post(`Expenses`, data) .then(() => {
|
||||
this.vnApp.showSuccess(this.$t('Expense saved!'));
|
||||
});
|
||||
} catch (e) {
|
||||
this.vnApp.showError(this.$t(e.message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInTax', {
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
import './index.js';
|
||||
import watcher from 'core/mocks/watcher';
|
||||
import crudModel from 'core/mocks/crud-model';
|
||||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
describe('InvoiceIn', () => {
|
||||
describe('Component tax', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
let vnApp;
|
||||
let $httpBackend;
|
||||
|
||||
beforeEach(ngModule('invoiceIn'));
|
||||
|
||||
beforeEach(inject(($componentController, $rootScope, _vnApp_) => {
|
||||
beforeEach(inject(($componentController, $rootScope, _vnApp_, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
vnApp = _vnApp_;
|
||||
jest.spyOn(vnApp, 'showError');
|
||||
$scope = $rootScope.$new();
|
||||
|
@ -19,6 +22,7 @@ describe('InvoiceIn', () => {
|
|||
|
||||
const $element = angular.element('<vn-invoice-in-tax></vn-invoice-in-tax>');
|
||||
controller = $componentController('vnInvoiceInTax', {$element, $scope});
|
||||
controller.$.model = crudModel;
|
||||
controller.invoiceIn = {id: 1};
|
||||
}));
|
||||
|
||||
|
@ -55,5 +59,56 @@ describe('InvoiceIn', () => {
|
|||
expect(controller.card.reload).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onResponse()', () => {
|
||||
it('should return success message', () => {
|
||||
controller.expense = {
|
||||
code: 7050000005,
|
||||
isWithheld: 0,
|
||||
description: 'Test'
|
||||
};
|
||||
|
||||
const data = [{
|
||||
id: controller.expense.code,
|
||||
isWithheld: controller.expense.isWithheld,
|
||||
name: controller.expense.description
|
||||
}];
|
||||
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
$httpBackend.expect('POST', `Expenses`, data).respond();
|
||||
|
||||
controller.onResponse();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Expense saved!');
|
||||
});
|
||||
|
||||
it('should return an error if code is empty', () => {
|
||||
controller.expense = {
|
||||
code: null,
|
||||
isWithheld: 0,
|
||||
description: 'Test'
|
||||
};
|
||||
|
||||
jest.spyOn(controller.vnApp, 'showError');
|
||||
controller.onResponse();
|
||||
|
||||
expect(controller.vnApp.showError).toHaveBeenCalledWith(`The code can't be empty`);
|
||||
});
|
||||
|
||||
it('should return an error if description is empty', () => {
|
||||
controller.expense = {
|
||||
code: 7050000005,
|
||||
isWithheld: 0,
|
||||
description: null
|
||||
};
|
||||
|
||||
jest.spyOn(controller.vnApp, 'showError');
|
||||
controller.onResponse();
|
||||
|
||||
expect(controller.vnApp.showError).toHaveBeenCalledWith(`The description can't be empty`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
Create expense: Crear gasto
|
||||
New expense: Nuevo gasto
|
||||
It's a withholding: Es una retención
|
||||
The fields can't be empty: Los campos no pueden estar vacíos
|
||||
The code can't be empty: El código no puede estar vacío
|
||||
The description can't be empty: La descripción no puede estar vacía
|
||||
Expense saved!: Gasto guardado!
|
|
@ -17,9 +17,6 @@
|
|||
},
|
||||
"isWithheld": {
|
||||
"type": "number"
|
||||
},
|
||||
"taxTypeFk": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
@ -28,13 +25,5 @@
|
|||
"model": "TaxType",
|
||||
"foreignKey": "taxTypeFk"
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
// Include after #3638 export database
|
||||
xdescribe('AgencyTerm createInvoiceIn()', () => {
|
||||
describe('AgencyTerm createInvoiceIn()', () => {
|
||||
const rows = [
|
||||
{
|
||||
routeFk: 2,
|
||||
|
@ -17,6 +16,7 @@ xdescribe('AgencyTerm createInvoiceIn()', () => {
|
|||
];
|
||||
|
||||
it('should make an invoiceIn', async() => {
|
||||
pending('Include after #3638 export database');
|
||||
const tx = await models.AgencyTerm.beginTransaction({});
|
||||
const options = {transaction: tx};
|
||||
|
||||
|
@ -32,8 +32,12 @@ xdescribe('AgencyTerm createInvoiceIn()', () => {
|
|||
await models.AgencyTerm.createInvoiceIn(rows, dms, options);
|
||||
|
||||
const [newInvoiceIn] = await models.InvoiceIn.rawSql('SELECT MAX(id) id FROM invoiceIn', null, options);
|
||||
const [newInvoiceInDueDay] = await models.InvoiceInDueDay.rawSql('SELECT MAX(id) id FROM invoiceInDueDay', null, options);
|
||||
const [newInvoiceInTax] = await models.InvoiceInTax.rawSql('SELECT MAX(id) id FROM invoiceInTax', null, options);
|
||||
|
||||
const dueDayQuery = 'SELECT MAX(id) id FROM invoiceInDueDay';
|
||||
const [newInvoiceInDueDay] = await models.InvoiceInDueDay.rawSql(dueDayQuery, null, options);
|
||||
|
||||
const taxQuery = 'SELECT MAX(id) id FROM invoiceInTax';
|
||||
const [newInvoiceInTax] = await models.InvoiceInTax.rawSql(taxQuery, null, options);
|
||||
|
||||
expect(newInvoiceIn.id).toBeGreaterThan(oldInvoiceIn.id);
|
||||
expect(newInvoiceInDueDay.id).toBeGreaterThan(oldInvoiceInDueDay.id);
|
||||
|
|
|
@ -1,9 +1,21 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('route guessPriority()', () => {
|
||||
const targetRouteId = 7;
|
||||
let routeTicketsToRestore;
|
||||
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
__: () => {}
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
let restoreFixtures = [];
|
||||
routeTicketsToRestore.forEach(ticket => {
|
||||
|
@ -12,12 +24,9 @@ describe('route guessPriority()', () => {
|
|||
await Promise.all(restoreFixtures);
|
||||
});
|
||||
|
||||
it('should call guessPriority() and then check the tickets in the target route now have their priorities defined', async() => {
|
||||
it('should call guessPriority() then check all tickets in that route have their priorities defined', async() => {
|
||||
const ctx = {
|
||||
req: {
|
||||
accessToken: {userId: 9},
|
||||
__: () => {}
|
||||
},
|
||||
req: activeCtx
|
||||
};
|
||||
routeTicketsToRestore = await app.models.Ticket.find({where: {routeFk: targetRouteId}});
|
||||
|
||||
|
|
|
@ -41,7 +41,9 @@ module.exports = Self => {
|
|||
'sageTaxTypeFk',
|
||||
'sageTransactionTypeFk',
|
||||
'sageWithholdingFk',
|
||||
'workerFk'
|
||||
'workerFk',
|
||||
'supplierActivityFk',
|
||||
'healthRegister'
|
||||
],
|
||||
include: [
|
||||
{
|
||||
|
@ -98,6 +100,12 @@ module.exports = Self => {
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'supplierActivity',
|
||||
scope: {
|
||||
fields: ['code', 'name']
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
|
|
@ -66,6 +66,8 @@ describe('Supplier updateFiscalData', () => {
|
|||
city: 'VALENCIA',
|
||||
provinceFk: 2,
|
||||
countryFk: 1,
|
||||
supplierActivityFk: 'animals',
|
||||
healthRegister: '400664487H'
|
||||
};
|
||||
|
||||
const result = await app.models.Supplier.updateFiscalData(ctx, supplierId);
|
||||
|
@ -80,6 +82,8 @@ describe('Supplier updateFiscalData', () => {
|
|||
expect(result.city).toEqual('VALENCIA');
|
||||
expect(result.provinceFk).toEqual(2);
|
||||
expect(result.countryFk).toEqual(1);
|
||||
expect(result.supplierActivityFk).toEqual('animals');
|
||||
expect(result.healthRegister).toEqual('400664487H');
|
||||
|
||||
// Restores
|
||||
ctx.args = defaultData;
|
||||
|
|
|
@ -56,6 +56,14 @@ module.exports = Self => {
|
|||
{
|
||||
arg: 'countryFk',
|
||||
type: 'any'
|
||||
},
|
||||
{
|
||||
arg: 'supplierActivityFk',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
arg: 'healthRegister',
|
||||
type: 'string'
|
||||
}],
|
||||
returns: {
|
||||
arg: 'res',
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
"SupplierAccount": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"SupplierActivity": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"SupplierAgencyTerm": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "SupplierActivity",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "supplierActivity"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"id": true
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -101,6 +101,12 @@
|
|||
},
|
||||
"isPayMethodChecked": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"supplierActivityFk": {
|
||||
"type": "string"
|
||||
},
|
||||
"healthRegister": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
@ -159,6 +165,11 @@
|
|||
"type": "hasMany",
|
||||
"model": "SupplierAddress",
|
||||
"foreignKey": "supplierFk"
|
||||
},
|
||||
"supplierActivity": {
|
||||
"type": "belongsTo",
|
||||
"model": "SupplierActivity",
|
||||
"foreignKey": "supplierActivityFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,11 @@
|
|||
data="sageWithholdings"
|
||||
order="withholding">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="SupplierActivities"
|
||||
data="supplierActivities">
|
||||
</vn-crud-model>
|
||||
<form name="form" vn-http-submit="watcher.submit()" class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal>
|
||||
|
@ -87,6 +92,22 @@
|
|||
<tpl-item>{{id}}: {{transaction}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
ng-model="$ctrl.supplier.supplierActivityFk"
|
||||
data="supplierActivities"
|
||||
show-field="name"
|
||||
value-field="code"
|
||||
label="Supplier activity"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Healt register"
|
||||
ng-model="$ctrl.supplier.healthRegister"
|
||||
rule>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
Sage tax type: Tipo de impuesto Sage
|
||||
Sage transaction type: Tipo de transacción Sage
|
||||
Sage withholding: Retención Sage
|
||||
Supplier activity: Actividad proveedor
|
||||
Healt register: Pasaporte sanitario
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
{"state": "supplier.card.basicData", "icon": "settings"},
|
||||
{"state": "supplier.card.fiscalData", "icon": "account_balance"},
|
||||
{"state": "supplier.card.billingData", "icon": "icon-payment"},
|
||||
{"state": "supplier.card.address.index", "icon": "icon-delivery"},
|
||||
{"state": "supplier.card.log", "icon": "history"},
|
||||
{"state": "supplier.card.account", "icon": "icon-account"},
|
||||
{"state": "supplier.card.contact", "icon": "contact_phone"},
|
||||
{"state": "supplier.card.agencyTerm.index", "icon": "icon-agency-term"},
|
||||
{"state": "supplier.card.log", "icon": "history"},
|
||||
{"state": "supplier.card.consumption", "icon": "show_chart"}
|
||||
{"state": "supplier.card.address.index", "icon": "icon-delivery"},
|
||||
{"state": "supplier.card.consumption", "icon": "show_chart"},
|
||||
{"state": "supplier.card.agencyTerm.index", "icon": "icon-agency-term"}
|
||||
]
|
||||
},
|
||||
"keybindings": [
|
||||
|
@ -97,7 +97,7 @@
|
|||
"url": "/index",
|
||||
"state": "supplier.card.agencyTerm.index",
|
||||
"component": "vn-supplier-agency-term-index",
|
||||
"description": "Autonomous",
|
||||
"description": "Agency Agreement",
|
||||
"params": {
|
||||
"supplier": "$ctrl.supplier"
|
||||
}
|
||||
|
|
|
@ -113,6 +113,13 @@
|
|||
label="Sage withholding"
|
||||
value="{{::$ctrl.summary.sageWithholding.withholding}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Supplier activity"
|
||||
value="{{::$ctrl.summary.supplierActivity.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Healt register"
|
||||
value="{{::$ctrl.summary.healthRegister}}">
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
|
|
@ -8,3 +8,5 @@ Sage transaction type: Tipo de transacción Sage
|
|||
Sage withholding: Retencion Sage
|
||||
Go to the supplier: Ir al proveedor
|
||||
Responsible: Responsable
|
||||
Supplier activity: Actividad proveedor
|
||||
Healt register: Pasaporte sanitario
|
|
@ -0,0 +1,41 @@
|
|||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('filter', {
|
||||
description: 'Find all instances of the model matched by filter from the data source.',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'},
|
||||
},
|
||||
],
|
||||
returns: {
|
||||
type: ['object'],
|
||||
root: true,
|
||||
},
|
||||
http: {
|
||||
path: `/filter`,
|
||||
verb: 'GET',
|
||||
},
|
||||
});
|
||||
|
||||
Self.filter = async(filter, options) => {
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const stmt = new ParameterizedSQL(
|
||||
`SELECT es.created, u.name, u.id workerFk, est.description state
|
||||
FROM vn.expeditionState es
|
||||
JOIN vn.expeditionStateType est ON est.id = es.typeFk
|
||||
JOIN account.user u ON u.id = es.userFk
|
||||
`);
|
||||
stmt.merge(Self.buildSuffix(filter, 'es'));
|
||||
|
||||
return Self.rawStmt(stmt, myOptions);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('expeditionState filter()', () => {
|
||||
it('should return the expedition states matching the filter', async() => {
|
||||
const tx = await models.ExpeditionState.beginTransaction({});
|
||||
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
|
||||
const filter = {where: {expeditionFk: 5}};
|
||||
const response = await models.ExpeditionState.filter(filter, options);
|
||||
|
||||
expect(response.length).toEqual(2);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -47,9 +47,10 @@ module.exports = Self => {
|
|||
e.packagingFk,
|
||||
es.workerFk expeditionScanWorkerFk,
|
||||
su.name scannerUserName,
|
||||
es.scanned
|
||||
FROM
|
||||
vn.expedition e
|
||||
es.scanned,
|
||||
est.description state
|
||||
FROM vn.expedition e
|
||||
LEFT JOIN vn.expeditionStateType est ON est.id = e.stateTypeFk
|
||||
LEFT JOIN vn.item i2 ON i2.id = e.itemFk
|
||||
INNER JOIN vn.item i1 ON i1.id = e.isBox
|
||||
LEFT JOIN vn.packaging p ON p.id = e.packagingFk
|
||||
|
|
|
@ -28,8 +28,9 @@ describe('ticket setDeleted()', () => {
|
|||
|
||||
expect(error.message).toEqual('You must delete the claim id %d first');
|
||||
});
|
||||
// test excluded by task #3693
|
||||
xit('should delete the ticket, remove the stowaway link and change the stowaway ticket state to "FIXING" and get rid of the itemshelving', async() => {
|
||||
|
||||
it('should delete ticket, remove stowaway and itemshelving then change stowaway state to "FIXING" ', async() => {
|
||||
pending('test excluded by task #3693');
|
||||
const tx = await models.Ticket.beginTransaction({});
|
||||
|
||||
try {
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
"Expedition": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ExpeditionState": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Packaging": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = function(Self) {
|
||||
require('../methods/expedition-state/filter')(Self);
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "ExpeditionState",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "expeditionState"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"created": {
|
||||
"type": "date"
|
||||
},
|
||||
"expeditionFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"typeFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,10 +19,9 @@
|
|||
<vn-th field="freightItemName">Package type</vn-th>
|
||||
<vn-th field="counter" number>Counter</vn-th>
|
||||
<vn-th field="externalId" number>externalId</vn-th>
|
||||
<vn-th field="workerFk">Packager</vn-th>
|
||||
<vn-th field="created" expand>Created</vn-th>
|
||||
<vn-th field="expeditionScanWorkerFk">Palletizer</vn-th>
|
||||
<vn-th field="scanned" expand>Scanned</vn-th>
|
||||
<vn-th field="state" expand>State</vn-th>
|
||||
<vn-th></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
|
@ -33,7 +32,7 @@
|
|||
vn-tooltip="Delete expedition">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
<vn-td number>{{expedition.id | zeroFill:6}}</vn-td>
|
||||
<vn-td number expand>{{expedition.id | zeroFill:6}}</vn-td>
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-class="{link: expedition.packagingItemFk}"
|
||||
|
@ -45,20 +44,15 @@
|
|||
<vn-td>{{::expedition.freightItemName}}</vn-td>
|
||||
<vn-td number>{{::expedition.counter}}</vn-td>
|
||||
<vn-td expand>{{::expedition.externalId}}</vn-td>
|
||||
<vn-td>
|
||||
<span
|
||||
class="link"
|
||||
ng-click="workerDescriptor.show($event, expedition.workerFk)">
|
||||
{{::expedition.userName | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink-datetime>{{::expedition.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
<vn-td>{{::expedition.state}}</vn-td>
|
||||
<vn-td>
|
||||
<span class="link" ng-click="workerDescriptor.show($event, expedition.expeditionScanWorkerFk)">
|
||||
{{::expedition.scannerUserName | dashIfEmpty}}
|
||||
</span>
|
||||
<vn-icon-button
|
||||
vn-click-stop="$ctrl.showLog(expedition)"
|
||||
vn-tooltip="Status log"
|
||||
icon="history">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
<vn-td shrink-datetime>{{::expedition.scanned | date:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
|
@ -78,3 +72,43 @@
|
|||
question="Delete expedition"
|
||||
message="Are you sure you want to delete this expedition?">
|
||||
</vn-confirm>
|
||||
|
||||
<vn-popup vn-id="statusLog">
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="ExpeditionStates/filter"
|
||||
link="{expeditionFk: $ctrl.expedition.id}"
|
||||
data="expeditionStates"
|
||||
order="created DESC"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-data-viewer model="model">
|
||||
<vn-card class="vn-w-md">
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="state">State</vn-th>
|
||||
<vn-th field="worker">Worker</vn-th>
|
||||
<vn-th field="created">Created</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="expeditionState in expeditionStates">
|
||||
<vn-td>{{::expeditionState.state}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
ng-class="{'link': expeditionState.workerFk}"
|
||||
ng-click="workerDescriptor.show($event, expeditionState.workerFk)">
|
||||
{{::expeditionState.name || 'System' | translate}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink-datetime>{{::expeditionState.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="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
</vn-popup>
|
|
@ -6,6 +6,11 @@ class Controller extends Section {
|
|||
return this.$http.delete(`Expeditions/${id}`)
|
||||
.then(() => this.$.model.refresh());
|
||||
}
|
||||
|
||||
showLog(expedition) {
|
||||
this.expedition = expedition;
|
||||
this.$.statusLog.show();
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnTicketExpedition', {
|
||||
|
|
|
@ -5,10 +5,12 @@ describe('Ticket', () => {
|
|||
let controller;
|
||||
let $scope;
|
||||
let $httpBackend;
|
||||
let $window;
|
||||
|
||||
beforeEach(ngModule('ticket'));
|
||||
|
||||
beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => {
|
||||
beforeEach(inject(($componentController, $rootScope, _$httpBackend_, _$window_) => {
|
||||
$window = _$window_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$scope = $rootScope.$new();
|
||||
$scope.model = {
|
||||
|
@ -30,5 +32,23 @@ describe('Ticket', () => {
|
|||
expect($scope.model.refresh).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('showLog()', () => {
|
||||
it('should show the popover status log', () => {
|
||||
controller.$.statusLog = {show: () => {}};
|
||||
jest.spyOn(controller.$.statusLog, 'show');
|
||||
|
||||
const expedition = {id: 1};
|
||||
|
||||
const event = new MouseEvent('click', {
|
||||
view: $window,
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
controller.showLog(event, expedition);
|
||||
|
||||
expect(controller.$.statusLog.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Status log: Hitorial de estados
|
|
@ -1,7 +1,6 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
// #2687 - Cannot make a data rollback because of the triggers
|
||||
xdescribe('Travel cloneWithEntries()', () => {
|
||||
describe('Travel cloneWithEntries()', () => {
|
||||
const models = app.models;
|
||||
const travelId = 5;
|
||||
const currentUserId = 1102;
|
||||
|
@ -9,44 +8,45 @@ xdescribe('Travel cloneWithEntries()', () => {
|
|||
let travelBefore;
|
||||
let newTravelId;
|
||||
|
||||
afterAll(async() => {
|
||||
try {
|
||||
const entries = await models.Entry.find({
|
||||
where: {
|
||||
travelFk: newTravelId
|
||||
}
|
||||
});
|
||||
const entriesId = entries.map(entry => entry.id);
|
||||
// afterAll(async() => {
|
||||
// try {
|
||||
// const entries = await models.Entry.find({
|
||||
// where: {
|
||||
// travelFk: newTravelId
|
||||
// }
|
||||
// });
|
||||
// const entriesId = entries.map(entry => entry.id);
|
||||
|
||||
// Destroy all entries buys
|
||||
await models.Buy.destroyAll({
|
||||
where: {
|
||||
entryFk: {inq: entriesId}
|
||||
}
|
||||
});
|
||||
// // Destroy all entries buys
|
||||
// await models.Buy.destroyAll({
|
||||
// where: {
|
||||
// entryFk: {inq: entriesId}
|
||||
// }
|
||||
// });
|
||||
|
||||
// Destroy travel entries
|
||||
await models.Entry.destroyAll({
|
||||
where: {
|
||||
travelFk: newTravelId
|
||||
}
|
||||
});
|
||||
// // Destroy travel entries
|
||||
// await models.Entry.destroyAll({
|
||||
// where: {
|
||||
// travelFk: newTravelId
|
||||
// }
|
||||
// });
|
||||
|
||||
// Destroy new travel
|
||||
await models.Travel.destroyById(newTravelId);
|
||||
// // Destroy new travel
|
||||
// await models.Travel.destroyById(newTravelId);
|
||||
|
||||
// Restore original travel shipped & landed
|
||||
const travel = await models.Travel.findById(travelId);
|
||||
await travel.updateAttributes({
|
||||
shipped: travelBefore.shipped,
|
||||
landed: travelBefore.landed
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
// // Restore original travel shipped & landed
|
||||
// const travel = await models.Travel.findById(travelId);
|
||||
// await travel.updateAttributes({
|
||||
// shipped: travelBefore.shipped,
|
||||
// landed: travelBefore.landed
|
||||
// });
|
||||
// } catch (error) {
|
||||
// console.error(error);
|
||||
// }
|
||||
// });
|
||||
|
||||
it(`should clone the travel and the containing entries`, async() => {
|
||||
pending('#2687 - Cannot make a data rollback because of the triggers');
|
||||
const warehouseThree = 3;
|
||||
const agencyModeOne = 1;
|
||||
const yesterday = new Date();
|
||||
|
|
10
package.json
10
package.json
|
@ -68,7 +68,6 @@
|
|||
"gulp-env": "^0.4.0",
|
||||
"gulp-file": "^0.4.0",
|
||||
"gulp-install": "^1.1.0",
|
||||
"gulp-jasmine": "^4.0.0",
|
||||
"gulp-merge-json": "^1.3.1",
|
||||
"gulp-nodemon": "^2.5.0",
|
||||
"gulp-print": "^2.0.1",
|
||||
|
@ -78,7 +77,7 @@
|
|||
"html-loader-jest": "^0.2.1",
|
||||
"html-webpack-plugin": "^4.0.0-beta.11",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jasmine": "^3.10.0",
|
||||
"jasmine": "^4.1.0",
|
||||
"jasmine-reporters": "^2.4.0",
|
||||
"jasmine-spec-reporter": "^7.0.0",
|
||||
"jest": "^26.0.1",
|
||||
|
@ -88,7 +87,7 @@
|
|||
"minimist": "^1.2.5",
|
||||
"mysql2": "^1.7.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"nodemon": "^1.19.4",
|
||||
"nodemon": "^2.0.16",
|
||||
"plugin-error": "^1.0.1",
|
||||
"raw-loader": "^1.0.0",
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
|
@ -102,7 +101,10 @@
|
|||
},
|
||||
"scripts": {
|
||||
"dbtest": "nodemon -q db/tests.js -w db/tests",
|
||||
"test": "jest --watch",
|
||||
"test:back": "nodemon -q back/tests.js --config back/nodemonConfig.json",
|
||||
"test:back:ci": "node back/tests.js ci",
|
||||
"test:e2e": "node e2e/helpers/tests.js",
|
||||
"test:front": "jest --watch",
|
||||
"back": "nodemon --inspect -w modules ./node_modules/gulp/bin/gulp.js back",
|
||||
"lint": "eslint ./ --cache --ignore-pattern .gitignore",
|
||||
"docker": "docker build --progress=plain -t salix-db ./db"
|
||||
|
|
Loading…
Reference in New Issue