diff --git a/Jenkinsfile b/Jenkinsfile
index 03ac84de3f..4a1f9ba546 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -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') {
diff --git a/README.md b/README.md
index 1e3ad5e9e7..f73a8551be 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/back/methods/account/specs/change-password.spec.js b/back/methods/account/specs/change-password.spec.js
index 9f1130df52..17fadb3c69 100644
--- a/back/methods/account/specs/change-password.spec.js
+++ b/back/methods/account/specs/change-password.spec.js
@@ -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');
});
});
diff --git a/back/methods/collection/spec/newCollection.spec.js b/back/methods/collection/spec/newCollection.spec.js
index 88d105b4b8..6abe73f8ea 100644
--- a/back/methods/collection/spec/newCollection.spec.js
+++ b/back/methods/collection/spec/newCollection.spec.js
@@ -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);
diff --git a/back/methods/dms/deleteTrashFiles.js b/back/methods/dms/deleteTrashFiles.js
new file mode 100644
index 0000000000..9d16e9d81e
--- /dev/null
+++ b/back/methods/dms/deleteTrashFiles.js
@@ -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;
+ }
+ };
+};
diff --git a/back/models/dms.js b/back/models/dms.js
index 91291a0c2a..24c072f565 100644
--- a/back/models/dms.js
+++ b/back/models/dms.js
@@ -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;
diff --git a/back/nodemonConfig.json b/back/nodemonConfig.json
new file mode 100644
index 0000000000..a1c9ca84fc
--- /dev/null
+++ b/back/nodemonConfig.json
@@ -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/**/*"
+ ]
+}
\ No newline at end of file
diff --git a/back/tests.js b/back/tests.js
index c715c96bf3..8099061771 100644
--- a/back/tests.js
+++ b/back/tests.js
@@ -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));
-jasmine.loadConfig({
- spec_dir: '.',
- spec_files: serviceSpecs,
- helpers: []
-});
+ Object.assign(dataSources.vn, {
+ host: container.dbConf.host,
+ port: container.dbConf.port
+ });
-jasmine.addReporter(new SpecReporter({
- spec: {
- // displayStacktrace: 'summary',
- displaySuccessful: verbose,
- displayFailedSpec: true,
- displaySpecDuration: true
+ 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;
}
-}));
-jasmine.execute();
+ const backSpecs = [
+ './back/**/*[sS]pec.js',
+ './loopback/**/*[sS]pec.js',
+ './modules/*/back/**/*.[sS]pec.js'
+ ];
+
+ jasmine.loadConfig({
+ spec_dir: '.',
+ spec_files: backSpecs,
+ helpers: [],
+ });
+
+ jasmine.exitOnCompletion = false;
+ await jasmine.execute();
+ if (app) await app.disconnect();
+ if (container) await container.rm();
+ console.log('app disconnected & container removed');
+}
+
+test();
diff --git a/db/changes/10451-april/00-aclExpeditionState.sql b/db/changes/10451-april/00-aclExpeditionState.sql
new file mode 100644
index 0000000000..d26117bbff
--- /dev/null
+++ b/db/changes/10451-april/00-aclExpeditionState.sql
@@ -0,0 +1,2 @@
+INSERT INTO `salix`.`ACL`(`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+VALUES('ExpeditionState', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
\ No newline at end of file
diff --git a/db/changes/10451-april/00-aclExpense.sql b/db/changes/10451-april/00-aclExpense.sql
new file mode 100644
index 0000000000..55ca8c3895
--- /dev/null
+++ b/db/changes/10451-april/00-aclExpense.sql
@@ -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');
diff --git a/db/changes/10451-april/00-aclSupplierActivity.sql b/db/changes/10451-april/00-aclSupplierActivity.sql
new file mode 100644
index 0000000000..bf73a15068
--- /dev/null
+++ b/db/changes/10451-april/00-aclSupplierActivity.sql
@@ -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');
diff --git a/db/changes/10460-mother/00-dmsForeignKey.sql b/db/changes/10460-mother/00-dmsForeignKey.sql
new file mode 100644
index 0000000000..f44391a17c
--- /dev/null
+++ b/db/changes/10460-mother/00-dmsForeignKey.sql
@@ -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;
diff --git a/db/changes/10460-mother/01-dmsType.sql b/db/changes/10460-mother/01-dmsType.sql
new file mode 100644
index 0000000000..e82c086cfe
--- /dev/null
+++ b/db/changes/10460-mother/01-dmsType.sql
@@ -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;
diff --git a/db/changes/10460-mother/02-dmsTrigger.sql b/db/changes/10460-mother/02-dmsTrigger.sql
new file mode 100644
index 0000000000..a92efcfab0
--- /dev/null
+++ b/db/changes/10460-mother/02-dmsTrigger.sql
@@ -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 ;
diff --git a/db/changes/10460-mother/03-clean.sql b/db/changes/10460-mother/03-clean.sql
new file mode 100644
index 0000000000..13951394fd
--- /dev/null
+++ b/db/changes/10460-mother/03-clean.sql
@@ -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 ;
diff --git a/db/changes/10460-mother/04-acl.sql b/db/changes/10460-mother/04-acl.sql
new file mode 100644
index 0000000000..c576bf1b0a
--- /dev/null
+++ b/db/changes/10460-mother/04-acl.sql
@@ -0,0 +1,2 @@
+INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
+ VALUES ('Dms','deleteTrashFiles','WRITE','ALLOW','ROLE','employee')
\ No newline at end of file
diff --git a/db/changes/10460-mothersDay/delete.keep b/db/changes/10460-mothersDay/delete.keep
deleted file mode 100644
index 0e7498f402..0000000000
--- a/db/changes/10460-mothersDay/delete.keep
+++ /dev/null
@@ -1 +0,0 @@
-Delete file
\ No newline at end of file
diff --git a/db/docker.js b/db/docker.js
index ea9fe8ed16..34026f85fe 100644
--- a/db/docker.js
+++ b/db/docker.js
@@ -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();
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 20de8844b5..c329e4c6e7 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -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
diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index 2ecb739609..29176489ce 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -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"]',
diff --git a/e2e/helpers/tests.js b/e2e/helpers/tests.js
new file mode 100644
index 0000000000..aac9963dd5
--- /dev/null
+++ b/e2e/helpers/tests.js
@@ -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();
diff --git a/e2e/paths/09-invoice-in/04_tax.spec.js b/e2e/paths/09-invoice-in/04_tax.spec.js
index 364a25d7e4..b1dbe20088 100644
--- a/e2e/paths/09-invoice-in/04_tax.spec.js
+++ b/e2e/paths/09-invoice-in/04_tax.spec.js
@@ -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');
});
diff --git a/gulpfile.js b/gulpfile.js
index 102a8a0bf3..d7e7d8e869 100644
--- a/gulpfile.js
+++ b/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
};
diff --git a/jest.front.config.js b/jest.front.config.js
index dbea13950e..a03c61d114 100644
--- a/jest.front.config.js
+++ b/jest.front.config.js
@@ -47,5 +47,6 @@ module.exports = {
'^.+\\.js?$': 'babel-jest',
'^.+\\.html$': 'html-loader-jest'
},
+ reporters: ['default', 'jest-junit']
};
diff --git a/modules/client/back/methods/client/specs/updatePortfolio.spec.js b/modules/client/back/methods/client/specs/updatePortfolio.spec.js
index 4830156fc4..f56555c08c 100644
--- a/modules/client/back/methods/client/specs/updatePortfolio.spec.js
+++ b/modules/client/back/methods/client/specs/updatePortfolio.spec.js
@@ -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);
diff --git a/modules/client/back/models/specs/address.spec.js b/modules/client/back/models/specs/address.spec.js
index 81af6ee283..f0b421d351 100644
--- a/modules/client/back/models/specs/address.spec.js
+++ b/modules/client/back/models/specs/address.spec.js
@@ -14,7 +14,7 @@ describe('loopback model address', () => {
}
};
- beforeEach(() => {
+ beforeAll(() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
diff --git a/modules/entry/back/methods/entry/specs/importBuysPreview.spec.js b/modules/entry/back/methods/entry/specs/importBuysPreview.spec.js
index edfdac9884..41971a64c0 100644
--- a/modules/entry/back/methods/entry/specs/importBuysPreview.spec.js
+++ b/modules/entry/back/methods/entry/specs/importBuysPreview.spec.js
@@ -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;
diff --git a/modules/invoiceIn/front/dueDay/index.html b/modules/invoiceIn/front/dueDay/index.html
index 579ef36098..1a1935e728 100644
--- a/modules/invoiceIn/front/dueDay/index.html
+++ b/modules/invoiceIn/front/dueDay/index.html
@@ -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>
{{id}}: {{bank}}
diff --git a/modules/invoiceIn/front/dueDay/index.js b/modules/invoiceIn/front/dueDay/index.js
index 22b697f7e2..3cc1c81e8a 100644
--- a/modules/invoiceIn/front/dueDay/index.js
+++ b/modules/invoiceIn/front/dueDay/index.js
@@ -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', {
diff --git a/modules/invoiceIn/front/tax/index.html b/modules/invoiceIn/front/tax/index.html
index c495d44d2f..acc9cf4924 100644
--- a/modules/invoiceIn/front/tax/index.html
+++ b/modules/invoiceIn/front/tax/index.html
@@ -33,6 +33,13 @@
show-field="id"
rule>
{{id}}: {{name}}
+
+
+
+
-
\ No newline at end of file
+
+
+
+
+
+
+ {{$ctrl.$t('New expense')}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/invoiceIn/front/tax/index.js b/modules/invoiceIn/front/tax/index.js
index 53cfc55980..d05a77f29f 100644
--- a/modules/invoiceIn/front/tax/index.js
+++ b/modules/invoiceIn/front/tax/index.js
@@ -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', {
diff --git a/modules/invoiceIn/front/tax/index.spec.js b/modules/invoiceIn/front/tax/index.spec.js
index 20d5d40d86..c62ada9ca8 100644
--- a/modules/invoiceIn/front/tax/index.spec.js
+++ b/modules/invoiceIn/front/tax/index.spec.js
@@ -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('');
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`);
+ });
+ });
});
});
+
diff --git a/modules/invoiceIn/front/tax/locale/es.yml b/modules/invoiceIn/front/tax/locale/es.yml
new file mode 100644
index 0000000000..3ff68ea402
--- /dev/null
+++ b/modules/invoiceIn/front/tax/locale/es.yml
@@ -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!
\ No newline at end of file
diff --git a/modules/item/back/models/expense.json b/modules/item/back/models/expense.json
index b349e9dcf4..368876fbed 100644
--- a/modules/item/back/models/expense.json
+++ b/modules/item/back/models/expense.json
@@ -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"
- }
- ]
+ }
}
\ No newline at end of file
diff --git a/modules/route/back/methods/agency-term/specs/createInvoiceIn.spec.js b/modules/route/back/methods/agency-term/specs/createInvoiceIn.spec.js
index 81686144d1..ad4613caf6 100644
--- a/modules/route/back/methods/agency-term/specs/createInvoiceIn.spec.js
+++ b/modules/route/back/methods/agency-term/specs/createInvoiceIn.spec.js
@@ -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);
diff --git a/modules/route/back/methods/route/specs/guessPriority.spec.js b/modules/route/back/methods/route/specs/guessPriority.spec.js
index 892324acfb..902647ba1f 100644
--- a/modules/route/back/methods/route/specs/guessPriority.spec.js
+++ b/modules/route/back/methods/route/specs/guessPriority.spec.js
@@ -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}});
diff --git a/modules/supplier/back/methods/supplier/getSummary.js b/modules/supplier/back/methods/supplier/getSummary.js
index c29a2a058e..bf3fa56f58 100644
--- a/modules/supplier/back/methods/supplier/getSummary.js
+++ b/modules/supplier/back/methods/supplier/getSummary.js
@@ -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']
+ }
+ }
]
};
diff --git a/modules/supplier/back/methods/supplier/specs/updateFiscalData.spec.js b/modules/supplier/back/methods/supplier/specs/updateFiscalData.spec.js
index 0eec549263..a47e547d19 100644
--- a/modules/supplier/back/methods/supplier/specs/updateFiscalData.spec.js
+++ b/modules/supplier/back/methods/supplier/specs/updateFiscalData.spec.js
@@ -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;
diff --git a/modules/supplier/back/methods/supplier/updateFiscalData.js b/modules/supplier/back/methods/supplier/updateFiscalData.js
index daa602af05..4604b3f910 100644
--- a/modules/supplier/back/methods/supplier/updateFiscalData.js
+++ b/modules/supplier/back/methods/supplier/updateFiscalData.js
@@ -56,6 +56,14 @@ module.exports = Self => {
{
arg: 'countryFk',
type: 'any'
+ },
+ {
+ arg: 'supplierActivityFk',
+ type: 'string'
+ },
+ {
+ arg: 'healthRegister',
+ type: 'string'
}],
returns: {
arg: 'res',
diff --git a/modules/supplier/back/model-config.json b/modules/supplier/back/model-config.json
index 7c1bba1ec6..dbc387ed20 100644
--- a/modules/supplier/back/model-config.json
+++ b/modules/supplier/back/model-config.json
@@ -11,6 +11,9 @@
"SupplierAccount": {
"dataSource": "vn"
},
+ "SupplierActivity": {
+ "dataSource": "vn"
+ },
"SupplierAgencyTerm": {
"dataSource": "vn"
},
diff --git a/modules/supplier/back/models/supplier-activity.json b/modules/supplier/back/models/supplier-activity.json
new file mode 100644
index 0000000000..7a0b9a5379
--- /dev/null
+++ b/modules/supplier/back/models/supplier-activity.json
@@ -0,0 +1,18 @@
+{
+ "name": "SupplierActivity",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "supplierActivity"
+ }
+ },
+ "properties": {
+ "code": {
+ "type": "string",
+ "id": true
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/supplier/back/models/supplier.json b/modules/supplier/back/models/supplier.json
index 8b4b8f26f0..b27073ca5c 100644
--- a/modules/supplier/back/models/supplier.json
+++ b/modules/supplier/back/models/supplier.json
@@ -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"
}
}
}
\ No newline at end of file
diff --git a/modules/supplier/front/fiscal-data/index.html b/modules/supplier/front/fiscal-data/index.html
index 4f34528f2d..77a5cce4ea 100644
--- a/modules/supplier/front/fiscal-data/index.html
+++ b/modules/supplier/front/fiscal-data/index.html
@@ -30,6 +30,11 @@
data="sageWithholdings"
order="withholding">
+
+