diff --git a/.eslintrc.yml b/.eslintrc.yml index 247319137..163ff22a7 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -31,3 +31,4 @@ rules: curly: [error, multi-or-nest] indent: [error, 4] arrow-parens: [error, as-needed] + jasmine/no-focused-tests: 0 diff --git a/back/methods/dms/download.js b/back/methods/dms/download.js new file mode 100644 index 000000000..9211cc8f8 --- /dev/null +++ b/back/methods/dms/download.js @@ -0,0 +1,76 @@ +const UserError = require('vn-loopback/util/user-error'); +const fs = require('fs-extra'); + +module.exports = Self => { + Self.remoteMethodCtx('download', { + description: 'Download a document', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'String', + description: 'The document id', + http: {source: 'path'} + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: `/:id/download`, + verb: 'GET' + } + }); + + Self.download = async function(ctx, id) { + const userId = ctx.req.accessToken.userId; + const env = process.env.NODE_ENV; + const document = await Self.findById(id, { + include: { + relation: 'dmsType', + scope: { + fields: ['path', 'readRoleFk'], + include: { + relation: 'readRole' + } + } + } + }); + const readRole = document.dmsType().readRole().name; + const hasRequiredRole = await Self.app.models.Account.hasRole(userId, readRole); + + if (!hasRequiredRole) + throw new UserError(`You don't have enough privileges`); + + if (env && env != 'development') { + const path = `/${document.companyFk}/${document.dmsType().path}/${document.file}`; + file = { + path: `/var/lib/salix/dms/${path}`, + contentType: 'application/octet-stream', + name: document.file + }; + } else { + file = { + path: `${process.cwd()}/README.md`, + contentType: 'text/plain', + name: `README.md` + }; + } + + await fs.access(file.path); + let stream = fs.createReadStream(file.path); + return [stream, file.contentType, `filename="${file.name}"`]; + }; +}; diff --git a/back/methods/dms/specs/download.spec.js b/back/methods/dms/specs/download.spec.js new file mode 100644 index 000000000..085662662 --- /dev/null +++ b/back/methods/dms/specs/download.spec.js @@ -0,0 +1,30 @@ +const app = require('vn-loopback/server/server'); + +/** + * Pendiente de fixtures dms, dmsType, ticketDms + * CAU: 10728 + */ +xdescribe('dms download()', () => { + let dmsId = 1; + it('should return a response for an employee with text content-type', async() => { + let workerFk = 107; + let ctx = {req: {accessToken: {userId: workerFk}}}; + const result = await app.models.Dms.download(ctx, dmsId); + + expect(result[1]).toEqual('text/plain'); + }); + + it(`should return an error for a user without enough privileges`, async() => { + let clientId = 101; + let ctx = {req: {accessToken: {userId: clientId}}}; + + let error; + await app.models.Dms.download(ctx, dmsId).catch(e => { + error = e; + }).finally(() => { + expect(error.message).toEqual(`You don't have enough privileges`); + }); + + expect(error).toBeDefined(); + }); +}); diff --git a/back/model-config.json b/back/model-config.json index d471f3230..dc67a5422 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -37,6 +37,12 @@ }, "EmailUser": { "dataSource": "vn" + }, + "Dms": { + "dataSource": "vn" + }, + "DmsType": { + "dataSource": "vn" } } diff --git a/back/models/dms.js b/back/models/dms.js new file mode 100644 index 000000000..97a405eef --- /dev/null +++ b/back/models/dms.js @@ -0,0 +1,3 @@ +module.exports = Self => { + require('../methods/dms/download')(Self); +}; diff --git a/back/models/dms.json b/back/models/dms.json new file mode 100644 index 000000000..d5ec4b8b7 --- /dev/null +++ b/back/models/dms.json @@ -0,0 +1,51 @@ +{ + "name": "Dms", + "description": "Documental Managment system", + "base": "VnModel", + "options": { + "mysql": { + "table": "dms" + } + }, + "properties": { + "id": { + "type": "Number", + "id": true, + "description": "Identifier" + }, + "file": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "description": { + "type": "string" + }, + "created": { + "type": "Date" + } + }, + "relations": { + "dmsType": { + "type": "belongsTo", + "model": "DmsType", + "foreignKey": "dmsTypeFk" + }, + "worker": { + "type": "belongsTo", + "model": "Worker", + "foreignKey": "workerFk" + }, + "warehouse": { + "type": "belongsTo", + "model": "Warehouse", + "foreignKey": "warehouseFk" + }, + "company": { + "type": "belongsTo", + "model": "Company", + "foreignKey": "companyFk" + } + } +} \ No newline at end of file diff --git a/back/models/dmsType.json b/back/models/dmsType.json new file mode 100644 index 000000000..9efc92cf5 --- /dev/null +++ b/back/models/dmsType.json @@ -0,0 +1,43 @@ +{ + "name": "DmsType", + "description": "Documental Managment system types", + "base": "VnModel", + "options": { + "mysql": { + "table": "dmsType" + } + }, + "properties": { + "id": { + "type": "Number", + "id": true, + "description": "Identifier" + }, + "name": { + "type": "string", + "required": true + }, + "path": { + "type": "string", + "required": true + } + }, + "relations": { + "readRole": { + "type": "belongsTo", + "model": "Role", + "foreignKey": "readRoleFk" + }, + "writeRole": { + "type": "belongsTo", + "model": "Role", + "foreignKey": "writeRoleFk" + } + }, + "acls": [{ + "accessType": "READ", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + }] +} \ No newline at end of file diff --git a/db/changes/10003-easter/00-ACL.sql b/db/changes/10003-easter/00-ACL.sql new file mode 100644 index 000000000..8dd09ff32 --- /dev/null +++ b/db/changes/10003-easter/00-ACL.sql @@ -0,0 +1,5 @@ +INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (162, 'InvoiceOut', 'delete', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'); +INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (163, 'InvoiceOut', 'book', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'); +INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (164, 'InvoiceOut', 'regenerate', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'); +INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (165, 'TicketDms', '*', 'READ', 'ALLOW', 'ROLE', 'employee'); +INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (166, 'Dms', 'download', 'READ', 'ALLOW', 'ROLE', 'employee'); diff --git a/db/changes/10003-easter/00-dmsView.sql b/db/changes/10003-easter/00-dmsView.sql new file mode 100644 index 000000000..88d32f93c --- /dev/null +++ b/db/changes/10003-easter/00-dmsView.sql @@ -0,0 +1,20 @@ +USE `vn`; +CREATE + OR REPLACE ALGORITHM = UNDEFINED + DEFINER = `root`@`%` + SQL SECURITY DEFINER +VIEW `vn`.`dms` AS + SELECT + `g`.`id` AS `id`, + `g`.`gesttip_id` AS `dmsTypeFk`, + `g`.`file` AS `file`, + `g`.`trabajador_id` AS `workerFk`, + `g`.`warehouse_id` AS `warehouseFk`, + `g`.`emp_id` AS `companyFk`, + `g`.`orden` AS `priority`, + `g`.`file` AS `hasFile`, + `g`.`sref` AS `reference`, + `g`.`brief` AS `description`, + `g`.`odbc_date` AS `created` + FROM + `vn2008`.`gestdoc` `g` \ No newline at end of file diff --git a/db/changes/10003-easter/00-nodeAdd.sql b/db/changes/10003-easter/00-nodeAdd.sql new file mode 100644 index 000000000..80c716b45 --- /dev/null +++ b/db/changes/10003-easter/00-nodeAdd.sql @@ -0,0 +1,71 @@ +DROP procedure IF EXISTS `nst`.`nodeAdd`; + +DELIMITER $$ +CREATE DEFINER=`root`@`%` PROCEDURE `nst`.`nodeAdd`(IN `vScheme` VARCHAR(45), IN `vTable` VARCHAR(45), IN `vParentFk` INT, IN `vChild` VARCHAR(100)) +BEGIN + DECLARE vSql TEXT; + DECLARE vTableClone VARCHAR(45); + + SET vTableClone = CONCAT(vTable, 'Clone'); + + CALL util.exec(CONCAT('DROP TEMPORARY TABLE IF EXISTS tmp.', vTableClone)); + CALL util.exec(CONCAT( + 'CREATE TEMPORARY TABLE tmp.', vTableClone, + ' ENGINE = MEMORY', + ' SELECT * FROM ', vScheme, '.', vTable + )); + + CALL util.exec(CONCAT( + 'SELECT COUNT(c.id) INTO @childs', + ' FROM ', vScheme, '.', vTable, ' p', + ' LEFT JOIN tmp.', vTableClone, ' c ON c.lft', + ' BETWEEN p.lft AND p.rgt AND c.id != ', vParentFk, + ' WHERE p.id = ', vParentFk + )); + + IF @childs = 0 THEN + CALL util.exec(CONCAT( + 'SELECT lft INTO @vLeft', + ' FROM ', vScheme, '.', vTable, + ' WHERE id = ', vParentFk + )); + ELSE + CALL util.exec(CONCAT( + 'SELECT c.rgt INTO @vLeft', + ' FROM ', vScheme, '.', vTable, ' p', + ' JOIN tmp.', vTableClone, ' c ON c.lft BETWEEN p.lft AND p.rgt', + ' WHERE p.id = ', vParentFk, + ' ORDER BY c.lft', + ' DESC LIMIT 1' + )); + END IF; + + CALL util.exec(CONCAT( + 'UPDATE ', vScheme, '.', vTable, ' SET rgt = rgt + 2', + ' WHERE rgt > @vLeft', + ' ORDER BY rgt DESC' + )); + CALL util.exec(CONCAT( + 'UPDATE ', vScheme, '.', vTable, ' SET lft = lft + 2', + ' WHERE lft > @vLeft', + ' ORDER BY lft DESC' + )); + + SET vChild = REPLACE(vChild, "'", "\\'"); + + CALL util.exec(CONCAT( + 'INSERT INTO ', vScheme, '.', vTable, ' (name, lft, rgt)', + ' VALUES ("', vChild, '", @vLeft + 1, @vLeft + 2)' + )); + + CALL util.exec(CONCAT( + 'SELECT id, name, lft, rgt, depth, sons', + ' FROM ', vScheme, '.', vTable, + ' WHERE id = LAST_INSERT_ID()' + )); + + CALL util.exec(CONCAT('DROP TEMPORARY TABLE tmp.', vTableClone)); +END$$ + +DELIMITER ; + diff --git a/db/changes/10003-easter/00-nodeDelete.sql b/db/changes/10003-easter/00-nodeDelete.sql new file mode 100644 index 000000000..906428c88 --- /dev/null +++ b/db/changes/10003-easter/00-nodeDelete.sql @@ -0,0 +1,34 @@ +DROP procedure IF EXISTS `nst`.`nodeDelete`; + +DELIMITER $$ +CREATE DEFINER=`root`@`%` PROCEDURE `nst`.`nodeDelete`(IN `vScheme` VARCHAR(45), IN `vTable` VARCHAR(45), IN `vNodeId` INT) +BEGIN + DECLARE vMyRight INT; + DECLARE vMyLeft INT; + DECLARE vMyWidth INT; + + CALL util.exec(CONCAT( + 'SELECT t.rgt, t.lft, t.rgt - t.lft + 1', + ' INTO @vMyRight, @vMyLeft, @vMyWidth', + ' FROM ', vScheme, '.', vTable, ' t', + ' WHERE t.id = ', vNodeId + )); + + CALL util.exec(CONCAT( + 'DELETE FROM ', vScheme, '.', vTable, + ' WHERE lft BETWEEN @vMyLeft AND @vMyRight' + )); + + CALL util.exec(CONCAT( + 'UPDATE ', vScheme, '.', vTable, ' SET rgt = rgt - @vMyWidth' + ' WHERE rgt > @vMyRight ORDER BY rgt' + )); + + CALL util.exec(CONCAT( + 'UPDATE ', vScheme, '.', vTable, ' SET lft = lft - @vMyWidth' + ' WHERE lft > @vMyRight ORDER BY lft' + )); +END$$ + +DELIMITER ; + diff --git a/db/changes/10003-easter/00-nodeRecalc.sql b/db/changes/10003-easter/00-nodeRecalc.sql new file mode 100644 index 000000000..ff103bda7 --- /dev/null +++ b/db/changes/10003-easter/00-nodeRecalc.sql @@ -0,0 +1,23 @@ +DROP procedure IF EXISTS `nst`.`nodeRecalc`; + +DELIMITER $$ +CREATE DEFINER=`root`@`%` PROCEDURE `nst`.`nodeRecalc`(IN `vScheme` VARCHAR(45), IN `vTable` VARCHAR(45)) +BEGIN + CALL util.exec(CONCAT ( + 'UPDATE ', vScheme, '.', vTable, ' d', + ' JOIN (SELECT', + ' node.id,', + ' COUNT(parent.id) - 1 as depth,', + ' cast((node.rgt - node.lft - 1) / 2 as DECIMAL) as sons', + ' FROM ', + ' ', vScheme, '.', vTable, ' AS node,', + ' ', vScheme, '.', vTable, ' AS parent', + ' WHERE node.lft BETWEEN parent.lft AND parent.rgt', + ' GROUP BY node.id', + ' ORDER BY node.lft) n ON n.id = d.id ', + ' SET d.`depth` = n.depth, d.sons = n.sons' + )); +END$$ + +DELIMITER ; + diff --git a/db/changes/10003-easter/01-dmsTicketRename.sql b/db/changes/10003-easter/01-dmsTicketRename.sql new file mode 100644 index 000000000..60318dfdb --- /dev/null +++ b/db/changes/10003-easter/01-dmsTicketRename.sql @@ -0,0 +1,12 @@ +DROP VIEW IF EXISTS `vn`.`dmsTicket` ; +USE `vn`; +CREATE + OR REPLACE ALGORITHM = UNDEFINED + DEFINER = `root`@`%` + SQL SECURITY DEFINER +VIEW `vn`.`ticketDms` AS + SELECT + `g`.`Id_Ticket` AS `ticketFk`, + `g`.`gestdoc_id` AS `dmsFk` + FROM + `vn2008`.`tickets_gestdoc` `g`; diff --git a/db/changes/10003-easter/02-dmsTypeAddRoleFields.sql b/db/changes/10003-easter/02-dmsTypeAddRoleFields.sql new file mode 100644 index 000000000..3898fb813 --- /dev/null +++ b/db/changes/10003-easter/02-dmsTypeAddRoleFields.sql @@ -0,0 +1,7 @@ +ALTER TABLE `vn2008`.`gesttip` +ADD COLUMN `writeRoleFk` INT(10) UNSIGNED NULL AFTER `path`, +ADD COLUMN `readRoleFk` INT(10) UNSIGNED NULL AFTER `writeRoleFk`, +ADD CONSTRAINT `readRoleFk` FOREIGN KEY (`readRoleFk`) REFERENCES `account`.`role` (`id`), +ADD CONSTRAINT `writeRoleFk` FOREIGN KEY (`writeRoleFk`) REFERENCES `account`.`role` (`id`); + +UPDATE `vn2008`.`gesttip` SET `readRoleFk`='1' WHERE `id`='14'; diff --git a/db/changes/10003-easter/03-dmsType.sql b/db/changes/10003-easter/03-dmsType.sql new file mode 100644 index 000000000..6f38571e6 --- /dev/null +++ b/db/changes/10003-easter/03-dmsType.sql @@ -0,0 +1,13 @@ +CREATE + OR REPLACE ALGORITHM = UNDEFINED + DEFINER = `root`@`%` + SQL SECURITY DEFINER +VIEW `vn`.`dmsType` AS + SELECT + `g`.`id` AS `id`, + `g`.`tipo` AS `name`, + `g`.`path` AS `path`, + `g`.`readRoleFk` AS `readRoleFk`, + `g`.`writeRoleFk` AS `writeRoleFk` + FROM + `vn2008`.`gesttip` `g`; diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index ccc722c44..2aa7bc22e 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -388,11 +388,11 @@ INSERT INTO `vn`.`company`(`id`, `code`, `supplierAccountFk`, `workerManagerFk`, INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `pdf`) VALUES - ( 1, 'T', 500 , DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 101, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), - ( 2, 'T', 350.50 , DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 102, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), - ( 3, 'T', 90.30 , CURDATE(), 103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), - ( 4, 'T', 290.30 , DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), - ( 5, 'A', 190.30 , DATE_ADD(CURDATE(), INTERVAL +2 MONTH), 103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1); + ( 1, 'T', 156.09, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 101, CURDATE(), 442, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), CURDATE(), 1, 1), + ( 2, 'T', 208.35, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 102, CURDATE(), 442, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), CURDATE(), 1, 1), + ( 3, 'T', 20.02, CURDATE(), 103, CURDATE(), 442, CURDATE(), null, 1, 1), + ( 4, 'T', 20.02, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 103, CURDATE(), 442, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), null, 1, 1), + ( 5, 'A', 20.22, DATE_ADD(CURDATE(), INTERVAL +2 MONTH), 103, CURDATE(), 442, DATE_ADD(CURDATE(), INTERVAL +2 MONTH), null, 1, 1); UPDATE `vn`.`invoiceOut` SET ref = 'T1111111' WHERE id = 1; UPDATE `vn`.`invoiceOut` SET ref = 'T2222222' WHERE id = 2; @@ -413,30 +413,43 @@ INSERT INTO `vn`.`invoiceOutTax` (`invoiceOutFk`, `taxableBase`, `vat`, `pgcFk`) (5, 100, 10, 4722000010), (5, 200, 21, 4722000021); +INSERT INTO `vn`.`taxArea` (`code`, `claveOperacionFactura`, `CodigoTransaccion`) + VALUES + ('CEE', 1, 10), + ('EQU', 0, 1), + ('NATIONAL', 0, 1), + ('WORLD', 2, 15); + +INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaFk`, `isCEE`) + VALUES + ('A', 'Global nacional', 1, 'NATIONAL', 0), + ('T', 'Española rapida', 1, 'NATIONAL', 0), + ('V', 'Intracomunitaria global', 0, 'CEE', 1); + INSERT INTO `vn`.`ticket`(`id`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `created`) VALUES - (1 , 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY) , DATE_ADD(CURDATE(), INTERVAL -15 DAY) , 101, 'address 21', 121, 'T1111111', 0, DATE_ADD(CURDATE(), INTERVAL -15 DAY) ), - (2 , 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -10 DAY) , DATE_ADD(CURDATE(), INTERVAL -10 DAY) , 101, 'address 21', 121, 'T2222222', 0, DATE_ADD(CURDATE(), INTERVAL -10 DAY) ), - (3 , 2, 2, 2, DATE_ADD(CURDATE(), INTERVAL -5 DAY) , DATE_ADD(CURDATE(), INTERVAL -5 DAY) , 102, 'address 22', 122, 'T2222222', 0, DATE_ADD(CURDATE(), INTERVAL -5 DAY) ), - (4 , 2, 2, 2, DATE_ADD(CURDATE(), INTERVAL -4 DAY) , DATE_ADD(CURDATE(), INTERVAL -4 DAY) , 102, 'address 22', 122, 'T3333333', 0, DATE_ADD(CURDATE(), INTERVAL -4 DAY) ), - (5 , 3, 3, 3, DATE_ADD(CURDATE(), INTERVAL -3 DAY) , DATE_ADD(CURDATE(), INTERVAL -3 DAY) , 103, 'address 23', 123, 'T3333333', 0, DATE_ADD(CURDATE(), INTERVAL -3 DAY) ), - (6 , 3, 3, 4, DATE_ADD(CURDATE(), INTERVAL -2 DAY) , DATE_ADD(CURDATE(), INTERVAL -2 DAY) , 103, 'address 23', 123, 'T4444444', 0, DATE_ADD(CURDATE(), INTERVAL -2 DAY) ), - (7 , 4, 4, 4, DATE_ADD(CURDATE(), INTERVAL -1 DAY) , DATE_ADD(CURDATE(), INTERVAL -1 DAY) , 104, 'address 24', 124, 'T4444444', 0, DATE_ADD(CURDATE(), INTERVAL -1 DAY) ), - (8 , 1, 1, 4, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 104, 'address 24', 124, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +1 MONTH) ), - (9 , 5, 5, 4, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 105, 'address 25', 125, NULL, 0, DATE_ADD(CURDATE(), INTERVAL -2 MONTH) ), - (10, 6, 5, 5, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), DATE_ADD(CURDATE(), INTERVAL -3 MONTH), 105, 'address 25', 125, NULL, 0, DATE_ADD(CURDATE(), INTERVAL -3 MONTH) ), - (11, 7, 1, 1, CURDATE() , CURDATE() , 101, 'address 21', 121, NULL, 0, CURDATE() ), - (12, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 101, 'address 21', 121, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +1 MONTH) ), - (13, 2, 2, 2, DATE_ADD(CURDATE(), INTERVAL +2 MONTH), DATE_ADD(CURDATE(), INTERVAL +2 MONTH), 101, 'address 21', 121, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +2 MONTH) ), - (14, 2, 2, 2, DATE_ADD(CURDATE(), INTERVAL +3 MONTH), DATE_ADD(CURDATE(), INTERVAL +3 MONTH), 101, 'address 21', 121, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +3 MONTH) ), - (15, 3, 3, 3, DATE_ADD(CURDATE(), INTERVAL +4 MONTH), DATE_ADD(CURDATE(), INTERVAL +4 MONTH), 101, 'address 21', 121, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +4 MONTH) ), - (16, 1, 1, 1, CURDATE(), CURDATE(), 101, 'address 21', 121, NULL, 0, CURDATE() ), - (17, 4, 4, 4, CURDATE(), CURDATE(), 106, 'address 26', 126, NULL, 0, CURDATE() ), - (18, 4, 4, 4, CURDATE(), CURDATE(), 107, 'address 27', 127, NULL, 0, CURDATE() ), - (19, 5, 5, 4, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), 108, 'address 28', 128, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +1 DAY) ), - (20, 5, 5, 4, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), 108, 'address 28', 128, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +1 DAY) ), - (21, 5, 5, 4, CURDATE(), CURDATE(), 110, 'address 29', 129, NULL, 1, CURDATE() ), - (22, 5, 5, 4, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), 108, 'address 28', 128, NULL, 1, DATE_ADD(CURDATE(), INTERVAL +1 DAY) ); + (1 , 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY) , DATE_ADD(CURDATE(), INTERVAL -15 DAY) , 101, 'address 21', 121, 'T1111111', 0, DATE_ADD(CURDATE(), INTERVAL -15 DAY) ), + (2 , 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -10 DAY) , DATE_ADD(CURDATE(), INTERVAL -10 DAY) , 101, 'address 21', 121, 'T2222222', 0, DATE_ADD(CURDATE(), INTERVAL -10 DAY) ), + (3 , 2, 2, 2, DATE_ADD(CURDATE(), INTERVAL -5 DAY) , DATE_ADD(CURDATE(), INTERVAL -5 DAY) , 102, 'address 22', 122, 'T2222222', 0, DATE_ADD(CURDATE(), INTERVAL -5 DAY) ), + (4 , 2, 2, 2, DATE_ADD(CURDATE(), INTERVAL -4 DAY) , DATE_ADD(CURDATE(), INTERVAL -4 DAY) , 102, 'address 22', 122, 'T3333333', 0, DATE_ADD(CURDATE(), INTERVAL -4 DAY) ), + (5 , 3, 3, 3, DATE_ADD(CURDATE(), INTERVAL -3 DAY) , DATE_ADD(CURDATE(), INTERVAL -3 DAY) , 103, 'address 23', 123, 'T3333333', 0, DATE_ADD(CURDATE(), INTERVAL -3 DAY) ), + (6 , 3, 3, 4, DATE_ADD(CURDATE(), INTERVAL -2 DAY) , DATE_ADD(CURDATE(), INTERVAL -2 DAY) , 103, 'address 23', 123, 'T4444444', 0, DATE_ADD(CURDATE(), INTERVAL -2 DAY) ), + (7 , 4, 4, 4, DATE_ADD(CURDATE(), INTERVAL -1 DAY) , DATE_ADD(CURDATE(), INTERVAL -1 DAY) , 104, 'address 24', 124, 'T4444444', 0, DATE_ADD(CURDATE(), INTERVAL -1 DAY) ), + (8 , 1, 1, 4, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 104, 'address 24', 124, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +1 MONTH) ), + (9 , 5, 5, 4, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 105, 'address 25', 125, 'A1111111', 0, DATE_ADD(CURDATE(), INTERVAL -2 MONTH) ), + (10, 6, 5, 5, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), DATE_ADD(CURDATE(), INTERVAL -3 MONTH), 105, 'address 25', 125, 'A1111111', 0, DATE_ADD(CURDATE(), INTERVAL -3 MONTH) ), + (11, 7, 1, 1, CURDATE() , CURDATE() , 101, 'address 21', 121, NULL, 0, CURDATE() ), + (12, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 101, 'address 21', 121, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +1 MONTH) ), + (13, 2, 2, 2, DATE_ADD(CURDATE(), INTERVAL +2 MONTH), DATE_ADD(CURDATE(), INTERVAL +2 MONTH), 101, 'address 21', 121, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +2 MONTH) ), + (14, 2, 2, 2, DATE_ADD(CURDATE(), INTERVAL +3 MONTH), DATE_ADD(CURDATE(), INTERVAL +3 MONTH), 101, 'address 21', 121, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +3 MONTH) ), + (15, 3, 3, 3, DATE_ADD(CURDATE(), INTERVAL +4 MONTH), DATE_ADD(CURDATE(), INTERVAL +4 MONTH), 101, 'address 21', 121, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +4 MONTH) ), + (16, 1, 1, 1, CURDATE(), CURDATE(), 101, 'address 21', 121, NULL, 0, CURDATE() ), + (17, 4, 4, 4, CURDATE(), CURDATE(), 106, 'address 26', 126, NULL, 0, CURDATE() ), + (18, 4, 4, 4, CURDATE(), CURDATE(), 107, 'address 27', 127, NULL, 0, CURDATE() ), + (19, 5, 5, 4, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), 108, 'address 28', 128, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +1 DAY) ), + (20, 5, 5, 4, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), 108, 'address 28', 128, NULL, 0, DATE_ADD(CURDATE(), INTERVAL +1 DAY) ), + (21, 5, 5, 4, CURDATE(), CURDATE(), 110, 'address 29', 129, NULL, 1, CURDATE() ), + (22, 5, 5, 4, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), 108, 'address 28', 128, NULL, 1, DATE_ADD(CURDATE(), INTERVAL +1 DAY) ); INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`) VALUES @@ -614,22 +627,22 @@ INSERT INTO `vn`.`ticketPackaging`(`id`, `ticketFk`, `packagingFk`, `quantity`, INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `price`, `discount`, `reserved`, `isPicked`, `created`) VALUES (1, 1, 1, 'Ranged weapon longbow 2m', 5, 9.10, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), - (2, 2, 1, 'Melee weapon combat first 15cm', 10, 1.07, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), + (2, 2, 1, 'Melee weapon combat fist 15cm', 10, 1.07, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), (3, 1, 1, 'Ranged weapon longbow 2m', 2, 9.10, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), (4, 4, 1, 'Melee weapon heavy shield 1x0.5m', 20, 3.06, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), (5, 1, 2, 'Ranged weapon longbow 2m', 10, 9.10, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL -10 DAY)), (6, 1, 3, 'Ranged weapon longbow 2m', 15, 6.50, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL -5 DAY)), - (7, 2, 11, 'Melee weapon combat first 15cm', 15, 1.46, 0, 0, 0, CURDATE()), + (7, 2, 11, 'Melee weapon combat fist 15cm', 15, 1.46, 0, 0, 0, CURDATE()), (8, 4, 11, 'Melee weapon heavy shield 1x0.5m', 10, 3.04, 0, 0, 0, CURDATE()), (9, 1, 16, 'Ranged weapon longbow 2m', 5, 9.10, 0, 0, 0, CURDATE()), - (10, 2, 16, 'Melee weapon combat first 15cm', 10, 1.07, 0, 0, 0, CURDATE()), + (10, 2, 16, 'Melee weapon combat fist 15cm', 10, 1.07, 0, 0, 0, CURDATE()), (11, 1, 16, 'Ranged weapon longbow 2m', 2, 9.10, 0, 0, 0, CURDATE()), (12, 4, 16, 'Melee weapon heavy shield 1x0.5m', 20, 3.06, 0, 0, 0, CURDATE()), - (13, 2, 8, 'Melee weapon combat first 15cm', 15, 1.30, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)), + (13, 2, 8, 'Melee weapon combat fist 15cm', 15, 1.30, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)), (14, 1, 8, 'Ranged weapon longbow 2m', 10, 2.30, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)), (15, 1, 19, 'Ranged weapon longbow 2m', 10, 1.50, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), - (16, 2, 20, 'Melee weapon combat first 15cm', 15, 1.30, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), - (17, 2, 22, 'Melee weapon combat first 15cm', 30, 2.30, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), + (16, 2, 20, 'Melee weapon combat fist 15cm', 15, 1.30, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), + (17, 2, 22, 'Melee weapon combat fist 15cm', 30, 2.30, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), (18, 4, 22, 'Melee weapon heavy shield 1x0.5m', 20, 3.00, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), (19, 1, 4, 'Ranged weapon longbow 2m', 1, 9.10, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL -4 DAY)), (20, 1, 5, 'Ranged weapon longbow 2m', 1, 9.10, 0, 0, 0, DATE_ADD(CURDATE(), INTERVAL -3 DAY)), @@ -816,7 +829,7 @@ INSERT INTO `vn`.`itemTag`(`id`,`itemFk`,`tagFk`,`value`,`priority`) (6 , 1, 67, 'precission', 6), (7 , 1, 23, '1', 7), (8 , 2, 56, 'Melee weapon', 1), - (9 , 2, 58, 'combat first', 2), + (9 , 2, 58, 'combat fist', 2), (10, 2, 27, '15cm', 3), (11, 2, 36, 'Stark Industries', 4), (12, 2, 1, 'Silver', 5), @@ -1210,16 +1223,18 @@ INSERT INTO `vn2008`.`workerTeam`(`id`, `team`, `user`) INSERT INTO `vn`.`ticketRequest`(`id`, `description`, `requesterFk`, `atenderFk`, `quantity`, `itemFk`, `price`, `isOk`, `saleFk`, `ticketFk`, `created`) VALUES - (1, 'Ranged weapon longbow 2m', 18, 35, 5, 1, 9.10, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), - (2, 'Melee weapon combat first 15cm', 18, 35, 10, 2, 1.07, 0, NULL, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), - (3, 'Melee weapon heavy shield 1x0.5m', 18, 35, 20, 4, 3.06, 0, NULL, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), - (4, 'Melee weapon combat first 15cm', 18, 35, 15, 2, 1.30, NULL, NULL, 11, CURDATE()); + (1, 'Ranged weapon longbow 2m', 18, 35, 5, 1, 9.10, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), + (2, 'Melee weapon combat first 15cm', 18, 35, 10, 2, 1.07, 0, NULL, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), + (3, 'Melee weapon heavy shield 1x0.5m', 18, 35, 20, 4, 3.06, 0, NULL, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)), + (4, 'Melee weapon combat first 15cm', 18, 35, 15, NULL, 1.30, NULL, NULL, 11, CURDATE()); INSERT INTO `vn`.`ticketService`(`id`, `description`, `quantity`, `price`, `taxClassFk`, `ticketFk`) VALUES - (1, 'delivery charge', 1, 2.00, 1, 1), - (2, 'training course', 1, 10.00, 1, 2), - (3, 'delivery charge', 1, 5.50, 1, 11); + (1, 'Documentos', 1, 2.00, 1, 1), + (2, 'Porte Agencia', 1, 10.00, 1, 2), + (3, 'Documentos', 1, 5.50, 1, 11), + (4, 'Documentos', 1, 2.00, 1, 9), + (5, 'Documentos', 1, 2.00, 1, 8); INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `warehouseFk`, `agencyModeFk`, `travelingDays`, `price`, `bonus`) @@ -1260,7 +1275,7 @@ INSERT INTO `pbx`.`sip`(`user_id`, `extension`, `secret`, `caller_id`) (9, 1201, '123456', 'developer'); INSERT INTO `postgresql`.`person`(`person_id`, `name`, `nickname`, `nif`, `firstname`, `id_trabajador`) - SELECT w.id, w.name, u.nickname,CONCAT(RPAD(CONCAT(w.id,9),8,w.id),'A'),w.firstName,w.id + SELECT w.id, w.lastName, u.nickname,CONCAT(RPAD(CONCAT(w.id,9),8,w.id),'A'),w.firstName,w.id FROM `vn`.`worker` `w` JOIN `account`.`user` `u` ON `u`.`id` = `w`.`userFk`; @@ -1273,7 +1288,7 @@ INSERT INTO `postgresql`.`profile`(`profile_id`, `person_id`, `profile_type_id`) FROM `postgresql`.`person` `p`; INSERT INTO `postgresql`.`business`(`business_id`, `client_id`, `provider_id`, `date_start`, `date_end`, `workerBusiness`, `reasonEndFk`) - SELECT p.profile_id, p.profile_id, 1000, DATE_ADD(CURDATE(), INTERVAL -15 DAY), DATE_ADD(CURDATE(), INTERVAL +6 MONTH), CONCAT('E-46-',RPAD(CONCAT(p.profile_id,9),8,p.profile_id)), NULL + SELECT p.profile_id, p.profile_id, 1000, CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)), '-12-31'), CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL +1 YEAR)), '-01-01'), CONCAT('E-46-',RPAD(CONCAT(p.profile_id,9),8,p.profile_id)), NULL FROM `postgresql`.`profile` `p`; INSERT INTO `postgresql`.`business_labour`(`business_id`, `notes`, `department_id`, `professional_category_id`, `incentivo`, `calendar_labour_type_id`, `porhoras`, `labour_agreement_id`, `workcenter_id`) diff --git a/docker-compose.yml b/docker-compose.yml index 05135c454..7fcf95a79 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,4 +18,5 @@ services: - NODE_ENV volumes: - /containers/salix:/etc/salix - - /mnt/storage/pdfs:/var/lib/salix/pdfs \ No newline at end of file + - /mnt/storage/pdfs:/var/lib/salix/pdfs + - /mnt/storage/dms:/var/lib/salix/dms \ No newline at end of file diff --git a/e2e/helpers/components_selectors.js b/e2e/helpers/components_selectors.js index 9afd06374..4cd8241ab 100644 --- a/e2e/helpers/components_selectors.js +++ b/e2e/helpers/components_selectors.js @@ -1,6 +1,3 @@ -// eslint max-len: ["error", 500] -// eslint key-spacing: ["error", 500] - export default { vnTextfield: 'vn-textfield > div > div > div > input', vnInputNumber: 'vn-input-number > div > div > div > input', diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index a8c3d44dc..9c458b750 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -2,30 +2,30 @@ import components from './components_selectors.js'; export default { globalItems: { - applicationsMenuButton: `#apps`, - applicationsMenuVisible: `vn-main-menu [vn-id="apps-menu"] ul`, - clientsButton: `vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="client.index"]`, - itemsButton: `vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="item.index"]`, - ticketsButton: `vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="ticket.index"]`, - claimsButton: `vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="claim.index"]`, + applicationsMenuButton: '#apps', + applicationsMenuVisible: 'vn-main-menu [vn-id="apps-menu"] ul', + clientsButton: 'vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="client.index"]', + itemsButton: 'vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="item.index"]', + ticketsButton: 'vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="ticket.index"]', + claimsButton: 'vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="claim.index"]', returnToModuleIndexButton: `a[translate-attr="{title: 'Return to module index'}"]`, - userMenuButton: `vn-topbar #user`, - userLocalWarehouse: `vn-topbar vn-popover vn-autocomplete[field="$ctrl.localWarehouseFk"]`, - userLocalBank: `vn-topbar vn-popover vn-autocomplete[field="$ctrl.localBankFk"]`, - userLocalCompany: `vn-topbar vn-popover vn-autocomplete[field="$ctrl.localCompanyFk"]`, - userWarehouse: `vn-topbar vn-popover vn-autocomplete[field="$ctrl.warehouseFk"]`, - userCompany: `vn-topbar vn-popover vn-autocomplete[field="$ctrl.companyFk"]`, + userMenuButton: 'vn-topbar #user', + userLocalWarehouse: 'vn-topbar vn-popover vn-autocomplete[field="$ctrl.localWarehouseFk"]', + userLocalBank: 'vn-topbar vn-popover vn-autocomplete[field="$ctrl.localBankFk"]', + userLocalCompany: 'vn-topbar vn-popover vn-autocomplete[field="$ctrl.localCompanyFk"]', + userWarehouse: 'vn-topbar vn-popover vn-autocomplete[field="$ctrl.warehouseFk"]', + userCompany: 'vn-topbar vn-popover vn-autocomplete[field="$ctrl.companyFk"]', userConfigFirstAutocompleteClear: '#localWarehouse > div > div > div > vn-icon.clear', userConfigSecondAutocompleteClear: '#localBank > div > div > div > vn-icon.clear', userConfigThirdAutocompleteClear: '#localCompany > div > div > div > vn-icon.clear', - acceptVnConfirm: `vn-confirm button[response=ACCEPT]` + acceptVnConfirm: 'vn-confirm button[response=ACCEPT]' }, clientsIndex: { searchClientInput: `${components.vnTextfield}`, - searchButton: `vn-searchbar vn-icon[icon="search"]`, - searchResult: `vn-client-index .vn-list-item`, + searchButton: 'vn-searchbar vn-icon[icon="search"]', + searchResult: 'vn-client-index .vn-list-item', createClientButton: `${components.vnFloatButton}`, - othersButton: `vn-left-menu li[name="Others"] > a` + othersButton: 'vn-left-menu li[name="Others"] > a' }, createClientView: { name: `${components.vnTextfield}[name="name"]`, @@ -37,53 +37,53 @@ export default { email: `${components.vnTextfield}[name="email"]`, salesPersonAutocomplete: `vn-autocomplete[field="$ctrl.client.salesPersonFk"]`, createButton: `${components.vnSubmit}`, - cancelButton: `vn-button[href="#!/client/index"]` + cancelButton: 'vn-button[href="#!/client/index"]' }, clientDescriptor: { - moreMenu: `vn-client-descriptor vn-icon-menu > div > vn-icon`, + moreMenu: 'vn-client-descriptor vn-icon-menu > div > vn-icon', simpleTicketButton: 'vn-client-descriptor vn-popover > div > div.content > div > div.list > ul > li' }, clientBasicData: { - basicDataButton: `vn-left-menu a[ui-sref="client.card.basicData"]`, + basicDataButton: 'vn-left-menu a[ui-sref="client.card.basicData"]', nameInput: `${components.vnTextfield}[name="name"]`, contactInput: `${components.vnTextfield}[name="contact"]`, phoneInput: `${components.vnTextfield}[name="phone"]`, mobileInput: `${components.vnTextfield}[name="mobile"]`, faxInput: `${components.vnTextfield}[name="fax"]`, emailInput: `${components.vnTextfield}[name="email"]`, - salesPersonAutocomplete: `vn-autocomplete[field="$ctrl.client.salesPersonFk"]`, - channelAutocomplete: `vn-autocomplete[field="$ctrl.client.contactChannelFk"]`, + salesPersonAutocomplete: 'vn-autocomplete[field="$ctrl.client.salesPersonFk"]', + channelAutocomplete: 'vn-autocomplete[field="$ctrl.client.contactChannelFk"]', saveButton: `${components.vnSubmit}` }, clientFiscalData: { - fiscalDataButton: `vn-left-menu a[ui-sref="client.card.fiscalData"]`, + fiscalDataButton: 'vn-left-menu a[ui-sref="client.card.fiscalData"]', socialNameInput: `${components.vnTextfield}[name="socialName"]`, fiscalIdInput: `${components.vnTextfield}[name="fi"]`, - equalizationTaxCheckbox: `vn-check[label='Is equalizated'] md-checkbox`, - acceptPropagationButton: `vn-client-fiscal-data > vn-confirm button[response=ACCEPT]`, + equalizationTaxCheckbox: 'vn-check[label="Is equalizated"] md-checkbox', + acceptPropagationButton: 'vn-client-fiscal-data > vn-confirm button[response=ACCEPT]', addressInput: `${components.vnTextfield}[name="street"]`, cityInput: `${components.vnTextfield}[name="city"]`, postcodeInput: `${components.vnTextfield}[name="postcode"]`, - provinceAutocomplete: `vn-autocomplete[field="$ctrl.client.provinceFk"]`, - countryAutocomplete: `vn-autocomplete[field="$ctrl.client.countryFk"]`, - activeCheckbox: `vn-check[label="Active"] md-checkbox`, - frozenCheckbox: `vn-check[label="Frozen"] md-checkbox`, - invoiceByAddressCheckbox: `vn-check[label='Invoice by address'] md-checkbox`, - verifiedDataCheckbox: `vn-check[label="Verified data"] md-checkbox`, - hasToInvoiceCheckbox: `vn-check[label='Has to invoice'] md-checkbox`, - invoiceByMailCheckbox: `vn-check[label='Invoice by mail'] md-checkbox`, - viesCheckbox: `vn-check[label='Vies'] md-checkbox`, + provinceAutocomplete: 'vn-autocomplete[field="$ctrl.client.provinceFk"]', + countryAutocomplete: 'vn-autocomplete[field="$ctrl.client.countryFk"]', + activeCheckbox: 'vn-check[label="Active"] md-checkbox', + frozenCheckbox: 'vn-check[label="Frozen"] md-checkbox', + invoiceByAddressCheckbox: 'vn-check[label="Invoice by address"] md-checkbox', + verifiedDataCheckbox: 'vn-check[label="Verified data"] md-checkbox', + hasToInvoiceCheckbox: 'vn-check[label="Has to invoice"] md-checkbox', + invoiceByMailCheckbox: 'vn-check[label="Invoice by mail"] md-checkbox', + viesCheckbox: 'vn-check[label="Vies"] md-checkbox', saveButton: `${components.vnSubmit}` }, - clientPayMethod: { - payMethodAutocomplete: `vn-autocomplete[field="$ctrl.client.payMethodFk"]`, + clientBillingData: { + payMethodAutocomplete: 'vn-autocomplete[field="$ctrl.client.payMethodFk"]', IBANInput: `${components.vnTextfield}[name="iban"]`, dueDayInput: `${components.vnInputNumber}[name="dueDay"]`, - receivedCoreLCRCheckbox: `vn-check[label='Received LCR'] md-checkbox`, - receivedCoreVNLCheckbox: `vn-check[label='Received core VNL'] md-checkbox`, - receivedB2BVNLCheckbox: `vn-check[label='Received B2B VNL'] md-checkbox`, + receivedCoreLCRCheckbox: 'vn-check[label="Received LCR"] md-checkbox', + receivedCoreVNLCheckbox: 'vn-check[label="Received core VNL"] md-checkbox', + receivedB2BVNLCheckbox: 'vn-check[label="Received B2B VNL"] md-checkbox', swiftBicAutocomplete: 'vn-client-billing-data vn-autocomplete[field="$ctrl.client.bankEntityFk"]', - clearswiftBicButton: `vn-client-billing-data vn-autocomplete[field="$ctrl.client.bankEntityFk"] > div > div > div > vn-icon > i`, + clearswiftBicButton: 'vn-client-billing-data vn-autocomplete[field="$ctrl.client.bankEntityFk"] > div > div > div > vn-icon > i', newBankEntityButton: 'vn-client-billing-data vn-icon-button[vn-tooltip="New bank entity"] > button', newBankEntityName: 'vn-client-billing-data > vn-dialog vn-textfield[label="Name"] input', newBankEntityBIC: 'vn-client-billing-data > vn-dialog vn-textfield[label="Swift / BIC"] input', @@ -92,41 +92,41 @@ export default { saveButton: `${components.vnSubmit}` }, clientAddresses: { - addressesButton: `vn-left-menu a[ui-sref="client.card.address.index"]`, + addressesButton: 'vn-left-menu a[ui-sref="client.card.address.index"]', createAddress: `vn-client-address-index ${components.vnFloatButton}`, - defaultCheckboxInput: `vn-check[label='Default'] md-checkbox`, + defaultCheckboxInput: 'vn-check[label="Default"] md-checkbox', consigneeInput: `${components.vnTextfield}[name="nickname"]`, streetAddressInput: `${components.vnTextfield}[name="street"]`, postcodeInput: `${components.vnTextfield}[name="postalCode"]`, cityInput: `${components.vnTextfield}[name="city"]`, - provinceAutocomplete: `vn-autocomplete[field="$ctrl.address.provinceFk"]`, - agencyAutocomplete: `vn-autocomplete[field="$ctrl.address.agencyModeFk"]`, + provinceAutocomplete: 'vn-autocomplete[field="$ctrl.address.provinceFk"]', + agencyAutocomplete: 'vn-autocomplete[field="$ctrl.address.agencyModeFk"]', phoneInput: `${components.vnTextfield}[name="phone"]`, mobileInput: `${components.vnTextfield}[name="mobile"]`, defaultAddress: 'vn-client-address-index vn-horizontal:nth-child(1) div[name="street"]', secondMakeDefaultStar: 'vn-client-address-index vn-card vn-horizontal:nth-child(2) vn-icon-button[icon="star_border"]', - firstEditButton: `vn-client-address-index vn-icon-button[icon='edit']`, - secondEditButton: `vn-client-address-index vn-horizontal:nth-child(2) vn-icon-button[icon='edit']`, - activeCheckbox: `vn-check[label='Enabled'] md-checkbox`, - equalizationTaxCheckbox: `vn-client-address-edit vn-check[label="Is equalizated"] md-checkbox`, - firstObservationTypeAutocomplete: `vn-client-address-edit [name=observations] :nth-child(1) [field="observation.observationTypeFk"]`, - firstObservationDescriptionInput: `vn-client-address-edit [name=observations] :nth-child(1) [model="observation.description"] input`, - secondObservationTypeAutocomplete: `vn-client-address-edit [name=observations] :nth-child(2) [field="observation.observationTypeFk"]`, - secondObservationDescriptionInput: `vn-client-address-edit [name=observations] :nth-child(2) [model="observation.description"] input`, - addObservationButton: `vn-client-address-edit vn-icon-button[icon="add_circle"]`, + firstEditButton: 'vn-client-address-index vn-icon-button[icon="edit"]', + secondEditButton: 'vn-client-address-index vn-horizontal:nth-child(2) vn-icon-button[icon="edit"]', + activeCheckbox: 'vn-check[label="Enabled"] md-checkbox', + equalizationTaxCheckbox: 'vn-client-address-edit vn-check[label="Is equalizated"] md-checkbox', + firstObservationTypeAutocomplete: 'vn-client-address-edit [name=observations] :nth-child(1) [field="observation.observationTypeFk"]', + firstObservationDescriptionInput: 'vn-client-address-edit [name=observations] :nth-child(1) [model="observation.description"] input', + secondObservationTypeAutocomplete: 'vn-client-address-edit [name=observations] :nth-child(2) [field="observation.observationTypeFk"]', + secondObservationDescriptionInput: 'vn-client-address-edit [name=observations] :nth-child(2) [model="observation.description"] input', + addObservationButton: 'vn-client-address-edit vn-icon-button[icon="add_circle"]', saveButton: `${components.vnSubmit}`, - cancelCreateAddressButton: `button[ui-sref="client.card.address.index"]`, + cancelCreateAddressButton: 'button[ui-sref="client.card.address.index"]', cancelEditAddressButton: 'vn-client-address-edit > form > vn-button-bar > vn-button > button' }, clientWebAccess: { - webAccessButton: `vn-left-menu a[ui-sref="client.card.webAccess"]`, - enableWebAccessCheckbox: `vn-check[label='Enable web access'] md-checkbox`, + webAccessButton: 'vn-left-menu a[ui-sref="client.card.webAccess"]', + enableWebAccessCheckbox: 'vn-check[label="Enable web access"] md-checkbox', userNameInput: `${components.vnTextfield}[name="name"]`, saveButton: `${components.vnSubmit}` }, clientNotes: { addNoteFloatButton: `${components.vnFloatButton}`, - noteInput: `vn-textarea[label="Note"]`, + noteInput: 'vn-textarea[label="Note"]', saveButton: `${components.vnSubmit}`, firstNoteText: 'vn-client-note .text' }, @@ -140,7 +140,7 @@ export default { addGreugeFloatButton: `${components.vnFloatButton}`, amountInput: `${components.vnInputNumber}[name="amount"]`, descriptionInput: `${components.vnTextfield}[name="description"]`, - typeAutocomplete: `vn-autocomplete[field="$ctrl.greuge.greugeTypeFk"]`, + typeAutocomplete: 'vn-autocomplete[field="$ctrl.greuge.greugeTypeFk"]', saveButton: `${components.vnSubmit}`, firstGreugeText: 'vn-client-greuge-index vn-card > div vn-table vn-tbody > vn-tr' }, @@ -151,20 +151,20 @@ export default { firstInvoiceText: 'vn-client-invoice vn-card > div vn-table vn-tbody > vn-tr' }, clientLog: { - logButton: `vn-left-menu a[ui-sref="client.card.log"]`, + logButton: 'vn-left-menu a[ui-sref="client.card.log"]', lastModificationDate: 'vn-client-log > vn-log vn-table vn-tbody > vn-tr > vn-td:nth-child(1)', lastModificationPreviousValue: 'vn-client-log vn-table vn-td.before', lastModificationCurrentValue: 'vn-client-log vn-table vn-td.after' }, - clientRisk: { - riskButton: `vn-left-menu a[ui-sref="client.card.risk.index"]`, - companyAutocomplete: 'vn-client-risk-index vn-autocomplete[field="$ctrl.companyFk"]', + clientBalance: { + balanceButton: 'vn-left-menu a[ui-sref="client.card.balance.index"]', + companyAutocomplete: 'vn-client-balance-index vn-autocomplete[field="$ctrl.companyFk"]', newPaymentButton: `${components.vnFloatButton}`, - newPaymentBankInut: `vn-client-risk-create vn-textfield[field="$ctrl.receipt.bankFk"] input`, - newPaymentAmountInput: `vn-client-risk-create vn-input-number[field="$ctrl.receipt.amountPaid"] input`, - saveButton: `vn-client-risk-create vn-button[label="Save"]`, - firstRiskLineBalance: 'vn-client-risk-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)' + newPaymentBankInut: 'vn-client-balance-create vn-textfield[field="$ctrl.receipt.bankFk"] input', + newPaymentAmountInput: 'vn-client-balance-create vn-input-number[field="$ctrl.receipt.amountPaid"] input', + saveButton: 'vn-client-balance-create vn-button[label="Save"]', + firstBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)' }, webPayment: { @@ -172,15 +172,15 @@ export default { firstPaymentConfirmed: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon[icon="check"][aria-hidden="false"]' }, itemsIndex: { - searchIcon: `vn-item-index vn-searchbar vn-icon[icon="search"]`, - goBackToModuleIndexButton: `vn-item-descriptor a[href="#!/item/index"]`, + searchIcon: 'vn-item-index vn-searchbar vn-icon[icon="search"]', + goBackToModuleIndexButton: 'vn-item-descriptor a[href="#!/item/index"]', createItemButton: `${components.vnFloatButton}`, - searchResult: `vn-item-index a.vn-tr`, - searchResultPreviewButton: `vn-item-index .buttons > [icon="desktop_windows"]`, - searchResultCloneButton: `vn-item-index .buttons > [icon="icon-clone"]`, - acceptClonationAlertButton: `vn-item-index [vn-id="clone"] [response="ACCEPT"]`, - searchItemInput: `vn-searchbar vn-textfield input`, - searchButton: `vn-searchbar vn-icon[icon="search"]`, + searchResult: 'vn-item-index a.vn-tr', + searchResultPreviewButton: 'vn-item-index .buttons > [icon="desktop_windows"]', + searchResultCloneButton: 'vn-item-index .buttons > [icon="icon-clone"]', + acceptClonationAlertButton: 'vn-item-index [vn-id="clone"] [response="ACCEPT"]', + searchItemInput: 'vn-searchbar vn-textfield input', + searchButton: 'vn-searchbar vn-icon[icon="search"]', closeItemSummaryPreview: 'vn-item-index [vn-id="preview"] button.close', fieldsToShowButton: 'vn-item-index vn-table > div.ng-scope > div > vn-icon-button[icon="menu"]', fieldsToShowForm: 'vn-item-index > div > vn-card > div > vn-table > div.ng-scope > div > vn-dialog > div > form', @@ -201,90 +201,90 @@ export default { }, itemCreateView: { temporalName: `${components.vnTextfield}[name="provisionalName"]`, - typeAutocomplete: `vn-autocomplete[field="$ctrl.item.typeFk"]`, - intrastatAutocomplete: `vn-autocomplete[field="$ctrl.item.intrastatFk"]`, - originAutocomplete: `vn-autocomplete[field="$ctrl.item.originFk"]`, + typeAutocomplete: 'vn-autocomplete[field="$ctrl.item.typeFk"]', + intrastatAutocomplete: 'vn-autocomplete[field="$ctrl.item.intrastatFk"]', + originAutocomplete: 'vn-autocomplete[field="$ctrl.item.originFk"]', createButton: `${components.vnSubmit}`, - cancelButton: `button[ui-sref="item.index"]` + cancelButton: 'button[ui-sref="item.index"]' }, itemDescriptor: { - moreMenu: `vn-item-descriptor vn-icon-menu > div > vn-icon`, - moreMenuRegularizeButton: `vn-item-descriptor vn-icon-menu > div > vn-drop-down > vn-popover ul > li:nth-child(1)`, - regularizeQuantityInput: `vn-item-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-textfield > div > div > div.infix > input`, + moreMenu: 'vn-item-descriptor vn-icon-menu > div > vn-icon', + moreMenuRegularizeButton: 'vn-item-descriptor vn-drop-down > vn-popover ul > li[name="Regularize stock"]', + regularizeQuantityInput: 'vn-item-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-textfield > div > div > div.infix > input', regularizeWarehouseAutocomplete: 'vn-item-descriptor vn-dialog vn-autocomplete[field="$ctrl.warehouseFk"]', editButton: 'vn-item-card vn-item-descriptor vn-float-button[icon="edit"]', - regularizeSaveButton: `vn-item-descriptor > vn-dialog > div > form > div.buttons > tpl-buttons > button`, + regularizeSaveButton: 'vn-item-descriptor > vn-dialog > div > form > div.buttons > tpl-buttons > button', inactiveIcon: 'vn-item-descriptor vn-icon[icon="icon-unavailable"]', navigateBackToIndex: 'vn-item-descriptor vn-icon[icon="chevron_left"]' }, itemBasicData: { - basicDataButton: `vn-left-menu a[ui-sref="item.card.data"]`, + basicDataButton: 'vn-left-menu a[ui-sref="item.card.basicData"]', goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]', - typeAutocomplete: `vn-autocomplete[field="$ctrl.item.typeFk"]`, - intrastatAutocomplete: `vn-autocomplete[field="$ctrl.item.intrastatFk"]`, - nameInput: `vn-textfield[label="Name"] input`, - relevancyInput: `vn-input-number[label="Relevancy"] input`, - originAutocomplete: `vn-autocomplete[field="$ctrl.item.originFk"]`, - expenceAutocomplete: `vn-autocomplete[field="$ctrl.item.expenceFk"]`, - longNameInput: `vn-textfield[field="$ctrl.item.longName"] input`, - isActiveCheckbox: `vn-check[label='Active'] md-checkbox`, + typeAutocomplete: 'vn-autocomplete[field="$ctrl.item.typeFk"]', + intrastatAutocomplete: 'vn-autocomplete[field="$ctrl.item.intrastatFk"]', + nameInput: 'vn-textfield[label="Name"] input', + relevancyInput: 'vn-input-number[label="Relevancy"] input', + originAutocomplete: 'vn-autocomplete[field="$ctrl.item.originFk"]', + expenceAutocomplete: 'vn-autocomplete[field="$ctrl.item.expenceFk"]', + longNameInput: 'vn-textfield[field="$ctrl.item.longName"] input', + isActiveCheckbox: 'vn-check[label="Active"] md-checkbox', submitBasicDataButton: `${components.vnSubmit}` }, itemTags: { goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]', - tagsButton: `vn-left-menu a[ui-sref="item.card.tags"]`, - fourthTagAutocomplete: `vn-item-tags vn-horizontal:nth-child(4) > vn-autocomplete[field="itemTag.tagFk"]`, - fourthValueInput: `vn-item-tags vn-horizontal:nth-child(4) > vn-textfield[label="Value"] input`, - fourthRelevancyInput: `vn-item-tags vn-horizontal:nth-child(4) > vn-textfield[label="Relevancy"] input`, - fourthRemoveTagButton: `vn-item-tags vn-horizontal:nth-child(4) vn-icon-button[icon="delete"]`, - fifthTagAutocomplete: `vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[field="itemTag.tagFk"]`, - fifthValueInput: `vn-item-tags vn-horizontal:nth-child(5) > vn-textfield[label="Value"] input`, - fifthRelevancyInput: `vn-item-tags vn-horizontal:nth-child(5) > vn-textfield[label="Relevancy"] input`, - sixthTagAutocomplete: `vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[field="itemTag.tagFk"]`, - sixthValueInput: `vn-item-tags vn-horizontal:nth-child(6) > vn-textfield[label="Value"] input`, - sixthRelevancyInput: `vn-item-tags vn-horizontal:nth-child(6) > vn-textfield[label="Relevancy"] input`, - seventhTagAutocomplete: `vn-item-tags vn-horizontal:nth-child(7) > vn-autocomplete[field="itemTag.tagFk"]`, - seventhValueInput: `vn-item-tags vn-horizontal:nth-child(7) > vn-textfield[label="Value"] input`, - seventhRelevancyInput: `vn-item-tags vn-horizontal:nth-child(7) > vn-textfield[label="Relevancy"] input`, - addItemTagButton: `vn-item-tags vn-icon-button[icon="add_circle"]`, + tagsButton: 'vn-left-menu a[ui-sref="item.card.tags"]', + fourthTagAutocomplete: 'vn-item-tags vn-horizontal:nth-child(4) > vn-autocomplete[field="itemTag.tagFk"]', + fourthValueInput: 'vn-item-tags vn-horizontal:nth-child(4) > vn-textfield[label="Value"] input', + fourthRelevancyInput: 'vn-item-tags vn-horizontal:nth-child(4) > vn-textfield[label="Relevancy"] input', + fourthRemoveTagButton: 'vn-item-tags vn-horizontal:nth-child(4) vn-icon-button[icon="delete"]', + fifthTagAutocomplete: 'vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[field="itemTag.tagFk"]', + fifthValueInput: 'vn-item-tags vn-horizontal:nth-child(5) > vn-textfield[label="Value"] input', + fifthRelevancyInput: 'vn-item-tags vn-horizontal:nth-child(5) > vn-textfield[label="Relevancy"] input', + sixthTagAutocomplete: 'vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[field="itemTag.tagFk"]', + sixthValueInput: 'vn-item-tags vn-horizontal:nth-child(6) > vn-textfield[label="Value"] input', + sixthRelevancyInput: 'vn-item-tags vn-horizontal:nth-child(6) > vn-textfield[label="Relevancy"] input', + seventhTagAutocomplete: 'vn-item-tags vn-horizontal:nth-child(7) > vn-autocomplete[field="itemTag.tagFk"]', + seventhValueInput: 'vn-item-tags vn-horizontal:nth-child(7) > vn-textfield[label="Value"] input', + seventhRelevancyInput: 'vn-item-tags vn-horizontal:nth-child(7) > vn-textfield[label="Relevancy"] input', + addItemTagButton: 'vn-item-tags vn-icon-button[icon="add_circle"]', submitItemTagsButton: `vn-item-tags ${components.vnSubmit}` }, itemTax: { - firstClassAutocomplete: `vn-item-tax vn-horizontal:nth-child(1) > vn-autocomplete[field="tax.taxClassFk"]`, - secondClassAutocomplete: `vn-item-tax vn-horizontal:nth-child(2) > vn-autocomplete[field="tax.taxClassFk"]`, - thirdClassAutocomplete: `vn-item-tax vn-horizontal:nth-child(3) > vn-autocomplete[field="tax.taxClassFk"]`, + firstClassAutocomplete: 'vn-item-tax vn-horizontal:nth-child(1) > vn-autocomplete[field="tax.taxClassFk"]', + secondClassAutocomplete: 'vn-item-tax vn-horizontal:nth-child(2) > vn-autocomplete[field="tax.taxClassFk"]', + thirdClassAutocomplete: 'vn-item-tax vn-horizontal:nth-child(3) > vn-autocomplete[field="tax.taxClassFk"]', submitTaxButton: `vn-item-tax ${components.vnSubmit}` }, itemBarcodes: { - addBarcodeButton: `vn-item-barcode vn-icon[icon="add_circle"]`, + addBarcodeButton: 'vn-item-barcode vn-icon[icon="add_circle"]', thirdCodeInput: `vn-item-barcode vn-horizontal:nth-child(3) > ${components.vnTextfield}`, submitBarcodesButton: `vn-item-barcode ${components.vnSubmit}`, - firstCodeRemoveButton: `vn-item-barcode vn-horizontal vn-none vn-icon[icon="delete"]` + firstCodeRemoveButton: 'vn-item-barcode vn-horizontal vn-none vn-icon[icon="delete"]' }, itemNiches: { - addNicheButton: `vn-item-niche vn-icon[icon="add_circle"]`, - firstWarehouseAutocomplete: `vn-item-niche vn-autocomplete[field="niche.warehouseFk"]`, - firstCodeInput: `vn-item-niche vn-horizontal:nth-child(1) > vn-textfield[label="Code"] input`, - secondWarehouseAutocomplete: `vn-item-niche vn-horizontal:nth-child(2) > vn-autocomplete[field="niche.warehouseFk"]`, - secondCodeInput: `vn-item-niche vn-horizontal:nth-child(2) > vn-textfield[label="Code"] input`, - secondNicheRemoveButton: `vn-item-niche vn-horizontal:nth-child(2) > vn-none > vn-icon-button[icon="delete"]`, - thirdWarehouseAutocomplete: `vn-item-niche vn-horizontal:nth-child(3) > vn-autocomplete[field="niche.warehouseFk"]`, - thirdCodeInput: `vn-item-niche vn-horizontal:nth-child(3) > vn-textfield[label="Code"] input`, + addNicheButton: 'vn-item-niche vn-icon[icon="add_circle"]', + firstWarehouseAutocomplete: 'vn-item-niche vn-autocomplete[field="niche.warehouseFk"]', + firstCodeInput: 'vn-item-niche vn-horizontal:nth-child(1) > vn-textfield[label="Code"] input', + secondWarehouseAutocomplete: 'vn-item-niche vn-horizontal:nth-child(2) > vn-autocomplete[field="niche.warehouseFk"]', + secondCodeInput: 'vn-item-niche vn-horizontal:nth-child(2) > vn-textfield[label="Code"] input', + secondNicheRemoveButton: 'vn-item-niche vn-horizontal:nth-child(2) > vn-none > vn-icon-button[icon="delete"]', + thirdWarehouseAutocomplete: 'vn-item-niche vn-horizontal:nth-child(3) > vn-autocomplete[field="niche.warehouseFk"]', + thirdCodeInput: 'vn-item-niche vn-horizontal:nth-child(3) > vn-textfield[label="Code"] input', submitNichesButton: `vn-item-niche ${components.vnSubmit}` }, itemBotanical: { botanicalInput: `vn-item-botanical vn-horizontal:nth-child(1) > ${components.vnTextfield}`, - genusAutocomplete: `vn-item-botanical vn-autocomplete[field="$ctrl.botanical.genusFk"]`, - speciesAutocomplete: `vn-item-botanical vn-autocomplete[field="$ctrl.botanical.specieFk"]`, + genusAutocomplete: 'vn-item-botanical vn-autocomplete[field="$ctrl.botanical.genusFk"]', + speciesAutocomplete: 'vn-item-botanical vn-autocomplete[field="$ctrl.botanical.specieFk"]', submitBotanicalButton: `vn-item-botanical ${components.vnSubmit}` }, itemSummary: { - basicData: `vn-item-summary [name="basicData"]`, - vat: `vn-item-summary [name="tax"]`, - tags: `vn-item-summary [name="tags"]`, - niche: `vn-item-summary [name="niche"]`, - botanical: `vn-item-summary [name="botanical"]`, - barcode: `vn-item-summary [name="barcode"]` + basicData: 'vn-item-summary [name="basicData"]', + vat: 'vn-item-summary [name="tax"]', + tags: 'vn-item-summary [name="tags"]', + niche: 'vn-item-summary [name="niche"]', + botanical: 'vn-item-summary [name="botanical"]', + barcode: 'vn-item-summary [name="barcode"]' }, itemDiary: { thirdTicketId: 'vn-item-diary vn-tbody > vn-tr:nth-child(3) > vn-td:nth-child(2) > span', @@ -301,20 +301,20 @@ export default { firstSaleItemId: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span', popoverDiaryButton: 'vn-ticket-summary vn-item-descriptor-popover vn-item-descriptor vn-icon[icon="icon-transaction"]', firstSaleQuantity: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3)', - firstSaleDiscount: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6)' + firstSaleDiscount: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6)', + invoiceOutRef: 'vn-ticket-summary > vn-card > div > vn-horizontal > vn-one:nth-child(1) > vn-label-value:nth-child(6) > section > span' }, ticketsIndex: { newTicketButton: 'vn-ticket-index > a', - searchResult: `vn-ticket-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr`, - searchResultDate: `vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(4)`, - searchResultAddress: `vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(6)`, + searchResult: 'vn-ticket-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr', + searchResultDate: 'vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(5)', searchTicketInput: `vn-ticket-index ${components.vnTextfield}`, - searchButton: `vn-ticket-index vn-searchbar vn-icon[icon="search"]`, - moreMenu: `vn-ticket-index vn-icon-menu[vn-id="more-button"] > div > vn-icon`, - moreMenuTurns: `vn-ticket-index vn-icon-menu vn-drop-down > vn-popover li`, - sixthWeeklyTicketTurn: `vn-ticket-weekly > form > div > vn-card > div > vn-table > div > vn-tbody > vn-tr:nth-child(6) > vn-td:nth-child(3) > vn-autocomplete > div > div > input`, - weeklyTicket: `vn-ticket-weekly vn-table > div > vn-tbody > vn-tr`, - sixthWeeklyTicketDeleteIcon: `vn-ticket-weekly > form vn-tbody > vn-tr:nth-child(6) > vn-td:nth-child(6) > vn-icon-button[icon="delete"]` + searchButton: 'vn-ticket-index vn-searchbar vn-icon[icon="search"]', + moreMenu: 'vn-ticket-index vn-icon-menu[vn-id="more-button"] > div > vn-icon', + moreMenuTurns: 'vn-ticket-index vn-icon-menu vn-drop-down > vn-popover li:nth-child(2)', + sixthWeeklyTicketTurn: 'vn-ticket-weekly > form > div > vn-card > div > vn-table > div > vn-tbody > vn-tr:nth-child(6) > vn-td:nth-child(3) > vn-autocomplete > div > div > input', + weeklyTicket: 'vn-ticket-weekly vn-table > div > vn-tbody > vn-tr', + sixthWeeklyTicketDeleteIcon: 'vn-ticket-weekly > form vn-tbody > vn-tr:nth-child(6) > vn-td:nth-child(6) > vn-icon-button[icon="delete"]' }, createTicketView: { clientAutocomplete: 'vn-ticket-create vn-autocomplete[field="$ctrl.clientFk"]', @@ -325,57 +325,59 @@ export default { createButton: `${components.vnSubmit}` }, ticketDescriptor: { - moreMenu: `vn-ticket-descriptor vn-icon-menu > div > vn-icon`, - moreMenuAddStowaway: `vn-ticket-descriptor vn-icon-menu > div > vn-drop-down > vn-popover ul > li:nth-child(1)`, - moreMenuDeleteStowawayButton: 'vn-ticket-descriptor vn-icon-menu > div > vn-drop-down > vn-popover ul > li:nth-child(5)', - moreMenuAddToTurn: `vn-ticket-descriptor vn-icon-menu > div > vn-drop-down > vn-popover ul > li:nth-child(2)`, - moreMenuDeleteTicket: `vn-ticket-descriptor vn-icon-menu > div > vn-drop-down > vn-popover ul > li:nth-child(3)`, + moreMenu: 'vn-ticket-descriptor vn-icon-menu > div > vn-icon', + moreMenuAddStowaway: 'vn-ticket-descriptor vn-drop-down > vn-popover ul > li[name="Add stowaway"]', + moreMenuDeleteStowawayButton: 'vn-ticket-descriptor vn-drop-down > vn-popover ul > li[name="Remove stowaway"]', + moreMenuAddToTurn: 'vn-ticket-descriptor vn-drop-down > vn-popover ul > li[name="Add turn"]', + moreMenuDeleteTicket: 'vn-ticket-descriptor vn-drop-down > vn-popover ul > li[name="Delete ticket"]', + moreMenuMakeInvoice: 'vn-ticket-descriptor vn-drop-down > vn-popover ul > li[name="Make invoice"]', addStowawayDialogSecondTicket: 'vn-ticket-descriptor > vn-add-stowaway > vn-dialog vn-table vn-tr:nth-child(2)', shipSelectButton: 'vn-ticket-descriptor > div > div.body > div.quicklinks > vn-button-menu[icon="icon-stowaway"]', shipButton: 'vn-ticket-descriptor > div > div.body > div.quicklinks vn-icon[icon="icon-stowaway"]', shipMenuSecondTicket: 'vn-ticket-descriptor div.quicklinks vn-drop-down li:nth-child(2)', - thursdayButton: `vn-ticket-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-tool-bar > vn-button:nth-child(4)`, - saturdayButton: `vn-ticket-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-tool-bar > vn-button:nth-child(6)`, + thursdayButton: 'vn-ticket-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-tool-bar > vn-button:nth-child(4)', + saturdayButton: 'vn-ticket-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-tool-bar > vn-button:nth-child(6)', closeStowawayDialog: 'vn-ticket-descriptor > vn-add-stowaway > vn-dialog > div > button[class="close"]', acceptDeleteButton: 'vn-ticket-descriptor button[response="ACCEPT"]', + acceptInvoiceOutButton: 'vn-ticket-descriptor vn-confirm[vn-id="makeInvoiceConfirmation"] button[response="ACCEPT"]', acceptDeleteStowawayButton: 'vn-ticket-descriptor > vn-remove-stowaway button[response="ACCEPT"]' }, ticketNotes: { - firstNoteRemoveButton: `vn-icon[icon="delete"]`, - addNoteButton: `vn-icon[icon="add_circle"]`, - firstNoteTypeAutocomplete: `vn-autocomplete[field="observation.observationTypeFk"]`, - firstDescriptionInput: `vn-textfield[label="Description"] input`, + firstNoteRemoveButton: 'vn-icon[icon="delete"]', + addNoteButton: 'vn-icon[icon="add_circle"]', + firstNoteTypeAutocomplete: 'vn-autocomplete[field="observation.observationTypeFk"]', + firstDescriptionInput: 'vn-textfield[label="Description"] input', submitNotesButton: `${components.vnSubmit}` }, ticketExpedition: { - expeditionButton: `vn-left-menu a[ui-sref="ticket.card.expedition"]`, - secondExpeditionRemoveButton: `vn-ticket-expedition vn-table div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(1) > vn-icon-button[icon="delete"]`, - acceptDeleteRowButton: `vn-ticket-expedition > vn-confirm[vn-id="delete-expedition"] button[response=ACCEPT]`, - expeditionRow: `vn-ticket-expedition vn-table vn-tbody > vn-tr` + expeditionButton: 'vn-left-menu a[ui-sref="ticket.card.expedition"]', + secondExpeditionRemoveButton: 'vn-ticket-expedition vn-table div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(1) > vn-icon-button[icon="delete"]', + acceptDeleteRowButton: 'vn-ticket-expedition > vn-confirm[vn-id="delete-expedition"] button[response=ACCEPT]', + expeditionRow: 'vn-ticket-expedition vn-table vn-tbody > vn-tr' }, ticketPackages: { - packagesButton: `vn-left-menu a[ui-sref="ticket.card.package.index"]`, - firstPackageAutocomplete: `vn-autocomplete[label="Package"]`, - firstQuantityInput: `vn-input-number[label="Quantity"] input`, - firstRemovePackageButton: `vn-icon-button[vn-tooltip="Remove package"]`, - addPackageButton: `vn-icon-button[vn-tooltip="Add package"]`, - clearPackageAutocompleteButton: `vn-autocomplete[label="Package"] > div > div > div > vn-icon > i`, + packagesButton: 'vn-left-menu a[ui-sref="ticket.card.package"]', + firstPackageAutocomplete: 'vn-autocomplete[label="Package"]', + firstQuantityInput: 'vn-input-number[label="Quantity"] input', + firstRemovePackageButton: 'vn-icon-button[vn-tooltip="Remove package"]', + addPackageButton: 'vn-icon-button[vn-tooltip="Add package"]', + clearPackageAutocompleteButton: 'vn-autocomplete[label="Package"] > div > div > div > vn-icon > i', savePackagesButton: `${components.vnSubmit}` }, ticketSales: { - saleButton: `vn-left-menu a[ui-sref="ticket.card.sale"]`, - saleLine: `vn-table div > vn-tbody > vn-tr`, + saleButton: 'vn-left-menu a[ui-sref="ticket.card.sale"]', + saleLine: 'vn-table div > vn-tbody > vn-tr', saleDescriptorPopover: 'vn-ticket-sale vn-item-descriptor-popover > vn-popover', saleDescriptorPopoverSummaryButton: 'vn-item-descriptor-popover a[href="#!/item/1/summary"]', - descriptorItemDiaryButton: `vn-item-descriptor .quicklinks.ng-scope > vn-horizontal > a > vn-icon > i`, + descriptorItemDiaryButton: 'vn-item-descriptor .quicklinks.ng-scope > vn-horizontal > a > vn-icon > i', newItemButton: 'vn-float-button[icon="add"]', firstSaleDescriptorImage: 'vn-ticket-sale vn-item-descriptor-popover > vn-popover vn-item-descriptor img', - firstSaleText: `vn-table div > vn-tbody > vn-tr:nth-child(1)`, + firstSaleText: 'vn-table div > vn-tbody > vn-tr:nth-child(1)', firstSaleThumbnailImage: 'vn-ticket-sale:nth-child(1) vn-tr:nth-child(1) vn-td:nth-child(3) > img', firstSaleZoomedImage: 'body > div > div > img', - firstSaleQuantity: `vn-textfield[model="sale.quantity"]:nth-child(1) input`, - firstSaleQuantityCell: `vn-ticket-sale vn-tr:nth-child(1) > vn-td-editable`, - firstSaleQuantityClearInput: `vn-textfield[model="sale.quantity"] div.suffix > i`, + firstSaleQuantity: 'vn-textfield[model="sale.quantity"]:nth-child(1) input', + firstSaleQuantityCell: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td-editable', + firstSaleQuantityClearInput: 'vn-textfield[model="sale.quantity"] div.suffix > i', firstSaleID: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(4) > span', firstSalePrice: 'vn-ticket-sale:nth-child(1) vn-tr:nth-child(1) > vn-td:nth-child(7) > span', firstSalePriceInput: 'vn-ticket-sale:nth-child(1) vn-popover.edit.dialog-summary.ng-isolate-scope.vn-popover.shown vn-textfield input', @@ -383,52 +385,45 @@ export default { firstSaleDiscountInput: 'vn-ticket-sale:nth-child(1) vn-ticket-sale-edit-discount vn-textfield input', firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(9)', firstSaleReservedIcon: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td:nth-child(2) > vn-icon:nth-child(3)', - firstSaleColour: `vn-ticket-sale vn-tr:nth-child(1) vn-td:nth-child(6) section:nth-child(1)`, - firstSaleLength: `vn-ticket-sale vn-tr:nth-child(1) vn-td:nth-child(6) section:nth-child(3)`, - firstSaleCheckbox: `vn-ticket-sale vn-tr:nth-child(1) vn-check[field="sale.checked"] md-checkbox`, + firstSaleColour: 'vn-ticket-sale vn-tr:nth-child(1) vn-td:nth-child(6) section:nth-child(1)', + firstSaleLength: 'vn-ticket-sale vn-tr:nth-child(1) vn-td:nth-child(6) section:nth-child(3)', + firstSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(1) vn-check[field="sale.checked"] md-checkbox', secondSaleClaimIcon: 'vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(2) > a > vn-icon', - secondSaleColour: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(6) section:nth-child(5)`, - secondSalePrice: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(7) > span`, - secondSaleDiscount: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(8)`, - secondSaleImport: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(9)`, - secondSaleText: `vn-table div > vn-tbody > vn-tr:nth-child(2)`, + secondSaleColour: 'vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(6) section:nth-child(5)', + secondSalePrice: 'vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(7) > span', + secondSaleDiscount: 'vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(8)', + secondSaleImport: 'vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(9)', + secondSaleText: 'vn-table div > vn-tbody > vn-tr:nth-child(2)', totalImport: 'vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-horizontal > vn-one > p:nth-child(3) > strong', - selectAllSalesCheckbox: `vn-ticket-sale vn-thead vn-check md-checkbox`, - secondSaleCheckbox: `vn-ticket-sale vn-tr:nth-child(2) vn-check[field="sale.checked"] md-checkbox`, - thirdSaleCheckbox: `vn-ticket-sale vn-tr:nth-child(3) vn-check[field="sale.checked"] md-checkbox`, + selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check md-checkbox', + secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[field="sale.checked"] md-checkbox', + thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[field="sale.checked"] md-checkbox', deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]', transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]', moveToTicketInput: 'vn-ticket-sale vn-popover.transfer vn-textfield[model="$ctrl.moveToTicketFk"] input', moveToTicketInputClearButton: 'vn-popover.shown i[title="Clear"]', moveToTicketButton: 'vn-ticket-sale vn-popover.transfer vn-icon[icon="arrow_forward_ios"]', moveToNewTicketButton: 'vn-ticket-sale vn-popover.transfer vn-button[label="New ticket"]', - acceptDeleteLineButton: `vn-ticket-sale > vn-confirm[vn-id="delete-lines"] button[response=ACCEPT]`, - acceptDeleteTicketButton: `vn-ticket-sale > vn-confirm[vn-id="deleteConfirmation"] button[response=ACCEPT]`, - stateMenuButton: 'vn-ticket-sale vn-tool-bar > vn-button-menu[label="State"] button', - stateMenuOptions: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(1)', - moreMenuButton: 'vn-ticket-sale vn-tool-bar > vn-button-menu[label="More"] button', - moreMenuReseveOption: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(2)', - moreMenuUnmarkResevedOption: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(3)', - moreMenuUpdateDiscount: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(4)', - moreMenuUpdateDiscountInput: 'vn-ticket-sale vn-dialog.shown vn-ticket-sale-edit-discount input', - moreMenuCreateClaim: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(1)' + acceptDeleteLineButton: 'vn-ticket-sale > vn-confirm[vn-id="delete-lines"] button[response=ACCEPT]', + acceptDeleteTicketButton: 'vn-ticket-sale > vn-confirm[vn-id="deleteConfirmation"] button[response=ACCEPT]', + stateMenuButton: 'vn-ticket-sale vn-tool-bar > vn-button-menu[label="State"]' }, ticketTracking: { - trackingButton: `vn-left-menu a[ui-sref="ticket.card.tracking.index"]`, + trackingButton: 'vn-left-menu a[ui-sref="ticket.card.tracking.index"]', createStateButton: `${components.vnFloatButton}`, stateAutocomplete: 'vn-ticket-tracking-edit vn-autocomplete[field="$ctrl.stateFk"]', saveButton: `${components.vnSubmit}`, - cancelButton: `vn-ticket-tracking-edit vn-button[ui-sref="ticket.card.tracking.index"]` + cancelButton: 'vn-ticket-tracking-edit vn-button[ui-sref="ticket.card.tracking.index"]' }, ticketBasicData: { - basicDataButton: `vn-left-menu a[ui-sref="ticket.card.data.stepOne"]`, - clientAutocomplete: `vn-autocomplete[field="$ctrl.clientFk"]`, - addressAutocomplete: `vn-autocomplete[field="$ctrl.ticket.addressFk"]`, - agencyAutocomplete: `vn-autocomplete[field="$ctrl.ticket.agencyModeFk"]`, - nextStepButton: `vn-step-control > section > section.buttons > section:nth-child(2) > vn-button`, - finalizeButton: `vn-step-control > section > section.buttons > section:nth-child(2) > vn-submit`, - stepTwoTotalPriceDif: `vn-ticket-data-step-two > form > vn-card > div > vn-horizontal > table > tfoot > tr > td:nth-child(4)`, - chargesReasonAutocomplete: `vn-autocomplete[field="$ctrl.ticket.option"]`, + basicDataButton: 'vn-left-menu a[ui-sref="ticket.card.basicData.stepOne"]', + clientAutocomplete: 'vn-autocomplete[field="$ctrl.clientFk"]', + addressAutocomplete: 'vn-autocomplete[field="$ctrl.ticket.addressFk"]', + agencyAutocomplete: 'vn-autocomplete[field="$ctrl.ticket.agencyModeFk"]', + nextStepButton: 'vn-step-control > section > section.buttons > section:nth-child(2) > vn-button', + finalizeButton: 'vn-step-control > section > section.buttons > section:nth-child(2) > vn-submit', + stepTwoTotalPriceDif: 'vn-ticket-basic-data-step-two > form > vn-card > div > vn-horizontal > table > tfoot > tr > td:nth-child(4)', + chargesReasonAutocomplete: 'vn-autocomplete[field="$ctrl.ticket.option"]', }, ticketComponents: { base: 'vn-ticket-components tfoot > tr:nth-child(1) > td', @@ -436,19 +431,19 @@ export default { total: 'vn-ticket-components tfoot > tr:nth-child(3) > td' }, ticketRequests: { - addRequestButton: `vn-ticket-request-index > a > vn-float-button > button`, + addRequestButton: 'vn-ticket-request-index > a > vn-float-button > button', request: 'vn-ticket-request-index > form > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr', - descriptionInput: `vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(1) > vn-textfield > div > div > div.infix > input`, - atenderAutocomplete: `vn-ticket-request-create vn-autocomplete[field="$ctrl.ticketRequest.atenderFk"]`, - quantityInput: `vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(2) > vn-input-number:nth-child(1) > div > div > div.infix > input`, - priceInput: `vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(2) > vn-input-number:nth-child(2) > div > div > div.infix > input`, - firstRemoveRequestButton: `vn-ticket-request-index vn-icon[icon="delete"]:nth-child(1)`, - saveButton: `vn-ticket-request-create > form > div > vn-button-bar > vn-submit[label="Create"] input`, + descriptionInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(1) > vn-textfield > div > div > div.infix > input', + atenderAutocomplete: 'vn-ticket-request-create vn-autocomplete[field="$ctrl.ticketRequest.atenderFk"]', + quantityInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(2) > vn-input-number:nth-child(1) > div > div > div.infix > input', + priceInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(2) > vn-input-number:nth-child(2) > div > div > div.infix > input', + firstRemoveRequestButton: 'vn-ticket-request-index vn-icon[icon="delete"]:nth-child(1)', + saveButton: 'vn-ticket-request-create > form > div > vn-button-bar > vn-submit[label="Create"] input', firstDescription: 'vn-ticket-request-index > form > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2)', }, ticketLog: { - logButton: `vn-left-menu a[ui-sref="ticket.card.log"]`, + logButton: 'vn-left-menu a[ui-sref="ticket.card.log"]', changedBy: 'vn-ticket-log > vn-log > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2) > span', actionTaken: 'vn-ticket-log > vn-log > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > div > div:nth-child(3) > span.value.ng-scope.ng-binding', id: 'vn-ticket-log > vn-log > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr > vn-td.before > vn-one:nth-child(1) > div > span.value.ng-scope.ng-binding' @@ -464,25 +459,25 @@ export default { saveServiceButton: `${components.vnSubmit}` }, createStateView: { - stateAutocomplete: `vn-autocomplete[field="$ctrl.stateFk"]`, - workerAutocomplete: `vn-autocomplete[field="$ctrl.workerFk"]`, - clearStateInputButton: `vn-autocomplete[field="$ctrl.stateFk"] > div > div > div > vn-icon > i`, + stateAutocomplete: 'vn-autocomplete[field="$ctrl.stateFk"]', + workerAutocomplete: 'vn-autocomplete[field="$ctrl.workerFk"]', + clearStateInputButton: 'vn-autocomplete[field="$ctrl.stateFk"] > div > div > div > vn-icon > i', saveStateButton: `${components.vnSubmit}` }, claimsIndex: { searchClaimInput: `vn-claim-index ${components.vnTextfield}`, - searchResult: `vn-claim-index vn-card > div > vn-table > div > vn-tbody > a`, - searchButton: `vn-claim-index vn-searchbar vn-icon[icon="search"]` + searchResult: 'vn-claim-index vn-card > div > vn-table > div > vn-tbody > a', + searchButton: 'vn-claim-index vn-searchbar vn-icon[icon="search"]' }, claimBasicData: { claimStateAutocomplete: 'vn-claim-basic-data vn-autocomplete[field="$ctrl.claim.claimStateFk"]', isPaidWithManaCheckbox: 'vn-check[field="$ctrl.claim.isChargedToMana"] md-checkbox', - responsabilityInputRange: `vn-input-range`, - observationInput: `vn-textarea[label="Observation"] textarea`, + responsabilityInputRange: 'vn-input-range', + observationInput: 'vn-textarea[label="Observation"] textarea', saveButton: `${components.vnSubmit}` }, claimDetail: { - addItemButton: `vn-claim-detail a vn-float-button`, + addItemButton: 'vn-claim-detail a vn-float-button', firstClaimableSaleFromTicket: 'vn-claim-detail > vn-dialog vn-tbody > vn-tr', claimDetailLine: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr', secondItemQuantityInput: 'vn-claim-detail vn-tr:nth-child(2) vn-input-number[model="saleClaimed.quantity"] input', @@ -516,29 +511,29 @@ export default { }, ordersIndex: { - searchResult: `vn-order-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr`, - searchResultDate: `vn-order-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(4)`, - searchResultAddress: `vn-order-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(6)`, + searchResult: 'vn-order-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr', + searchResultDate: 'vn-order-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(4)', + searchResultAddress: 'vn-order-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(6)', searchOrderInput: `vn-order-index ${components.vnTextfield}`, - searchButton: `vn-order-index vn-searchbar vn-icon[icon="search"]`, + searchButton: 'vn-order-index vn-searchbar vn-icon[icon="search"]', createOrderButton: `${components.vnFloatButton}`, }, createOrderView: { - clientAutocomplete: `vn-autocomplete[label="Client"]`, - addressAutocomplete: `vn-autocomplete[label="Address"]`, - agencyAutocomplete: `vn-autocomplete[label="Agency"]`, - landedDatePicker: `vn-date-picker[label="Landed"]`, + clientAutocomplete: 'vn-autocomplete[label="Client"]', + addressAutocomplete: 'vn-autocomplete[label="Address"]', + agencyAutocomplete: 'vn-autocomplete[label="Agency"]', + landedDatePicker: 'vn-date-picker[label="Landed"]', createButton: `${components.vnSubmit}`, - cancelButton: `vn-button[href="#!/client/index"]` + cancelButton: 'vn-button[href="#!/client/index"]' }, orderCatalog: { - orderByAutocomplete: `vn-autocomplete[label="Order by"]`, + orderByAutocomplete: 'vn-autocomplete[label="Order by"]', }, orderBasicData: { - clientAutocomplete: `vn-autocomplete[label="Client"]`, - addressAutocomplete: `vn-autocomplete[label="Address"]`, - agencyAutocomplete: `vn-autocomplete[label="Agency"]`, - observationInput: `vn-textarea[label="Observation"] textarea`, + clientAutocomplete: 'vn-autocomplete[label="Client"]', + addressAutocomplete: 'vn-autocomplete[label="Address"]', + agencyAutocomplete: 'vn-autocomplete[label="Agency"]', + observationInput: 'vn-textarea[label="Observation"] textarea', saveButton: `${components.vnSubmit}` }, orderLine: { diff --git a/e2e/paths/02-client-module/01_create_client.spec.js b/e2e/paths/02-client-module/01_create_client.spec.js index 0a8396edc..2d7b58b20 100644 --- a/e2e/paths/02-client-module/01_create_client.spec.js +++ b/e2e/paths/02-client-module/01_create_client.spec.js @@ -41,7 +41,7 @@ describe('Client create path', () => { .write(selectors.createClientView.taxNumber, '74451390E') .write(selectors.createClientView.userName, 'CaptainMarvel') .write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es') - .autocompleteSearch(selectors.createClientView.salesPersonAutocomplete, 'Accessory') + .autocompleteSearch(selectors.createClientView.salesPersonAutocomplete, 'replenisher') .waitToClick(selectors.createClientView.createButton) .waitForLastSnackbar(); diff --git a/e2e/paths/02-client-module/02_edit_basic_data.spec.js b/e2e/paths/02-client-module/02_edit_basic_data.spec.js index ddd1dc528..988ad82c8 100644 --- a/e2e/paths/02-client-module/02_edit_basic_data.spec.js +++ b/e2e/paths/02-client-module/02_edit_basic_data.spec.js @@ -114,7 +114,7 @@ describe('Client Edit basicData path', () => { .write(selectors.clientBasicData.mobileInput, '987654321') .clearInput(selectors.clientBasicData.emailInput) .write(selectors.clientBasicData.emailInput, 'Storm@verdnatura.es') - .autocompleteSearch(selectors.clientBasicData.salesPersonAutocomplete, 'AccessoryNick') + .autocompleteSearch(selectors.clientBasicData.salesPersonAutocomplete, 'replenisherNick') .autocompleteSearch(selectors.clientBasicData.channelAutocomplete, 'Metropolis newspaper') .waitToClick(selectors.clientBasicData.saveButton) .waitForLastSnackbar(); @@ -162,7 +162,7 @@ describe('Client Edit basicData path', () => { const result = await nightmare .waitToGetProperty(`${selectors.clientBasicData.salesPersonAutocomplete} input`, 'value'); - expect(result).toEqual('accessoryNick'); + expect(result).toEqual('replenisherNick'); }); it('should now confirm the channel have been selected', async() => { diff --git a/e2e/paths/02-client-module/04_edit_billing_data.spec.js b/e2e/paths/02-client-module/04_edit_billing_data.spec.js new file mode 100644 index 000000000..a73172d00 --- /dev/null +++ b/e2e/paths/02-client-module/04_edit_billing_data.spec.js @@ -0,0 +1,121 @@ +import selectors from '../../helpers/selectors.js'; +import createNightmare from '../../helpers/nightmare'; + +describe('Client Edit billing data path', () => { + const nightmare = createNightmare(); + + beforeAll(() => { + nightmare + .loginAndModule('administrative', 'client') + .accessToSearchResult('Bruce Banner') + .accessToSection('client.card.billingData'); + }); + + it(`should attempt to edit the billing data without an IBAN but fail`, async() => { + const snackbarMessage = await nightmare + .autocompleteSearch(selectors.clientBillingData.payMethodAutocomplete, 'PayMethod with IBAN') + .autocompleteSearch(selectors.clientBillingData.swiftBicAutocomplete, 'BBKKESMMMMM') + .clearInput(selectors.clientBillingData.dueDayInput) + .write(selectors.clientBillingData.dueDayInput, '60') + .waitForTextInInput(selectors.clientBillingData.dueDayInput, '60') + .waitToClick(selectors.clientBillingData.receivedCoreLCRCheckbox) + .waitToClick(selectors.clientBillingData.receivedCoreVNLCheckbox) + .waitToClick(selectors.clientBillingData.receivedB2BVNLCheckbox) + .waitToClick(selectors.clientBillingData.saveButton) + .waitForLastSnackbar(); + + expect(snackbarMessage).toEqual('That payment method requires an IBAN'); + }); + + it(`should add the IBAN but fail as it requires a BIC code`, async() => { + const snackbarMessage = await nightmare + .waitToClick(selectors.clientBillingData.clearswiftBicButton) + .clearInput(selectors.clientBillingData.IBANInput) + .write(selectors.clientBillingData.IBANInput, 'FR9121000418450200051332') + .waitForTextInInput(selectors.clientBillingData.IBANInput, 'FR9121000418450200051332') + .wait(1000) + .waitToClick(selectors.clientBillingData.saveButton) + .waitForLastSnackbar(); + + expect(snackbarMessage).toEqual('That payment method requires a BIC'); + }); + + it(`should create a new BIC code`, async() => { + const newcode = await nightmare + .waitToClick(selectors.clientBillingData.newBankEntityButton) + .write(selectors.clientBillingData.newBankEntityName, 'Gotham City Bank') + .write(selectors.clientBillingData.newBankEntityCode, 9999) + .write(selectors.clientBillingData.newBankEntityBIC, 'GTHMCT') + .waitToClick(selectors.clientBillingData.acceptBankEntityButton) + .waitToGetProperty(`${selectors.clientBillingData.swiftBicAutocomplete} input`, 'value'); + + expect(newcode).toEqual('GTHMCT Gotham City Bank'); + }); + + it(`should confirm the IBAN pay method is sucessfully saved`, async() => { + const payMethod = await nightmare + .waitToGetProperty(`${selectors.clientBillingData.payMethodAutocomplete} input`, 'value'); + + expect(payMethod).toEqual('PayMethod with IBAN'); + }); + + it(`should clear the BIC code field, update the IBAN to see how he BIC code autocompletes`, async() => { + const AutomaticCode = await nightmare + .clearInput(selectors.clientBillingData.IBANInput) + .waitToClick(selectors.clientBillingData.clearswiftBicButton) + .write(selectors.clientBillingData.IBANInput, 'ES9121000418450200051332') + .waitToGetProperty(`${selectors.clientBillingData.swiftBicAutocomplete} input`, 'value'); + + expect(AutomaticCode).toEqual('CAIXESBB Caixa Bank'); + }); + + it(`should save the form with all its new data`, async() => { + const snackbarMessages = await nightmare + .waitToClick(selectors.clientBillingData.saveButton) + .waitForSnackbar(); + + expect(snackbarMessages).toEqual(jasmine.arrayContaining(['Data saved!'])); + }); + + it('should confirm the due day have been edited', async() => { + const dueDate = await nightmare + .waitToGetProperty(selectors.clientBillingData.dueDayInput, 'value'); + + expect(dueDate).toEqual('60'); + }); + + it('should confirm the IBAN was saved', async() => { + const IBAN = await nightmare + .waitToGetProperty(selectors.clientBillingData.IBANInput, 'value'); + + expect(IBAN).toEqual('ES9121000418450200051332'); + }); + + it('should confirm the swift / BIC code was saved', async() => { + const code = await nightmare + .waitToGetProperty(`${selectors.clientBillingData.swiftBicAutocomplete} input`, 'value'); + + expect(code).toEqual('CAIXESBB Caixa Bank'); + }); + + it('should confirm Received LCR checkbox is checked', async() => { + const result = await nightmare + .checkboxState(selectors.clientBillingData.receivedCoreLCRCheckbox); + + expect(result).toBe('checked'); + }); + + it('should confirm Received core VNL checkbox is unchecked', async() => { + const result = await nightmare + .checkboxState(selectors.clientBillingData.receivedCoreVNLCheckbox); + + expect(result).toBe('unchecked'); + }); + + it('should confirm Received B2B VNL checkbox is unchecked', async() => { + const result = await nightmare + .checkboxState(selectors.clientBillingData.receivedB2BVNLCheckbox); + + expect(result).toBe('unchecked'); + }); +}); diff --git a/e2e/paths/02-client-module/04_edit_pay_method.spec.js b/e2e/paths/02-client-module/04_edit_pay_method.spec.js deleted file mode 100644 index c315371e0..000000000 --- a/e2e/paths/02-client-module/04_edit_pay_method.spec.js +++ /dev/null @@ -1,121 +0,0 @@ -import selectors from '../../helpers/selectors.js'; -import createNightmare from '../../helpers/nightmare'; - -describe('Client Edit pay method path', () => { - const nightmare = createNightmare(); - - beforeAll(() => { - nightmare - .loginAndModule('administrative', 'client') - .accessToSearchResult('Bruce Banner') - .accessToSection('client.card.billingData'); - }); - - it(`should attempt to edit the Pay method without an IBAN but fail`, async() => { - const snackbarMessage = await nightmare - .autocompleteSearch(selectors.clientPayMethod.payMethodAutocomplete, 'PayMethod with IBAN') - .autocompleteSearch(selectors.clientPayMethod.swiftBicAutocomplete, 'BBKKESMMMMM') - .clearInput(selectors.clientPayMethod.dueDayInput) - .write(selectors.clientPayMethod.dueDayInput, '60') - .waitForTextInInput(selectors.clientPayMethod.dueDayInput, '60') - .waitToClick(selectors.clientPayMethod.receivedCoreLCRCheckbox) - .waitToClick(selectors.clientPayMethod.receivedCoreVNLCheckbox) - .waitToClick(selectors.clientPayMethod.receivedB2BVNLCheckbox) - .waitToClick(selectors.clientPayMethod.saveButton) - .waitForLastSnackbar(); - - expect(snackbarMessage).toEqual('That payment method requires an IBAN'); - }); - - it(`should add the IBAN but fail as it requires a BIC code`, async() => { - const snackbarMessage = await nightmare - .waitToClick(selectors.clientPayMethod.clearswiftBicButton) - .clearInput(selectors.clientPayMethod.IBANInput) - .write(selectors.clientPayMethod.IBANInput, 'FR9121000418450200051332') - .waitForTextInInput(selectors.clientPayMethod.IBANInput, 'FR9121000418450200051332') - .wait(1000) - .waitToClick(selectors.clientPayMethod.saveButton) - .waitForLastSnackbar(); - - expect(snackbarMessage).toEqual('That payment method requires a BIC'); - }); - - it(`should create a new BIC code`, async() => { - const newcode = await nightmare - .waitToClick(selectors.clientPayMethod.newBankEntityButton) - .write(selectors.clientPayMethod.newBankEntityName, 'Gotham City Bank') - .write(selectors.clientPayMethod.newBankEntityCode, 9999) - .write(selectors.clientPayMethod.newBankEntityBIC, 'GTHMCT') - .waitToClick(selectors.clientPayMethod.acceptBankEntityButton) - .waitToGetProperty(`${selectors.clientPayMethod.swiftBicAutocomplete} input`, 'value'); - - expect(newcode).toEqual('GTHMCT Gotham City Bank'); - }); - - it(`should confirm the IBAN pay method is sucessfully saved`, async() => { - const payMethod = await nightmare - .waitToGetProperty(`${selectors.clientPayMethod.payMethodAutocomplete} input`, 'value'); - - expect(payMethod).toEqual('PayMethod with IBAN'); - }); - - it(`should clear the BIC code field, update the IBAN to see how he BIC code autocompletes`, async() => { - const AutomaticCode = await nightmare - .clearInput(selectors.clientPayMethod.IBANInput) - .waitToClick(selectors.clientPayMethod.clearswiftBicButton) - .write(selectors.clientPayMethod.IBANInput, 'ES9121000418450200051332') - .waitToGetProperty(`${selectors.clientPayMethod.swiftBicAutocomplete} input`, 'value'); - - expect(AutomaticCode).toEqual('CAIXESBB Caixa Bank'); - }); - - it(`should save the form with all its new data`, async() => { - const snackbarMessages = await nightmare - .waitToClick(selectors.clientPayMethod.saveButton) - .waitForSnackbar(); - - expect(snackbarMessages).toEqual(jasmine.arrayContaining(['Data saved!'])); - }); - - it('should confirm the due day have been edited', async() => { - const dueDate = await nightmare - .waitToGetProperty(selectors.clientPayMethod.dueDayInput, 'value'); - - expect(dueDate).toEqual('60'); - }); - - it('should confirm the IBAN was saved', async() => { - const IBAN = await nightmare - .waitToGetProperty(selectors.clientPayMethod.IBANInput, 'value'); - - expect(IBAN).toEqual('ES9121000418450200051332'); - }); - - it('should confirm the swift / BIC code was saved', async() => { - const code = await nightmare - .waitToGetProperty(`${selectors.clientPayMethod.swiftBicAutocomplete} input`, 'value'); - - expect(code).toEqual('CAIXESBB Caixa Bank'); - }); - - it('should confirm Received LCR checkbox is checked', async() => { - const result = await nightmare - .checkboxState(selectors.clientPayMethod.receivedCoreLCRCheckbox); - - expect(result).toBe('checked'); - }); - - it('should confirm Received core VNL checkbox is unchecked', async() => { - const result = await nightmare - .checkboxState(selectors.clientPayMethod.receivedCoreVNLCheckbox); - - expect(result).toBe('unchecked'); - }); - - it('should confirm Received B2B VNL checkbox is unchecked', async() => { - const result = await nightmare - .checkboxState(selectors.clientPayMethod.receivedB2BVNLCheckbox); - - expect(result).toBe('unchecked'); - }); -}); diff --git a/e2e/paths/02-client-module/14_risk.spec.js b/e2e/paths/02-client-module/14_risk.spec.js index 58cfb5b6e..93f68d144 100644 --- a/e2e/paths/02-client-module/14_risk.spec.js +++ b/e2e/paths/02-client-module/14_risk.spec.js @@ -1,7 +1,7 @@ import selectors from '../../helpers/selectors.js'; import createNightmare from '../../helpers/nightmare'; -describe('Client risk path', () => { +describe('Client balance path', () => { const nightmare = createNightmare(); beforeAll(() => { @@ -19,10 +19,10 @@ describe('Client risk path', () => { expect(result).toEqual('Data saved!'); }); - it('should access to the risk section to check the data shown matches the local settings', async() => { + it('should access to the balance section to check the data shown matches the local settings', async() => { let result = await nightmare - .accessToSection('client.card.risk.index') - .waitToGetProperty(`${selectors.clientRisk.companyAutocomplete} input`, 'value'); + .accessToSection('client.card.balance.index') + .waitToGetProperty(`${selectors.clientBalance.companyAutocomplete} input`, 'value'); expect(result).toEqual('CCs'); }); @@ -38,19 +38,19 @@ describe('Client risk path', () => { it('should click the new payment button', async() => { let url = await nightmare - .reloadSection('client.card.risk.index') - .waitToClick(selectors.clientRisk.newPaymentButton) - .waitForURL('/risk') + .reloadSection('client.card.balance.index') + .waitToClick(selectors.clientBalance.newPaymentButton) + .waitForURL('/balance') .parsedUrl(); - expect(url.hash).toContain('/risk'); + expect(url.hash).toContain('/balance'); }); it('should create a new payment that clears the debt', async() => { let result = await nightmare - .clearInput(selectors.clientRisk.newPaymentBankInut) - .write(selectors.clientRisk.newPaymentBankInut, '2') - .waitToClick(selectors.clientRisk.saveButton) + .clearInput(selectors.clientBalance.newPaymentBankInut) + .write(selectors.clientBalance.newPaymentBankInut, '2') + .waitToClick(selectors.clientBalance.saveButton) .waitForLastSnackbar(); expect(result).toContain('Data saved!'); @@ -58,30 +58,30 @@ describe('Client risk path', () => { it('should check balance is now 0 and the company is now VNL becouse the user local settings were removed', async() => { let company = await nightmare - .waitToGetProperty(`${selectors.clientRisk.companyAutocomplete} input`, 'value'); + .waitToGetProperty(`${selectors.clientBalance.companyAutocomplete} input`, 'value'); - let firstRiskLineBalance = await nightmare - .waitToGetProperty(selectors.clientRisk.firstRiskLineBalance, 'innerText'); + let firstBalanceLine = await nightmare + .waitToGetProperty(selectors.clientBalance.firstBalanceLine, 'innerText'); expect(company).toEqual('VNL'); - expect(firstRiskLineBalance).toContain('0.00'); + expect(firstBalanceLine).toContain('0.00'); }); it('should now click the new payment button', async() => { let url = await nightmare - .waitToClick(selectors.clientRisk.newPaymentButton) - .waitForURL('/risk') + .waitToClick(selectors.clientBalance.newPaymentButton) + .waitForURL('/balance') .parsedUrl(); - expect(url.hash).toContain('/risk'); + expect(url.hash).toContain('/balance'); }); it('should create a new payment that sets the balance to positive value', async() => { let result = await nightmare - .clearInput(selectors.clientRisk.newPaymentAmountInput) - .write(selectors.clientRisk.newPaymentAmountInput, '100') - .waitToClick(selectors.clientRisk.saveButton) + .clearInput(selectors.clientBalance.newPaymentAmountInput) + .write(selectors.clientBalance.newPaymentAmountInput, '100') + .waitToClick(selectors.clientBalance.saveButton) .waitForLastSnackbar(); expect(result).toContain('Data saved!'); @@ -89,26 +89,26 @@ describe('Client risk path', () => { it('should check balance is now 100', async() => { let result = await nightmare - .waitToGetProperty(selectors.clientRisk.firstRiskLineBalance, 'innerText'); + .waitToGetProperty(selectors.clientBalance.firstBalanceLine, 'innerText'); expect(result).toContain('100.00'); }); it('should again click the new payment button', async() => { let url = await nightmare - .waitToClick(selectors.clientRisk.newPaymentButton) - .waitForURL('/risk') + .waitToClick(selectors.clientBalance.newPaymentButton) + .waitForURL('/balance') .parsedUrl(); - expect(url.hash).toContain('/risk'); + expect(url.hash).toContain('/balance'); }); it('should create a new payment that sets the balance back to the original negative value', async() => { let result = await nightmare - .clearInput(selectors.clientRisk.newPaymentAmountInput) - .write(selectors.clientRisk.newPaymentAmountInput, '-150') + .clearInput(selectors.clientBalance.newPaymentAmountInput) + .write(selectors.clientBalance.newPaymentAmountInput, '-150') .wait(1999) - .waitToClick(selectors.clientRisk.saveButton) + .waitToClick(selectors.clientBalance.saveButton) .waitForLastSnackbar(); expect(result).toContain('Data saved!'); @@ -116,7 +116,7 @@ describe('Client risk path', () => { it('should check balance is now -50', async() => { let result = await nightmare - .waitToGetProperty(selectors.clientRisk.firstRiskLineBalance, 'innerText'); + .waitToGetProperty(selectors.clientBalance.firstBalanceLine, 'innerText'); expect(result).toContain('€50.00'); }); @@ -143,20 +143,20 @@ describe('Client risk path', () => { expect(resultCount).toEqual(1); }); - it(`should click on the search result to access to the client's risk`, async() => { + it(`should click on the search result to access to the client's balance`, async() => { let url = await nightmare .waitForTextInElement(selectors.clientsIndex.searchResult, 'Petter Parker') .waitToClick(selectors.clientsIndex.searchResult) - .waitToClick(selectors.clientRisk.riskButton) - .waitForURL('/risk') + .waitToClick(selectors.clientBalance.balanceButton) + .waitForURL('/balance') .parsedUrl(); - expect(url.hash).toContain('/risk'); + expect(url.hash).toContain('/balance'); }); it('should not be able to click the new payment button as it isnt present', async() => { let result = await nightmare - .exists(selectors.clientRisk.newPaymentButton); + .exists(selectors.clientBalance.newPaymentButton); expect(result).toBeFalsy(); }); diff --git a/e2e/paths/04-item-module/01_summary.spec.js b/e2e/paths/04-item-module/01_summary.spec.js index e4b27d127..1cbfc4af8 100644 --- a/e2e/paths/04-item-module/01_summary.spec.js +++ b/e2e/paths/04-item-module/01_summary.spec.js @@ -84,7 +84,7 @@ describe('Item summary path', () => { const result = await nightmare .clearInput('vn-item-index vn-searchbar input') .waitToClick(selectors.itemsIndex.searchButton) - .write(selectors.itemsIndex.searchItemInput, 'Melee weapon combat first 15cm') + .write(selectors.itemsIndex.searchItemInput, 'Melee weapon combat fist 15cm') .waitToClick(selectors.itemsIndex.searchButton) .waitForNumberOfElements(selectors.itemsIndex.searchResult, 1) .countElement(selectors.itemsIndex.searchResult); @@ -94,7 +94,7 @@ describe('Item summary path', () => { it(`should now click on the search result summary button to open the item summary popup`, async() => { const isVisibleBefore = await nightmare - .waitForTextInElement(selectors.itemsIndex.searchResult, 'Melee weapon combat first 15cm') + .waitForTextInElement(selectors.itemsIndex.searchResult, 'Melee weapon combat fist 15cm') .isVisible(selectors.itemSummary.basicData); const isVisibleAfter = await nightmare @@ -108,10 +108,10 @@ describe('Item summary path', () => { it(`should now check the item summary preview shows fields from basic data`, async() => { const result = await nightmare - .waitForTextInElement(selectors.itemSummary.basicData, 'Melee weapon combat first 15cm') + .waitForTextInElement(selectors.itemSummary.basicData, 'Melee weapon combat fist 15cm') .waitToGetProperty(selectors.itemSummary.basicData, 'innerText'); - expect(result).toContain('Melee weapon combat first 15cm'); + expect(result).toContain('Melee weapon combat fist 15cm'); }); it(`should now check the item summary preview shows fields from tags`, async() => { @@ -172,10 +172,10 @@ describe('Item summary path', () => { it(`should check the item summary shows fields from basic data section`, async() => { const result = await nightmare - .waitForTextInElement(selectors.itemSummary.basicData, 'Melee weapon combat first 15cm') + .waitForTextInElement(selectors.itemSummary.basicData, 'Melee weapon combat fist 15cm') .waitToGetProperty(selectors.itemSummary.basicData, 'innerText'); - expect(result).toContain('Melee weapon combat first 15cm'); + expect(result).toContain('Melee weapon combat fist 15cm'); }); it(`should check the item summary shows fields from tags section`, async() => { diff --git a/e2e/paths/04-item-module/02_basic_data.spec.js b/e2e/paths/04-item-module/02_basic_data.spec.js index 257b12e17..ebab836bf 100644 --- a/e2e/paths/04-item-module/02_basic_data.spec.js +++ b/e2e/paths/04-item-module/02_basic_data.spec.js @@ -7,8 +7,8 @@ describe('Item Edit basic data path', () => { beforeAll(() => { nightmare .loginAndModule('buyer', 'item') - .accessToSearchResult('Melee weapon combat first 15cm') - .accessToSection('item.card.data'); + .accessToSearchResult('Melee weapon combat fist 15cm') + .accessToSection('item.card.basicData'); }); it(`should check the descritor edit button is visible for buyer`, async() => { @@ -39,7 +39,7 @@ describe('Item Edit basic data path', () => { it(`should confirm the item name was edited`, async() => { const result = await nightmare - .reloadSection('item.card.data') + .reloadSection('item.card.basicData') .waitToGetProperty(selectors.itemBasicData.nameInput, 'value'); expect(result).toEqual('Rose of Purity'); diff --git a/e2e/paths/04-item-module/09_regularize.spec.js b/e2e/paths/04-item-module/09_regularize.spec.js index 23d8904e4..8d352b493 100644 --- a/e2e/paths/04-item-module/09_regularize.spec.js +++ b/e2e/paths/04-item-module/09_regularize.spec.js @@ -1,8 +1,7 @@ import selectors from '../../helpers/selectors.js'; import createNightmare from '../../helpers/nightmare'; -// #1186 repearar e2e ticket.sale, item.regularize. -xdescribe('Item regularize path', () => { +describe('Item regularize path', () => { const nightmare = createNightmare(); beforeAll(() => { nightmare @@ -177,7 +176,7 @@ xdescribe('Item regularize path', () => { it('should search for the ticket with id 23 once again', async() => { const result = await nightmare - .write(selectors.ticketsIndex.searchTicketInput, 'id:24') + .write(selectors.ticketsIndex.searchTicketInput, 23) .waitToClick(selectors.ticketsIndex.searchButton) .waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1) .countElement(selectors.ticketsIndex.searchResult); @@ -187,7 +186,7 @@ xdescribe('Item regularize path', () => { it(`should now click on the search result to access to the ticket summary`, async() => { const url = await nightmare - .waitForTextInElement(selectors.ticketsIndex.searchResult, '24') + .waitForTextInElement(selectors.ticketsIndex.searchResult, '23') .waitToClick(selectors.ticketsIndex.searchResult) .waitForURL('/summary') .parsedUrl(); diff --git a/e2e/paths/04-item-module/12_descriptor.spec.js b/e2e/paths/04-item-module/12_descriptor.spec.js index e5b6b2c2f..d008d0d4e 100644 --- a/e2e/paths/04-item-module/12_descriptor.spec.js +++ b/e2e/paths/04-item-module/12_descriptor.spec.js @@ -7,7 +7,7 @@ describe('Item descriptor path', () => { nightmare .loginAndModule('buyer', 'item') .accessToSearchResult(1) - .accessToSection('item.card.data'); + .accessToSection('item.card.basicData'); }); it('should check the descriptor inactive icon is dark as the item is active', async() => { @@ -30,7 +30,7 @@ describe('Item descriptor path', () => { it('should reload the section and check the inactive icon is bright', async() => { let brightIcon = await nightmare - .reloadSection('item.card.data') + .reloadSection('item.card.basicData') .waitForClassPresent(selectors.itemDescriptor.inactiveIcon, 'bright') .isVisible(selectors.itemDescriptor.inactiveIcon); diff --git a/e2e/paths/05-ticket-module/04_create_ticket_packages.spec.js b/e2e/paths/05-ticket-module/04_create_ticket_packages.spec.js index 3c2f0b123..30324aec2 100644 --- a/e2e/paths/05-ticket-module/04_create_ticket_packages.spec.js +++ b/e2e/paths/05-ticket-module/04_create_ticket_packages.spec.js @@ -8,7 +8,7 @@ describe('Ticket Create packages path', () => { return nightmare .loginAndModule('employee', 'ticket') .accessToSearchResult('id:1') - .accessToSection('ticket.card.package.index'); + .accessToSection('ticket.card.package'); }); it(`should attempt create a new package but receive an error if package is blank`, async() => { @@ -53,7 +53,7 @@ describe('Ticket Create packages path', () => { it(`should confirm the first select is the expected one`, async() => { const result = await nightmare - .reloadSection('ticket.card.package.index') + .reloadSection('ticket.card.package') .waitForTextInInput(`${selectors.ticketPackages.firstPackageAutocomplete} input`, 'Container medical box 1m') .waitToGetProperty(`${selectors.ticketPackages.firstPackageAutocomplete} input`, 'value'); diff --git a/e2e/paths/05-ticket-module/05_create_new_tracking_state.spec.js b/e2e/paths/05-ticket-module/05_create_new_tracking_state.spec.js index 787809a86..a67c3fc1d 100644 --- a/e2e/paths/05-ticket-module/05_create_new_tracking_state.spec.js +++ b/e2e/paths/05-ticket-module/05_create_new_tracking_state.spec.js @@ -88,7 +88,7 @@ describe('Ticket Create new tracking state path', () => { it(`should create a new state with all it's data`, async() => { let result = await nightmare - .autocompleteSearch(selectors.createStateView.workerAutocomplete, 'accessory') + .autocompleteSearch(selectors.createStateView.workerAutocomplete, 'replenisher') .waitToClick(selectors.createStateView.saveStateButton) .waitForLastSnackbar(); diff --git a/e2e/paths/05-ticket-module/06_edit_basic_data_steps.spec.js b/e2e/paths/05-ticket-module/06_edit_basic_data_steps.spec.js index ebdace2a7..7e44c473b 100644 --- a/e2e/paths/05-ticket-module/06_edit_basic_data_steps.spec.js +++ b/e2e/paths/05-ticket-module/06_edit_basic_data_steps.spec.js @@ -8,7 +8,7 @@ describe('Ticket Edit basic data path', () => { return nightmare .loginAndModule('employee', 'ticket') .accessToSearchResult('id:11') - .accessToSection('ticket.card.data.stepOne'); + .accessToSection('ticket.card.basicData.stepOne'); }); it(`should edit the client and address of the ticket then click next`, async() => { diff --git a/e2e/paths/05-ticket-module/07_edit_sale.spec.js b/e2e/paths/05-ticket-module/07_edit_sale.spec.js index f339f6a57..3deffa33b 100644 --- a/e2e/paths/05-ticket-module/07_edit_sale.spec.js +++ b/e2e/paths/05-ticket-module/07_edit_sale.spec.js @@ -1,7 +1,7 @@ import selectors from '../../helpers/selectors.js'; import createNightmare from '../../helpers/nightmare'; -// #1186 repearar e2e ticket.sale, item.regularize. +// #1387 e2e Ticket Edit sale path xdescribe('Ticket Edit sale path', () => { const nightmare = createNightmare(); diff --git a/e2e/paths/05-ticket-module/12_descriptor.spec.js b/e2e/paths/05-ticket-module/12_descriptor.spec.js index b8e610891..5d47d504d 100644 --- a/e2e/paths/05-ticket-module/12_descriptor.spec.js +++ b/e2e/paths/05-ticket-module/12_descriptor.spec.js @@ -148,4 +148,43 @@ describe('Ticket descriptor path', () => { expect(exists).toBeFalsy(); }); }); + + describe('Make invoice', () => { + it('should login as adminBoss role then search for a ticket', async() => { + const invoiceableTicketId = 11; + + const url = await nightmare + .loginAndModule('adminBoss', 'ticket') + .accessToSearchResult(invoiceableTicketId) + .waitForURL('/summary') + .parsedUrl(); + + expect(url.hash).toContain(`ticket/${invoiceableTicketId}/summary`); + }); + + it(`should make sure the ticket doesn't have an invoiceOutFk yet`, async() => { + const result = await nightmare + .waitToGetProperty(selectors.ticketSummary.invoiceOutRef, 'innerText'); + + expect(result).toEqual('-'); + }); + + it('should invoice the ticket using the descriptor more menu', async() => { + const result = await nightmare + .waitToClick(selectors.ticketDescriptor.moreMenu) + .waitToClick(selectors.ticketDescriptor.moreMenuMakeInvoice) + .waitToClick(selectors.ticketDescriptor.acceptInvoiceOutButton) + .waitForLastSnackbar(); + + expect(result).toEqual('Ticket invoiced'); + }); + + it(`should make sure the ticket summary have an invoiceOutFk`, async() => { + const result = await nightmare + .waitForTextInElement(selectors.ticketSummary.invoiceOutRef, 'T4444445') + .waitToGetProperty(selectors.ticketSummary.invoiceOutRef, 'innerText'); + + expect(result).toEqual('T4444445'); + }); + }); }); diff --git a/e2e/paths/05-ticket-module/13_create_ticket_services.spec.js b/e2e/paths/05-ticket-module/13_create_ticket_services.spec.js index 5a35ba337..90373366b 100644 --- a/e2e/paths/05-ticket-module/13_create_ticket_services.spec.js +++ b/e2e/paths/05-ticket-module/13_create_ticket_services.spec.js @@ -7,7 +7,7 @@ describe('Ticket services path', () => { beforeAll(() => { nightmare .loginAndModule('employee', 'ticket') - .accessToSearchResult('1') + .accessToSearchResult(8) .accessToSection('ticket.card.service'); }); diff --git a/front/core/components/calendar/index.js b/front/core/components/calendar/index.js index 8948b5d65..bc356053b 100644 --- a/front/core/components/calendar/index.js +++ b/front/core/components/calendar/index.js @@ -3,7 +3,7 @@ import Component from '../../lib/component'; import './style.scss'; /** - * Calendar. + * Flat calendar. * */ export default class Calendar extends Component { diff --git a/front/core/components/date-picker/date-picker.spec.js b/front/core/components/date-picker/date-picker.spec.js index 0a81136a0..55bfb0f83 100644 --- a/front/core/components/date-picker/date-picker.spec.js +++ b/front/core/components/date-picker/date-picker.spec.js @@ -1,5 +1,4 @@ -// #937 front test datePicker awaiting loopback connector refactor to store dates correctly. -xdescribe('Component vnDatePicker', () => { +describe('Component vnDatePicker', () => { let controller; let $attrs; let $element; diff --git a/front/core/components/drop-down/drop-down.js b/front/core/components/drop-down/drop-down.js index 123df1994..d1cc11601 100755 --- a/front/core/components/drop-down/drop-down.js +++ b/front/core/components/drop-down/drop-down.js @@ -277,6 +277,7 @@ export default class DropDown extends Component { if (data) { for (let i = 0; i < data.length; i++) { let option = data[i]; + option.orgShowField = option[this.showField]; if (this.translateFields) { option = Object.assign({}, option); @@ -285,6 +286,8 @@ export default class DropDown extends Component { } let li = this.document.createElement('li'); + + li.setAttribute('name', option.orgShowField); fragment.appendChild(li); if (this.multiple) { diff --git a/front/core/components/multi-check/multi-check.html b/front/core/components/multi-check/multi-check.html index 53c0262ed..2d51324f0 100644 --- a/front/core/components/multi-check/multi-check.html +++ b/front/core/components/multi-check/multi-check.html @@ -1 +1,5 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/front/core/components/multi-check/multi-check.js b/front/core/components/multi-check/multi-check.js index 14c5d6a9a..9eb9a5148 100644 --- a/front/core/components/multi-check/multi-check.js +++ b/front/core/components/multi-check/multi-check.js @@ -10,23 +10,104 @@ import Input from '../../lib/input'; export default class MultiCheck extends Input { constructor($element, $scope) { super($element, $scope); - this._checkAll = false; + this._checked = false; this.checkField = 'checked'; + this.isIntermediate = false; } - get checkAll() { - return this._checkAll; + /** + * Gets array model instance + * + * @return {ArrayModel} - Array model instance + */ + get model() { + return this._model; } - set checkAll(value) { - this._checkAll = value; - this.switchChecks(); + /** + * Sets the array model instance + * Changes intermediate property for + * the check component + * + * @param {ArrayModel} value - Array model instance + */ + set model(value) { + this._model = value; + + if (value) { + value.on('rowChange', () => { + this.isIntermediate = !this.areAllUnchecked() && !this.areAllChecked(); + + if (this.areAllChecked()) + this._checked = true; + else if (!this.areAllChecked()) + this._checked = false; + }); + + value.on('dataChange', () => { + if (this.checked) this.toggle(); + }); + } } - switchChecks() { - if (!this.data) return; - this.data.forEach(el => { - el[this.checkField] = this._checkAll; + /** + * Gets current check state + */ + get checked() { + return this._checked; + } + + /** + * Sets current check state + * + * @param {Boolean} value - Checkbox state [undefined, true, false] + */ + set checked(value) { + this._checked = value; + this.checkAll = value; + + this.toggle(); + } + + /** + * Returns a bolean result for + * checked instances + * + * @return {Boolean} - True if all instances are checked + */ + areAllChecked() { + if (!this.model || !this.model.data) return; + + const data = this.model.data; + return data.every(item => { + return item[this.checkField] === true; + }); + } + + /** + * Returns a bolean result for + * checked instances + * + * @return {Boolean} - False if all instances are checked + */ + areAllUnchecked() { + if (!this.model || !this.model.data) return; + + const data = this.model.data; + return data.every(item => { + return item[this.checkField] === false; + }); + } + + /** + * Toggles checked property on + * all instances + */ + toggle() { + const data = this.model.data; + if (!data) return; + data.forEach(el => { + el[this.checkField] = this.checkAll; }); } } @@ -35,7 +116,7 @@ ngModule.component('vnMultiCheck', { template: require('./multi-check.html'), controller: MultiCheck, bindings: { - data: '=', + model: '<', checkField: ' { let controller; @@ -9,33 +10,94 @@ describe('Component vnMultiCheck', () => { beforeEach(angular.mock.inject($componentController => { $element = angular.element(`
`); controller = $componentController('vnMultiCheck', {$element: $element}); + controller._model = crudModel; + controller._model.data = [ + {id: 1, name: 'My item 1'}, + {id: 2, name: 'My item 2'}, + {id: 3, name: 'My item 3'} + ]; })); - describe('checkAll() setter', () => { - it(`should set controller _checkAll property with the argument received then call switchChecks()`, () => { - let argument = 'I am the model'; - spyOn(controller, 'switchChecks'); - controller.checkAll = argument; + describe('checked() setter', () => { + it(`should set controller _checked property with the argument received then call toggle()`, () => { + spyOn(controller, 'toggle'); + controller.checked = crudModel; - expect(controller._checkAll).toEqual(argument); - expect(controller.switchChecks).toHaveBeenCalledWith(); + expect(controller._checked).toEqual(crudModel); + expect(controller.toggle).toHaveBeenCalledWith(); }); }); - describe('switchChecks()', () => { + describe('toggle()', () => { it(`should set checked property inside each existing element`, () => { - controller.data = [ - {name: 'name'}, - {name: null} - ]; + const data = controller.model.data; - expect(controller.data[0].checked).not.toBeDefined(); - expect(controller.data[1].checked).not.toBeDefined(); - controller._checkAll = 1; - controller.switchChecks(); + expect(data[0].checked).not.toBeDefined(); + expect(data[1].checked).not.toBeDefined(); + expect(data[2].checked).not.toBeDefined(); - expect(controller.data[0].checked).toBeTruthy(); - expect(controller.data[1].checked).toBeTruthy(); + controller._checked = true; + controller.checkAll = true; + controller.toggle(); + + expect(data[0].checked).toBeTruthy(); + expect(data[1].checked).toBeTruthy(); + expect(data[2].checked).toBeTruthy(); + }); + + it(`should unset checked property inside each existing element`, () => { + const data = controller.model.data; + data[0].checked = true; + data[1].checked = true; + data[2].checked = true; + + controller._checked = false; + controller.checkAll = false; + controller.toggle(); + + expect(data[0].checked).toBeFalsy(); + expect(data[1].checked).toBeFalsy(); + expect(data[2].checked).toBeFalsy(); + }); + }); + + describe('areAllChecked()', () => { + it(`should set return true if all elements are checked`, () => { + const data = controller.model.data; + data[0].checked = true; + data[1].checked = true; + data[2].checked = true; + + expect(controller.areAllChecked()).toBeTruthy(); + }); + + it(`should set return false if not all elements are checked`, () => { + const data = controller.model.data; + data[0].checked = true; + data[1].checked = false; + data[2].checked = true; + + expect(controller.areAllChecked()).toBeFalsy(); + }); + }); + + describe('areAllUnchecked()', () => { + it(`should set return true if all elements are unchecked`, () => { + const data = controller.model.data; + data[0].checked = false; + data[1].checked = false; + data[2].checked = false; + + expect(controller.areAllUnchecked()).toBeTruthy(); + }); + + it(`should set return false if not all elements are unchecked`, () => { + const data = controller.model.data; + data[0].checked = false; + data[1].checked = true; + data[2].checked = false; + + expect(controller.areAllUnchecked()).toBeFalsy(); }); }); }); diff --git a/front/core/components/treeview/child.html b/front/core/components/treeview/child.html index a079d8f40..eedd63b19 100644 --- a/front/core/components/treeview/child.html +++ b/front/core/components/treeview/child.html @@ -1,18 +1,17 @@ \ No newline at end of file + {{::item.name}} + + + + + + + + +
  • + + + + +
    + Create new one +
    +
    +
  • + \ No newline at end of file diff --git a/front/core/components/treeview/child.js b/front/core/components/treeview/child.js index ca5b59efb..8fecbd89b 100644 --- a/front/core/components/treeview/child.js +++ b/front/core/components/treeview/child.js @@ -15,9 +15,8 @@ class Controller extends Component { this.treeview.onSelection(item, value); } - onClick(icon, item, parent, index) { - let parentScope = this.$scope.$parent.$parent; - let parentController = parentScope.$ctrl; + onIconClick(icon, item, parent, index) { + let parentController = this.parentScope.$ctrl; icon.callback.call(parentController, item, parent, index); } @@ -25,6 +24,10 @@ class Controller extends Component { this.treeview.onCreate(parent); } + onDrop(item, dragged, dropped) { + this.treeview.onDrop(item, dragged, dropped); + } + get isInsertable() { return Array.isArray(this.parent) || this.parent.childs; } @@ -40,7 +43,10 @@ ngModule.component('vnTreeviewChild', { disabled: ' + parent-scope="$ctrl.$scope.$parent" + draggable="$ctrl.draggable" + droppable="$ctrl.droppable" + vn-droppable="{{$ctrl.droppable}}"> diff --git a/front/core/components/treeview/index.js b/front/core/components/treeview/index.js index 9f2a0a3fa..ac4186c58 100644 --- a/front/core/components/treeview/index.js +++ b/front/core/components/treeview/index.js @@ -3,13 +3,14 @@ import Component from '../../lib/component'; import './style.scss'; /** - * A simple tooltip. + * Treeview * * @property {String} position The relative position to the parent */ export default class Treeview extends Component { constructor($element, $scope) { super($element, $scope); + this.$scope = $scope; this.data = []; } @@ -69,6 +70,10 @@ export default class Treeview extends Component { item.active = !item.active; } + + onDrop(item, dragged, dropped) { + this.emit('drop', {item, dragged, dropped}); + } } Treeview.$inject = ['$element', '$scope']; @@ -82,6 +87,8 @@ ngModule.component('vnTreeview', { disabled: ' vn-horizontal > .description { color: $color-notice; font-weight: bold; - - & > vn-check .md-icon { - background-color: $color-notice - } } + & > vn-horizontal > vn-check .md-icon { + background-color: $color-notice + } } li.excluded { & > vn-horizontal > .description { color: $color-alert; font-weight: bold; - + } + + & > vn-horizontal > vn-check .md-icon { + background-color: $color-alert; + border-color: transparent } } } diff --git a/front/core/directives/draggable.js b/front/core/directives/draggable.js new file mode 100644 index 000000000..3b68a6cb6 --- /dev/null +++ b/front/core/directives/draggable.js @@ -0,0 +1,43 @@ +import ngModule from '../module'; + +/** + * Enables a draggable element and his drag events + * + * @return {Object} The directive + */ +export function directive() { + return { + restrict: 'A', + link: function($scope, $element, $attrs) { + const element = $element[0]; + const isDraggable = $attrs.vnDraggable === 'true'; + + if (!isDraggable) return; + + // Set draggable style properties + element.style.cursor = 'move'; + + + // Enable as draggable element + element.setAttribute('draggable', true); + + /** + * Fires when a drag event starts + */ + element.addEventListener('dragstart', event => { + element.style.opacity = 0.5; + event.stopPropagation(); + }); + + /** + * Fires when a drag event ends + */ + element.addEventListener('dragend', event => { + element.style.opacity = 1; + event.stopPropagation(); + }); + } + }; +} + +ngModule.directive('vnDraggable', directive); diff --git a/front/core/directives/droppable.js b/front/core/directives/droppable.js new file mode 100644 index 000000000..b99f397c7 --- /dev/null +++ b/front/core/directives/droppable.js @@ -0,0 +1,93 @@ +import ngModule from '../module'; + + +export function directive($parse) { + return { + restrict: 'A', + link: function($scope, $element, $attrs) { + const element = $element[0]; + const onDropEvent = $parse($attrs.onDrop); + const isDroppable = $attrs.vnDroppable === 'true'; + + if (!isDroppable) return; + + /** + * Captures current dragging element + */ + element.addEventListener('dragstart', () => { + this.dragged = element; + }); + + /** + * Enter droppable area event + */ + element.addEventListener('dragenter', event => { + element.style.backgroundColor = 'yellow'; + + event.stopImmediatePropagation(); + event.preventDefault(); + }, false); + + + /** + * Exit droppable area event + */ + element.addEventListener('dragleave', event => { + element.style.backgroundColor = 'transparent'; + + event.stopImmediatePropagation(); + event.preventDefault(); + }); + + /** + * Prevent dragover for allowing + * dispatch drop event + */ + element.addEventListener('dragover', event => { + event.stopPropagation(); + event.preventDefault(); + }); + + /** + * Fires when a drop events + */ + element.addEventListener('drop', event => { + const draggedParent = this.dragged.parentNode; + const targetChild = element.querySelector('ul'); + + + element.style.transition = 'background 2s'; + element.style.backgroundColor = 'transparent'; + + if (this.dragged === element) + return event.preventDefault(); + + + if (targetChild) { + const targetNodes = targetChild.querySelectorAll('li'); + const before = targetNodes[targetNodes.length - 1]; + + targetChild.insertBefore(this.dragged, before); + } else + draggedParent.removeChild(this.dragged); + + onDropEvent($scope, { + dragged: { + element: this.dragged, + scope: angular.element(this.dragged).scope() + }, + dropped: { + element: element, + scope: angular.element(element).scope() + } + }); + + event.stopImmediatePropagation(); + }); + } + }; +} + +directive.$inject = ['$parse']; + +ngModule.directive('vnDroppable', directive); diff --git a/front/core/directives/index.js b/front/core/directives/index.js index 9aed1aea3..7db806caf 100644 --- a/front/core/directives/index.js +++ b/front/core/directives/index.js @@ -11,3 +11,5 @@ import './bind'; import './repeat-last'; import './title'; import './uvc'; +import './draggable'; +import './droppable'; diff --git a/front/core/locale/es.yml b/front/core/locale/es.yml index 7c413dd22..1b8d527c5 100644 --- a/front/core/locale/es.yml +++ b/front/core/locale/es.yml @@ -41,4 +41,5 @@ Has delivery: Hay reparto Loading: Cargando Fields to show: Campos a mostrar Create new one: Crear nuevo -Toggle: Desplegar/Plegar \ No newline at end of file +Toggle: Desplegar/Plegar +Check all: Seleccionar todo \ No newline at end of file diff --git a/front/core/mocks/crud-model.js b/front/core/mocks/crud-model.js index e86f9d63e..af6406eec 100644 --- a/front/core/mocks/crud-model.js +++ b/front/core/mocks/crud-model.js @@ -24,7 +24,14 @@ module.exports = { } }; }, + on: () => { + return { + then: callback => { + callback({data: {id: 1234}}); + } + }; + }, refresh: () => {}, addFilter: () => {}, - applyFilter: () => {} + applyFilter: () => {}, }; diff --git a/front/test-index.js b/front/test-index.js index 5a7c5c713..e5113f0db 100644 --- a/front/test-index.js +++ b/front/test-index.js @@ -24,5 +24,5 @@ window.ngModule = function(moduleName) { let testsContext = require.context('./', true, /\.spec\.js$/); testsContext.keys().forEach(testsContext); -let modulesContext = require.context('../modules/', true, /^\.\/[a-z0-9]+\/front\/.+\.spec\.js$/); +let modulesContext = require.context('../modules/', true, /^\.\/[a-zA-Z0-9-]+\/front\/.+\.spec\.js$/); modulesContext.keys().forEach(modulesContext); diff --git a/loopback/locale/en.json b/loopback/locale/en.json index b323c1c36..f7792a56a 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -41,5 +41,7 @@ "City cannot be empty": "City cannot be empty", "EXTENSION_INVALID_FORMAT": "Invalid extension", "The secret can't be blank": "The secret can't be blank", - "Invalid TIN": "Invalid Tax number" + "Invalid TIN": "Invalid Tax number", + "This ticket can't be invoiced": "This ticket can't be invoiced", + "The value should be a number": "The value should be a number" } \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 1ac73f084..96d3ad070 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -79,6 +79,7 @@ "We weren't able to send this SMS": "No hemos podido enviar el SMS", "This client can't be invoiced": "Este cliente no puede ser facturado", "This ticket can't be invoiced": "Este ticket no puede ser facturado", - "That item is not available on that day": "That item is not available on that day", - "That item doesn't exists": "That item doesn't exists" + "That item is not available on that day": "El item no esta disponible para esa fecha", + "That item doesn't exists": "That item doesn't exists", + "You cannot add or modify services to an invoiced ticket": "No puedes añadir o modificar servicios a un ticket facturado" } \ No newline at end of file diff --git a/modules/agency/front/card/index.spec.js b/modules/agency/front/card/index.spec.js index 15e8fada9..072ce5175 100644 --- a/modules/agency/front/card/index.spec.js +++ b/modules/agency/front/card/index.spec.js @@ -1,36 +1,34 @@ import './index.js'; -xdescribe('Agency', () => { - describe('Component vnZoneCard', () => { - let $scope; - let controller; - let $httpBackend; - let $stateParams; +describe('Agency Component vnZoneCard', () => { + let $scope; + let controller; + let $httpBackend; + let $stateParams; - beforeEach(ngModule('agency')); + beforeEach(ngModule('agency')); - beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => { - $httpBackend = _$httpBackend_; - $scope = $rootScope.$new(); - $stateParams = {id: 1}; - controller = $componentController('vnZoneCard', {$scope, $stateParams}); - })); + beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => { + $httpBackend = _$httpBackend_; + $scope = $rootScope.$new(); + $stateParams = {id: 1}; + controller = $componentController('vnZoneCard', {$scope, $stateParams}); + })); - describe('getCard()', () => { - it(`should make a query and define zone property`, () => { - let filter = { - include: [ - {relation: 'warehouse', fields: ['name']}, - {relation: 'agencyMode', fields: ['name']} - ] - }; - let json = encodeURIComponent(JSON.stringify(filter)); - $httpBackend.expectGET(`/agency/api/Zones/1?filter=${json}`).respond({id: 1}); - controller.getCard(); - $httpBackend.flush(); + describe('getCard()', () => { + it(`should make a query and define zone property`, () => { + let filter = { + include: [ + {relation: 'warehouse', fields: ['name']}, + {relation: 'agencyMode', fields: ['name']} + ] + }; + let json = encodeURIComponent(JSON.stringify(filter)); + $httpBackend.expectGET(`/agency/api/Zones/1?filter=${json}`).respond({id: 1}); + controller.getCard(); + $httpBackend.flush(); - expect(controller.zone).toEqual({id: 1}); - }); + expect(controller.zone).toEqual({id: 1}); }); }); }); diff --git a/modules/agency/front/create/index.spec.js b/modules/agency/front/create/index.spec.js index 70e061612..5b2a022f8 100644 --- a/modules/agency/front/create/index.spec.js +++ b/modules/agency/front/create/index.spec.js @@ -1,40 +1,39 @@ import './index'; import watcher from 'core/mocks/watcher'; -xdescribe('Agency', () => { - describe('Component vnZoneCreate', () => { - let $scope; - let $state; - let controller; +describe('Agency Component vnZoneCreate', () => { + let $scope; + let $state; + let controller; - beforeEach(ngModule('agency')); + beforeEach(ngModule('agency')); - beforeEach(angular.mock.inject(($componentController, $rootScope, _$state_) => { - $scope = $rootScope.$new(); - $state = _$state_; - $scope.watcher = watcher; - $scope.watcher.submit = () => { - return { - then: callback => { - callback({data: {id: 1234}}); - } - }; + beforeEach(angular.mock.inject(($componentController, $rootScope, _$state_) => { + $scope = $rootScope.$new(); + $state = _$state_; + $scope.watcher = watcher; + $scope.watcher.submit = () => { + return { + then: callback => { + callback({data: {id: 1234}}); + } }; - controller = $componentController('vnZoneCreate', {$scope}); - })); + }; + controller = $componentController('vnZoneCreate', {$scope}); + })); - describe('onSubmit()', () => { - it(`should call submit() on the watcher then expect a callback`, () => { - spyOn($state, 'go'); + describe('onSubmit()', () => { + it(`should call submit() on the watcher then expect a callback`, () => { + spyOn($state, 'go'); - controller.zone = { - name: 'Zone One' - }; + controller.zone = { + name: 'Zone One' + }; - controller.onSubmit(); + controller.onSubmit(); - expect(controller.$state.go).toHaveBeenCalledWith('zone.card.basicData', {id: 1234}); - }); + expect(controller.$state.go).toHaveBeenCalledWith('zone.card.location', Object({id: 1234})); }); }); }); + diff --git a/modules/agency/front/index/index.spec.js b/modules/agency/front/index/index.spec.js index 2e5e5d013..8ded387bd 100644 --- a/modules/agency/front/index/index.spec.js +++ b/modules/agency/front/index/index.spec.js @@ -1,41 +1,39 @@ import './index.js'; -xdescribe('Agency', () => { - describe('Component vnZoneIndex', () => { - let $componentController; - let controller; +describe('Agency Component vnZoneIndex', () => { + let $componentController; + let controller; - beforeEach(ngModule('agency')); + beforeEach(ngModule('agency')); - beforeEach(angular.mock.inject(_$componentController_ => { - $componentController = _$componentController_; - controller = $componentController('vnZoneIndex'); - })); + beforeEach(angular.mock.inject(_$componentController_ => { + $componentController = _$componentController_; + controller = $componentController('vnZoneIndex'); + })); - describe('exprBuilder()', () => { - it('should return a formated object with the id in case of search', () => { - let param = 'search'; - let value = 1; - let result = controller.exprBuilder(param, value); + describe('exprBuilder()', () => { + it('should return a formated object with the id in case of search', () => { + let param = 'search'; + let value = 1; + let result = controller.exprBuilder(param, value); - expect(result).toEqual({id: 1}); - }); + expect(result).toEqual({id: 1}); + }); - it('should return a formated object with the warehouseFk in case of warehouseFk', () => { - let param = 'warehouseFk'; - let value = 'Silla'; - let result = controller.exprBuilder(param, value); + it('should return a formated object with the warehouseFk in case of warehouseFk', () => { + let param = 'warehouseFk'; + let value = 'Silla'; + let result = controller.exprBuilder(param, value); - expect(result).toEqual({warehouseFk: 'Silla'}); - }); + expect(result).toEqual({warehouseFk: 'Silla'}); + }); - it('should return a formated object with the warehouseFk in case of warehouseFk', () => { - let param = 'agencyModeFk'; - let value = 'My Delivery'; - let result = controller.exprBuilder(param, value); + it('should return a formated object with the warehouseFk in case of agencyModeFk', () => { + let param = 'agencyModeFk'; + let value = 'My Delivery'; + let result = controller.exprBuilder(param, value); - expect(result).toEqual({agencyModeFk: 'My Delivery'}); - }); + expect(result).toEqual({agencyModeFk: 'My Delivery'}); }); }); }); diff --git a/modules/agency/front/location/index.html b/modules/agency/front/location/index.html index c33a71e3c..42662ef2b 100644 --- a/modules/agency/front/location/index.html +++ b/modules/agency/front/location/index.html @@ -12,8 +12,9 @@ on-search="$ctrl.onSearch()" vn-focus> - + diff --git a/modules/claim/back/methods/claim/filter.js b/modules/claim/back/methods/claim/filter.js index 7a8f3c40c..38212d004 100644 --- a/modules/claim/back/methods/claim/filter.js +++ b/modules/claim/back/methods/claim/filter.js @@ -99,7 +99,7 @@ module.exports = Self => { let stmt; stmt = new ParameterizedSQL( - `SELECT cl.id, c.name, u.nickName, cs.description, cl.created + `SELECT cl.id, c.name, cl.clientFk, cl.workerFk, u.nickName, cs.description, cl.created FROM claim cl LEFT JOIN client c ON c.id = cl.clientFk LEFT JOIN worker w ON w.id = cl.workerFk diff --git a/modules/claim/front/action/index.spec.js b/modules/claim/front/action/index.spec.js index 9842bf646..0823b19ef 100644 --- a/modules/claim/front/action/index.spec.js +++ b/modules/claim/front/action/index.spec.js @@ -161,11 +161,13 @@ describe('claim', () => { describe('onUpdateGreugeResponse()', () => { it('should do nothing', () => { + spyOn(controller.$http, 'post'); spyOn(controller.card, 'reload'); spyOn(controller.vnApp, 'showSuccess'); controller.onUpdateGreugeResponse('CANCEL'); + expect(controller.$http.post).not.toHaveBeenCalledWith(); expect(controller.card.reload).not.toHaveBeenCalledWith(); expect(controller.vnApp.showSuccess).not.toHaveBeenCalledWith('Greuge inserted!'); }); diff --git a/modules/claim/front/descriptor/index.html b/modules/claim/front/descriptor/index.html index 27d984fb6..2c6af5965 100644 --- a/modules/claim/front/descriptor/index.html +++ b/modules/claim/front/descriptor/index.html @@ -26,7 +26,7 @@ value="{{$ctrl.claim.claimState.description}}"> + value="{{$ctrl.claim.created | dateTime: 'dd/MM/yyyy HH:mm'}}"> diff --git a/modules/claim/front/index/index.html b/modules/claim/front/index/index.html index f6945e834..4d15eaba5 100644 --- a/modules/claim/front/index/index.html +++ b/modules/claim/front/index/index.html @@ -35,7 +35,7 @@ ui-sref="claim.card.summary({id: claim.id})"> {{::claim.id}} - + {{::claim.name}} @@ -43,7 +43,7 @@ + ng-click="$ctrl.showWorkerDescriptor($event, claim.workerFk)"> {{::claim.nickName}} @@ -68,7 +68,7 @@ + worker-fk="$ctrl.selectedWorker"> diff --git a/modules/claim/front/index/index.js b/modules/claim/front/index/index.js index c8462bc48..21464fea9 100644 --- a/modules/claim/front/index/index.js +++ b/modules/claim/front/index/index.js @@ -25,10 +25,10 @@ export default class Controller { event.stopImmediatePropagation(); } - showWorkerDescriptor(event, userId) { + showWorkerDescriptor(event, workerFk) { event.preventDefault(); event.stopImmediatePropagation(); - this.selectedWorker = userId; + this.selectedWorker = workerFk; this.$.workerDescriptor.parent = event.target; this.$.workerDescriptor.show(); } diff --git a/modules/claim/front/summary/index.html b/modules/claim/front/summary/index.html index ec650c86e..0e4b62a09 100644 --- a/modules/claim/front/summary/index.html +++ b/modules/claim/front/summary/index.html @@ -93,7 +93,7 @@ + ng-click="$ctrl.showWorkerDescriptor($event, development.workerFk)"> {{::development.worker.user.nickname}} @@ -156,7 +156,7 @@ + worker-fk="$ctrl.selectedWorker"> diff --git a/modules/claim/front/summary/index.js b/modules/claim/front/summary/index.js index b8fedca7a..4a953ca9e 100644 --- a/modules/claim/front/summary/index.js +++ b/modules/claim/front/summary/index.js @@ -32,8 +32,8 @@ class Controller { this.$.itemDescriptor.show(); } - showWorkerDescriptor(event, userId) { - this.selectedWorker = userId; + showWorkerDescriptor(event, workerFk) { + this.selectedWorker = workerFk; this.$.workerDescriptor.parent = event.target; this.$.workerDescriptor.show(); } diff --git a/modules/client/back/methods/client/listWorkers.js b/modules/client/back/methods/client/listWorkers.js index 92339e32f..8fa4c085e 100644 --- a/modules/client/back/methods/client/listWorkers.js +++ b/modules/client/back/methods/client/listWorkers.js @@ -16,14 +16,14 @@ module.exports = function(Self) { Self.listWorkers = function() { let query = `SELECT w.id, - CONCAT(w.firstName, IFNULL(CONCAT(" ", w.name), "")) \`name\` + CONCAT(w.firstName, IFNULL(CONCAT(" ", w.lastName), "")) \`name\` FROM worker w JOIN account.user u ON w.userFk = u.id JOIN account.roleRole rr ON rr.role = u.role JOIN account.role r ON r.id = rr.inheritsFrom WHERE u.active AND r.\`name\` = 'employee' - ORDER BY w.name ASC`; + ORDER BY w.lastName ASC`; return Self.rawSql(query); }; diff --git a/modules/client/back/methods/client/specs/getCard.spec.js b/modules/client/back/methods/client/specs/getCard.spec.js index 821dd23f7..04cb7918e 100644 --- a/modules/client/back/methods/client/specs/getCard.spec.js +++ b/modules/client/back/methods/client/specs/getCard.spec.js @@ -7,6 +7,6 @@ describe('Client get', () => { expect(result.id).toEqual(101); expect(result.name).toEqual('Bruce Wayne'); - expect(result.debt).toEqual(329.13); + expect(result.debt).toEqual(-14.78); }); }); diff --git a/modules/client/back/methods/client/specs/getDebt.spec.js b/modules/client/back/methods/client/specs/getDebt.spec.js index b69ae8624..2d4ebdb0d 100644 --- a/modules/client/back/methods/client/specs/getDebt.spec.js +++ b/modules/client/back/methods/client/specs/getDebt.spec.js @@ -4,7 +4,7 @@ describe('client getDebt()', () => { it('should return the client debt', async() => { let result = await app.models.Client.getDebt(101); - expect(result.debt).toEqual(329.13); + expect(result.debt).toEqual(-14.78); }); }); diff --git a/modules/client/back/methods/client/specs/summary.spec.js b/modules/client/back/methods/client/specs/summary.spec.js index 55801fdb9..d9847b2c1 100644 --- a/modules/client/back/methods/client/specs/summary.spec.js +++ b/modules/client/back/methods/client/specs/summary.spec.js @@ -17,7 +17,7 @@ describe('client summary()', () => { it('should return a summary object containing debt', async() => { let result = await app.models.Client.summary(101); - expect(result.debt.debt).toEqual(329.13); + expect(result.debt.debt).toEqual(-14.78); }); it('should return a summary object containing averageInvoiced', async() => { diff --git a/modules/client/back/methods/receipt/filter.js b/modules/client/back/methods/receipt/filter.js index 4de7e72f8..17a8fcadd 100644 --- a/modules/client/back/methods/receipt/filter.js +++ b/modules/client/back/methods/receipt/filter.js @@ -34,6 +34,7 @@ module.exports = Self => { r.id, r.isConciliate, r.payed, + r.workerFk, c.code company, r.created, r.invoiceFk ref, @@ -41,7 +42,6 @@ module.exports = Self => { r.amountPaid credit, r.bankFk, u.nickname userNickname, - u.id userId, r.clientFk, FALSE pdf, FALSE isInvoice diff --git a/modules/client/back/models/receipt.json b/modules/client/back/models/receipt.json index 6ff863535..c953ae507 100644 --- a/modules/client/back/models/receipt.json +++ b/modules/client/back/models/receipt.json @@ -26,6 +26,12 @@ }, "isConciliate": { "type": "date" + }, + "description": { + "type": "string", + "mysql": { + "columnName": "invoiceFk" + } } }, "relations": { @@ -48,11 +54,6 @@ "type": "belongsTo", "model": "Bank", "foreignKey": "bankFk" - }, - "invoice": { - "type": "belongsTo", - "model": "InvoiceOut", - "foreignKey": "invoiceFk" } } } \ No newline at end of file diff --git a/modules/client/front/risk/create/index.html b/modules/client/front/balance/create/index.html similarity index 100% rename from modules/client/front/risk/create/index.html rename to modules/client/front/balance/create/index.html diff --git a/modules/client/front/risk/create/index.js b/modules/client/front/balance/create/index.js similarity index 80% rename from modules/client/front/risk/create/index.js rename to modules/client/front/balance/create/index.js index 11e701791..6d028e885 100644 --- a/modules/client/front/risk/create/index.js +++ b/modules/client/front/balance/create/index.js @@ -29,11 +29,31 @@ class Controller { this.receipt.amountPaid = value; } + get amountPaid() { + return this.receipt.amountPaid; + } + + set clientFk(value) { + this.receipt.clientFk = value; + } + + get clientFk() { + return this.receipt.clientFk; + } + set companyFk(value) { this.receipt.companyFk = value; this.getAmountPaid(); } + set description(value) { + this.receipt.description = value; + } + + get description() { + return this.receipt.description; + } + getAmountPaid() { let filter = { where: { @@ -68,7 +88,7 @@ class Controller { } Controller.$inject = ['$scope', '$state', '$http', 'vnApp', '$translate']; -ngModule.component('vnClientRiskCreate', { +ngModule.component('vnClientBalanceCreate', { template: require('./index.html'), controller: Controller, bindings: { @@ -76,6 +96,8 @@ ngModule.component('vnClientRiskCreate', { bankFk: ' + data="$ctrl.clientRisks"> + - - - -
    +
    Total by company
    - + @@ -62,7 +61,7 @@ + ng-click="$ctrl.showWorkerDescriptor($event, balance.workerFk)"> {{::balance.userNickname}} @@ -89,7 +88,7 @@ href="api/InvoiceOuts/{{::balance.id}}/download?access_token={{::$ctrl.accessToken}}"> + title="{{'Download PDF' | translate}}"> @@ -111,12 +110,12 @@ ng-click="$ctrl.openCreateDialog()"> - - + + + worker-fk="$ctrl.selectedWorker"> { if (response.data) { - this.riskTotal = response.data; + this.clientRisks = response.data; this.getBalances(); } @@ -59,7 +59,7 @@ class Controller { getCurrentBalance() { const selectedCompany = this.$.company.selection; - const currentBalance = this.riskTotal.find(balance => { + const currentBalance = this.clientRisks.find(balance => { return balance.companyFk === selectedCompany.id; }); @@ -80,24 +80,20 @@ class Controller { openCreateDialog() { - this.$.riskCreateDialog.companyFk = this.companyFk; - this.$.riskCreateDialog.onResponse = () => { + this.$.balanceCreateDialog.companyFk = this.companyFk; + this.$.balanceCreateDialog.onResponse = () => { this.refresh(); }; - this.$.riskCreateDialog.show(); + this.$.balanceCreateDialog.show(); } - onDownload() { - alert('Not implemented yet'); - } - - showWorkerDescriptor(event, userId) { + showWorkerDescriptor(event, workerFk) { if (event.defaultPrevented) return; event.preventDefault(); event.stopPropagation(); - this.selectedWorker = userId; + this.selectedWorker = workerFk; this.$.workerDescriptor.parent = event.target; this.$.workerDescriptor.show(); } @@ -117,7 +113,7 @@ class Controller { Controller.$inject = ['$stateParams', '$translate', '$scope', 'vnToken', '$http']; -ngModule.component('vnClientRiskIndex', { +ngModule.component('vnClientBalanceIndex', { template: require('./index.html'), controller: Controller, }); diff --git a/modules/client/front/risk/index/index.spec.js b/modules/client/front/balance/index/index.spec.js similarity index 92% rename from modules/client/front/risk/index/index.spec.js rename to modules/client/front/balance/index/index.spec.js index 1db4a7a8b..8c88b5f1c 100644 --- a/modules/client/front/risk/index/index.spec.js +++ b/modules/client/front/balance/index/index.spec.js @@ -1,7 +1,7 @@ import './index'; describe('Client', () => { - describe('Component vnClientRiskIndex', () => { + describe('Component vnClientBalanceIndex', () => { let $componentController; let $scope; let $httpBackend; @@ -15,7 +15,7 @@ describe('Client', () => { $httpBackend = _$httpBackend_; $httpParamSerializer = _$httpParamSerializer_; $scope = $rootScope.$new(); - controller = $componentController('vnClientRiskIndex', {$scope}); + controller = $componentController('vnClientBalanceIndex', {$scope}); })); describe('balances() setter', () => { diff --git a/modules/client/front/risk/index/locale/es.yml b/modules/client/front/balance/index/locale/es.yml similarity index 100% rename from modules/client/front/risk/index/locale/es.yml rename to modules/client/front/balance/index/locale/es.yml diff --git a/modules/client/front/balance/index/style.scss b/modules/client/front/balance/index/style.scss new file mode 100644 index 000000000..74d3bc09b --- /dev/null +++ b/modules/client/front/balance/index/style.scss @@ -0,0 +1,10 @@ + +@import "./variables"; + +vn-client-balance-index { + .totalBox { + border: $border-thin-light; + text-align: left; + float: right + } +} \ No newline at end of file diff --git a/modules/client/front/billing-data/index.html b/modules/client/front/billing-data/index.html index 0829381d8..b17f5dbf1 100644 --- a/modules/client/front/billing-data/index.html +++ b/modules/client/front/billing-data/index.html @@ -10,7 +10,7 @@ { + Self.remoteMethod('book', { + description: 'Book a invoiceOut', + accessType: 'WRITE', + accepts: { + arg: 'ref', + type: 'string', + required: true, + description: 'The invoiceOut ref', + http: {source: 'path'} + }, + returns: { + type: 'object', + root: true + }, + http: { + path: '/:ref/book', + verb: 'POST' + } + }); + + Self.book = async ref => { + return Self.rawSql(`CALL vn.invoiceOutAgain(?)`, [ref]); + }; +}; diff --git a/modules/invoiceOut/back/methods/invoiceOut/delete.js b/modules/invoiceOut/back/methods/invoiceOut/delete.js new file mode 100644 index 000000000..afbd226a8 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/delete.js @@ -0,0 +1,45 @@ + +module.exports = Self => { + Self.remoteMethod('delete', { + description: 'Delete a invoiceOut', + accessType: 'WRITE', + accepts: { + arg: 'id', + type: 'string', + required: true, + description: 'The invoiceOut id', + http: {source: 'path'} + }, + returns: { + type: 'object', + root: true + }, + http: { + path: '/:id/delete', + verb: 'POST' + } + }); + + Self.delete = async id => { + const transaction = await Self.beginTransaction({}); + try { + let invoiceOut = await Self.findById(id); + let tickets = await Self.app.models.Ticket.find({where: {refFk: invoiceOut.ref}}); + + const promises = []; + tickets.forEach(ticket => { + promises.push(ticket.updateAttribute('refFk', null, {transaction})); + }); + + return Promise.all(promises).then(async() => { + await invoiceOut.destroy({transaction}); + await transaction.commit(); + + return tickets; + }); + } catch (e) { + await transaction.rollback(); + throw e; + } + }; +}; diff --git a/modules/invoiceOut/back/methods/invoiceOut/filter.js b/modules/invoiceOut/back/methods/invoiceOut/filter.js new file mode 100644 index 000000000..e9f60473a --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/filter.js @@ -0,0 +1,128 @@ + +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; +const buildFilter = require('vn-loopback/util/filter').buildFilter; +const mergeFilters = require('vn-loopback/util/filter').mergeFilters; + +module.exports = Self => { + Self.remoteMethodCtx('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'} + }, + { + arg: 'search', + type: 'String', + description: 'Searchs the invoiceOut by id', + http: {source: 'query'} + }, { + arg: 'clientFk', + type: 'Integer', + description: 'The client id', + http: {source: 'query'} + }, { + arg: 'hasPdf', + type: 'Boolean', + description: 'Whether the the invoiceOut has PDF or not', + http: {source: 'query'} + }, { + arg: 'amount', + type: 'Number', + description: 'The amount filter', + http: {source: 'query'} + }, { + arg: 'min', + type: 'Number', + description: 'The minimun amount flter', + http: {source: 'query'} + }, { + arg: 'max', + type: 'Number', + description: 'The maximun amount flter', + http: {source: 'query'} + }, { + arg: 'issued', + type: 'Date', + description: 'The issued date filter', + http: {source: 'query'} + }, { + arg: 'created', + type: 'Date', + description: 'The created date filter', + http: {source: 'query'} + }, { + arg: 'dued', + type: 'Date', + description: 'The due date filter', + http: {source: 'query'} + } + ], + returns: { + type: ['Object'], + root: true + }, + http: { + path: `/filter`, + verb: 'GET' + } + }); + + Self.filter = async(ctx, filter) => { + let conn = Self.dataSource.connector; + + let where = buildFilter(ctx.args, (param, value) => { + switch (param) { + case 'search': + return {ref: {like: `%${value}%`}}; + case 'min': + return {amount: {gte: value}}; + case 'max': + return {amount: {lte: value}}; + case 'hasPdf': + return {'i.pdf': value}; + case 'created': + return {'i.created': value}; + case 'amount': + case 'clientFk': + case 'companyFk': + case 'issued': + case 'dued': + return {[param]: value}; + } + }); + + filter = mergeFilters(ctx.args.filter, {where}); + + let stmts = []; + let stmt; + + stmt = new ParameterizedSQL( + `SELECT + i.id, + i.ref, + i.issued, + i.amount, + i.created, + i.dued, + i.clientFk, + i.pdf AS hasPdf, + c.socialName AS clientSocialName, + co.code AS companyCode + FROM invoiceOut i + LEFT JOIN client c ON c.id = i.clientFk + LEFT JOIN company co ON co.id = i.companyFk` + ); + + stmt.merge(conn.makeSuffix(filter)); + let itemsIndex = stmts.push(stmt) - 1; + + let sql = ParameterizedSQL.join(stmts, ';'); + let result = await conn.executeStmt(sql); + return itemsIndex === 0 ? result : result[itemsIndex]; + }; +}; + diff --git a/modules/invoiceOut/back/methods/invoiceOut/regenerate.js b/modules/invoiceOut/back/methods/invoiceOut/regenerate.js new file mode 100644 index 000000000..77123318a --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/regenerate.js @@ -0,0 +1,49 @@ +module.exports = Self => { + Self.remoteMethodCtx('regenerate', { + description: 'Sends an invoice to a regeneration queue', + accessType: 'WRITE', + accepts: [{ + arg: 'id', + type: 'number', + required: true, + description: 'The invoiceOut id', + http: {source: 'path'} + }], + returns: { + type: 'object', + root: true + }, + http: { + path: '/:id/regenerate', + verb: 'POST' + } + }); + + Self.regenerate = async(ctx, id) => { + const userId = ctx.req.accessToken.userId; + const models = Self.app.models; + const invoiceReportFk = 30; // FIXME - Should be deprecated + const worker = await models.Worker.findOne({where: {userFk: userId}}); + const transaction = await Self.beginTransaction({}); + + try { + // Remove all invoice references from tickets + const invoiceOut = await models.InvoiceOut.findById(id, {transaction}); + await invoiceOut.updateAttributes({ + hasPdf: false + }); + + // Send to print queue + await Self.rawSql(` + INSERT INTO vn.printServerQueue (reportFk, param1, workerFk) + VALUES (?, ?, ?)`, [invoiceReportFk, id, worker.id], {transaction}); + + await transaction.commit(); + + return invoiceOut; + } catch (e) { + await transaction.rollback(); + throw e; + } + }; +}; diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/book.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/book.spec.js new file mode 100644 index 000000000..383e952b6 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/book.spec.js @@ -0,0 +1,32 @@ +const app = require('vn-loopback/server/server'); + +describe('invoiceOut book()', () => { + const invoiceOutId = 5; + let invoiceOutRef; + let OriginalInvoiceOut; + let updatedInvoiceOut; + afterAll(async done => { + updatedInvoiceOut.updateAttributes({booked: OriginalInvoiceOut.booked, hasPdf: OriginalInvoiceOut.hasPdf}); + + done(); + }); + + it('should check that invoice out booked is untainted', async() => { + const invoiceOut = await app.models.InvoiceOut.findById(invoiceOutId); + + expect(invoiceOut.booked).toBeNull(); + expect(invoiceOut.hasPdf).toBeTruthy(); + }); + + it(`should confirm the book property have been updated`, async() => { + OriginalInvoiceOut = await app.models.InvoiceOut.findById(invoiceOutId); + invoiceOutRef = OriginalInvoiceOut.ref; + + await app.models.InvoiceOut.book(invoiceOutRef); + + updatedInvoiceOut = await app.models.InvoiceOut.findById(invoiceOutId); + + expect(updatedInvoiceOut.booked).toEqual(jasmine.any(Object)); + expect(updatedInvoiceOut.hasPdf).toBeFalsy(); + }); +}); diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/delete.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/delete.spec.js new file mode 100644 index 000000000..1fba84cbd --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/delete.spec.js @@ -0,0 +1,38 @@ +const app = require('vn-loopback/server/server'); + +describe('invoiceOut delete()', () => { + const invoiceOutId = 2; + let OriginalInvoiceOut; + let OriginalTickets; + afterAll(async done => { + const newInvoiceOut = await app.models.InvoiceOut.create(OriginalInvoiceOut); + await newInvoiceOut.updateAttribute('ref', OriginalInvoiceOut.ref); + + const promises = []; + OriginalTickets.forEach(ticket => { + promises.push(ticket.updateAttribute('refFk', newInvoiceOut.ref)); + }); + Promise.all(promises); + + done(); + }); + + it('should check that there is two tickets from the invoice id 2', async() => { + const invoiceOut = await app.models.InvoiceOut.findById(invoiceOutId); + const tickets = await app.models.Ticket.find({where: {refFk: invoiceOut.ref}}); + + expect(tickets.length).toEqual(2); + expect(tickets[0].id).toEqual(2); + }); + + it(`should check the two tickets from the invoice id 2 that are not invoiced`, async() => { + OriginalInvoiceOut = await app.models.InvoiceOut.findById(invoiceOutId); + await app.models.InvoiceOut.delete(invoiceOutId); + OriginalTickets = await app.models.Ticket.find({where: {id: {inq: [2, 3]}}}); + const invoiceOut = await app.models.InvoiceOut.findById(invoiceOutId); + + expect(OriginalTickets[0].refFk).toBeNull(); + expect(OriginalTickets[1].refFk).toBeNull(); + expect(invoiceOut).toBeNull(); + }); +}); diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/regenerate.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/regenerate.spec.js new file mode 100644 index 000000000..39e5f5171 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/regenerate.spec.js @@ -0,0 +1,39 @@ +const app = require('vn-loopback/server/server'); + +describe('invoiceOut regenerate()', () => { + const invoiceReportFk = 30; // FIXME - Should be deprecated + const invoiceOutId = 1; + + afterAll(async done => { + const invoiceOut = await app.models.InvoiceOut.findById(invoiceOutId); + await invoiceOut.updateAttributes({hasPdf: true}); + await app.models.InvoiceOut.rawSql(` + DELETE FROM vn.printServerQueue + WHERE reportFk = ?`, [invoiceReportFk]); + + done(); + }); + + it('should check that the invoice has a PDF and is not in print generation queue', async() => { + const invoiceOut = await app.models.InvoiceOut.findById(invoiceOutId); + const [queue] = await app.models.InvoiceOut.rawSql(` + SELECT COUNT(*) AS total + FROM vn.printServerQueue + WHERE reportFk = ?`, [invoiceReportFk]); + + expect(invoiceOut.hasPdf).toBeTruthy(); + expect(queue.total).toEqual(0); + }); + + it(`should mark the invoice as doesn't have PDF and add it to a print queue`, async() => { + const ctx = {req: {accessToken: {userId: 5}}}; + const invoiceOut = await app.models.InvoiceOut.regenerate(ctx, invoiceOutId); + const [queue] = await app.models.InvoiceOut.rawSql(` + SELECT COUNT(*) AS total + FROM vn.printServerQueue + WHERE reportFk = ?`, [invoiceReportFk]); + + expect(invoiceOut.hasPdf).toBeFalsy(); + expect(queue.total).toEqual(1); + }); +}); diff --git a/modules/invoiceOut/back/methods/invoiceOut/summary.js b/modules/invoiceOut/back/methods/invoiceOut/summary.js index 6369f3ca1..caa2a1c06 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/summary.js +++ b/modules/invoiceOut/back/methods/invoiceOut/summary.js @@ -81,14 +81,11 @@ module.exports = Self => { let ticketTotalsIndex = stmts.push('SELECT * FROM tmp.ticketTotal') - 1; stmt = new ParameterizedSQL(` - SELECT tc.description as type, SUM(ROUND(s.quantity * s.price * (100 - s.discount) / 100,2)) AS base - FROM vn.sale s - JOIN vn.ticket t ON t.id = s.ticketFk - LEFT JOIN vn.itemTaxCountry itc ON itc.itemFk = s.itemFk - JOIN vn.country c ON c.id = itc.countryFK AND c.id = ? - LEFT JOIN vn.taxClass tc ON tc.id = itc.taxClassFk - WHERE t.refFk = ? - GROUP BY type`, [summary.invoiceOut.supplier().countryFk, summary.invoiceOut.ref]); + SELECT iot.* , pgc.*, IF(pe.equFk IS NULL, taxableBase, 0) AS Base, pgc.rate / 100 as vatPercent + FROM vn.invoiceOutTax iot + JOIN vn.pgc ON pgc.code = iot.pgcFk + LEFT JOIN vn.pgcEqu pe ON pe.equFk = pgc.code + WHERE invoiceOutFk = ?`, [summary.invoiceOut.id]); let invoiceOutTaxesIndex = stmts.push(stmt) - 1; stmts.push( diff --git a/modules/invoiceOut/back/models/invoiceOut.js b/modules/invoiceOut/back/models/invoiceOut.js index a3edaa28f..8046f1dc4 100644 --- a/modules/invoiceOut/back/models/invoiceOut.js +++ b/modules/invoiceOut/back/models/invoiceOut.js @@ -1,4 +1,8 @@ module.exports = Self => { + require('../methods/invoiceOut/filter')(Self); require('../methods/invoiceOut/summary')(Self); require('../methods/invoiceOut/download')(Self); + require('../methods/invoiceOut/regenerate')(Self); + require('../methods/invoiceOut/delete')(Self); + require('../methods/invoiceOut/book')(Self); }; diff --git a/modules/invoiceOut/back/models/invoiceOut.json b/modules/invoiceOut/back/models/invoiceOut.json index 7990949e9..0d8881de2 100644 --- a/modules/invoiceOut/back/models/invoiceOut.json +++ b/modules/invoiceOut/back/models/invoiceOut.json @@ -35,7 +35,7 @@ "type": "date" }, "hasPdf": { - "type": "Number", + "type": "Boolean", "mysql": { "columnName": "pdf" } diff --git a/modules/invoiceOut/front/descriptor/index.html b/modules/invoiceOut/front/descriptor/index.html index 65d4816fe..211560d28 100644 --- a/modules/invoiceOut/front/descriptor/index.html +++ b/modules/invoiceOut/front/descriptor/index.html @@ -6,6 +6,16 @@ + +
    @@ -40,14 +50,16 @@ icon="{{::$ctrl.quicklinks.btnTwo.icon}}"> - - - -
    -
    \ No newline at end of file + + + + + \ No newline at end of file diff --git a/modules/invoiceOut/front/descriptor/index.js b/modules/invoiceOut/front/descriptor/index.js index 777ab6bb1..bd9891193 100644 --- a/modules/invoiceOut/front/descriptor/index.js +++ b/modules/invoiceOut/front/descriptor/index.js @@ -1,6 +1,34 @@ import ngModule from '../module'; class Controller { + constructor($scope, vnToken, vnApp, $state, $translate, $http, aclService) { + this.$scope = $scope; + this.accessToken = vnToken.token; + this.vnApp = vnApp; + this.$state = $state; + this.$translate = $translate; + this.$http = $http; + this.aclService = aclService; + this.moreOptions = [ + {callback: this.showInvoiceOutPdf, name: 'Show invoice PDF'}, + {callback: this.showDeleteInvoiceOutDialog, name: 'Delete Invoice', acl: 'invoicing'}, + {callback: this.showBookInvoiceOutDialog, name: 'Book invoice', acl: 'invoicing'} + ]; + } + + onMoreOpen() { + let options = this.moreOptions.filter(option => { + const hasAclProperty = Object.hasOwnProperty.call(option, 'acl'); + + return !hasAclProperty || (hasAclProperty && this.aclService.hasAny([option.acl])); + }); + this.$scope.moreButton.data = options; + } + + onMoreChange(callback) { + callback.call(this); + } + set invoiceOut(value) { this._invoiceOut = value; @@ -24,6 +52,39 @@ class Controller { return this._invoiceOut; } + showInvoiceOutPdf() { + let url = `api/InvoiceOuts/${this.invoiceOut.id}/download?access_token=${this.accessToken}`; + window.open(url, '_blank'); + } + + showDeleteInvoiceOutDialog() { + this.$scope.deleteConfirmation.show(); + } + + showBookInvoiceOutDialog() { + this.$scope.bookConfirmation.show(); + } + + deleteInvoiceOut(response) { + if (response === 'ACCEPT') { + const query = `/invoiceOut/api/InvoiceOuts/${this.invoiceOut.id}/delete`; + this.$http.post(query).then(() => { + this.vnApp.showSuccess(this.$translate.instant('InvoiceOut deleted')); + this.$state.go('invoiceOut.index'); + }); + } + } + + bookInvoiceOut(response) { + if (response === 'ACCEPT') { + const query = `/invoiceOut/api/InvoiceOuts/${this.invoiceOut.ref}/book`; + this.$http.post(query).then(() => { + this.vnApp.showSuccess(this.$translate.instant('InvoiceOut booked')); + this.$state.reload(); + }); + } + } + set quicklinks(value = {}) { this._quicklinks = Object.assign(value, this._quicklinks); } @@ -33,7 +94,7 @@ class Controller { } } -Controller.$inject = ['$http', '$state']; +Controller.$inject = ['$scope', 'vnToken', 'vnApp', '$state', '$translate', '$http', 'aclService']; ngModule.component('vnInvoiceOutDescriptor', { template: require('./index.html'), diff --git a/modules/invoiceOut/front/descriptor/locale/es.yml b/modules/invoiceOut/front/descriptor/locale/es.yml index 63ea7b6b5..4f6abcea3 100644 --- a/modules/invoiceOut/front/descriptor/locale/es.yml +++ b/modules/invoiceOut/front/descriptor/locale/es.yml @@ -1,4 +1,11 @@ Volume exceded: Volumen excedido Volume: Volumen Client card: Ficha del cliente -Invoice ticket list: Listado de tickets de la factura \ No newline at end of file +Invoice ticket list: Listado de tickets de la factura +Show invoice PDF: Ver factura en PDF +Delete Invoice: Borrar factura +InvoiceOut deleted: Factura eliminada +Are you sure you want to delete this invoice?: Estas seguro de eliminar esta factura? +Book invoice: Asentar factura +InvoiceOut booked: Factura asentada +Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura? \ No newline at end of file diff --git a/modules/invoiceOut/front/index/index.html b/modules/invoiceOut/front/index/index.html index 98c286dbc..8a7db4f25 100644 --- a/modules/invoiceOut/front/index/index.html +++ b/modules/invoiceOut/front/index/index.html @@ -1,20 +1,16 @@ + data="invoiceOuts" + order="issued DESC">
    @@ -36,7 +32,7 @@ - {{::invoiceOut.ref | dashIfEmpty}} @@ -46,11 +42,11 @@ - {{::invoiceOut.client.name | dashIfEmpty}} + {{::invoiceOut.clientSocialName | dashIfEmpty}} {{::invoiceOut.created | dateTime:'dd/MM/yyyy' | dashIfEmpty}} - {{::invoiceOut.company.code | dashIfEmpty}} + {{::invoiceOut.companyCode | dashIfEmpty}} {{::invoiceOut.dued | dateTime:'dd/MM/yyyy' | dashIfEmpty}} - - - - - - - - + +

    Desglose impositivo

    + + + + Type + Taxable base + Rate + Fee + + + + + {{tax.name}} + {{tax.taxableBase | currency: 'EUR': 2}} + {{tax.rate}}% + {{tax.vat | currency: 'EUR': 2}} + + + +

    Ticket

    @@ -40,6 +46,7 @@ Ticket id Alias + Shipped Amount @@ -59,6 +66,7 @@ {{ticket.nickname}}
    + {{ticket.shipped | dateTime: 'dd/MM/yyyy'}} {{ticket.total | currency: 'EUR': 2}}
    diff --git a/modules/invoiceOut/front/summary/index.js b/modules/invoiceOut/front/summary/index.js index ed82242e8..6135942fb 100644 --- a/modules/invoiceOut/front/summary/index.js +++ b/modules/invoiceOut/front/summary/index.js @@ -18,13 +18,6 @@ class Controller { return this._invoiceOut; } - openPdf(id, event) { - let url = `api/InvoiceOuts/${id}/download?access_token=${this.accessToken}`; - window.open(url, '_blank'); - event.preventDefault(); - event.stopImmediatePropagation(); - } - getSummary() { this.$http.get(`/api/InvoiceOuts/${this.invoiceOut.id}/summary`).then(response => { this.summary = response.data; @@ -36,7 +29,6 @@ class Controller { this.$.clientDescriptor.parent = event.target; this.$.clientDescriptor.show(); event.preventDefault(); - event.stopImmediatePropagation(); } showTicketDescriptor(event, ticketFk) { @@ -44,14 +36,12 @@ class Controller { this.$.ticketDescriptor.parent = event.target; this.$.ticketDescriptor.show(); event.preventDefault(); - event.stopImmediatePropagation(); } preview(event, invoiceOut) { this.selectedInvoiceOut = invoiceOut; this.$.invoiceOutSummaryDialog.show(); event.preventDefault(); - event.stopImmediatePropagation(); } } diff --git a/modules/invoiceOut/front/summary/index.spec.js b/modules/invoiceOut/front/summary/index.spec.js index 34b306de8..b4d5b743e 100644 --- a/modules/invoiceOut/front/summary/index.spec.js +++ b/modules/invoiceOut/front/summary/index.spec.js @@ -1,40 +1,26 @@ import './index.js'; -describe('Route', () => { +describe('InvoiceOut', () => { describe('Component summary', () => { let controller; let $httpBackend; - beforeEach(ngModule('route')); + beforeEach(ngModule('invoiceOut')); beforeEach(angular.mock.inject(($componentController, _$httpBackend_) => { $httpBackend = _$httpBackend_; - controller = $componentController('vnRouteSummary'); - controller.route = {id: 1}; + controller = $componentController('vnInvoiceOutSummary'); + controller.invoiceOut = {id: 1}; })); describe('getSummary()', () => { it('should perform a query to set summary', () => { - $httpBackend.when('GET', `/api/Routes/1/summary`).respond(200, 24); - $httpBackend.expect('GET', `/api/Routes/1/summary`); + $httpBackend.when('GET', `/api/InvoiceOuts/1/summary`).respond(200, 'the data you are looking for'); + $httpBackend.expect('GET', `/api/InvoiceOuts/1/summary`); controller.getSummary(); $httpBackend.flush(); - expect(controller.summary).toEqual(24); - }); - }); - - describe('sumPackages()', () => { - it('should calculate the packages total', () => { - controller.summary = { - tickets: [ - {packages: 3}, - {packages: 1} - ] - }; - controller.sumPackages(); - - expect(controller.packagesTotal).toEqual(4); + expect(controller.summary).toEqual('the data you are looking for'); }); }); }); diff --git a/modules/invoiceOut/front/summary/locale/es.yml b/modules/invoiceOut/front/summary/locale/es.yml index 74ddf1df3..d1b4a2406 100644 --- a/modules/invoiceOut/front/summary/locale/es.yml +++ b/modules/invoiceOut/front/summary/locale/es.yml @@ -1,15 +1,11 @@ -Driver: Conductor -Vehicle: Vehículo -Packages: Bultos -Starting time: H. Inicio -Finishing time: H. Fin -Km Start: Km de inicio -Km End: Km de fin -PC: CP Date: Fecha Created: Creada Due: Vencimiento Booked: Asentado General VAT: IVA general Reduced VAT: IVA reducido - +Shipped: F. envío +Type: Tipo +Rate: Tasa +Fee: Cuota +Taxable base: Base imp. \ No newline at end of file diff --git a/modules/invoiceOut/front/summary/style.scss b/modules/invoiceOut/front/summary/style.scss index aef44fbf9..f2cf53381 100644 --- a/modules/invoiceOut/front/summary/style.scss +++ b/modules/invoiceOut/front/summary/style.scss @@ -1,7 +1,7 @@ @import "variables"; -vn-route-summary .summary { +vn-invoice-out-summary .summary { max-width: $width-large; vn-icon[icon=insert_drive_file]{ diff --git a/modules/item/back/methods/item/filter.js b/modules/item/back/methods/item/filter.js index 0da463ad4..05cd87ca2 100644 --- a/modules/item/back/methods/item/filter.js +++ b/modules/item/back/methods/item/filter.js @@ -41,7 +41,7 @@ module.exports = Self => { }, { arg: 'hasVisible', type: 'Boolean', - description: 'Whether the the item has o not visible', + description: 'Whether the the item has visible or not', http: {source: 'query'} }, { arg: 'isActive', @@ -73,7 +73,7 @@ module.exports = Self => { case 'search': return /^\d+$/.test(value) ? {or: [{'i.id': value}, {'ib.code': value}]} - : {'i.name': {like: `%${value}%`}}; + : {or: [{'i.name': {like: `%${value}%`}}, {'ib.code': value}]}; case 'id': return {'i.id': value}; case 'description': @@ -94,16 +94,30 @@ module.exports = Self => { let stmt; stmt = new ParameterizedSQL( - `SELECT i.id, i.image, i.name, i.description, - i.size, i.tag5, i.value5, i.tag6, i.value6, - i.tag7, i.value7, i.tag8, i.value8, - i.tag9, i.value9, i.tag10, i.value10, i.subName, - i.isActive, t.name type, u.nickname userNickname, - t.name type, u.id userId, - intr.description AS intrastat, i.stems, - ori.code AS origin, t.name AS type, - ic.name AS category, i.density, - b.grouping, b.packing, itn.code AS niche, @visibleCalc + `SELECT i.id, + i.image, + i.name, + i.description, + i.size, + i.tag5, i.value5, + i.tag6, i.value6, + i.tag7, i.value7, + i.tag8, i.value8, + i.tag9, i.value9, + i.tag10, i.value10, + i.subName, + i.isActive, + t.name type, + t.workerFk buyerFk, + u.nickname userNickname, + intr.description AS intrastat, + i.stems, + ori.code AS origin, + ic.name AS category, + i.density, + b.grouping, + b.packing, + itn.code AS niche, @visibleCalc FROM item i LEFT JOIN itemType t ON t.id = i.typeFk LEFT JOIN itemCategory ic ON ic.id = t.categoryFk diff --git a/modules/item/back/methods/item/specs/filter.spec.js b/modules/item/back/methods/item/specs/filter.spec.js index 7efb50033..7344b3116 100644 --- a/modules/item/back/methods/item/specs/filter.spec.js +++ b/modules/item/back/methods/item/specs/filter.spec.js @@ -22,12 +22,12 @@ describe('item filter()', () => { order: 'isActive ASC, name', limit: 8 }; - let tags = [{value: 'combat first', tagFk: 58}]; + let tags = [{value: 'combat fist', tagFk: 58}]; let result = await app.models.Item.filter({args: {filter: filter, typeFk: 2, tags: tags}}); expect(result.length).toEqual(1); expect(result[0].id).toEqual(2); - expect(result[0].name).toEqual('Melee weapon combat first 15cm'); + expect(result[0].name).toEqual('Melee weapon combat fist 15cm'); expect(result[0].type).toEqual('Anthurium'); }); }); diff --git a/modules/item/front/data/index.html b/modules/item/front/basic-data/index.html similarity index 97% rename from modules/item/front/data/index.html rename to modules/item/front/basic-data/index.html index 4f9bf3366..b12e9fc53 100644 --- a/modules/item/front/data/index.html +++ b/modules/item/front/basic-data/index.html @@ -76,7 +76,6 @@ label="Density" field="$ctrl.item.density"> - diff --git a/modules/item/front/data/index.js b/modules/item/front/basic-data/index.js similarity index 91% rename from modules/item/front/data/index.js rename to modules/item/front/basic-data/index.js index 6096a4bfa..123aa59cd 100644 --- a/modules/item/front/data/index.js +++ b/modules/item/front/basic-data/index.js @@ -15,7 +15,7 @@ class Controller { Controller.$inject = ['$scope', '$timeout']; -ngModule.component('vnItemData', { +ngModule.component('vnItemBasicData', { template: require('./index.html'), bindings: { item: '<' diff --git a/modules/item/front/data/locale/es.yml b/modules/item/front/basic-data/locale/es.yml similarity index 100% rename from modules/item/front/data/locale/es.yml rename to modules/item/front/basic-data/locale/es.yml diff --git a/modules/item/front/create/index.js b/modules/item/front/create/index.js index b983078ea..646baa8cd 100644 --- a/modules/item/front/create/index.js +++ b/modules/item/front/create/index.js @@ -11,7 +11,7 @@ class Controller { onSubmit() { this.$.watcher.submit().then( - json => this.$state.go('item.card.data', {id: json.data.id}) + json => this.$state.go('item.card.basicData', {id: json.data.id}) ); } } diff --git a/modules/item/front/create/index.spec.js b/modules/item/front/create/index.spec.js index 14d7bf513..cb58cdaa3 100644 --- a/modules/item/front/create/index.spec.js +++ b/modules/item/front/create/index.spec.js @@ -30,7 +30,7 @@ describe('Item', () => { spyOn($state, 'go'); controller.onSubmit(); - expect(controller.$state.go).toHaveBeenCalledWith('item.card.data', {id: 1}); + expect(controller.$state.go).toHaveBeenCalledWith('item.card.basicData', {id: 1}); }); }); }); diff --git a/modules/item/front/index.js b/modules/item/front/index.js index 4ff9e3e3f..bc280d529 100644 --- a/modules/item/front/index.js +++ b/modules/item/front/index.js @@ -7,7 +7,7 @@ import './create'; import './card'; import './descriptor'; import './descriptor-popover'; -import './data'; +import './basic-data'; import './fetched-tags'; import './tags'; import './tax'; diff --git a/modules/item/front/index/index.html b/modules/item/front/index/index.html index 6fb0fdfb5..6054c7bb7 100644 --- a/modules/item/front/index/index.html +++ b/modules/item/front/index/index.html @@ -94,7 +94,7 @@ + ng-click="$ctrl.showWorkerDescriptor($event, item.buyerFk)"> {{::item.userNickname}} @@ -143,5 +143,5 @@ + worker-fk="$ctrl.selectedWorker"> \ No newline at end of file diff --git a/modules/item/front/index/index.js b/modules/item/front/index/index.js index 524587afb..14529d402 100644 --- a/modules/item/front/index/index.js +++ b/modules/item/front/index/index.js @@ -68,13 +68,13 @@ class Controller { } - showWorkerDescriptor(event, userId) { + showWorkerDescriptor(event, workerFk) { if (event.defaultPrevented) return; event.preventDefault(); event.stopPropagation(); - this.selectedWorker = userId; + this.selectedWorker = workerFk; this.$.workerDescriptor.parent = event.target; this.$.workerDescriptor.show(); } diff --git a/modules/item/front/locale/es.yml b/modules/item/front/locale/es.yml index 12522459a..56c96c403 100644 --- a/modules/item/front/locale/es.yml +++ b/modules/item/front/locale/es.yml @@ -45,6 +45,8 @@ stems: Tallos Compression: Compresión Density: Densidad Search items by id, name or barcode: Buscar articulos por identificador, nombre o codigo de barras +SalesPerson: Comercial +Concept: Concepto # Sections Items: Artículos diff --git a/modules/item/front/request-search-panel/index.html b/modules/item/front/request-search-panel/index.html index ba517d1ca..cb1734442 100644 --- a/modules/item/front/request-search-panel/index.html +++ b/modules/item/front/request-search-panel/index.html @@ -50,6 +50,16 @@ model="filter.to"> + + + + + + diff --git a/modules/item/front/request/index.html b/modules/item/front/request/index.html index 786e71e86..700e70dec 100644 --- a/modules/item/front/request/index.html +++ b/modules/item/front/request/index.html @@ -1,6 +1,6 @@ @@ -17,7 +17,7 @@
    - + @@ -29,9 +29,9 @@ Quantity Price Atender - itemFk + Item Concept - Quantity + Quantity State @@ -43,15 +43,36 @@ {{request.ticketFk}} - - {{::request.shipped | dateTime: 'dd/MM/yyyy'}} + + + {{::request.shipped | dateTime: 'dd/MM/yyyy'}} + {{::request.warehouse}} - {{::request.salesPersonNickname}} - {{::request.description}} + + + {{::request.salesPersonNickname}} + + + + + {{::request.description}} + + {{::request.quantity}} - {{::request.price}} - {{::request.atenderNickname}} + {{::request.price | currency: 'EUR':2}} + + + {{::request.atenderNickname}} + + {{request.itemFk}} @@ -88,10 +109,15 @@
    - + + + + diff --git a/modules/item/front/request/index.js b/modules/item/front/request/index.js index 5e3726d81..2f110bf48 100644 --- a/modules/item/front/request/index.js +++ b/modules/item/front/request/index.js @@ -2,11 +2,11 @@ import ngModule from '../module'; import './style.scss'; export default class Controller { - constructor($scope, vnApp, $translate, $http, $state, $stateParams) { + constructor($, vnApp, $translate, $http, $state, $stateParams) { this.$state = $state; this.$stateParams = $stateParams; this.$http = $http; - this.$scope = $scope; + this.$ = $; this.vnApp = vnApp; this._ = $translate; if (!$stateParams.q) @@ -39,7 +39,7 @@ export default class Controller { this.$http.post(endpoint, params).then(() => { this.vnApp.showSuccess(this._.instant('Data saved!')); }).catch( e => { - this.$scope.model.refresh(); + this.$.model.refresh(); throw e; }); } @@ -56,7 +56,7 @@ export default class Controller { this.$http.patch(endpoint, params).then(() => { this.vnApp.showSuccess(this._.instant('Data saved!')); }).catch( e => { - this.$scope.model.refresh(); + this.$.model.refresh(); throw e; }); } @@ -78,15 +78,15 @@ export default class Controller { onSearch(params) { if (params) - this.$scope.model.applyFilter(null, params); + this.$.model.applyFilter(null, params); else - this.$scope.model.clear(); + this.$.model.clear(); } showDenyReason(event, requestId) { this.denyRequestId = requestId; - this.$scope.denyReason.parent = event.target; - this.$scope.denyReason.show(); + this.$.denyReason.parent = event.target; + this.$.denyReason.show(); } clear() { @@ -102,35 +102,38 @@ export default class Controller { this.$http.post(endpoint, params).then(() => { this.vnApp.showSuccess(this._.instant('Data saved!')); - this.$scope.model.refresh(); - this.$scope.denyReason.hide(); + this.$.model.refresh(); + this.$.denyReason.hide(); this.denyObservation = null; }); } - showClientDescriptor(event, clientFk) { - this.$scope.clientDescriptor.clientFk = clientFk; - this.$scope.clientDescriptor.parent = event.target; - this.$scope.clientDescriptor.show(); + showTicketDescriptor(event, ticketFk) { + this.$.ticketDescriptor.ticketFk = ticketFk; + this.$.ticketDescriptor.parent = event.target; + this.$.ticketDescriptor.show(); event.preventDefault(); event.stopImmediatePropagation(); } - showTicketDescriptor(event, ticketFk) { - this.$scope.ticketDescriptor.ticketFk = ticketFk; - this.$scope.ticketDescriptor.parent = event.target; - this.$scope.ticketDescriptor.show(); - event.preventDefault(); - event.stopImmediatePropagation(); + showItemDescriptor(event, itemFk) { + this.$.itemDescriptor.itemFk = itemFk; + this.$.itemDescriptor.parent = event.target; + this.$.itemDescriptor.show(); + } + + showWorkerDescriptor(event, workerFk) { + this.$.workerDescriptor.workerFk = workerFk; + this.$.workerDescriptor.parent = event.target; + this.$.workerDescriptor.show(); } onDescriptorLoad() { - this.$scope.popover.relocate(); + this.$.popover.relocate(); } preventNavigation(event) { event.preventDefault(); - event.stopImmediatePropagation(); } } diff --git a/modules/item/front/routes.json b/modules/item/front/routes.json index 3271ebe3a..b0dc7c26a 100644 --- a/modules/item/front/routes.json +++ b/modules/item/front/routes.json @@ -5,7 +5,7 @@ "validations" : true, "dependencies": ["worker", "client", "ticket"], "menu": [ - {"state": "item.card.data", "icon": "settings"}, + {"state": "item.card.basicData", "icon": "settings"}, {"state": "item.card.tags", "icon": "icon-tags"}, {"state": "item.card.tax", "icon": "icon-tax"}, {"state": "item.card.niche", "icon": "place"}, @@ -41,9 +41,9 @@ "abstract": true, "component": "vn-item-card" }, { - "url" : "/data", - "state": "item.card.data", - "component": "vn-item-data", + "url" : "/basic-data", + "state": "item.card.basicData", + "component": "vn-item-basic-data", "description": "Basic data", "params": { "item": "$ctrl.item" @@ -57,7 +57,7 @@ "params": { "item-tags": "$ctrl.itemTags" }, - "acl": ["buyer", "accessory"] + "acl": ["buyer", "replenisher"] }, { "url" : "/tax", "state": "item.card.tax", diff --git a/modules/order/back/methods/order/catalogFilter.js b/modules/order/back/methods/order/catalogFilter.js index 9fa74647c..6e805d957 100644 --- a/modules/order/back/methods/order/catalogFilter.js +++ b/modules/order/back/methods/order/catalogFilter.js @@ -106,7 +106,7 @@ module.exports = Self => { i.value8, tci.price, tci.available, - w.name AS lastName, + w.lastName AS lastName, w.firstName FROM tmp.ticketCalculateItem tci JOIN vn.item i ON i.id = tci.itemFk diff --git a/modules/order/back/methods/order/filter.js b/modules/order/back/methods/order/filter.js index 628b85343..e5d18b44a 100644 --- a/modules/order/back/methods/order/filter.js +++ b/modules/order/back/methods/order/filter.js @@ -114,8 +114,8 @@ module.exports = Self => { o.source_app sourceApp, o.confirmed isConfirmed, c.name clientName, + c.salesPersonFk, u.nickname workerNickname, - u.id userId, co.code companyCode FROM hedera.order o LEFT JOIN address a ON a.id = o.address_id diff --git a/modules/order/front/catalog/index.html b/modules/order/front/catalog/index.html index 5ec0aeac0..7f6e13ee1 100644 --- a/modules/order/front/catalog/index.html +++ b/modules/order/front/catalog/index.html @@ -7,7 +7,7 @@ on-data-change="$ctrl.onDataChange()">
    - +
    diff --git a/modules/order/front/index/index.html b/modules/order/front/index/index.html index c5d29c292..0fd53f2f6 100644 --- a/modules/order/front/index/index.html +++ b/modules/order/front/index/index.html @@ -45,7 +45,7 @@ + ng-click="$ctrl.showWorkerDescriptor($event, order.salesPersonFk)"> {{::order.workerNickname | dashIfEmpty}} @@ -81,7 +81,7 @@ + worker-fk="$ctrl.selectedWorker"> { + Self.remoteMethodCtx('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'} + }, { + arg: 'search', + type: 'String', + description: 'Searchs the route by id', + http: {source: 'query'} + }, { + arg: 'workerFk', + type: 'Integer', + description: 'The worker id', + http: {source: 'query'} + }, { + arg: 'agencyModeFk', + type: 'Integer', + description: 'The agencyMode id', + http: {source: 'query'} + }, { + arg: 'to', + type: 'Date', + description: 'The to date filter', + http: {source: 'query'} + }, { + arg: 'from', + type: 'Date', + description: 'The to date filter', + http: {source: 'query'} + }, { + arg: 'vehicleFk', + type: 'Integer', + description: 'The vehicle id', + http: {source: 'query'} + }, { + arg: 'm3', + type: 'Number', + description: 'The m3 filter', + http: {source: 'query'} + }, { + arg: 'description', + type: 'String', + description: 'The description filter', + http: {source: 'query'} + } + ], + returns: { + type: ['Object'], + root: true + }, + http: { + path: `/filter`, + verb: 'GET' + } + }); + + Self.filter = async(ctx, filter) => { + let conn = Self.dataSource.connector; + + let where = buildFilter(ctx.args, (param, value) => { + switch (param) { + case 'search': + return {'r.id': value}; + case 'from': + return {'r.created': {gte: value}}; + case 'to': + return {'r.created': {lte: value}}; + case 'm3': + return {'r.m3': value}; + case 'description': + return {'r.description': {like: `%${value}%`}}; + case 'workerFk': + case 'vehicleFk': + case 'agencyModeFk': + return {[param]: value}; + } + }); + + filter = mergeFilters(ctx.args.filter, {where}); + + let stmts = []; + let stmt; + + stmt = new ParameterizedSQL( + `SELECT + r.id, + r.workerFk, + r.created, + r.vehicleFk, + r.agencyModeFk, + r.time, + r.isOk, + r.kmStart, + r.kmEnd, + r.started, + r.finished, + r.gestdocFk, + r.cost, + r.m3, + r.description, + am.name agencyName, + u.nickname AS workerNickname, + v.numberPlate AS vehiclePlateNumber + FROM route r + LEFT JOIN agencyMode am ON am.id = r.agencyModeFk + LEFT JOIN vehicle v ON v.id = r.vehicleFk + LEFT JOIN worker w ON w.id = r.workerFk + LEFT JOIN account.user u ON u.id = w.userFk` + ); + + + stmt.merge(conn.makeSuffix(filter)); + let itemsIndex = stmts.push(stmt) - 1; + + let sql = ParameterizedSQL.join(stmts, ';'); + let result = await conn.executeStmt(sql); + return itemsIndex === 0 ? result : result[itemsIndex]; + }; +}; + diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js index e3ebabb68..bd637822f 100644 --- a/modules/route/back/models/route.js +++ b/modules/route/back/models/route.js @@ -1,4 +1,5 @@ module.exports = Self => { + require('../methods/route/filter')(Self); require('../methods/route/summary')(Self); require('../methods/route/getTickets')(Self); require('../methods/route/guessPriority')(Self); diff --git a/modules/route/front/index/index.html b/modules/route/front/index/index.html index 43238fd4d..b9935ba45 100644 --- a/modules/route/front/index/index.html +++ b/modules/route/front/index/index.html @@ -1,7 +1,6 @@ @@ -11,9 +10,7 @@ @@ -41,12 +38,12 @@ - {{::route.worker.user.nickname}} + ng-click="$ctrl.showWorkerDescriptor($event, route.workerFk)"> + {{::route.workerNickname}} - {{::route.agencyMode.name | dashIfEmpty}} - {{::route.vehicle.numberPlate | dashIfEmpty}} + {{::route.agencyName | dashIfEmpty}} + {{::route.vehiclePlateNumber | dashIfEmpty}} {{::route.created | dateTime:'dd/MM/yyyy' | dashIfEmpty}} {{::route.m3 | dashIfEmpty}} {{::route.description | dashIfEmpty}} @@ -72,7 +69,7 @@ + worker-fk="$ctrl.selectedWorker"> diff --git a/modules/route/front/index/index.js b/modules/route/front/index/index.js index 0fa102c4d..4b0536fd0 100644 --- a/modules/route/front/index/index.js +++ b/modules/route/front/index/index.js @@ -4,61 +4,15 @@ export default class Controller { constructor($scope, vnToken) { this.accessToken = vnToken.token; this.$ = $scope; - - this.filter = { - include: [ - { - relation: 'agencyMode', - scope: { - fields: ['name'] - } - }, - { - relation: 'vehicle', - scope: { - fields: ['numberPlate'] - } - }, - { - relation: 'worker', - scope: { - fields: ['userFk'], - include: { - relation: 'user', - scope: { - fields: ['nickname'] - } - } - } - }, - ] - }; } - exprBuilder(param, value) { - switch (param) { - case 'search': - return {id: value}; - case 'from': - return {created: {gte: value}}; - case 'to': - return {created: {lte: value}}; - case 'workerFk': - case 'vehicleFk': - case 'agencyModeFk': - case 'm3': - case 'description': - return {[param]: value}; - } - } - - showWorkerDescriptor(event, userId) { + showWorkerDescriptor(event, workerFk) { if (event.defaultPrevented) return; event.preventDefault(); - event.stopPropagation(); + event.stopImmediatePropagation(); - this.selectedWorker = userId; + this.selectedWorker = workerFk; this.$.workerDescriptor.parent = event.target; this.$.workerDescriptor.show(); } @@ -69,6 +23,13 @@ export default class Controller { event.preventDefault(); event.stopImmediatePropagation(); } + + onSearch(params) { + if (params) + this.$.model.applyFilter(null, params); + else + this.$.model.clear(); + } } Controller.$inject = ['$scope', 'vnToken']; diff --git a/modules/route/front/tickets/index.html b/modules/route/front/tickets/index.html index 7149e1b7b..a8d8655e7 100644 --- a/modules/route/front/tickets/index.html +++ b/modules/route/front/tickets/index.html @@ -30,7 +30,7 @@ + model="model"> Order diff --git a/modules/ticket/back/methods/expedition/filter.js b/modules/ticket/back/methods/expedition/filter.js index 74c542806..3491a9b2d 100644 --- a/modules/ticket/back/methods/expedition/filter.js +++ b/modules/ticket/back/methods/expedition/filter.js @@ -25,11 +25,18 @@ module.exports = Self => { Self.filter = async filter => { const stmt = new ParameterizedSQL( `SELECT - e.id, e.ticketFk, e.isBox, - i1.name namePackage, e.counter, - e.checked, i2.name nameBox, - e.itemFk, u.nickname userNickname, - u.id userId, e.created, e.externalId + e.id, + e.ticketFk, + e.isBox, + e.workerFk, + i1.name namePackage, + e.counter, + e.checked, + i2.name nameBox, + e.itemFk, + u.nickname userNickname, + e.created, + e.externalId FROM vn.expedition e LEFT JOIN vn.item i2 ON i2.id = e.itemFk diff --git a/modules/ticket/back/methods/sale-tracking/listSaleTracking.js b/modules/ticket/back/methods/sale-tracking/listSaleTracking.js index 7ee037161..8d3e0c248 100644 --- a/modules/ticket/back/methods/sale-tracking/listSaleTracking.js +++ b/modules/ticket/back/methods/sale-tracking/listSaleTracking.js @@ -32,7 +32,6 @@ module.exports = Self => { st.created, st.workerFk, u.nickname userNickname, - u.id userId, ste.name AS state FROM saleTracking st JOIN sale s ON s.id = st.saleFk diff --git a/modules/ticket/back/methods/ticket-request/confirm.js b/modules/ticket/back/methods/ticket-request/confirm.js index f9888f9e0..79676b9b2 100644 --- a/modules/ticket/back/methods/ticket-request/confirm.js +++ b/modules/ticket/back/methods/ticket-request/confirm.js @@ -48,14 +48,13 @@ module.exports = Self => { let params = [ ctx.args.itemFk, - request.ticket().warehouseFk, request.ticket().shipped, + request.ticket().warehouseFk, false ]; - + console.log(params); let [res] = await Self.rawSql(query, params); let available = res[0].available; - if (!available) throw new UserError(`That item is not available on that day`); diff --git a/modules/ticket/back/methods/ticket-request/filter.js b/modules/ticket/back/methods/ticket-request/filter.js index 1d19120ff..4e0db40f8 100644 --- a/modules/ticket/back/methods/ticket-request/filter.js +++ b/modules/ticket/back/methods/ticket-request/filter.js @@ -43,6 +43,10 @@ module.exports = Self => { arg: 'to', type: 'Date', description: `Date to` + }, { + arg: 'isOk', + type: 'Boolean', + description: `Search request by request state` } ], returns: { @@ -111,7 +115,8 @@ module.exports = Self => { t.clientFk, w.name AS warehouse, u.nickname AS salesPersonNickname, - ua.nickname AS atenderNickname + ua.nickname AS atenderNickname, + c.salesPersonFk FROM ticketRequest tr LEFT JOIN ticket t ON t.id = tr.ticketFk LEFT JOIN warehouse w ON w.id = t.warehouseFk diff --git a/modules/ticket/back/methods/ticket/filter.js b/modules/ticket/back/methods/ticket/filter.js index 9c6c5cbe6..c006f0985 100644 --- a/modules/ticket/back/methods/ticket/filter.js +++ b/modules/ticket/back/methods/ticket/filter.js @@ -187,12 +187,12 @@ module.exports = Self => { w.name AS warehouse, am.name AS agencyMode, st.name AS state, - wk.name AS salesPerson, + wk.lastName AS salesPerson, ts.stateFk as stateFk, ts.alertLevel as alertLevel, ts.code as alertLevelCode, u.nickname userNickname, - u.id userId + c.salesPersonFk FROM ticket t LEFT JOIN address a ON a.id = t.addressFk LEFT JOIN province p ON p.id = a.provinceFk diff --git a/modules/ticket/back/model-config.json b/modules/ticket/back/model-config.json index a919827b4..3b38f1a16 100644 --- a/modules/ticket/back/model-config.json +++ b/modules/ticket/back/model-config.json @@ -38,6 +38,9 @@ "Ticket": { "dataSource": "vn" }, + "TicketDms": { + "dataSource": "vn" + }, "TicketLog": { "dataSource": "vn" }, diff --git a/modules/ticket/back/models/ticket-dms.json b/modules/ticket/back/models/ticket-dms.json new file mode 100644 index 000000000..b725d47cd --- /dev/null +++ b/modules/ticket/back/models/ticket-dms.json @@ -0,0 +1,38 @@ +{ + "name": "TicketDms", + "base": "Loggable", + "log": { + "model": "TicketLog", + "relation": "ticket", + "showField": "dmsFk" + }, + "options": { + "mysql": { + "table": "ticketDms" + } + }, + "properties": { + "ticketFk": { + "type": "Number", + "id": true, + "required": true + }, + "dmsFk": { + "type": "Number", + "id": true, + "required": true + } + }, + "relations": { + "ticket": { + "type": "belongsTo", + "model": "Ticket", + "foreignKey": "ticketFk" + }, + "dms": { + "type": "belongsTo", + "model": "Dms", + "foreignKey": "dmsFk" + } + } +} \ No newline at end of file diff --git a/modules/ticket/back/models/ticket-service.js b/modules/ticket/back/models/ticket-service.js new file mode 100644 index 000000000..751885116 --- /dev/null +++ b/modules/ticket/back/models/ticket-service.js @@ -0,0 +1,13 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.observe('before save', async ctx => { + let changes = ctx.currentInstance || ctx.instance; + if (changes) { + let ticketId = changes.ticketFk; + let ticket = await Self.app.models.Ticket.findById(ticketId); + if (ticket.refFk) + throw new UserError('You cannot add or modify services to an invoiced ticket'); + } + }); +}; diff --git a/modules/ticket/front/data/index.html b/modules/ticket/front/basic-data/index.html similarity index 51% rename from modules/ticket/front/data/index.html rename to modules/ticket/front/basic-data/index.html index 4864c774f..4439069e8 100644 --- a/modules/ticket/front/data/index.html +++ b/modules/ticket/front/basic-data/index.html @@ -2,9 +2,9 @@ diff --git a/modules/ticket/front/data/index.js b/modules/ticket/front/basic-data/index.js similarity index 93% rename from modules/ticket/front/data/index.js rename to modules/ticket/front/basic-data/index.js index df04b75ea..1afe6f9aa 100644 --- a/modules/ticket/front/data/index.js +++ b/modules/ticket/front/basic-data/index.js @@ -27,7 +27,7 @@ class Controller { Controller.$inject = ['$scope', '$state']; -ngModule.component('vnTicketData', { +ngModule.component('vnTicketBasicData', { template: require('./index.html'), bindings: { ticket: '<' diff --git a/modules/ticket/front/data/step-one/index.html b/modules/ticket/front/basic-data/step-one/index.html similarity index 100% rename from modules/ticket/front/data/step-one/index.html rename to modules/ticket/front/basic-data/step-one/index.html diff --git a/modules/ticket/front/data/step-one/index.js b/modules/ticket/front/basic-data/step-one/index.js similarity index 98% rename from modules/ticket/front/data/step-one/index.js rename to modules/ticket/front/basic-data/step-one/index.js index 125c10a75..0a4708dfe 100644 --- a/modules/ticket/front/data/step-one/index.js +++ b/modules/ticket/front/basic-data/step-one/index.js @@ -159,13 +159,13 @@ class Controller { Controller.$inject = ['$scope', '$http', '$translate', 'vnApp']; -ngModule.component('vnTicketDataStepOne', { +ngModule.component('vnTicketBasicDataStepOne', { template: require('./index.html'), controller: Controller, bindings: { ticket: '<' }, require: { - data: '^vnTicketData' + data: '^vnTicketBasicData' } }); diff --git a/modules/ticket/front/data/step-one/index.spec.js b/modules/ticket/front/basic-data/step-one/index.spec.js similarity index 97% rename from modules/ticket/front/data/step-one/index.spec.js rename to modules/ticket/front/basic-data/step-one/index.spec.js index e7049394b..c3bac09d6 100644 --- a/modules/ticket/front/data/step-one/index.spec.js +++ b/modules/ticket/front/basic-data/step-one/index.spec.js @@ -1,7 +1,7 @@ import './index.js'; describe('Ticket', () => { - describe('Component vnTicketDataStepOne', () => { + describe('Component vnTicketBasicDataStepOne', () => { let $state; let controller; let $httpBackend; @@ -11,7 +11,7 @@ describe('Ticket', () => { beforeEach(angular.mock.inject(($componentController, _$state_, _$httpBackend_) => { $state = _$state_; $httpBackend = _$httpBackend_; - controller = $componentController('vnTicketDataStepOne', {$state}); + controller = $componentController('vnTicketBasicDataStepOne', {$state}); })); describe('ticket() setter', () => { diff --git a/modules/ticket/front/data/step-one/locale/es.yml b/modules/ticket/front/basic-data/step-one/locale/es.yml similarity index 100% rename from modules/ticket/front/data/step-one/locale/es.yml rename to modules/ticket/front/basic-data/step-one/locale/es.yml diff --git a/modules/ticket/front/data/step-one/style.scss b/modules/ticket/front/basic-data/step-one/style.scss similarity index 100% rename from modules/ticket/front/data/step-one/style.scss rename to modules/ticket/front/basic-data/step-one/style.scss diff --git a/modules/ticket/front/data/step-three/index.html b/modules/ticket/front/basic-data/step-three/index.html similarity index 100% rename from modules/ticket/front/data/step-three/index.html rename to modules/ticket/front/basic-data/step-three/index.html diff --git a/modules/ticket/front/data/step-three/index.js b/modules/ticket/front/basic-data/step-three/index.js similarity index 95% rename from modules/ticket/front/data/step-three/index.js rename to modules/ticket/front/basic-data/step-three/index.js index 67df50c97..f6ab66a37 100644 --- a/modules/ticket/front/data/step-three/index.js +++ b/modules/ticket/front/basic-data/step-three/index.js @@ -54,7 +54,7 @@ class Controller { Controller.$inject = ['$http', '$scope', '$state', '$translate', 'vnApp']; -ngModule.component('vnTicketDataStepThree', { +ngModule.component('vnTicketBasicDataStepThree', { template: require('./index.html'), controller: Controller, bindings: { @@ -62,6 +62,6 @@ ngModule.component('vnTicketDataStepThree', { }, require: { card: '^vnTicketCard', - data: '^vnTicketData' + data: '^vnTicketBasicData' } }); diff --git a/modules/ticket/front/data/step-three/index.spec.js b/modules/ticket/front/basic-data/step-three/index.spec.js similarity index 93% rename from modules/ticket/front/data/step-three/index.spec.js rename to modules/ticket/front/basic-data/step-three/index.spec.js index bb7f3430e..190a51f75 100644 --- a/modules/ticket/front/data/step-three/index.spec.js +++ b/modules/ticket/front/basic-data/step-three/index.spec.js @@ -1,7 +1,7 @@ import './index.js'; describe('ticket', () => { - describe('Component vnTicketDataStepThree', () => { + describe('Component vnTicketBasicDataStepThree', () => { let now = Date.now(); let $state; let controller; @@ -16,7 +16,7 @@ describe('ticket', () => { vnApp = _vnApp_; spyOn(vnApp, 'showError'); $httpBackend = _$httpBackend_; - controller = $componentController('vnTicketDataStepThree', {$state}); + controller = $componentController('vnTicketBasicDataStepThree', {$state}); })); describe('onSubmit()', () => { diff --git a/modules/ticket/front/data/step-three/locale/es.yml b/modules/ticket/front/basic-data/step-three/locale/es.yml similarity index 100% rename from modules/ticket/front/data/step-three/locale/es.yml rename to modules/ticket/front/basic-data/step-three/locale/es.yml diff --git a/modules/ticket/front/data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html similarity index 100% rename from modules/ticket/front/data/step-two/index.html rename to modules/ticket/front/basic-data/step-two/index.html diff --git a/modules/ticket/front/data/step-two/index.js b/modules/ticket/front/basic-data/step-two/index.js similarity index 94% rename from modules/ticket/front/data/step-two/index.js rename to modules/ticket/front/basic-data/step-two/index.js index 02f44b8cb..739f08a87 100644 --- a/modules/ticket/front/data/step-two/index.js +++ b/modules/ticket/front/basic-data/step-two/index.js @@ -46,13 +46,13 @@ class Controller { Controller.$inject = ['$http']; -ngModule.component('vnTicketDataStepTwo', { +ngModule.component('vnTicketBasicDataStepTwo', { template: require('./index.html'), controller: Controller, bindings: { ticket: '<' }, require: { - data: '^vnTicketData' + data: '^vnTicketBasicData' } }); diff --git a/modules/ticket/front/data/step-two/index.spec.js b/modules/ticket/front/basic-data/step-two/index.spec.js similarity index 93% rename from modules/ticket/front/data/step-two/index.spec.js rename to modules/ticket/front/basic-data/step-two/index.spec.js index 8ee21da39..8fe400584 100644 --- a/modules/ticket/front/data/step-two/index.spec.js +++ b/modules/ticket/front/basic-data/step-two/index.spec.js @@ -1,13 +1,13 @@ import './index.js'; describe('Ticket', () => { - describe('Component vnTicketDataStepTwo', () => { + describe('Component vnTicketBasicDataStepTwo', () => { let controller; beforeEach(ngModule('ticket')); beforeEach(angular.mock.inject($componentController => { - controller = $componentController('vnTicketDataStepTwo'); + controller = $componentController('vnTicketBasicDataStepTwo'); })); describe('getTotalPrice()', () => { diff --git a/modules/ticket/front/data/step-two/locale/es.yml b/modules/ticket/front/basic-data/step-two/locale/es.yml similarity index 100% rename from modules/ticket/front/data/step-two/locale/es.yml rename to modules/ticket/front/basic-data/step-two/locale/es.yml diff --git a/modules/ticket/front/card/index.js b/modules/ticket/front/card/index.js index 9c1e45e78..2386b1bb6 100644 --- a/modules/ticket/front/card/index.js +++ b/modules/ticket/front/card/index.js @@ -7,6 +7,7 @@ class Controller { this.filter = { include: [ {relation: 'warehouse', scope: {fields: ['name']}}, + {relation: 'invoiceOut', scope: {fields: ['id']}}, {relation: 'address'}, {relation: 'ship'}, {relation: 'agencyMode', scope: {fields: ['name']}}, diff --git a/modules/ticket/front/descriptor/index.html b/modules/ticket/front/descriptor/index.html index 779ce7e53..6d3d74d7f 100644 --- a/modules/ticket/front/descriptor/index.html +++ b/modules/ticket/front/descriptor/index.html @@ -160,7 +160,6 @@ on-response="$ctrl.returnDialog(response)" question="Pickup order" message="Do you want to send it directly?"> - asd Change shipped hour - +
    @@ -181,13 +180,22 @@ + + + + + \ No newline at end of file diff --git a/modules/ticket/front/descriptor/index.js b/modules/ticket/front/descriptor/index.js index 0e153b8fc..307c88833 100644 --- a/modules/ticket/front/descriptor/index.js +++ b/modules/ticket/front/descriptor/index.js @@ -9,32 +9,50 @@ class Controller { this.$translate = $translate; this.aclService = aclService; this.moreOptions = [ - {callback: this.showAddTurnDialog, name: 'Add turn'}, - {callback: this.showAddStowaway, name: 'Add stowaway', show: () => this.isTicketModule()}, - {callback: this.showRemoveStowaway, name: 'Remove stowaway', show: () => this.shouldShowRemoveStowaway()}, - {callback: this.showInvoiceOutMakeDialog, name: 'Make invoice', acl: 'invoicing'}, - {callback: this.showDeliveryNote, name: 'Show Delivery Note'}, - {callback: this.showDeleteTicketDialog, name: 'Delete ticket'}, - {callback: this.showChangeShipped, name: 'Change shipped hour'}, - {callback: this.showSMSDialog, name: 'Send SMS'}, - {callback: this.openRptRoute, name: 'Show pallet report'} + {name: 'Add turn', callback: this.showAddTurnDialog}, + {name: 'Show Delivery Note', callback: this.showDeliveryNote}, + {name: 'Delete ticket', callback: this.showDeleteTicketDialog}, + {name: 'Change shipped hour', callback: this.showChangeShipped}, + {name: 'Send SMS', callback: this.showSMSDialog}, + {name: 'Show pallet report', callback: this.openRptRoute}, + { + name: 'Add stowaway', + callback: this.showAddStowaway, + show: () => this.isTicketModule() + }, + { + name: 'Remove stowaway', + callback: this.showRemoveStowaway, + show: () => this.shouldShowRemoveStowaway() + }, + { + name: 'Make invoice', + acl: 'invoicing', + callback: this.showMakeInvoiceDialog, + show: () => !this.hasInvoice() + }, + { + name: 'Regenerate invoice', + acl: 'invoicing', + callback: this.showRegenerateInvoiceDialog, + show: () => this.hasInvoice() + }, ]; } - // Change shipped hour showChangeShipped() { if (!this.isEditable) { this.vnApp.showError(this.$translate.instant('This ticket can\'t be modified')); return; } - this.newShipped = new Date(this.ticket.shipped); + this.newShipped = this.ticket.shipped; this.$scope.changeShippedDialog.show(); } changeShipped(response) { if (response === 'ACCEPT') { let params = {shipped: this.newShipped}; - this.$http.patch(`/ticket/api/Tickets/${this.ticket.id}/`, params).then(() => { + this.$http.patch(`/ticket/api/Tickets/${this.ticket.id}`, params).then(() => { this.vnApp.showSuccess(this.$translate.instant('Shipped hour updated')); this.cardReload(); }); @@ -84,7 +102,6 @@ class Controller { return true; } - // Add Turn showAddTurnDialog() { this.$scope.addTurn.show(); } @@ -97,7 +114,6 @@ class Controller { }); } - // Delete Ticket showDeleteTicketDialog() { if (!this.isEditable) { this.vnApp.showError(this.$translate.instant('This ticket cant be deleted')); @@ -192,8 +208,8 @@ class Controller { /** * Shows an invoice confirmation */ - showInvoiceOutMakeDialog() { - this.$scope.invoiceMakeConfirmation.show(); + showMakeInvoiceDialog() { + this.$scope.makeInvoiceConfirmation.show(); } /** @@ -202,7 +218,7 @@ class Controller { * * @param {String} response - Response result */ - invoiceMakeOut(response) { + makeInvoice(response) { if (response === 'ACCEPT') { const query = `/ticket/api/Tickets/${this.ticket.id}/makeInvoice`; this.$http.post(query).then(() => { @@ -211,6 +227,40 @@ class Controller { }); } } + + /** + * Shows an invoice confirmation + */ + showRegenerateInvoiceDialog() { + this.$scope.regenerateInvoiceConfirmation.show(); + } + + /** + * Sends an invoice to a regeneration queue + * for the current ticket + * + * @param {String} response - Response result + */ + regenerateInvoice(response) { + if (response === 'ACCEPT') { + const invoiceId = this.ticket.invoiceOut.id; + const query = `/invoiceOut/api/InvoiceOuts/${invoiceId}/regenerate`; + this.$http.post(query).then(() => { + const snackbarMessage = this.$translate.instant( + `Invoice sent for a regeneration, will be available in a few minutes`); + this.vnApp.showSuccess(snackbarMessage); + }); + } + } + + /** + * Returns if the current ticket + * is already invoiced + * @return {Boolean} - True if invoiced + */ + hasInvoice() { + return this.ticket.refFk !== null; + } } Controller.$inject = ['$state', '$scope', '$http', 'vnApp', '$translate', 'aclService']; diff --git a/modules/ticket/front/descriptor/index.spec.js b/modules/ticket/front/descriptor/index.spec.js index 8e5a43f71..92939c246 100644 --- a/modules/ticket/front/descriptor/index.spec.js +++ b/modules/ticket/front/descriptor/index.spec.js @@ -9,7 +9,10 @@ describe('Ticket Component vnTicketDescriptor', () => { beforeEach(angular.mock.inject(($componentController, _$httpBackend_) => { $httpBackend = _$httpBackend_; controller = $componentController('vnTicketDescriptor'); - controller.ticket = {id: 2}; + controller.ticket = {id: 2, invoiceOut: {id: 1}}; + controller.cardReload = ()=> { + return true; + }; })); describe('showAddTurnDialog()', () => { @@ -78,19 +81,46 @@ describe('Ticket Component vnTicketDescriptor', () => { }); }); - describe('invoiceMakeOut(response)', () => { + describe('makeInvoice(response)', () => { it('should make a query and call $state.reload() method if the response is ACCEPT', () => { spyOn(controller.$state, 'reload'); spyOn(controller.vnApp, 'showSuccess'); $httpBackend.when('POST', `/ticket/api/Tickets/2/makeInvoice`).respond(); $httpBackend.expect('POST', `/ticket/api/Tickets/2/makeInvoice`).respond(); - controller.invoiceMakeOut('ACCEPT'); + controller.makeInvoice('ACCEPT'); $httpBackend.flush(); expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Ticket invoiced'); expect(controller.$state.reload).toHaveBeenCalledWith(); }); }); + + describe('regenerateInvoice(response)', () => { + it('should make a query and show a success snackbar if the response is ACCEPT', () => { + spyOn(controller.vnApp, 'showSuccess'); + + $httpBackend.when('POST', `/invoiceOut/api/InvoiceOuts/1/regenerate`).respond(); + $httpBackend.expect('POST', `/invoiceOut/api/InvoiceOuts/1/regenerate`).respond(); + controller.regenerateInvoice('ACCEPT'); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Invoice sent for a regeneration, will be available in a few minutes'); + }); + }); + + describe('changeShipped(response)', () => { + it('should make a query and change the shipped hour if the response is ACCEPT', () => { + spyOn(controller.vnApp, 'showSuccess'); + spyOn(controller, 'cardReload'); + $httpBackend.when('PATCH', `/ticket/api/Tickets/2`,).respond(); + $httpBackend.expect('PATCH', `/ticket/api/Tickets/2`).respond(); + controller.changeShipped('ACCEPT'); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Shipped hour updated'); + expect(controller.cardReload).toHaveBeenCalledWith(); + }); + }); }); diff --git a/modules/ticket/front/descriptor/locale/es.yml b/modules/ticket/front/descriptor/locale/es.yml index 0e0d0bdd6..e12c95f64 100644 --- a/modules/ticket/front/descriptor/locale/es.yml +++ b/modules/ticket/front/descriptor/locale/es.yml @@ -8,13 +8,18 @@ Add stowaway: Añadir polizón Remove stowaway: Borrar polizón Are you sure you want to delete this stowaway?: ¿Seguro que quieres borrar este polizón? Show Delivery Note: Ver albarán -Show pallet report: Mostrar hoja de pallet +Show pallet report: Ver hoja de pallet Change shipped hour: Cambiar hora de envío Shipped hour: Hora de envío SMSPayment: >- Verdnatura le comunica: Su pedido está pendiente de pago. Por favor, entre en la página web y efectue el pago con tarjeta. Muchas gracias. Ticket invoiced: Ticket facturado -Make invoice: Facturar +Make invoice: Crear factura +Regenerate invoice: Regenerar factura You are going to invoice this ticket: Vas a facturar este ticket -Are you sure you want to invoice this ticket?: ¿Seguro que quieres facturar este ticket? \ No newline at end of file +Are you sure you want to invoice this ticket?: ¿Seguro que quieres facturar este ticket? +You are going to regenerate the invoice: Vas a regenerar la factura +Are you sure you want to regenerate the invoice?: ¿Seguro que quieres regenerar la factura? +Invoice sent for a regeneration, will be available in a few minutes: La factura ha sido enviada para ser regenerada, estará disponible en unos minutos +Shipped hour updated: Hora de envio modificada \ No newline at end of file diff --git a/modules/ticket/front/dms/index.html b/modules/ticket/front/dms/index.html new file mode 100644 index 000000000..878fd3277 --- /dev/null +++ b/modules/ticket/front/dms/index.html @@ -0,0 +1,51 @@ + + + + + + + + + Id + Type + Employee + Created + + + + + + {{::document.dmsFk}} + {{::document.dms.dmsType.name}} + + + {{::document.dms.worker.user.nickname | dashIfEmpty}} + + {{::document.dms.created | dateTime:'dd/MM/yyyy HH:mm'}} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/ticket/front/dms/index.js b/modules/ticket/front/dms/index.js new file mode 100644 index 000000000..ab6456b5f --- /dev/null +++ b/modules/ticket/front/dms/index.js @@ -0,0 +1,51 @@ +import ngModule from '../module'; +import './style.scss'; + +class Controller { + constructor($stateParams, $scope, vnToken) { + this.$stateParams = $stateParams; + this.$ = $scope; + this.accessToken = vnToken.token; + this.filter = { + include: { + relation: 'dms', + scope: { + fields: ['dmsTypeFk', 'workerFk', 'file', 'created'], + include: [{ + relation: 'dmsType', + scope: { + fields: ['name'] + } + }, + { + relation: 'worker', + scope: { + fields: ['userFk'], + include: { + relation: 'user', + scope: { + fields: ['nickname'] + } + }, + } + }] + }, + } + }; + } + + showWorkerDescriptor(event, workerFk) { + event.preventDefault(); + event.stopImmediatePropagation(); + this.$.workerDescriptor.parent = event.target; + this.$.workerDescriptor.workerFk = workerFk; + this.$.workerDescriptor.show(); + } +} + +Controller.$inject = ['$stateParams', '$scope', 'vnToken']; + +ngModule.component('vnTicketDms', { + template: require('./index.html'), + controller: Controller, +}); diff --git a/modules/ticket/front/dms/index.spec.js b/modules/ticket/front/dms/index.spec.js new file mode 100644 index 000000000..8c88b5f1c --- /dev/null +++ b/modules/ticket/front/dms/index.spec.js @@ -0,0 +1,44 @@ +import './index'; + +describe('Client', () => { + describe('Component vnClientBalanceIndex', () => { + let $componentController; + let $scope; + let $httpBackend; + let $httpParamSerializer; + let controller; + + beforeEach(ngModule('client')); + + beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$httpParamSerializer_) => { + $componentController = _$componentController_; + $httpBackend = _$httpBackend_; + $httpParamSerializer = _$httpParamSerializer_; + $scope = $rootScope.$new(); + controller = $componentController('vnClientBalanceIndex', {$scope}); + })); + + describe('balances() setter', () => { + it('should calculate the balance for each line from the oldest date to the newest', () => { + controller.getCurrentBalance = jasmine.createSpy(controller, 'getCurrentBalance').and.returnValue(1000); + let balances = [ + {credit: -100, debit: 0}, + {credit: 0, debit: 300}, + {credit: 100, debit: 0}, + {credit: 0, debit: -300} + ]; + const params = {filter: controller.filter}; + let serializedParams = $httpParamSerializer(params); + $httpBackend.when('GET', `/client/api/ClientRisks?${serializedParams}`).respond(balances); + $httpBackend.expect('GET', `/client/api/ClientRisks?${serializedParams}`); + controller.balances = balances; + $httpBackend.flush(); + + expect(controller.balances[0].balance).toEqual(1000); + expect(controller.balances[1].balance).toEqual(900); + expect(controller.balances[2].balance).toEqual(600); + expect(controller.balances[3].balance).toEqual(700); + }); + }); + }); +}); diff --git a/modules/ticket/front/dms/locale/es.yml b/modules/ticket/front/dms/locale/es.yml new file mode 100644 index 000000000..6422279d9 --- /dev/null +++ b/modules/ticket/front/dms/locale/es.yml @@ -0,0 +1,2 @@ +Type: Tipo +File management: Gestión documental \ No newline at end of file diff --git a/modules/client/front/risk/index/style.scss b/modules/ticket/front/dms/style.scss similarity index 100% rename from modules/client/front/risk/index/style.scss rename to modules/ticket/front/dms/style.scss diff --git a/modules/ticket/front/expedition/index.html b/modules/ticket/front/expedition/index.html index 118206c75..eafd318a2 100644 --- a/modules/ticket/front/expedition/index.html +++ b/modules/ticket/front/expedition/index.html @@ -48,7 +48,7 @@ + ng-click="$ctrl.showWorkerDescriptor($event, expedition.workerFk)"> {{::expedition.userNickname | dashIfEmpty}} @@ -67,7 +67,7 @@ + worker-fk="$ctrl.selectedWorker"> + + + + Id Salesperson @@ -53,6 +58,12 @@ + + + + + ng-click="$ctrl.showWorkerDescriptor($event, ticket.salesPersonFk)"> {{::ticket.userNickname | dashIfEmpty}} @@ -138,9 +149,13 @@ - + - \ No newline at end of file + worker-fk="$ctrl.selectedWorker"> + + + \ No newline at end of file diff --git a/modules/ticket/front/index/index.js b/modules/ticket/front/index/index.js index 01b95dcd1..d88662604 100644 --- a/modules/ticket/front/index/index.js +++ b/modules/ticket/front/index/index.js @@ -11,8 +11,12 @@ export default class Controller { this.selectedTicket = null; this.moreOptions = [ {callback: () => { - this.goToTurns('ticket.weekly'); + this.$state.go('ticket.weekly'); }, name: 'Turns', always: true}, + {callback: () => { + this.setBalanceCreateDialog(); + this.$.balanceCreateDialog.show(); + }, name: 'Payment on account...', always: true} ]; if (!$stateParams.q) @@ -29,6 +33,23 @@ export default class Controller { }); } + setBalanceCreateDialog() { + let data = this.$.tickets; + let description = []; + this.$.balanceCreateDialog.amountPaid = 0; + if (data) { + for (let i = 0; i < data.length; i++) { + if (data[i].checked) { + this.$.balanceCreateDialog.amountPaid += data[i].total; + this.$.balanceCreateDialog.clientFk = data[i].clientFk; + description.push(`${data[i].id}`); + } + } + } + this.$.balanceCreateDialog.description = 'Albaran: '; + this.$.balanceCreateDialog.description += description.join(', '); + } + buildFilterDates() { let today = new Date(); this.today = today.setHours(0, 0, 0, 0); @@ -64,10 +85,6 @@ export default class Controller { window.open(url, '_blank'); } - goToTurns() { - this.$state.go('ticket.weekly'); - } - onMoreOpen() { let options = this.moreOptions.filter(o => o.always || this.isChecked); this.$.moreButton.data = options; @@ -109,9 +126,9 @@ export default class Controller { this.$.clientDescriptor.show(); } - showWorkerDescriptor(event, userId) { + showWorkerDescriptor(event, workerFk) { this.preventDefault(event); - this.selectedWorker = userId; + this.selectedWorker = workerFk; this.$.workerDescriptor.parent = event.target; this.$.workerDescriptor.show(); } diff --git a/modules/ticket/front/index/index.spec.js b/modules/ticket/front/index/index.spec.js index e529f552f..6ca026814 100644 --- a/modules/ticket/front/index/index.spec.js +++ b/modules/ticket/front/index/index.spec.js @@ -1,35 +1,33 @@ import './index.js'; - describe('Component vnTicketIndex', () => { - let $element; let controller; let $window; let tickets = [{ id: 1, clientFk: 1, - salesPersonFk: 9, - shipped: new Date(), - nickname: 'Test', - total: 10.5 + total: 10.5, + checked: false + }, { + id: 2, + clientFk: 1, + total: 20.5, + checked: true + }, { + id: 3, + clientFk: 1, + total: 30, + checked: true }]; beforeEach(() => { - ngModule('worker'); - ngModule('client'); - ngModule('item'); ngModule('ticket'); }); - beforeEach(inject(($compile, $rootScope, _$window_) => { + beforeEach(inject(($componentController, _$window_) => { $window = _$window_; - $element = $compile('')($rootScope); - controller = $element.controller('vnTicketIndex'); + controller = $componentController('vnTicketIndex'); })); - afterEach(() => { - $element.remove(); - }); - describe('compareDate()', () => { it('should return warning when the date is the present', () => { let curDate = new Date(); @@ -57,8 +55,8 @@ describe('Component vnTicketIndex', () => { describe('showClientDescriptor()', () => { it('should show the client descriptor popover', () => { - spyOn(controller.$.clientDescriptor, 'show'); - + controller.$.clientDescriptor = {show: () => {}}; + controller.$.clientDescriptor.show = jasmine.createSpy('show'); let event = new MouseEvent('click', { view: $window, bubbles: true, @@ -72,6 +70,7 @@ describe('Component vnTicketIndex', () => { describe('preview()', () => { it('should show the dialog summary', () => { + controller.$.summary = {show: () => {}}; spyOn(controller.$.summary, 'show'); let event = new MouseEvent('click', { @@ -84,4 +83,19 @@ describe('Component vnTicketIndex', () => { expect(controller.$.summary.show).toHaveBeenCalledWith(); }); }); + + describe('setBalanceCreateDialog()', () => { + it('should fill the object for the component balanceCreateDialog', () => { + controller.$.tickets = tickets; + controller.$.balanceCreateDialog = {}; + controller.$.balanceCreateDialog.amountPaid = 0; + controller.setBalanceCreateDialog(); + + let description = controller.$.balanceCreateDialog.description; + let amountPaid = controller.$.balanceCreateDialog.amountPaid; + + expect(description).toEqual('Albaran: 2, 3'); + expect(amountPaid).toEqual(50.5); + }); + }); }); diff --git a/modules/ticket/front/index/locale/es.yml b/modules/ticket/front/index/locale/es.yml index 293ef9fdc..34fca7fb0 100644 --- a/modules/ticket/front/index/locale/es.yml +++ b/modules/ticket/front/index/locale/es.yml @@ -1,3 +1,4 @@ Turns: Turnos Go to lines: Ir a lineas -Not available: No disponible \ No newline at end of file +Not available: No disponible +Payment on account...: Pago a cuenta... \ No newline at end of file diff --git a/modules/ticket/front/package/index.js b/modules/ticket/front/package/index.js index a225c4349..d73c000c7 100644 --- a/modules/ticket/front/package/index.js +++ b/modules/ticket/front/package/index.js @@ -26,7 +26,7 @@ class Controller { Controller.$inject = ['$scope', '$stateParams']; -ngModule.component('vnTicketPackageIndex', { +ngModule.component('vnTicketPackage', { template: require('./index.html'), controller: Controller }); diff --git a/modules/ticket/front/request/index/index.html b/modules/ticket/front/request/index/index.html index eb2de0af0..015aa0615 100644 --- a/modules/ticket/front/request/index/index.html +++ b/modules/ticket/front/request/index/index.html @@ -38,14 +38,14 @@ + ng-click="$ctrl.showWorkerDescriptor($event, request.requesterFk)"> {{::request.requester.user.nickname | dashIfEmpty}} + ng-click="$ctrl.showWorkerDescriptor($event, request.atenderFk)"> {{::request.atender.user.nickname | dashIfEmpty}} @@ -87,7 +87,7 @@ + worker-fk="$ctrl.selectedWorker"> + ng-click="$ctrl.showWorkerDescriptor($event, sale.workerFk)"> {{::sale.userNickname | dashIfEmpty}} @@ -67,5 +67,5 @@ + worker-fk="$ctrl.selectedWorker"> \ No newline at end of file diff --git a/modules/ticket/front/sale-tracking/index.js b/modules/ticket/front/sale-tracking/index.js index b0f7e8041..41ff12a4a 100644 --- a/modules/ticket/front/sale-tracking/index.js +++ b/modules/ticket/front/sale-tracking/index.js @@ -23,10 +23,10 @@ class Controller { this.$.itemDescriptor.show(); } - showWorkerDescriptor(event, userId) { + showWorkerDescriptor(event, workerFk) { event.preventDefault(); event.stopImmediatePropagation(); - this.selectedWorker = userId; + this.selectedWorker = workerFk; this.$.workerDescriptor.parent = event.target; this.$.workerDescriptor.show(); } diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html index 89848a99f..d57c0b7c2 100644 --- a/modules/ticket/front/sale/index.html +++ b/modules/ticket/front/sale/index.html @@ -56,7 +56,7 @@ + model="model"> diff --git a/modules/ticket/front/sale/locale/es.yml b/modules/ticket/front/sale/locale/es.yml index 9cb44405b..707de7c0f 100644 --- a/modules/ticket/front/sale/locale/es.yml +++ b/modules/ticket/front/sale/locale/es.yml @@ -31,3 +31,4 @@ Reserved: Reservado SMSAvailability: >- Verdnatura le comunica: Pedido {{ticketFk}} día {{created | date: "dd/MM/yyyy"}}. {{notAvailables}} no disponible/s. Disculpe las molestias. +Continue anyway?: ¿Continuar de todas formas? \ No newline at end of file diff --git a/modules/ticket/front/tracking/index/index.html b/modules/ticket/front/tracking/index/index.html index 3252385a8..1292c797e 100644 --- a/modules/ticket/front/tracking/index/index.html +++ b/modules/ticket/front/tracking/index/index.html @@ -41,5 +41,5 @@ + worker-fk="$ctrl.selectedWorker"> \ No newline at end of file diff --git a/modules/ticket/front/tracking/index/index.js b/modules/ticket/front/tracking/index/index.js index 58db5f774..adc1ac5a2 100644 --- a/modules/ticket/front/tracking/index/index.js +++ b/modules/ticket/front/tracking/index/index.js @@ -28,10 +28,10 @@ class Controller { }; } - showWorkerDescriptor(event, userId) { + showWorkerDescriptor(event, workerFk) { event.preventDefault(); event.stopImmediatePropagation(); - this.selectedWorker = userId; + this.selectedWorker = workerFk; this.$.workerDescriptor.parent = event.target; this.$.workerDescriptor.show(); } diff --git a/modules/worker/back/methods/department/nodeAdd.js b/modules/worker/back/methods/department/nodeAdd.js index bbbcd82ef..58c50f0bd 100644 --- a/modules/worker/back/methods/department/nodeAdd.js +++ b/modules/worker/back/methods/department/nodeAdd.js @@ -29,7 +29,7 @@ module.exports = Self => { let stmts = []; let conn = Self.dataSource.connector; let nodeIndex = stmts.push(new ParameterizedSQL( - `CALL nst.NodeAdd('vn', 'department', ?, ?)`, [parentFk, name])) - 1; + `CALL nst.nodeAdd('vn', 'department', ?, ?)`, [parentFk, name])) - 1; stmts.push(`CALL nst.nodeRecalc('vn', 'department')`); diff --git a/modules/worker/back/methods/worker-calendar/absences.js b/modules/worker/back/methods/worker-calendar/absences.js index 1ca212863..b6eae8a13 100644 --- a/modules/worker/back/methods/worker-calendar/absences.js +++ b/modules/worker/back/methods/worker-calendar/absences.js @@ -25,10 +25,12 @@ module.exports = Self => { arg: 'calendar' }, { - arg: 'absences' + arg: 'absences', + type: 'Number' }, { - arg: 'holidays' + arg: 'holidays', + type: 'Number' }], http: { path: `/absences`, @@ -147,8 +149,16 @@ module.exports = Self => { const startedTime = started.getTime(); const contractDays = Math.floor((endedTime - startedTime) / dayTimestamp); - if (contractDays < 365) - return Math.floor(contract.holidays().days * (contractDays + 1) / 365); + if (contractDays < 365) { + let holidays = contract.holidays().days * (contractDays + 1) / 365; + let integerPart = parseInt(holidays); + let decimalPart = holidays - integerPart; + let decimal = decimalPart >= 0.5 ? 0.5 : 0; + + holidays = integerPart + decimal; + + return holidays; + } return contract.holidays().days; } diff --git a/modules/worker/back/methods/worker-calendar/specs/absences.spec.js b/modules/worker/back/methods/worker-calendar/specs/absences.spec.js index 526366d6f..336f55636 100644 --- a/modules/worker/back/methods/worker-calendar/specs/absences.spec.js +++ b/modules/worker/back/methods/worker-calendar/specs/absences.spec.js @@ -1,6 +1,19 @@ const app = require('vn-loopback/server/server'); describe('Worker absences()', () => { + afterAll(async done => { + const hiredWorker = await app.models.WorkerLabour.findById(106); + + const endedDate = new Date(); + endedDate.setFullYear(endedDate.getFullYear() + 1); + endedDate.setHours(0, 0, 0, 0); + endedDate.setMonth(0); + endedDate.setDate(1); + + await hiredWorker.updateAttributes({ended: endedDate}); + done(); + }); + it('should get the absence calendar for the given dates then evaluate the type of absences', async() => { let ctx = {req: {accessToken: {userId: 106}}}; let workerFk = 106; @@ -20,7 +33,121 @@ describe('Worker absences()', () => { let calendar = result[0]; let absences = result[1]; - expect(calendar.totalHolidays).toEqual(21); + expect(calendar.totalHolidays).toEqual(27.5); + expect(calendar.holidaysEnjoyed).toEqual(5); + + let firstType = absences[0].absenceType().name; + let sixthType = absences[5].absenceType().name; + + expect(firstType).toEqual('Leave of absence'); + expect(sixthType).toEqual('Holidays'); + }); + + it(`should fire the worker 106 on July and see he/she has 13.75`, async() => { + const firedWorker = await app.models.WorkerLabour.findById(106); + + const endedDate = new Date(); + endedDate.setHours(0, 0, 0, 0); + endedDate.setMonth(5); + endedDate.setDate(31); + + await firedWorker.updateAttributes({ended: endedDate}); + + let ctx = {req: {accessToken: {userId: 106}}}; + let workerFk = 106; + + const started = new Date(); + started.setHours(0, 0, 0, 0); + started.setMonth(0); + started.setDate(1); + + const monthIndex = 11; + const ended = new Date(); + ended.setHours(0, 0, 0, 0); + ended.setMonth(monthIndex + 1); + ended.setDate(0); + + let result = await app.models.WorkerCalendar.absences(ctx, workerFk, started, ended); + let calendar = result[0]; + let absences = result[1]; + + expect(calendar.totalHolidays).toEqual(13.5); + expect(calendar.holidaysEnjoyed).toEqual(5); + + let firstType = absences[0].absenceType().name; + let sixthType = absences[5].absenceType().name; + + expect(firstType).toEqual('Leave of absence'); + expect(sixthType).toEqual('Holidays'); + }); + + it(`should fire the worker 106 on March and see he/she has 6.5`, async() => { + const firedWorker = await app.models.WorkerLabour.findById(106); + + const endedDate = new Date(); + endedDate.setHours(0, 0, 0, 0); + endedDate.setMonth(2); + endedDate.setDate(31); + + await firedWorker.updateAttributes({ended: endedDate}); + + let ctx = {req: {accessToken: {userId: 106}}}; + let workerFk = 106; + + const started = new Date(); + started.setHours(0, 0, 0, 0); + started.setMonth(0); + started.setDate(1); + + const monthIndex = 11; + const ended = new Date(); + ended.setHours(0, 0, 0, 0); + ended.setMonth(monthIndex + 1); + ended.setDate(0); + + let result = await app.models.WorkerCalendar.absences(ctx, workerFk, started, ended); + let calendar = result[0]; + let absences = result[1]; + + expect(calendar.totalHolidays).toEqual(6.5); + expect(calendar.holidaysEnjoyed).toEqual(5); + + let firstType = absences[0].absenceType().name; + let sixthType = absences[5].absenceType().name; + + expect(firstType).toEqual('Leave of absence'); + expect(sixthType).toEqual('Holidays'); + }); + + it(`should fire the worker 106 on january and see he/she has x`, async() => { + const firedWorker = await app.models.WorkerLabour.findById(106); + + const endedDate = new Date(); + endedDate.setHours(0, 0, 0, 0); + endedDate.setMonth(0); + endedDate.setDate(28); + + await firedWorker.updateAttributes({ended: endedDate}); + + let ctx = {req: {accessToken: {userId: 106}}}; + let workerFk = 106; + + const started = new Date(); + started.setHours(0, 0, 0, 0); + started.setMonth(0); + started.setDate(1); + + const monthIndex = 11; + const ended = new Date(); + ended.setHours(0, 0, 0, 0); + ended.setMonth(monthIndex + 1); + ended.setDate(0); + + let result = await app.models.WorkerCalendar.absences(ctx, workerFk, started, ended); + let calendar = result[0]; + let absences = result[1]; + + expect(calendar.totalHolidays).toEqual(2); expect(calendar.holidaysEnjoyed).toEqual(5); let firstType = absences[0].absenceType().name; diff --git a/modules/worker/back/methods/worker/filter.js b/modules/worker/back/methods/worker/filter.js index 961abf291..21462eb42 100644 --- a/modules/worker/back/methods/worker/filter.js +++ b/modules/worker/back/methods/worker/filter.js @@ -28,6 +28,11 @@ module.exports = Self => { type: 'Integer', description: 'The worker id', http: {source: 'query'} + }, { + arg: 'userFk', + type: 'Integer', + description: 'The user id', + http: {source: 'query'} }, { arg: 'fi', type: 'String', @@ -56,7 +61,7 @@ module.exports = Self => { }, { arg: 'nickname', type: 'String', - description: 'The worker name', + description: 'The worker nickname', http: {source: 'query'} } ], @@ -80,13 +85,16 @@ module.exports = Self => { ? {'w.id': value} : {or: [ {'w.firstName': {like: `%${value}%`}}, - {'w.name': {like: `%${value}%`}}, - {'u.name': {like: `%${value}%`}} + {'w.lastName': {like: `%${value}%`}}, + {'u.name': {like: `%${value}%`}}, + {'u.nickname': {like: `%${value}%`}} ]}; case 'id': return {'w.id': value}; + case 'userFk': + return {'w.userFk': value}; case 'name': - return {'w.name': {like: `%${value}%`}}; + return {'w.lastName': {like: `%${value}%`}}; case 'firstName': return {'w.firstName': {like: `%${value}%`}}; case 'extension': @@ -107,7 +115,7 @@ module.exports = Self => { stmt = new ParameterizedSQL( `SELECT w.id, u.email, p.extension, u.name as userName, - d.name AS department, w.name, u.nickname, mu.email + d.name AS department, w.lastName, u.nickname, mu.email FROM worker w LEFT JOIN workerDepartment wd ON wd.workerFk = w.id LEFT JOIN department d ON d.id = wd.departmentFk diff --git a/modules/worker/back/methods/worker/specs/filter.spec.js b/modules/worker/back/methods/worker/specs/filter.spec.js new file mode 100644 index 000000000..c1bc05ae8 --- /dev/null +++ b/modules/worker/back/methods/worker/specs/filter.spec.js @@ -0,0 +1,25 @@ +const app = require('vn-loopback/server/server'); + +describe('worker filter()', () => { + it('should return 1 result filtering by id', async() => { + let result = await app.models.Worker.filter({args: {filter: {}, search: 1}}); + + expect(result.length).toEqual(1); + expect(result[0].id).toEqual(1); + }); + + it('should return 1 result filtering by string', async() => { + let result = await app.models.Worker.filter({args: {filter: {}, search: 'administrativeNick'}}); + + expect(result.length).toEqual(1); + expect(result[0].id).toEqual(5); + }); + + it('should return 2 results filtering by name', async() => { + let result = await app.models.Worker.filter({args: {filter: {}, name: 'agency'}}); + + expect(result.length).toEqual(2); + expect(result[0].nickname).toEqual('agencyNick'); + expect(result[1].nickname).toEqual('agencyBossNick'); + }); +}); diff --git a/modules/worker/back/models/department.js b/modules/worker/back/models/department.js index 99b470dbb..085c2bf9b 100644 --- a/modules/worker/back/models/department.js +++ b/modules/worker/back/models/department.js @@ -8,10 +8,6 @@ module.exports = Self => { Self.rewriteDbError(function(err) { if (err.code === 'ER_ROW_IS_REFERENCED_2') return new UserError(`You cannot remove this department`); - return err; - }); - - Self.rewriteDbError(function(err) { if (err.code === 'ER_DUP_ENTRY') return new UserError(`The department name can't be repeated`); return err; diff --git a/modules/worker/front/department/index.html b/modules/worker/front/department/index.html index 7cf4bade7..6cf2cd063 100644 --- a/modules/worker/front/department/index.html +++ b/modules/worker/front/department/index.html @@ -11,7 +11,10 @@ + on-drop="$ctrl.onDrop(item, dragged, dropped)" + icons="$ctrl.icons" + draggable="true" droppable="true" + acl-role="hr" editable="true">
    diff --git a/modules/worker/front/department/index.js b/modules/worker/front/department/index.js index 99d65a478..2047c06c7 100644 --- a/modules/worker/front/department/index.js +++ b/modules/worker/front/department/index.js @@ -26,6 +26,20 @@ class Controller { this.$scope.deleteNode.show(); } + onDrop(item, dragged, dropped) { + if (dropped.scope.item) { + const droppedItem = dropped.scope.item; + const draggedItem = dragged.scope.item; + + if (droppedItem.childs) + droppedItem.childs.push(Object.assign({}, draggedItem)); + + dragged.element.remove(); + + this.$scope.$apply(); + } + } + onCreateDialogOpen() { this.newNode.name = ''; } diff --git a/modules/worker/front/descriptor-popover/index.js b/modules/worker/front/descriptor-popover/index.js index cd8916ec5..168b2f423 100644 --- a/modules/worker/front/descriptor-popover/index.js +++ b/modules/worker/front/descriptor-popover/index.js @@ -11,16 +11,16 @@ class Controller extends Component { this.worker = null; } - set userId(id) { - if (id == this._userId) return; + set workerFk(workerFk) { + if (workerFk == this._workerFk) return; - this._userId = id; + this._workerFk = workerFk; this.worker = null; this.loadData(); } - get userId() { - return this._userId; + get workerFk() { + return this._workerFk; } set quicklinks(value = {}) { @@ -40,7 +40,7 @@ class Controller extends Component { let query = `api/Workers/findOne`; let filter = { where: { - userFk: this._userId + id: this._workerFk }, include: [ { @@ -88,7 +88,7 @@ ngModule.component('vnWorkerDescriptorPopover', { template: require('./index.html'), controller: Controller, bindings: { - userId: '<', + workerFk: '<', quicklinks: '<' } }); diff --git a/modules/worker/front/descriptor-popover/index.spec.js b/modules/worker/front/descriptor-popover/index.spec.js index d6c04e9e7..74dc3164b 100644 --- a/modules/worker/front/descriptor-popover/index.spec.js +++ b/modules/worker/front/descriptor-popover/index.spec.js @@ -21,23 +21,23 @@ describe('worker Component vnWorkerDescriptorPopover', () => { describe('workerFk()', () => { it(`should not apply any changes if the received id is the same stored in _workerFk`, () => { controller.worker = 'I exist!'; - controller._userId = 1; + controller._workerFk = 1; spyOn(controller, 'loadData'); - controller.userId = 1; + controller.workerFk = 1; expect(controller.worker).toEqual('I exist!'); - expect(controller._userId).toEqual(1); + expect(controller._workerFk).toEqual(1); expect(controller.loadData).not.toHaveBeenCalled(); }); it(`should set the received id into _workerFk, set the worker to null and then call loadData()`, () => { controller.worker = `Please don't`; - controller._userId = 1; + controller._workerFk = 1; spyOn(controller, 'loadData'); - controller.userId = 999; + controller.workerFk = 999; expect(controller.worker).toBeNull(); - expect(controller._userId).toEqual(999); + expect(controller._workerFk).toEqual(999); expect(controller.loadData).toHaveBeenCalledWith(); }); }); @@ -53,14 +53,14 @@ describe('worker Component vnWorkerDescriptorPopover', () => { describe('loadData()', () => { it(`should perform a get query to store the worker data into the controller`, () => { - controller.userId = 1; + controller.workerFk = 1; controller.canceler = null; let response = {}; let config = { filter: { where: { - userFk: controller.userId + id: controller.workerFk }, include: [ { diff --git a/modules/worker/front/log/index.html b/modules/worker/front/log/index.html index a060289a6..1c3c76459 100644 --- a/modules/worker/front/log/index.html +++ b/modules/worker/front/log/index.html @@ -94,5 +94,5 @@ + worker-fk="$ctrl.selectedWorker"> diff --git a/modules/worker/front/log/index.js b/modules/worker/front/log/index.js index 6cd36d47c..632b1c889 100644 --- a/modules/worker/front/log/index.js +++ b/modules/worker/front/log/index.js @@ -12,13 +12,13 @@ export default class Controller { }; } - showWorkerDescriptor(event, userId) { + showWorkerDescriptor(event, workerFk) { if (event.defaultPrevented) return; event.preventDefault(); event.stopPropagation(); - this.selectedWorker = userId; + this.selectedWorker = workerFk; this.$.workerDescriptor.parent = event.target; this.$.workerDescriptor.show(); } diff --git a/modules/worker/front/search-panel/index.html b/modules/worker/front/search-panel/index.html index 14abcad45..eda57c540 100644 --- a/modules/worker/front/search-panel/index.html +++ b/modules/worker/front/search-panel/index.html @@ -18,7 +18,7 @@ + model="filter.userFk"> diff --git a/package-lock.json b/package-lock.json index 0c1499004..21ae3042c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3687,7 +3687,7 @@ "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "integrity": "sha1-HxngwuGqDjJ5fEl5nyg3rGr2nFc=", "dev": true, "requires": { "is-obj": "^1.0.0" @@ -3860,7 +3860,7 @@ }, "jsonfile": { "version": "2.4.0", - "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { @@ -4271,9 +4271,9 @@ } }, "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -5162,14 +5162,14 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.8.tgz", + "integrity": "sha512-tPvHgPGB7m40CZ68xqFGkKuzN+RnpGmSV+hgeKxhRpbxdqKXUFJGC3yonBOLzQBcJyGpdZFDfCsdOC2KFsXzeA==", "dev": true, "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { @@ -5191,7 +5191,7 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, @@ -5217,7 +5217,7 @@ } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -5247,16 +5247,16 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "4.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -5305,7 +5305,7 @@ } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, @@ -5325,12 +5325,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -5395,17 +5395,17 @@ "optional": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, "optional": true, "requires": { - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, @@ -5423,35 +5423,35 @@ } }, "ms": { - "version": "2.0.0", + "version": "2.1.1", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.2.0", + "version": "2.3.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^2.1.2", + "debug": "^4.1.0", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.12.0", "bundled": true, "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", - "needle": "^2.2.0", + "needle": "^2.2.1", "nopt": "^4.0.1", "npm-packlist": "^1.1.6", "npmlog": "^4.0.2", - "rc": "^1.1.7", + "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", "tar": "^4" @@ -5468,13 +5468,13 @@ } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.6", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.4.1", "bundled": true, "dev": true, "optional": true, @@ -5551,12 +5551,12 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" @@ -5586,16 +5586,16 @@ } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, "dev": true, "optional": true @@ -5613,7 +5613,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.7.0", "bundled": true, "dev": true, "optional": true @@ -5666,17 +5666,17 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.2" } }, @@ -5687,12 +5687,12 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { @@ -5702,7 +5702,7 @@ "optional": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, "dev": true, "optional": true @@ -7703,9 +7703,9 @@ "dev": true }, "js-yaml": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", - "integrity": "sha1-LnhEFka9RoLpY/IrbpKCPDCcYtw=", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -7880,7 +7880,7 @@ "karma-chrome-launcher": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", - "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "integrity": "sha1-zxudBxNswY/iOTJ9JGVMPbw2is8=", "dev": true, "requires": { "fs-access": "^1.0.0", @@ -9704,7 +9704,7 @@ "dependencies": { "commander": { "version": "1.0.4", - "resolved": "http://registry.npmjs.org/commander/-/commander-1.0.4.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-1.0.4.tgz", "integrity": "sha1-Xt6xruI8T7VBprcNaSq+8ZZpotM=", "dev": true, "requires": { @@ -12242,7 +12242,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -12254,7 +12254,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, @@ -12983,13 +12983,13 @@ "resolved": "https://registry.npmjs.org/require-yaml/-/require-yaml-0.0.1.tgz", "integrity": "sha1-LhsY2RPDuqcqWk03O28Tjd0sMr0=", "requires": { - "js-yaml": "^3.10.0" + "js-yaml": "^3.13.1" }, "dependencies": { "js-yaml": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", - "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -13527,7 +13527,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -15079,7 +15079,7 @@ "touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "integrity": "sha1-/jZfX3XsntTlaCXgu3bSSrdK+Ds=", "dev": true, "requires": { "nopt": "~1.0.10" diff --git a/print/report/client-welcome/index.js b/print/report/client-welcome/index.js index 1e6b7934c..b2278b4ee 100755 --- a/print/report/client-welcome/index.js +++ b/print/report/client-welcome/index.js @@ -30,7 +30,7 @@ module.exports = { u.lang locale, u.name AS userName, c.email recipient, - CONCAT(w.name, ' ', w.firstName) salesPersonName, + CONCAT(w.lastName, ' ', w.firstName) salesPersonName, w.phone AS salesPersonPhone, CONCAT(wu.name, '@verdnatura.es') AS salesPersonEmail FROM client c diff --git a/print/report/printer-setup/index.js b/print/report/printer-setup/index.js index 5a2c5758b..1353d996c 100755 --- a/print/report/printer-setup/index.js +++ b/print/report/printer-setup/index.js @@ -38,7 +38,7 @@ module.exports = { u.lang locale, u.name AS userName, c.email recipient, - CONCAT(w.name, ' ', w.firstName) salesPersonName, + CONCAT(w.lastName, ' ', w.firstName) salesPersonName, w.phone AS salesPersonPhone, CONCAT(wu.name, '@verdnatura.es') AS salesPersonEmail FROM client c