diff --git a/.eslintrc.yml b/.eslintrc.yml index 82a1af5010..d8b869d919 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -34,4 +34,5 @@ rules: no-multiple-empty-lines: ["error", { "max": 1, "maxEOF": 1 }] space-in-parens: ["error", "never"] jasmine/no-focused-tests: 0 - jasmine/prefer-toHaveBeenCalledWith: 0 \ No newline at end of file + jasmine/prefer-toHaveBeenCalledWith: 0 + arrow-spacing: ["error", { "before": true, "after": true }] \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 8f87ffe610..85914ad623 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -49,7 +49,7 @@ pipeline { NODE_ENV = "" } steps { - nodejs('node-lts') { + nodejs('node-v12') { sh 'npm install --no-audit --prefer-offline' sh 'gulp install --ci' } @@ -66,14 +66,14 @@ pipeline { parallel { stage('Frontend') { steps { - nodejs('node-lts') { + nodejs('node-v12') { sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2' } } } // stage('Backend') { // steps { - // nodejs('node-lts') { + // nodejs('node-v12') { // sh 'gulp launchBackTest --ci' // } // } @@ -89,7 +89,7 @@ pipeline { CREDS = credentials('docker-registry') } steps { - nodejs('node-lts') { + nodejs('node-v12') { sh 'gulp build' } diff --git a/back/methods/chat/notifyIssues.js b/back/methods/chat/notifyIssues.js new file mode 100644 index 0000000000..54eb41c895 --- /dev/null +++ b/back/methods/chat/notifyIssues.js @@ -0,0 +1,39 @@ +module.exports = Self => { + Self.remoteMethodCtx('notifyIssues', { + description: 'Notifies new urgent issues', + accessType: 'READ', + returns: { + type: 'Object', + root: true + }, + http: { + path: `/notifyIssues`, + verb: 'GET' + } + }); + + Self.notifyIssues = async ctx => { + const models = Self.app.models; + const $t = ctx.req.__; // $translate + const [urgentIssue] = await Self.rawSql(` + SELECT * FROM managedesktop.vn_workOrderInmediata LIMIT 1 + `); + + if (!urgentIssue) return; + + const message = $t(`There's a new urgent ticket`, { + title: urgentIssue.title, + issueId: urgentIssue.workOrderId + }); + + const department = await models.Department.findOne({ + where: {code: 'IT'} + }); + const channelName = department && department.chatName; + + if (channelName) + return Self.send(ctx, `#${channelName}`, `@all ➔ ${message}`); + + return; + }; +}; diff --git a/back/methods/chat/spec/notifyIssue.spec.js b/back/methods/chat/spec/notifyIssue.spec.js new file mode 100644 index 0000000000..e23c33859e --- /dev/null +++ b/back/methods/chat/spec/notifyIssue.spec.js @@ -0,0 +1,38 @@ +const app = require('vn-loopback/server/server'); + +describe('Chat notifyIssue()', () => { + const ctx = {req: {accessToken: {userId: 1}}}; + ctx.req.__ = value => { + return value; + }; + const chatModel = app.models.Chat; + const departmentId = 31; + + it(`should not call to the send() method and neither return a response`, async() => { + spyOn(chatModel, 'send').and.callThrough(); + spyOn(chatModel, 'rawSql').and.returnValue([]); + + const response = await chatModel.notifyIssues(ctx); + + expect(chatModel.send).not.toHaveBeenCalled(); + expect(response).toBeUndefined(); + }); + + it(`should return a response calling the send() method`, async() => { + spyOn(chatModel, 'send').and.callThrough(); + spyOn(chatModel, 'rawSql').and.returnValue([{title: 'Issue title'}]); + + const department = await app.models.Department.findById(departmentId); + let orgChatName = department.chatName; + await department.updateAttribute('chatName', 'IT'); + + const response = await chatModel.notifyIssues(ctx); + + expect(response.statusCode).toEqual(200); + expect(response.message).toEqual('Fake notification sent'); + expect(chatModel.send).toHaveBeenCalledWith(ctx, '#IT', `@all ➔ There's a new urgent ticket`); + + // restores + await department.updateAttribute('chatName', orgChatName); + }); +}); diff --git a/back/methods/chat/spec/send.spec.js b/back/methods/chat/spec/send.spec.js index 56f2a9c275..2c23bb5918 100644 --- a/back/methods/chat/spec/send.spec.js +++ b/back/methods/chat/spec/send.spec.js @@ -1,6 +1,6 @@ const app = require('vn-loopback/server/server'); -describe('chat send()', () => { +describe('Chat send()', () => { it('should return a "Fake notification sent" as response', async() => { let ctx = {req: {accessToken: {userId: 1}}}; let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something'); diff --git a/back/methods/chat/spec/sendCheckingPresence.spec.js b/back/methods/chat/spec/sendCheckingPresence.spec.js index b3e89180ce..aa4a80801e 100644 --- a/back/methods/chat/spec/sendCheckingPresence.spec.js +++ b/back/methods/chat/spec/sendCheckingPresence.spec.js @@ -1,6 +1,6 @@ const app = require('vn-loopback/server/server'); -describe('chat sendCheckingPresence()', () => { +describe('Chat sendCheckingPresence()', () => { const today = new Date(); today.setHours(6, 0); const ctx = {req: {accessToken: {userId: 1}}}; diff --git a/back/methods/dms/updateFile.js b/back/methods/dms/updateFile.js index a420f2ea11..314761932b 100644 --- a/back/methods/dms/updateFile.js +++ b/back/methods/dms/updateFile.js @@ -11,25 +11,36 @@ module.exports = Self => { type: 'Number', description: 'The document id', http: {source: 'path'} - }, { + }, + { arg: 'warehouseId', type: 'Number', description: 'The warehouse id' - }, { + }, + { arg: 'companyId', type: 'Number', description: 'The company id' - }, { + }, + { arg: 'dmsTypeId', type: 'Number', description: 'The dms type id' - }, { + }, + { arg: 'reference', type: 'String' - }, { + }, + { arg: 'description', type: 'String' - }, { + }, + { + arg: 'hasFile', + type: 'Boolean', + description: 'True if has an attached file' + }, + { arg: 'hasFileAttached', type: 'Boolean', description: 'True if has an attached file' @@ -70,7 +81,8 @@ module.exports = Self => { companyFk: args.companyId, warehouseFk: args.warehouseId, reference: args.reference, - description: args.description + description: args.description, + hasFile: args.hasFile }, myOptions); if (args.hasFileAttached) diff --git a/back/methods/image/download.js b/back/methods/image/download.js index 9b02a7b395..bbfe8e41a1 100644 --- a/back/methods/image/download.js +++ b/back/methods/image/download.js @@ -57,6 +57,9 @@ module.exports = Self => { const entity = await models[imageCollection.model].findById(id, { fields: ['id', imageCollection.property] }); + + if (!entity) return false; + const image = await models.Image.findOne({where: { collectionFk: collection, name: entity[imageCollection.property]} diff --git a/back/model-config.json b/back/model-config.json index 5e4cc23a25..7759c32fad 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -35,6 +35,15 @@ "DmsContainer": { "dataSource": "dmsStorage" }, + "Dms": { + "dataSource": "vn" + }, + "DmsType": { + "dataSource": "vn" + }, + "EmailUser": { + "dataSource": "vn" + }, "Image": { "dataSource": "vn" }, @@ -53,38 +62,32 @@ "Province": { "dataSource": "vn" }, - "TempContainer": { - "dataSource": "tempStorage" - }, - "UserConfig": { - "dataSource": "vn" - }, - "Warehouse": { - "dataSource": "vn" - }, - "SageWithholding": { - "dataSource": "vn" - }, - "UserConfigView": { - "dataSource": "vn" - }, - "EmailUser": { - "dataSource": "vn" - }, - "Dms": { - "dataSource": "vn" - }, - "DmsType": { - "dataSource": "vn" - }, - "Town": { + "Payment": { "dataSource": "vn" }, "Postcode": { "dataSource": "vn" }, + "SageWithholding": { + "dataSource": "vn" + }, + "TempContainer": { + "dataSource": "tempStorage" + }, + "Town": { + "dataSource": "vn" + }, + "UserConfig": { + "dataSource": "vn" + }, + "UserConfigView": { + "dataSource": "vn" + }, "UserLog": { "dataSource": "vn" + }, + "Warehouse": { + "dataSource": "vn" } } diff --git a/back/models/accounting-type.json b/back/models/accounting-type.json index 7967933428..86befe2ea6 100644 --- a/back/models/accounting-type.json +++ b/back/models/accounting-type.json @@ -8,17 +8,20 @@ }, "properties": { "id": { - "type": "Number", + "type": "number", "id": true, "description": "Identifier" }, "description": { - "type": "String", + "type": "string", "required": true }, "receiptDescription": { - "type": "String", + "type": "string", "required": true + }, + "code": { + "type": "string" } }, "acls": [{ diff --git a/back/models/chat.js b/back/models/chat.js index ab23ef7131..5487569c10 100644 --- a/back/models/chat.js +++ b/back/models/chat.js @@ -1,4 +1,5 @@ module.exports = Self => { require('../methods/chat/send')(Self); require('../methods/chat/sendCheckingPresence')(Self); + require('../methods/chat/notifyIssues')(Self); }; diff --git a/back/models/company.json b/back/models/company.json index eb349477b4..80ad026e4e 100644 --- a/back/models/company.json +++ b/back/models/company.json @@ -18,6 +18,9 @@ }, "expired": { "type": "date" + }, + "isOfficial": { + "type": "boolean" } }, diff --git a/back/models/dms.json b/back/models/dms.json index 1d9e3ec21b..f517a23ffe 100644 --- a/back/models/dms.json +++ b/back/models/dms.json @@ -30,7 +30,7 @@ "type": "string" }, "hardCopyNumber": { - "type": "Number" + "type": "number" }, "hasFile": { "type": "boolean" diff --git a/back/models/image.json b/back/models/image.json index 047e5f5e4f..57e33a6845 100644 --- a/back/models/image.json +++ b/back/models/image.json @@ -26,7 +26,7 @@ "nRefs": { "type": "Number", "required": true, - "default": 0 + "default": 1 } }, "relations": { diff --git a/back/models/payment.json b/back/models/payment.json new file mode 100644 index 0000000000..7eca36e4df --- /dev/null +++ b/back/models/payment.json @@ -0,0 +1,64 @@ +{ + "name": "Payment", + "base": "VnModel", + "options": { + "mysql": { + "table": "payment" + } + }, + "properties": { + "id": { + "type": "number", + "id": true, + "description": "Identifier" + }, + "received": { + "type": "date" + }, + "amount": { + "type": "number" + }, + "divisa": { + "type": "number" + }, + "concept": { + "type": "string" + }, + "created": { + "type": "date" + }, + "isConciliated": { + "type": "boolean" + }, + "dueDated": { + "type": "date" + } + }, + "relations": { + "supplier": { + "type": "belongsTo", + "model": "Supplier", + "foreignKey": "supplierFk" + }, + "currency": { + "type": "belongsTo", + "model": "Currency", + "foreignKey": "currencyFk" + }, + "bank": { + "type": "belongsTo", + "model": "Bank", + "foreignKey": "bankFk" + }, + "payMethod": { + "type": "belongsTo", + "model": "PayMethodFk", + "foreignKey": "payMethodFk" + }, + "company": { + "type": "belongsTo", + "model": "Company", + "foreignKey": "companyFk" + } + } +} \ No newline at end of file diff --git a/db/changes/10260-holidays/00-ACL.sql b/db/changes/10260-holidays/00-ACL.sql index e72e6fa73b..83b8aded66 100644 --- a/db/changes/10260-holidays/00-ACL.sql +++ b/db/changes/10260-holidays/00-ACL.sql @@ -1,2 +1 @@ -INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId) VALUES ('Image', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'); -INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('PayDem', '*', 'READ', 'ALLOW', 'ROLE', 'employee'); \ No newline at end of file +INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId) VALUES ('Image', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'); \ No newline at end of file diff --git a/db/changes/10271-wisemen/00-ACL.sql b/db/changes/10271-wisemen/00-ACL.sql index e4b84a3e4b..180c07bd6c 100644 --- a/db/changes/10271-wisemen/00-ACL.sql +++ b/db/changes/10271-wisemen/00-ACL.sql @@ -1,3 +1,5 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('FixedPrice', '*', '*', 'ALLOW', 'ROLE', 'buyer'); +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('PayDem', '*', 'READ', 'ALLOW', 'ROLE', 'employee'); +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Client', 'createReceipt', '*', 'ALLOW', 'ROLE', 'administrative'); INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId) VALUES ('PrintServerQueue', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'); -INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('FixedPrice', '*', '*', 'ALLOW', 'ROLE', 'buyer'); diff --git a/db/changes/10271-wisemen/01-doCompensation.sql b/db/changes/10271-wisemen/01-doCompensation.sql new file mode 100644 index 0000000000..d1021ae429 --- /dev/null +++ b/db/changes/10271-wisemen/01-doCompensation.sql @@ -0,0 +1,82 @@ +DROP PROCEDURE IF EXISTS vn.ledger_doCompensation; + + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ledger_doCompensation`(vDated DATE, vCompensationAccount VARCHAR(10) , vBankFk VARCHAR(10), vConcept VARCHAR(255), vAmount DECIMAL(10,2), vCompanyFk INT, vOriginalAccount VARCHAR(10)) +BEGIN +/** + * Compensa un pago o un recibo insertando en contabilidad + * + * @param vDated fecha en la cual se anota + * @param vCompensationAccount cuenta contable contra la que se compensa + * @param vBankFk banco de la compensacion + * @param vConcept descripcion + * @param vAmount cantidad que se compensa + * @param vCompany empresa + * @param vOriginalAccount cuenta contable desde la cual se compensa + * + */ + DECLARE vNewBookEntry INT; + DECLARE vIsClientCompensation INT; + DECLARE vClientFk INT; + DECLARE vSupplierFk INT; + DECLARE vIsOriginalAClient BOOL; + DECLARE vPayMethodCompensation INT; + + CALL ledger_next(vNewBookEntry); + + SELECT COUNT(id) INTO vIsOriginalAClient FROM client WHERE accountingAccount LIKE vOriginalAccount COLLATE utf8_general_ci; + + SELECT id, COUNT(id) INTO vClientFk, vIsClientCompensation + FROM client + WHERE accountingAccount LIKE vCompensationAccount COLLATE utf8_general_ci; + + SET @vAmount1:= 0.0; + SET @vAmount2:= 0.0; + + INSERT INTO XDiario (ASIEN, FECHA, SUBCTA, CONTRA, CONCEPTO, EURODEBE, EUROHABER, empresa_id) + VALUES ( vNewBookEntry, + vDated, + vOriginalAccount, + vCompensationAccount, + vConcept, + @vAmount1:= IF( + (vIsOriginalAClient OR NOT vIsOriginalAClient) + AND vAmount > 0, + 0, + ABS(vAmount) + ), + @vAmount2:= IF(@vAmount1, + 0, + ABS(vAmount) + ), + vCompanyFk + ), + ( vNewBookEntry, + vDated, + vCompensationAccount, + vOriginalAccount, + vConcept, + @vAmount2, + @vAmount1, + vCompanyFk); + + IF vIsClientCompensation THEN + IF vIsOriginalAClient THEN + SET vAmount = -vAmount; + END IF; + INSERT INTO receipt(invoiceFk, amountPaid, payed, bankFk, companyFk, clientFk, isConciliate) + VALUES (vConcept, vAmount, vDated, vBankFk, vCompanyFk, vClientFk, TRUE); + ELSE + IF NOT vIsOriginalAClient THEN + SET vAmount = -vAmount; + END IF; + SELECT id INTO vSupplierFk FROM supplier WHERE `account` LIKE vCompensationAccount COLLATE utf8_general_ci; + SELECT id INTO vPayMethodCompensation FROM payMethod WHERE `code` = 'compensation'; + + INSERT INTO payment (received, dueDated, supplierFk, amount, bankFk, payMethodFk, concept, companyFk, isConciliated) + VALUES(vDated, vDated, vSupplierFk, vAmount, vBankFk, vPayMethodCompensation, vConcept, vCompanyFk, TRUE); + END IF; +END$$ +DELIMITER ; diff --git a/db/changes/10271-wisemen/02-triggerReceipt.sql b/db/changes/10271-wisemen/02-triggerReceipt.sql new file mode 100644 index 0000000000..9b08a302f1 --- /dev/null +++ b/db/changes/10271-wisemen/02-triggerReceipt.sql @@ -0,0 +1,17 @@ +DROP TRIGGER IF EXISTS vn.receipt_beforInsert; + +DELIMITER $$ +$$ +CREATE TRIGGER receipt_beforInsert +BEFORE INSERT +ON receipt FOR EACH ROW +BEGIN + SELECT isAutoConciliated INTO @isAutoConciliated + FROM accounting a + JOIN accountingType at2 ON at2.id = a.accountingTypeFk + WHERE a.id =NEW.bankFk; + + SET NEW.isConciliate = @isAutoConciliated; +END +$$ +DELIMITER ; diff --git a/db/changes/10280-valentineDay/00-department.sql b/db/changes/10280-valentineDay/00-department.sql new file mode 100644 index 0000000000..bb30628250 --- /dev/null +++ b/db/changes/10280-valentineDay/00-department.sql @@ -0,0 +1,4 @@ +ALTER TABLE `vn`.`department` + ADD code VARCHAR(45) NULL AFTER id; + +UPDATE `vn`.`department` t SET t.code = 'IT', t.chatName = 'informatica-cau' WHERE t.id = 31; diff --git a/db/changes/10280-valentineDay/delete.keep b/db/changes/10280-valentineDay/delete.keep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/db/changes/10281-valentineDay/00-item_getBalance.sql b/db/changes/10281-valentineDay/00-item_getBalance.sql new file mode 100644 index 0000000000..96c82cc016 --- /dev/null +++ b/db/changes/10281-valentineDay/00-item_getBalance.sql @@ -0,0 +1,137 @@ +DROP PROCEDURE `vn`.`item_getBalance`; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`item_getBalance`(IN vItemId INT, IN vWarehouse INT) +BEGIN + DECLARE vDateInventory DATETIME; + DECLARE vCurdate DATE DEFAULT CURDATE(); + DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate); + + SELECT inventoried INTO vDateInventory FROM config; + SET @a = 0; + SET @currentLineFk = 0; + SET @shipped = ''; + + SELECT DATE(@shipped:= shipped) shipped, + alertLevel, + stateName, + origin, + reference, + clientFk, + name, + `in`, + `out`, + @a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance, + @currentLineFk := IF (@shipped < CURDATE() + OR (@shipped = CURDATE() AND (isPicked OR alertLevel >= 2)), + lineFk,@currentLineFk) lastPreparedLineFk, + isTicket, + lineFk, + isPicked, + clientType + FROM + ( SELECT tr.landed AS shipped, + b.quantity AS `in`, + NULL AS `out`, + al.alertLevel AS alertLevel, + st.name AS stateName, + s.name AS name, + e.ref AS reference, + e.id AS origin, + s.id AS clientFk, + IF(al.alertLevel = 3, TRUE, FALSE) isPicked, + FALSE AS isTicket, + b.id lineFk, + NULL `order`, + NULL AS clientType + FROM buy b + JOIN entry e ON e.id = b.entryFk + JOIN travel tr ON tr.id = e.travelFk + JOIN supplier s ON s.id = e.supplierFk + JOIN alertLevel al ON al.alertLevel = + CASE + WHEN tr.shipped < CURDATE() THEN 3 + WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3 + ELSE 0 + END + JOIN state st ON st.code = al.code + WHERE tr.landed >= vDateInventory + AND vWarehouse = tr.warehouseInFk + AND b.itemFk = vItemId + AND e.isInventory = FALSE + AND e.isRaid = FALSE + UNION ALL + + SELECT tr.shipped, + NULL as `in`, + b.quantity AS `out`, + al.alertLevel AS alertLevel, + st.name AS stateName, + s.name AS name, + e.ref AS reference, + e.id AS origin, + s.id AS clientFk, + IF(al.alertLevel = 3, TRUE, FALSE) isPicked, + FALSE AS isTicket, + b.id, + NULL `order`, + NULL AS clientType + FROM buy b + JOIN entry e ON e.id = b.entryFk + JOIN travel tr ON tr.id = e.travelFk + JOIN warehouse w ON w.id = tr.warehouseOutFk + JOIN supplier s ON s.id = e.supplierFk + JOIN alertLevel al ON al.alertLevel = + CASE + WHEN tr.shipped < CURDATE() THEN 3 + WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3 + ELSE 0 + END + JOIN state st ON st.code = al.code + WHERE tr.shipped >= vDateInventory + AND vWarehouse =tr.warehouseOutFk + AND s.id <> 4 + AND b.itemFk = vItemId + AND e.isInventory = FALSE + AND w.isFeedStock = FALSE + AND e.isRaid = FALSE + UNION ALL + + SELECT DATE(t.shipped), + NULL as `in`, + s.quantity AS `out`, + al.alertLevel AS alertLevel, + st.name AS stateName, + t.nickname AS name, + t.refFk AS reference, + t.id AS origin, + t.clientFk, + stk.id AS isPicked, + TRUE AS isTicket, + s.id, + st.`order`, + ct.code AS clientType + FROM sale s + JOIN ticket t ON t.id = s.ticketFk + LEFT JOIN ticketState ts ON ts.ticket = t.id + LEFT JOIN state st ON st.code = ts.code + JOIN client c ON c.id = t.clientFk + JOIN clientType ct ON ct.id = c.clientTypeFk + JOIN alertLevel al ON al.alertLevel = + CASE + WHEN t.shipped < curdate() THEN 3 + WHEN t.shipped > util.dayEnd(curdate()) THEN 0 + ELSE IFNULL(ts.alertLevel, 0) + END + LEFT JOIN state stPrep ON stPrep.`code` = 'PREPARED' + LEFT JOIN saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = stPrep.id + WHERE t.shipped >= vDateInventory + AND s.itemFk = vItemId + AND vWarehouse =t.warehouseFk + ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC + ) AS itemDiary; + +END$$ +DELIMITER ; + diff --git a/db/changes/10281-valentineDay/00-supplier.sql b/db/changes/10281-valentineDay/00-supplier.sql new file mode 100644 index 0000000000..c35a86a230 --- /dev/null +++ b/db/changes/10281-valentineDay/00-supplier.sql @@ -0,0 +1,2 @@ +ALTER TABLE `vn`.`supplier` ADD COLUMN `workerFk` INT(11) NULL DEFAULT NULL COMMENT 'Responsible for approving invoices' AFTER `isTrucker`; +ALTER TABLE `vn`.`supplier` ADD CONSTRAINT `supplier_workerFk` FOREIGN KEY (`workerFk`) REFERENCES `vn`.`worker` (`id`) ON UPDATE CASCADE; \ No newline at end of file diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 0e4e1b33d9..d821c7bfc4 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -150,21 +150,20 @@ INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `park INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`) VALUES - (1, 'CC y Polizas de crédito', NULL, NULL), - (2, 'Caja registradora', NULL, NULL), - (3, 'Tarjeta de credito', NULL, NULL), - (4, 'Lineas de financiacion', NULL, NULL), - (5, 'Otros productos', NULL, NULL), - (6, 'Prestamos', NULL, NULL), - (7, 'Leasing', NULL, NULL), - (8, 'Compensaciones', NULL, NULL), - (9, 'Cash', 'Cash', NULL), - (10, 'Card', 'Pay on receipt', NULL); - + (1, 'CC y Polizas de crédito', NULL, NULL), + (2, 'Cash', 'Cash', 'cash'), + (3, 'Credit card', 'Credit Card', 'creditCard'), + (4, 'Finalcial lines', NULL, NULL), + (5, 'Other products', NULL, NULL), + (6, 'Loans', NULL, NULL), + (7, 'Leasing', NULL, NULL), + (8, 'Compensations', 'Compensations', 'compensation'); + INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`) VALUES - (1, 'Pay on receipt', '0000000000', 10, 0, 1, 1), - (2, 'Cash', '1111111111', 9, 0, 1, 1); + (1, 'Pay on receipt', '5720000001', 3, 0, 1, 1), + (2, 'Cash', '5700000001', 2, 0, 1, 1), + (3, 'Compensation', '4000000000', 8, 0, 1, 1); INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`) VALUES @@ -212,13 +211,13 @@ UPDATE `vn`.`agencyMode` SET `web` = 1; UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23; -INSERT INTO `vn`.`payMethod`(`id`, `name`, `graceDays`, `outstandingDebt`, `ibanRequired`) +INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt`, `ibanRequired`) VALUES - (1, 'PayMethod one', 0, 001, 0), - (2, 'PayMethod two', 10, 001, 0), - (3, 'PayMethod three', 0, 001, 0), - (4, 'PayMethod with IBAN', 0, 001, 1), - (5, 'PayMethod five', 10, 001, 0); + (1, NULL, 'PayMethod one', 0, 001, 0), + (2, NULL, 'PayMethod two', 10, 001, 0), + (3, 'compensation', 'PayMethod three', 0, 001, 0), + (4, NULL, 'PayMethod with IBAN', 0, 001, 1), + (5, NULL, 'PayMethod five', 10, 001, 0); INSERT INTO `vn`.`payDem`(`id`, `payDem`) VALUES @@ -271,17 +270,17 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`) INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`fax`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`,`mailAddress`,`cplusTerIdNifFk`,`hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`) VALUES (101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1), - (102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1), - (103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1), - (104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1), + (102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1), + (103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1), + (104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1), (105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 8, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1), - (106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'Evil hideout', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1), - (107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1), + (106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'City of New York, New York, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1), + (107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill, San Francisco, California', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1), (108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1), (109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1), (110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1), - (111, 'Missing', NULL, 'Missing man', 'Anton', 'The space', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1), - (112, 'Trash', NULL, 'Garbage man', 'Unknown name', 'New York city', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1); + (111, 'Missing', NULL, 'Missing man', 'Anton', 'The space, Universe far away', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1), + (112, 'Trash', NULL, 'Garbage man', 'Unknown name', 'New York city, Underground', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1); INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `gestdocFk`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`) SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), CONCAT(name, 'Social'), CONCAT(name, 'Contact'), CONCAT(name, 'Street'), 'SILLA', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5, CURDATE(), 1 @@ -1234,11 +1233,11 @@ INSERT INTO `vn`.`annualAverageInvoiced`(`clientFk`, `invoiced`) (104, 500), (105, 5000); -INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`) +INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`) VALUES - (1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1), - (2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8), - (442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3); + (1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18), + (2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8, 18), + (442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3, 18); INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`) VALUES diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 0ff57b2d61..ca521f4454 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -186,8 +186,11 @@ export default { clientBalance: { company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]', newPaymentButton: `vn-float-button`, - newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]', - newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.receipt.amountPaid"]', + newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.bankFk"]', + newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.amountPaid"]', + newDescription: 'vn-textfield[ng-model="$ctrl.receipt.description"]', + deliveredAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.deliveredAmount"]', + refundAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.amountToReturn"]', saveButton: '.vn-dialog.shown [response="accept"]', firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)', firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable', @@ -313,7 +316,7 @@ export default { fourthRelevancy: 'vn-item-tags vn-horizontal:nth-child(4) [ng-model="itemTag.priority"]', fourthRemoveTagButton: 'vn-item-tags vn-horizontal:nth-child(4) vn-icon-button[icon="delete"]', fifthTag: 'vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[ng-model="itemTag.tagFk"]', - fifthValue: 'vn-item-tags vn-horizontal:nth-child(5) vn-textfield[ng-model="itemTag.value"]', + fifthValue: 'vn-item-tags vn-horizontal:nth-child(5) vn-autocomplete[ng-model="itemTag.value"]', fifthRelevancy: 'vn-item-tags vn-horizontal:nth-child(5) vn-input-number[ng-model="itemTag.priority"]', sixthTag: 'vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[ng-model="itemTag.tagFk"]', sixthValue: 'vn-item-tags vn-horizontal:nth-child(6) vn-textfield[ng-model="itemTag.value"]', @@ -389,18 +392,22 @@ export default { descriptorTicketId: 'vn-ticket-descriptor > vn-descriptor-content > div > div.body > div.top > div' }, ticketsIndex: { + anySearchResult: 'vn-ticket-index vn-tbody > a', openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]', advancedSearchInvoiceOut: 'vn-ticket-search-panel vn-textfield[ng-model="filter.refFk"]', advancedSearchDaysOnward: 'vn-ticket-search-panel vn-input-number[ng-model="filter.scopeDays"]', + advancedSearchClient: 'vn-ticket-search-panel vn-textfield[ng-model="filter.clientFk"]', advancedSearchButton: 'vn-ticket-search-panel button[type=submit]', newTicketButton: 'vn-ticket-index a[ui-sref="ticket.create"]', searchResult: 'vn-ticket-index vn-card > vn-table > div > vn-tbody > a.vn-tr', + firstTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(1) > vn-td:nth-child(1) > vn-check', secondTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(2) > vn-td:nth-child(1) > vn-check', thirdTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(3) > vn-td:nth-child(1) > vn-check', sixthTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(6) > vn-td:nth-child(1) > vn-check', payoutButton: 'vn-ticket-index vn-button[icon="icon-recovery"]', payoutCompany: '.vn-dialog vn-autocomplete[ng-model="$ctrl.receipt.companyFk"]', - payoutBank: '.vn-dialog vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]', + payoutBank: '.vn-dialog vn-autocomplete[ng-model="$ctrl.bankFk"]', + payoutDescription: 'vn-textfield[ng-model="$ctrl.receipt.description"]', submitPayout: '.vn-dialog button[response="accept"]', searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr', searchResultDate: 'vn-ticket-summary [label=Landed] span', diff --git a/e2e/paths/02-client/14_balance.spec.js b/e2e/paths/02-client/14_balance.spec.js index b069a4cfb8..4917937fa4 100644 --- a/e2e/paths/02-client/14_balance.spec.js +++ b/e2e/paths/02-client/14_balance.spec.js @@ -38,7 +38,7 @@ describe('Client balance path', () => { expect(message.text).toContain('Data saved!'); }); - it('should click the new payment button', async() => { + it('should reload the section', async() => { await page.closePopup(); await page.reloadSection('client.card.balance.index'); }); @@ -46,7 +46,8 @@ describe('Client balance path', () => { it('should create a new payment that clears the debt', async() => { await page.closePopup(); await page.waitToClick(selectors.clientBalance.newPaymentButton); - await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Pay on receipt'); + await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Cash'); + await page.write(selectors.clientBalance.newDescription, 'Description'); await page.waitToClick(selectors.clientBalance.saveButton); const message = await page.waitForSnackbar(); @@ -78,16 +79,24 @@ describe('Client balance path', () => { expect(firstBalanceLine).toContain('0.00'); }); - it('should create a new payment that sets the balance to positive value', async() => { + it('should create a new payment and check the cash comparison works correctly', async() => { + const amountPaid = '100'; + const cashHanded = '500'; + const expectedRefund = '400'; + await page.waitToClick(selectors.clientBalance.newPaymentButton); - await page.overwrite(selectors.clientBalance.newPaymentAmount, '100'); + await page.write(selectors.clientBalance.newPaymentAmount, amountPaid); + await page.write(selectors.clientBalance.newDescription, 'Payment'); + await page.write(selectors.clientBalance.deliveredAmount, cashHanded); + const refund = await page.waitToGetProperty(selectors.clientBalance.refundAmount, 'value'); await page.waitToClick(selectors.clientBalance.saveButton); const message = await page.waitForSnackbar(); + expect(refund).toEqual(expectedRefund); expect(message.text).toContain('Data saved!'); }); - it('should check balance is now -100', async() => { + it('should check the balance value is now -100', async() => { let result = await page .waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText'); @@ -96,7 +105,9 @@ describe('Client balance path', () => { it('should create a new payment that sets the balance back to the original negative value', async() => { await page.waitToClick(selectors.clientBalance.newPaymentButton); + await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Pay on receipt'); await page.overwrite(selectors.clientBalance.newPaymentAmount, '-150'); + await page.write(selectors.clientBalance.newDescription, 'Description'); await page.waitToClick(selectors.clientBalance.saveButton); const message = await page.waitForSnackbar(); diff --git a/e2e/paths/04-item/04_tags.spec.js b/e2e/paths/04-item/04_tags.spec.js index 9f2a8e2952..574ff7562b 100644 --- a/e2e/paths/04-item/04_tags.spec.js +++ b/e2e/paths/04-item/04_tags.spec.js @@ -16,7 +16,7 @@ describe('Item create tags path', () => { await browser.close(); }); - it(`should create a new tag and delete a former one`, async() => { + it('should create a new tag and delete a former one', async() => { await page.waitToClick(selectors.itemTags.fourthRemoveTagButton); await page.waitToClick(selectors.itemTags.addItemTagButton); await page.autocompleteSearch(selectors.itemTags.seventhTag, 'Ancho de la base'); @@ -29,7 +29,7 @@ describe('Item create tags path', () => { expect(message.text).toContain('Data saved!'); }); - it(`should confirm the fourth row data is the expected one`, async() => { + it('should confirm the fourth row data is the expected one', async() => { await page.reloadSection('item.card.tags'); await page.waitForSelector('vn-item-tags'); let result = await page.waitToGetProperty(selectors.itemTags.fourthTag, 'value'); @@ -47,7 +47,7 @@ describe('Item create tags path', () => { expect(result).toEqual('4'); }); - it(`should confirm the fifth row data is the expected one`, async() => { + it('should confirm the fifth row data is the expected one', async() => { let tag = await page .waitToGetProperty(selectors.itemTags.fifthTag, 'value'); @@ -62,7 +62,7 @@ describe('Item create tags path', () => { expect(relevancy).toEqual('5'); }); - it(`should confirm the sixth row data is the expected one`, async() => { + it('should confirm the sixth row data is the expected one', async() => { let tag = await page .waitToGetProperty(selectors.itemTags.sixthTag, 'value'); diff --git a/e2e/paths/05-ticket/18_index_payout.spec.js b/e2e/paths/05-ticket/18_index_payout.spec.js index 4c6799dcb0..3d83e6fca0 100644 --- a/e2e/paths/05-ticket/18_index_payout.spec.js +++ b/e2e/paths/05-ticket/18_index_payout.spec.js @@ -22,23 +22,31 @@ describe('Ticket index payout path', () => { it('should check the second ticket from a client and 1 of another', async() => { await page.waitToClick(selectors.globalItems.searchButton); await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox); - await page.waitToClick(selectors.ticketsIndex.sixthTicketCheckbox); + await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox); await page.waitToClick(selectors.ticketsIndex.payoutButton); const message = await page.waitForSnackbar(); expect(message.text).toContain('You cannot make a payment on account from multiple clients'); }); - it('should uncheck the sixth ticket result and check the third which is from the same client then open the payout form', async() => { - await page.waitToClick(selectors.ticketsIndex.sixthTicketCheckbox); - await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox); + it('should search for tickets of the same client then open the payout form', async() => { + await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton); + await page.write(selectors.ticketsIndex.advancedSearchClient, '101'); + await page.keyboard.press('Enter'); + await page.waitForNumberOfElements(selectors.ticketsIndex.anySearchResult, 6); + await page.waitToClick(selectors.ticketsIndex.firstTicketCheckbox); + await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox); + await page.waitToClick(selectors.ticketsIndex.payoutButton); await page.waitForSelector(selectors.ticketsIndex.payoutCompany); }); it('should fill the company and bank to perform a payout', async() => { + await page.autocompleteSearch(selectors.ticketsIndex.payoutCompany, 'VNL'); await page.autocompleteSearch(selectors.ticketsIndex.payoutBank, 'cash'); + await page.write(selectors.clientBalance.newPaymentAmount, '100'); + await page.write(selectors.ticketsIndex.payoutDescription, 'Payment'); await page.waitToClick(selectors.ticketsIndex.submitPayout); const message = await page.waitForSnackbar(); diff --git a/front/core/components/autocomplete/index.js b/front/core/components/autocomplete/index.js index 18c277f062..56b30667e7 100755 --- a/front/core/components/autocomplete/index.js +++ b/front/core/components/autocomplete/index.js @@ -20,7 +20,7 @@ export default class Autocomplete extends Field { constructor($element, $, $compile, $transclude) { super($element, $, $compile); this.$transclude = $transclude; - + this.$compile = $compile; this._selection = null; this.input = this.element.querySelector('input'); } @@ -149,6 +149,9 @@ export default class Autocomplete extends Field { where: where }; + if (this.include) + filter.include = this.include; + let json = encodeURIComponent(JSON.stringify(filter)); this.$http.get(`${this.url}?filter=${json}`).then( json => this.onSelectionRequest(json.data), @@ -182,8 +185,14 @@ export default class Autocomplete extends Field { } else { display = this._selection[this.showField]; if (hasTemplate) { - let template = this.$transclude(() => {}, null, 'tplItem').text(); - display = this.$interpolate(template)(this._selection); + let template = this.$transclude(() => {}, null, 'tplItem'); + const element = template[0]; + const description = element.querySelector('.text-secondary'); + if (description) description.remove(); + + const displayElement = angular.element(element); + const displayText = displayElement.text(); + display = this.$interpolate(displayText)(this._selection); } } } diff --git a/front/salix/components/summary/index.js b/front/salix/components/summary/index.js index 5cbbec3e79..232abc3e60 100644 --- a/front/salix/components/summary/index.js +++ b/front/salix/components/summary/index.js @@ -2,7 +2,13 @@ import ngModule from '../../module'; import Section from '../section'; import './style.scss'; -export default class Summary extends Section {} +export default class Summary extends Section { + listEmails(email) { + if (!email) return; + const emailList = email.split(','); + return emailList.join(', '); + } +} ngModule.vnComponent('vnSummary', { controller: Summary diff --git a/front/salix/components/summary/index.spec.js b/front/salix/components/summary/index.spec.js new file mode 100644 index 0000000000..8b5ec0de33 --- /dev/null +++ b/front/salix/components/summary/index.spec.js @@ -0,0 +1,30 @@ +import './index.js'; + +describe('Salix', () => { + describe('Component vnSummary', () => { + let controller; + + beforeEach(ngModule('salix')); + + beforeEach(inject($componentController => { + const $element = angular.element(''); + controller = $componentController('vnSummary', {$element}); + })); + + describe('listEmails()', () => { + it('should do nothing when receives no arguments', () => { + const emailList = controller.listEmails(); + + expect(emailList).toBeUndefined(); + }); + + it('should format the receives emails to be separated with comma', () => { + const expectedResult = 'captainmarvel@marvel.com, ironman@marvel.com'; + + const emailList = controller.listEmails('captainmarvel@marvel.com,ironman@marvel.com'); + + expect(emailList).toEqual(expectedResult); + }); + }); + }); +}); diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 0ac49d5b50..44f8826384 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -85,8 +85,11 @@ "You need to fill sage information before you check verified data": "You need to fill sage information before you check verified data", "The social name cannot be empty": "The social name cannot be empty", "The nif cannot be empty": "The nif cannot be empty", + "Amount cannot be zero": "Amount cannot be zero", + "Company has to be official": "Company has to be official", "A travel with this data already exists": "A travel with this data already exists", "The observation type can't be repeated": "The observation type can't be repeated", - "New ticket request has been created with price": "New ticket request has been created '{{description}}' for day {{shipped}}, with a quantity of {{quantity}} and a price of {{price}} €", - "New ticket request has been created": "New ticket request has been created '{{description}}' for day {{shipped}}, with a quantity of {{quantity}}" + "New ticket request has been created with price": "New ticket request has been created *'{{description}}'* for day *{{shipped}}*, with a quantity of *{{quantity}}* and a price of *{{price}} €*", + "New ticket request has been created": "New ticket request has been created *'{{description}}'* for day *{{shipped}}*, with a quantity of *{{quantity}}*", + "There's a new urgent ticket": "There's a new urgent ticket: [{{title}}](https://cau.verdnatura.es/WorkOrder.do?woMode=viewWO&woID={{issueId}})" } \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 7b72130461..5b73a2d729 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -161,6 +161,8 @@ "The nif cannot be empty": "El NIF no puede quedar en blanco", "You need to fill sage information before you check verified data": "Debes rellenar la información de sage antes de marcar datos comprobados", "ASSIGN_ZONE_FIRST": "Asigna una zona primero", + "Amount cannot be zero": "El importe no puede ser cero", + "Company has to be official": "Empresa inválida", "You can not select this payment method without a registered bankery account": "No se puede utilizar este método de pago si no has registrado una cuenta bancaria", "You can't upload images on the test environment": "No puedes subir imágenes en el entorno de pruebas", "The selected ticket is not suitable for this route": "El ticket seleccionado no es apto para esta ruta", diff --git a/loopback/util/date.js b/loopback/util/date.js new file mode 100644 index 0000000000..66774544c0 --- /dev/null +++ b/loopback/util/date.js @@ -0,0 +1,25 @@ +/** + * Transforms a UTC date to string without datetime. + * + * @param {date} date Date to format + * @return {String} Formatted date string + */ +function toString(date) { + date = new Date(date); + + let day = date.getDate(); + let month = date.getMonth() + 1; + let year = date.getFullYear(); + + if (day < 10) + day = `0${day}`; + + if (month < 10) + month = `0${month}`; + + return `${day}-${month}-${year}`; +} + +module.exports = { + toString: toString +}; diff --git a/modules/claim/front/detail/index.js b/modules/claim/front/detail/index.js index 4e0017baa3..7c3c04f448 100644 --- a/modules/claim/front/detail/index.js +++ b/modules/claim/front/detail/index.js @@ -86,16 +86,15 @@ class Controller extends Section { }); } - showDeleteConfirm(index) { - this.sale = this.salesClaimed[index]; + showDeleteConfirm($index) { + this.claimedIndex = $index; this.$.confirm.show(); } deleteClaimedSale() { - let query = `ClaimBeginnings/${this.sale.id}`; - this.$http.delete(query).then(() => { + this.$.model.remove(this.claimedIndex); + this.$.model.save().then(() => { this.vnApp.showSuccess(this.$t('Data saved!')); - this.$.model.remove(this.sale); this.calculateTotals(); }); } diff --git a/modules/claim/front/detail/index.spec.js b/modules/claim/front/detail/index.spec.js index 972d487e5f..b36f3a1727 100644 --- a/modules/claim/front/detail/index.spec.js +++ b/modules/claim/front/detail/index.spec.js @@ -73,13 +73,16 @@ describe('claim', () => { describe('deleteClaimedSale()', () => { it('should make a delete and call refresh and showSuccess', () => { - controller.sale = {id: 1}; + const claimedIndex = 1; + controller.claimedIndex = claimedIndex; jest.spyOn(controller.$.model, 'remove'); + jest.spyOn(controller.$.model, 'save'); jest.spyOn(controller.vnApp, 'showSuccess'); - $httpBackend.expectDELETE(`ClaimBeginnings/1`).respond('ok'); - controller.deleteClaimedSale(); - $httpBackend.flush(); + controller.deleteClaimedSale(); + + expect(controller.$.model.remove).toHaveBeenCalledWith(claimedIndex); + expect(controller.$.model.save).toHaveBeenCalledWith(); expect(controller.vnApp.showSuccess).toHaveBeenCalled(); }); }); diff --git a/modules/client/back/methods/client/createReceipt.js b/modules/client/back/methods/client/createReceipt.js new file mode 100644 index 0000000000..976ff7cf27 --- /dev/null +++ b/modules/client/back/methods/client/createReceipt.js @@ -0,0 +1,145 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = function(Self) { + Self.remoteMethodCtx('createReceipt', { + description: 'Creates receipt and its compensation if necessary', + accepts: [{ + arg: 'clientFk', + type: 'number', + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'payed', + type: 'Date', + required: true + }, + { + arg: 'companyFk', + type: 'number', + required: true + }, + { + arg: 'bankFk', + type: 'number', + required: true + }, + { + arg: 'amountPaid', + type: 'number', + required: true + }, + { + arg: 'description', + type: 'string', + required: true + }, + { + arg: 'compensationAccount', + type: 'any' + }], + returns: { + root: true, + type: 'Object' + }, + http: { + verb: 'post', + path: '/:clientFk/createReceipt' + } + }); + + Self.createReceipt = async ctx => { + const models = Self.app.models; + const args = ctx.args; + const tx = await models.Address.beginTransaction({}); + + try { + const options = {transaction: tx}; + + delete args.ctx; // Remove unwanted properties + const newReceipt = await models.Receipt.create(args, options); + const clientOriginal = await models.Client.findById(args.clientFk); + const bank = await models.Bank.findById(args.bankFk); + const accountingType = await models.AccountingType.findById(bank.accountingTypeFk); + + if (accountingType.code == 'compensation') { + if (!args.compensationAccount) + throw new UserError('Compensation account is empty'); + + const supplierCompensation = await models.Supplier.findOne({ + where: { + account: args.compensationAccount + } + }); + let clientCompensation = {}; + if (!supplierCompensation) { + clientCompensation = await models.Client.findOne({ + where: { + accountingAccount: args.compensationAccount + } + }); + } + if (!supplierCompensation && !clientCompensation) + throw new UserError('Invalid account'); + + await Self.rawSql( + `CALL vn.ledger_doCompensation(?, ?, ?, ?, ?, ?, ?)`, + [ + Date(), + args.compensationAccount, + args.bankFk, + accountingType.receiptDescription + args.compensationAccount, + args.amountPaid, + args.companyFk, + clientOriginal.accountingAccount + ], + options); + } else { + const description = `${clientOriginal.id} : ${clientOriginal.socialName} - ${accountingType.receiptDescription}`; + const [xdiarioNew] = await Self.rawSql( + `SELECT xdiario_new(?, CURDATE(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ledger;`, + [ + null, + bank.account, + clientOriginal.accountingAccount, + description, + args.amountPaid, + 0, + 0, + '', + '', + null, + null, + false, + args.companyFk + ], + options); + + await Self.rawSql( + `SELECT xdiario_new(?, CURDATE(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`, + [ + xdiarioNew.ledger, + clientOriginal.accountingAccount, + bank.account, + description, + 0, + args.amountPaid, + 0, + '', + '', + null, + null, + false, + args.companyFk + ], + options); + } + + await tx.commit(); + return newReceipt; + } catch (e) { + await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/client/back/methods/client/specs/createReceipt.spec.js b/modules/client/back/methods/client/specs/createReceipt.spec.js new file mode 100644 index 0000000000..3bd560cdd7 --- /dev/null +++ b/modules/client/back/methods/client/specs/createReceipt.spec.js @@ -0,0 +1,171 @@ +const app = require('vn-loopback/server/server'); + +describe('Client createReceipt', () => { + const clientFk = 108; + const payed = Date(); + const companyFk = 442; + const amountPaid = 12.50; + const description = 'Receipt description'; + + it('should create a new receipt', async() => { + const bankFk = 1; + let ctx = { + args: { + clientFk: clientFk, + payed: payed, + companyFk: companyFk, + bankFk: bankFk, + amountPaid: amountPaid, + description: description + } + }; + + const receipt = await app.models.Client.createReceipt(ctx); + delete ctx.args.payed; + + const till = await app.models.Till.findOne({ + where: { + bankFk: bankFk, + in: amountPaid, + number: clientFk + } + }); + + expect(receipt).toEqual(jasmine.objectContaining(ctx.args)); + + // restores + await receipt.destroy(); + await till.destroy(); + }); + + it('should throw Compensation account is empty', async() => { + const bankFk = 3; + let ctx = { + args: { + clientFk: clientFk, + payed: payed, + companyFk: companyFk, + bankFk: bankFk, + amountPaid: amountPaid, + description: description + } + }; + + try { + await app.models.Client.createReceipt(ctx); + } catch (e) { + error = e; + } + + expect(error).toBeDefined(); + expect(error.message).toEqual('Compensation account is empty'); + }); + + it('should throw Invalid account if compensationAccount does not belongs to a client nor a supplier', async() => { + let error; + const bankFk = 3; + const ctx = { + args: { + clientFk: clientFk, + payed: payed, + companyFk: companyFk, + bankFk: bankFk, + amountPaid: amountPaid, + description: description, + compensationAccount: 'non existing account' + } + }; + + try { + await app.models.Client.createReceipt(ctx); + } catch (e) { + error = e; + } + + expect(error).toBeDefined(); + expect(error.message).toEqual('Invalid account'); + }); + + it('should create a new receipt with a compensation for a client', async() => { + const bankFk = 3; + const ctx = { + args: { + clientFk: clientFk, + payed: payed, + companyFk: companyFk, + bankFk: bankFk, + amountPaid: amountPaid, + description: description, + compensationAccount: '4300000001' + } + }; + const receipt = await app.models.Client.createReceipt(ctx); + const receiptCompensated = await app.models.Receipt.findOne({ + where: { + clientFk: 1, + bankFk: ctx.args.bankFk + } + }); + + const till = await app.models.Till.findOne({ + where: { + bankFk: bankFk, + in: amountPaid, + number: clientFk + } + }); + + delete ctx.args.payed; + + expect(receipt).toEqual(jasmine.objectContaining(ctx.args)); + expect(receipt.amountPaid).toEqual(-receiptCompensated.amountPaid); + + // restores + await receipt.destroy(); + await receiptCompensated.destroy(); + await till.destroy(); + }); + + it('should create a new receipt with a compensation for a supplier', async() => { + const ctx = { + args: { + clientFk: clientFk, + payed: payed, + companyFk: companyFk, + bankFk: 3, + amountPaid: amountPaid, + description: description, + compensationAccount: '4100000001' + } + }; + const receipt = await app.models.Client.createReceipt(ctx); + + const paymentCompensated = await app.models.Payment.findOne({ + where: { + clientFk: ctx.args.sale, + payed: ctx.args.payed, + amountPaid: ctx.args.amountPaid, + bankFk: ctx.args.bankFk + } + }); + + const till = await app.models.Till.findOne({ + where: { + bankFk: ctx.args.bankFk, + in: amountPaid, + number: clientFk + } + }); + + delete ctx.args.payed; + + expect(receipt).toEqual(jasmine.objectContaining(ctx.args)); + + expect(paymentCompensated.amountPaid).toEqual(paymentCompensated.amountPaid); + + // restores + await receipt.destroy(); + await paymentCompensated.destroy(); + await till.destroy(); + }); +}); diff --git a/modules/client/back/methods/client/specs/updateAddress.spec.js b/modules/client/back/methods/client/specs/updateAddress.spec.js index 6855d8e180..a30dcc96dd 100644 --- a/modules/client/back/methods/client/specs/updateAddress.spec.js +++ b/modules/client/back/methods/client/specs/updateAddress.spec.js @@ -8,6 +8,7 @@ describe('Address updateAddress', () => { const customAgentOneId = 1; it('should throw the non uee member error if no incoterms is defined', async() => { + let err; const ctx = { args: { provinceFk: provinceId, @@ -26,6 +27,7 @@ describe('Address updateAddress', () => { }); it('should throw a non uee member error if no customsAgent is defined', async() => { + let err; const ctx = { args: { provinceFk: provinceId, diff --git a/modules/client/back/model-config.json b/modules/client/back/model-config.json index 340ddeb18d..1f18f4963e 100644 --- a/modules/client/back/model-config.json +++ b/modules/client/back/model-config.json @@ -104,6 +104,9 @@ "ClientDms": { "dataSource": "vn" }, + "Till": { + "dataSource": "vn" + }, "CustomsAgent": { "dataSource": "vn" }, diff --git a/modules/client/back/models/XDiario.json b/modules/client/back/models/XDiario.json new file mode 100644 index 0000000000..be2d258f98 --- /dev/null +++ b/modules/client/back/models/XDiario.json @@ -0,0 +1,84 @@ +{ + "name": "XDiario", + "base": "VnModel", + "options": { + "mysql": { + "table": "XDiario" + } + }, + "properties": { + "ASIEN": { + "type": "number", + "id": true, + "description": "Identifier" + }, + "FECHA": { + "type": "date" + }, + "SUBCTA": { + "type": "string" + }, + "CONTRA": { + "type": "string" + }, + "CONCEPTO": { + "type": "string" + }, + "EURODEBE": { + "type": "number" + }, + "EUROHABER": { + "type": "number" + }, + "BASEEURO": { + "type": "number" + }, + "SERIE": { + "type": "string" + }, + "CAMBIO": { + "type": "number" + }, + "DEBEME": { + "type": "number" + }, + "HABERME": { + "type": "number" + }, + "FACTURA": { + "type": "string" + }, + "IVA": { + "type": "number" + }, + "RECEQUIV": { + "type": "number" + }, + "METAL": { + "type": "number" + }, + "METALIMP": { + "type": "number" + }, + "CLIENTE": { + "type": "string" + }, + "METALEJE": { + "type": "string" + }, + "AUXILIAR": { + "type": "string" + }, + "MONEDAUSO": { + "type": "string" + } + }, + "relations": { + "company": { + "type": "belongsTo", + "model": "Company", + "foreignKey": "empresa_id" + } + } +} + \ No newline at end of file diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 1e500ab11d..26b20ef48f 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -30,6 +30,7 @@ module.exports = Self => { require('../methods/client/createAddress')(Self); require('../methods/client/updateAddress')(Self); require('../methods/client/consumption')(Self); + require('../methods/client/createReceipt')(Self); // Validations diff --git a/modules/client/back/models/receipt.js b/modules/client/back/models/receipt.js index 6cc767e2c9..88b7bfb5bb 100644 --- a/modules/client/back/models/receipt.js +++ b/modules/client/back/models/receipt.js @@ -1,13 +1,44 @@ module.exports = function(Self) { require('../methods/receipt/filter')(Self); + Self.validateBinded('amountPaid', isNotZero, { + message: 'Amount cannot be zero', + allowNull: false, + allowBlank: false + }); + + function isNotZero(value) { + return !isNaN(value) && value != 0; + } + + Self.validateAsync('companyFk', isOfficialCompany, { + message: 'Company has to be official' + }); + + async function isOfficialCompany(err, done) { + const hasCompany = await Self.app.models.Company.exists(this.companyFk); + if (!hasCompany) err(); + done(); + } + Self.observe('before save', async function(ctx) { if (ctx.isNewInstance) { let token = ctx.options.accessToken; let userId = token && token.userId; - let worker = await Self.app.models.Worker.findOne({where: {userFk: userId}}); - ctx.instance.workerFk = worker.id; + ctx.instance.workerFk = userId; + + await Self.app.models.Till.create({ + workerFk: userId, + bankFk: ctx.instance.bankFk, + in: ctx.instance.amountPaid, + concept: ctx.instance.description, + dated: ctx.instance.payed, + serie: 'A', + isAccountable: true, + number: ctx.instance.clientFk, + companyFk: ctx.instance.companyFk + }); } }); }; diff --git a/modules/client/back/models/receipt.json b/modules/client/back/models/receipt.json index c953ae5078..3207546a30 100644 --- a/modules/client/back/models/receipt.json +++ b/modules/client/back/models/receipt.json @@ -9,17 +9,19 @@ "properties": { "id": { "id": true, - "type": "Number", + "type": "number", "description": "Identifier" }, "amountPaid": { - "type": "Number" + "type": "number", + "required": true }, "amountUnpaid": { - "type": "Number" + "type": "number" }, "payed": { - "type": "date" + "type": "date", + "required": true }, "created": { "type": "date" @@ -31,7 +33,16 @@ "type": "string", "mysql": { "columnName": "invoiceFk" - } + }, + "required": true + }, + "bankFk": { + "type": "number", + "required": true + }, + "companyFk": { + "type": "number", + "required": true } }, "relations": { diff --git a/modules/client/back/models/till.json b/modules/client/back/models/till.json new file mode 100644 index 0000000000..06f021dafe --- /dev/null +++ b/modules/client/back/models/till.json @@ -0,0 +1,64 @@ +{ + "name": "Till", + "base": "VnModel", + "options": { + "mysql": { + "table": "till" + } + }, + "properties": { + "id": { + "type": "number", + "id": true, + "description": "Identifier" + }, + "dated": { + "type": "date", + "required": true + }, + "isAccountable": { + "type": "boolean" + }, + "serie": { + "type": "string", + "required": true + }, + "number": { + "type": "number" + }, + "concept": { + "type": "string", + "required": true + }, + "in": { + "type": "number" + }, + "out": { + "type": "number" + }, + "created": { + "type": "date" + }, + "isConciliate": { + "type": "boolean" + } + }, + "relations": { + "bank": { + "type": "belongsTo", + "model": "Bank", + "foreignKey": "bankFk" + }, + "worker": { + "type": "belongsTo", + "model": "Account", + "foreignKey": "workerFk" + }, + "company": { + "type": "belongsTo", + "model": "Company", + "foreignKey": "companyFk" + } + } +} + \ No newline at end of file diff --git a/modules/client/front/balance/create/index.html b/modules/client/front/balance/create/index.html index a2775164d8..89ec3b049e 100644 --- a/modules/client/front/balance/create/index.html +++ b/modules/client/front/balance/create/index.html @@ -6,19 +6,23 @@ auto-load="true" url="Companies" data="companies" - order="code"> + order="code" + required="true"> + ng-model="$ctrl.receipt.payed" + required="true"> + ng-model="$ctrl.receipt.companyFk" + required="true" + rule> @@ -29,27 +33,51 @@ value-field="id" fields="['accountingTypeFk']" include="{relation: 'accountingType'}" - ng-model="$ctrl.receipt.bankFk" + ng-model="$ctrl.bankFk" search-function="{or: [{id: $search}, {bank: {like: '%'+ $search +'%'}}]}" selection="$ctrl.bankSelection" - order="id"> + order="id" + required="true"> {{id}}: {{bank}} + required="true"> + rule + required="true"> + +
Cash
+ + + + + + +
+ +
Compensation
+ + +
diff --git a/modules/client/front/balance/create/index.js b/modules/client/front/balance/create/index.js index 8b01cab4a7..22426a2693 100644 --- a/modules/client/front/balance/create/index.js +++ b/modules/client/front/balance/create/index.js @@ -6,10 +6,7 @@ class Controller extends Dialog { super($element, $, $transclude); this.receipt = { - payed: new Date(), - clientFk: this.$params.id, - companyFk: this.vnConfig.companyFk, - bankFk: this.vnConfig.bankFk + payed: new Date() }; } @@ -17,12 +14,9 @@ class Controller extends Dialog { this.receipt.payed = value; } - set bankFk(value) { - this.receipt.bankFk = value; - } - set amountPaid(value) { this.receipt.amountPaid = value; + this.amountToReturn = this.deliveredAmount - value; } get amountPaid() { @@ -63,6 +57,30 @@ class Controller extends Dialog { } } + set deliveredAmount(value) { + this._deliveredAmount = value; + this.amountToReturn = value - this.receipt.amountPaid; + } + + get deliveredAmount() { + return this._deliveredAmount; + } + + get bankFk() { + if (!this.receipt.bankFk) + this.receipt.bankFk = this.vnConfig.bankFk; + + return this.receipt.bankFk; + } + + set bankFk(value) { + this.receipt.bankFk = value; + } + + accountShortToStandard(value) { + this.receipt.compensationAccount = value.replace('.', '0'.repeat(11 - value.length)); + } + getAmountPaid() { const filter = { where: { @@ -80,7 +98,7 @@ class Controller extends Dialog { if (response !== 'accept') return super.responseHandler(response); - return this.$http.post(`Receipts`, this.receipt) + return this.$http.post(`Clients/${this.clientFk}/createReceipt`, this.receipt) .then(() => super.responseHandler(response)) .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))); } diff --git a/modules/client/front/balance/create/index.spec.js b/modules/client/front/balance/create/index.spec.js index 9f85387c8b..90015be19b 100644 --- a/modules/client/front/balance/create/index.spec.js +++ b/modules/client/front/balance/create/index.spec.js @@ -65,12 +65,30 @@ describe('Client', () => { controller.$params = {id: 101}; - $httpBackend.expect('POST', `Receipts`).respond({id: 1}); + $httpBackend.expect('POST', `Clients/101/createReceipt`).respond({id: 1}); controller.responseHandler('accept'); $httpBackend.flush(); expect(controller.vnApp.showSuccess).toHaveBeenCalled(); }); }); + + describe('deliveredAmount() setter', () => { + it('should set the deliveredAmount property', () => { + controller.amountPaid = 999; + controller.deliveredAmount = 1000; + + expect(controller.amountToReturn).toEqual(1); + }); + }); + + describe('accountShortToStandard()', () => { + it('should get de account in stardard format', () => { + const shortAccount = '4.3'; + controller.accountShortToStandard(shortAccount); + + expect(controller.receipt.compensationAccount).toEqual('4000000003'); + }); + }); }); }); diff --git a/modules/client/front/balance/index/index.html b/modules/client/front/balance/index/index.html index ac9c39d7f8..468ac98c38 100644 --- a/modules/client/front/balance/index/index.html +++ b/modules/client/front/balance/index/index.html @@ -139,7 +139,8 @@ + company-fk="$ctrl.companyId" + client-fk="$ctrl.$params.id"> diff --git a/modules/client/front/balance/locale/es.yml b/modules/client/front/balance/locale/es.yml new file mode 100644 index 0000000000..53750799cd --- /dev/null +++ b/modules/client/front/balance/locale/es.yml @@ -0,0 +1,2 @@ +Compensation: Compensación +Cash: Efectivo \ No newline at end of file diff --git a/modules/client/front/fiscal-data/index.html b/modules/client/front/fiscal-data/index.html index 2ae9e04751..ac419aa40a 100644 --- a/modules/client/front/fiscal-data/index.html +++ b/modules/client/front/fiscal-data/index.html @@ -82,7 +82,6 @@ value-field="id" label="Previous client" info="In case of a company succession, specify the grantor company" - vn-acl="salesAssistant" rule> diff --git a/modules/client/front/locale/es.yml b/modules/client/front/locale/es.yml index 166bdbe1b7..82cbb129e9 100644 --- a/modules/client/front/locale/es.yml +++ b/modules/client/front/locale/es.yml @@ -57,4 +57,7 @@ Contacts: Contactos Samples: Plantillas Send sample: Enviar plantilla Log: Historial -Consumption: Consumo \ No newline at end of file +Consumption: Consumo +Compensation Account: Cuenta para compensar +Amount to return: Cantidad a devolver +Delivered amount: Cantidad entregada \ No newline at end of file diff --git a/modules/client/front/summary/index.html b/modules/client/front/summary/index.html index 3e8f4f7056..b1ec1f7810 100644 --- a/modules/client/front/summary/index.html +++ b/modules/client/front/summary/index.html @@ -40,7 +40,7 @@ value="{{$ctrl.summary.mobile}}"> + value="{{$ctrl.listEmails($ctrl.summary.email)}}"> { type: 'String', description: 'Searchs the invoiceOut by id', http: {source: 'query'} - }, { + }, + { arg: 'clientFk', type: 'Integer', description: 'The client id', http: {source: 'query'} - }, { + }, + { + arg: 'fi', + type: 'String', + description: 'The client fiscal 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', @@ -88,6 +102,8 @@ module.exports = Self => { return {'i.created': value}; case 'clientFk': return {'i.clientFk': value}; + case 'fi': + return {'c.fi': value}; case 'amount': case 'companyFk': case 'issued': diff --git a/modules/invoiceOut/front/locale/es.yml b/modules/invoiceOut/front/locale/es.yml index d21c9c23c0..0a5b190eb0 100644 --- a/modules/invoiceOut/front/locale/es.yml +++ b/modules/invoiceOut/front/locale/es.yml @@ -1,2 +1,3 @@ InvoiceOut: Facturas -Search invoices by reference: Buscar facturas por referencia \ No newline at end of file +Search invoices by reference: Buscar facturas por referencia +Client fiscal id: CIF del cliente \ No newline at end of file diff --git a/modules/invoiceOut/front/search-panel/index.html b/modules/invoiceOut/front/search-panel/index.html index ec469264c4..f49002ccad 100644 --- a/modules/invoiceOut/front/search-panel/index.html +++ b/modules/invoiceOut/front/search-panel/index.html @@ -15,6 +15,11 @@ label="Client id" ng-model="filter.clientFk"> + + { const srcFile = image.url.split('/').pop(); const dotIndex = srcFile.lastIndexOf('.'); - const fileName = srcFile.substring(0, dotIndex); + + let fileName = srcFile.substring(0, dotIndex); + if (dotIndex == -1) + fileName = srcFile; + const file = `${fileName}.png`; const filePath = path.join(tempPath, file); diff --git a/modules/item/back/methods/item/getBalance.js b/modules/item/back/methods/item/getBalance.js index 26fc2a7dc5..916757c463 100644 --- a/modules/item/back/methods/item/getBalance.js +++ b/modules/item/back/methods/item/getBalance.js @@ -20,8 +20,12 @@ module.exports = Self => { }); Self.getBalance = async filter => { - let where = filter.where; + const where = filter.where; let [diary] = await Self.rawSql(`CALL vn.item_getBalance(?, ?)`, [where.itemFk, where.warehouseFk]); + + for (const entry of diary) + if (entry.clientType === 'loses') entry.highlighted = true; + return diary; }; }; diff --git a/modules/item/back/methods/item/specs/getBalance.spec.js b/modules/item/back/methods/item/specs/getBalance.spec.js new file mode 100644 index 0000000000..671b8c1036 --- /dev/null +++ b/modules/item/back/methods/item/specs/getBalance.spec.js @@ -0,0 +1,33 @@ +const app = require('vn-loopback/server/server'); +const LoopBackContext = require('loopback-context'); + +describe('item getBalance()', () => { + it('should return the balance lines of a client type loses in which one has highlighted true', async() => { + const activeCtx = { + accessToken: {userId: 9}, + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + + const losesClientId = 111; + const ticket = await app.models.Ticket.findById(7); + const originalClientId = ticket.clientFk; + await ticket.updateAttribute('clientFk', losesClientId); + + const filter = { + where: { + itemFk: 1, + warehouseFk: 1 + } + }; + const results = await app.models.Item.getBalance(filter); + + const result = results.find(element => element.clientType == 'loses'); + + expect(result.highlighted).toBe(true); + + // restores + await ticket.updateAttribute('clientFk', originalClientId); + }); +}); diff --git a/modules/item/back/models/item-image-queue.json b/modules/item/back/models/item-image-queue.json index a4b65b2048..6d2d2441b7 100644 --- a/modules/item/back/models/item-image-queue.json +++ b/modules/item/back/models/item-image-queue.json @@ -18,8 +18,7 @@ "required": true }, "error": { - "type": "string", - "required": true + "type": "string" }, "attempts": { "type": "number" diff --git a/modules/item/back/models/item.json b/modules/item/back/models/item.json index d48e4e95d4..4bef1c5f01 100644 --- a/modules/item/back/models/item.json +++ b/modules/item/back/models/item.json @@ -68,7 +68,8 @@ "stemMultiplier": { "type": "number", "description": "Multiplier" - },"image": { + }, + "image": { "type": "string", "description": "Image" }, diff --git a/modules/item/front/diary/index.html b/modules/item/front/diary/index.html index 3fdc9a9e49..7c210a26a6 100644 --- a/modules/item/front/diary/index.html +++ b/modules/item/front/diary/index.html @@ -64,14 +64,16 @@ {{::sale.stateName | dashIfEmpty}} {{::sale.reference | dashIfEmpty}} - - {{::sale.name | dashIfEmpty}} - - - {{::sale.name | dashIfEmpty}} + + + {{::sale.name | dashIfEmpty}} + + + {{::sale.name | dashIfEmpty}} + {{::sale.in | dashIfEmpty}} diff --git a/modules/item/front/tags/index.html b/modules/item/front/tags/index.html index 3775526be8..c040b99849 100644 --- a/modules/item/front/tags/index.html +++ b/modules/item/front/tags/index.html @@ -32,14 +32,14 @@ rule> { + this.$http.get(query).then(res=> { if (res.data) { let client = res.data[0]; let defaultAddress = client.defaultAddress; diff --git a/modules/route/front/main/index.html b/modules/route/front/main/index.html index 16243be032..7d4cd33eec 100644 --- a/modules/route/front/main/index.html +++ b/modules/route/front/main/index.html @@ -9,6 +9,7 @@ vn-focus panel="vn-route-search-panel" info="Search routes by id" + fetch-params="$ctrl.fetchParams($params)" filter="$ctrl.filterParams" model="model"> diff --git a/modules/route/front/main/index.js b/modules/route/front/main/index.js index a6d5bedd1d..938f81bcc4 100644 --- a/modules/route/front/main/index.js +++ b/modules/route/front/main/index.js @@ -3,16 +3,36 @@ import ModuleMain from 'salix/components/module-main'; export default class Route extends ModuleMain { $postLink() { - let to = new Date(); + const to = new Date(); to.setDate(to.getDate() + 1); to.setHours(0, 0, 0, 0); - let from = new Date(); + const from = new Date(); + from.setDate(from.getDate()); from.setHours(0, 0, 0, 0); - this.filterParams = {from, to, warehouseFk: this.vnConfig.warehouseFk}; + this.filterParams = {from, to}; this.$.model.applyFilter(null, this.filterParams); } + + fetchParams($params) { + const hasEntries = Object.entries($params).length; + if (!hasEntries) + $params.scopeDays = 1; + + if (typeof $params.scopeDays === 'number') { + const from = new Date(); + from.setHours(0, 0, 0, 0); + + const to = new Date(from.getTime()); + to.setDate(to.getDate() + $params.scopeDays); + to.setHours(23, 59, 59, 999); + + Object.assign($params, {from, to}); + } + + return $params; + } } ngModule.vnComponent('vnRoute', { diff --git a/modules/route/front/main/index.spec.js b/modules/route/front/main/index.spec.js new file mode 100644 index 0000000000..e5724b4933 --- /dev/null +++ b/modules/route/front/main/index.spec.js @@ -0,0 +1,49 @@ +import './index.js'; + +describe('Route Component vnRoute', () => { + let controller; + + beforeEach(ngModule('route')); + + beforeEach(inject($componentController => { + let $element = angular.element(`
`); + controller = $componentController('vnRoute', {$element}); + })); + + describe('fetchParams()', () => { + it('should return a range of dates with passed scope days', () => { + let params = controller.fetchParams({ + scopeDays: 2 + }); + const from = new Date(); + from.setHours(0, 0, 0, 0); + const to = new Date(from.getTime()); + to.setDate(to.getDate() + params.scopeDays); + to.setHours(23, 59, 59, 999); + + const expectedParams = { + from, + scopeDays: params.scopeDays, + to + }; + + expect(params).toEqual(expectedParams); + }); + + it('should return default value for scope days', () => { + let params = controller.fetchParams({ + scopeDays: 1 + }); + + expect(params.scopeDays).toEqual(1); + }); + + it('should return the given scope days', () => { + let params = controller.fetchParams({ + scopeDays: 2 + }); + + expect(params.scopeDays).toEqual(2); + }); + }); +}); diff --git a/modules/route/front/search-panel/index.html b/modules/route/front/search-panel/index.html index 2c7dd93b20..4c9dd3110f 100644 --- a/modules/route/front/search-panel/index.html +++ b/modules/route/front/search-panel/index.html @@ -1,6 +1,6 @@
-
- + + - + - - - - - - - +
+ + + + + + Or + + + + + +
+ - + - + diff --git a/modules/route/front/search-panel/index.js b/modules/route/front/search-panel/index.js index d2de05709d..b5abbd94ae 100644 --- a/modules/route/front/search-panel/index.js +++ b/modules/route/front/search-panel/index.js @@ -1,7 +1,43 @@ import ngModule from '../module'; import SearchPanel from 'core/components/searchbar/search-panel'; +class Controller extends SearchPanel { + constructor($, $element) { + super($, $element); + this.filter = this.$.filter; + } + + get from() { + return this._from; + } + + set from(value) { + this._from = value; + this.filter.scopeDays = null; + } + + get to() { + return this._to; + } + + set to(value) { + this._to = value; + this.filter.scopeDays = null; + } + + get scopeDays() { + return this._scopeDays; + } + + set scopeDays(value) { + this._scopeDays = value; + + this.filter.from = null; + this.filter.to = null; + } +} + ngModule.vnComponent('vnRouteSearchPanel', { template: require('./index.html'), - controller: SearchPanel + controller: Controller }); diff --git a/modules/route/front/search-panel/index.spec.js b/modules/route/front/search-panel/index.spec.js new file mode 100644 index 0000000000..16e1a5cfcf --- /dev/null +++ b/modules/route/front/search-panel/index.spec.js @@ -0,0 +1,48 @@ +import './index'; + +describe('Route Component vnRouteSearchPanel', () => { + let controller; + + beforeEach(ngModule('route')); + + beforeEach(inject($componentController => { + controller = $componentController('vnRouteSearchPanel', {$element: null}); + controller.$t = () => {}; + controller.filter = {}; + })); + + describe('from() setter', () => { + it('should clear the scope days when setting the from property', () => { + controller.filter.scopeDays = 1; + + controller.from = new Date(); + + expect(controller.filter.scopeDays).toBeNull(); + expect(controller.from).toBeDefined(); + }); + }); + + describe('to() setter', () => { + it('should clear the scope days when setting the to property', () => { + controller.filter.scopeDays = 1; + + controller.to = new Date(); + + expect(controller.filter.scopeDays).toBeNull(); + expect(controller.to).toBeDefined(); + }); + }); + + describe('scopeDays() setter', () => { + it('should clear the date range when setting the scopeDays property', () => { + controller.filter.from = new Date(); + controller.filter.to = new Date(); + + controller.scopeDays = 1; + + expect(controller.filter.from).toBeNull(); + expect(controller.filter.to).toBeNull(); + expect(controller.scopeDays).toBeDefined(); + }); + }); +}); diff --git a/modules/supplier/back/methods/supplier/getSummary.js b/modules/supplier/back/methods/supplier/getSummary.js index e6509eaa24..1148c16cb2 100644 --- a/modules/supplier/back/methods/supplier/getSummary.js +++ b/modules/supplier/back/methods/supplier/getSummary.js @@ -42,6 +42,7 @@ module.exports = Self => { 'sageTaxTypeFk', 'sageTransactionTypeFk', 'sageWithholdingFk', + 'workerFk' ], include: [ { @@ -85,7 +86,19 @@ module.exports = Self => { scope: { fields: ['id', 'withholding'] } - } + }, + { + relation: 'worker', + scope: { + fields: ['userFk'], + include: { + relation: 'user', + scope: { + fields: ['nickname'] + } + } + } + }, ] }; let supplier = await Self.app.models.Supplier.findOne(filter); diff --git a/modules/supplier/back/models/supplier.json b/modules/supplier/back/models/supplier.json index eb3c5989e6..4ec568c8be 100644 --- a/modules/supplier/back/models/supplier.json +++ b/modules/supplier/back/models/supplier.json @@ -11,75 +11,78 @@ }, "properties": { "id": { - "type": "Number", + "type": "number", "id": true, "description": "Identifier" }, "name": { - "type": "String" + "type": "string" }, "account": { - "type": "String" + "type": "string" }, "countryFk": { - "type": "Number" + "type": "number" }, "nif": { - "type": "String" + "type": "string" }, "isFarmer": { - "type": "Boolean" + "type": "boolean" }, "phone": { - "type": "Number" + "type": "number" }, "retAccount": { - "type": "Number" + "type": "number" }, "commission": { - "type": "Boolean" + "type": "boolean" }, "created": { - "type": "Date" + "type": "date" }, "postcodeFk": { - "type": "Number" + "type": "number" }, "isActive": { - "type": "Boolean" + "type": "boolean" }, "isOfficial": { - "type": "Boolean" + "type": "boolean" }, "isSerious": { - "type": "Boolean" + "type": "boolean" }, "note": { - "type": "String" + "type": "string" }, "street": { - "type": "String" + "type": "string" }, "city": { - "type": "String" + "type": "string" }, "provinceFk": { - "type": "Number" + "type": "number" }, "postCode": { - "type": "String" + "type": "string" }, "payMethodFk": { - "type": "Number" + "type": "number" }, "payDemFk": { - "type": "Number" + "type": "number" }, "payDay": { - "type": "Number" + "type": "number" }, "nickname": { - "type": "String" + "type": "string" + }, + "workerFk": { + "type": "number" }, "sageTaxTypeFk": { "type": "number", @@ -126,6 +129,11 @@ "model": "Client", "foreignKey": "nif", "primaryKey": "fi" + }, + "worker": { + "type": "belongsTo", + "model": "Worker", + "foreignKey": "workerFk" }, "sageTaxType": { "type": "belongsTo", diff --git a/modules/supplier/front/basic-data/index.html b/modules/supplier/front/basic-data/index.html index 72accfb5f3..7d2f801a44 100644 --- a/modules/supplier/front/basic-data/index.html +++ b/modules/supplier/front/basic-data/index.html @@ -15,6 +15,17 @@ rule vn-focus> + + + + + {{$ctrl.summary.worker.user.nickname}} + + diff --git a/modules/supplier/front/summary/locale/es.yml b/modules/supplier/front/summary/locale/es.yml index 6afaf857dc..512b75f9d4 100644 --- a/modules/supplier/front/summary/locale/es.yml +++ b/modules/supplier/front/summary/locale/es.yml @@ -6,4 +6,5 @@ Is Farmer: Es agrícola Sage tax type: Tipo de impuesto Sage Sage transaction type: Tipo de transacción Sage Sage withholding: Retencion Sage -Go to the supplier: Ir al proveedor \ No newline at end of file +Go to the supplier: Ir al proveedor +Responsible: Responsable \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/filter.js b/modules/ticket/back/methods/ticket/filter.js index 5341de8d17..5c941ef846 100644 --- a/modules/ticket/back/methods/ticket/filter.js +++ b/modules/ticket/back/methods/ticket/filter.js @@ -197,6 +197,7 @@ module.exports = Self => { t.id, t.shipped, CAST(DATE(t.shipped) AS CHAR) AS shippedDate, + HOUR(t.shipped) AS shippedHour, t.nickname, t.refFk, t.routeFk, diff --git a/modules/ticket/back/methods/ticket/new.js b/modules/ticket/back/methods/ticket/new.js index 8bafe5403e..cec7857bd1 100644 --- a/modules/ticket/back/methods/ticket/new.js +++ b/modules/ticket/back/methods/ticket/new.js @@ -101,7 +101,7 @@ module.exports = Self => { if (!shipped && landed) { const shippedResult = await models.Agency.getShipped(landed, address.id, agencyModeId, warehouseId); - shipped = shippedResult && shippedResult.shipped; + shipped = (shippedResult && shippedResult.shipped) || landed; } if (shipped && !landed) { diff --git a/modules/ticket/back/methods/ticket/specs/new.spec.js b/modules/ticket/back/methods/ticket/specs/new.spec.js index f240ce3729..671b9bffde 100644 --- a/modules/ticket/back/methods/ticket/specs/new.spec.js +++ b/modules/ticket/back/methods/ticket/specs/new.spec.js @@ -28,7 +28,7 @@ describe('ticket new()', () => { params.shipped, params.landed, params.warehouseId, - params.companyFk, + params.companyId, params.addressId ).catch(e => { error = e; @@ -53,7 +53,7 @@ describe('ticket new()', () => { params.shipped, params.landed, params.warehouseId, - params.companyFk, + params.companyId, params.addressId ).catch(response => { expect(response.message).toEqual(`This address doesn't exist`); @@ -79,7 +79,7 @@ describe('ticket new()', () => { params.shipped, params.landed, params.warehouseId, - params.companyFk, + params.companyId, params.addressId, params.agencyModeId); @@ -87,4 +87,27 @@ describe('ticket new()', () => { expect(ticket.id).toBeGreaterThan(newestTicketIdInFixtures); }); + + it('should return the set a shipped when the agency is not especified', async() => { + let params = { + clientId: 104, + landed: today, + shipped: null, + warehouseId: 2, + companyId: 442, + addressId: 4, + agencyModeId: null + }; + + ticket = await app.models.Ticket.new(ctx, + params.clientId, + params.shipped, + params.landed, + params.warehouseId, + params.companyId, + params.addressId, + params.agencyModeId); + + expect(ticket.shipped).toEqual(jasmine.any(Date)); + }); }); diff --git a/modules/ticket/back/models/ticket-request.js b/modules/ticket/back/models/ticket-request.js index 814f47bae6..234978f333 100644 --- a/modules/ticket/back/models/ticket-request.js +++ b/modules/ticket/back/models/ticket-request.js @@ -1,4 +1,5 @@ const LoopBackContext = require('loopback-context'); +const dateUtil = require('vn-loopback/util/date'); module.exports = function(Self) { require('../methods/ticket-request/filter')(Self); @@ -26,12 +27,7 @@ module.exports = function(Self) { if (instance.price) messageText = 'New ticket request has been created with price'; - const shipped = new Intl.DateTimeFormat('es', { - year: 'numeric', - month: 'numeric', - day: 'numeric' - }).format(ticket.shipped); - + const shipped = dateUtil.toString(ticket.shipped); const message = $t(messageText, { description: instance.description, shipped: shipped, diff --git a/modules/ticket/front/create/card.html b/modules/ticket/front/create/card.html index 36e62d8e65..65c45d3dce 100644 --- a/modules/ticket/front/create/card.html +++ b/modules/ticket/front/create/card.html @@ -39,7 +39,7 @@ { - this._availableAgencies = res.data; - - this.agencyModeId = this.defaultAddress.agencyModeFk; + this.agencies = res.data; + const defaultAgency = this.agencies.find(agency=> { + return agency.agencyModeFk == this.defaultAddress.agencyModeFk; + }); + if (defaultAgency) + this.agencyModeId = defaultAgency.agencyModeFk; }); } } diff --git a/modules/ticket/front/index/index.html b/modules/ticket/front/index/index.html index d137d40be6..4243ef1ab9 100644 --- a/modules/ticket/front/index/index.html +++ b/modules/ticket/front/index/index.html @@ -18,12 +18,12 @@ Salesperson Date Hour + Closure Alias Province State Zone Warehouse - Closure Total @@ -86,6 +86,7 @@ {{::ticket.shipped | date: 'HH:mm'}} + {{::ticket.zoneLanding | date: 'HH:mm'}} {{::ticket.warehouse}} - {{::ticket.zoneLanding | date: 'HH:mm'}} {{::ticket.total | currency: 'EUR': 2}} diff --git a/modules/ticket/front/main/index.html b/modules/ticket/front/main/index.html index 953dc8a6be..8e9af1e128 100644 --- a/modules/ticket/front/main/index.html +++ b/modules/ticket/front/main/index.html @@ -2,7 +2,7 @@ vn-id="model" url="Tickets/filter" limit="20" - order="shipped DESC, zoneHour DESC, zoneMinute DESC, clientFk"> + order="shippedDate DESC, shippedHour ASC, zoneLanding ASC"> - O + Or this.reload()) + .then(() => { + if ('id' in this.$params) this.reload(); + }) .then(() => { this.vnApp.showSuccess(this.$t('Data saved!')); }); diff --git a/modules/travel/front/main/index.spec.js b/modules/travel/front/main/index.spec.js index 96d819a6f0..6d9db4dc84 100644 --- a/modules/travel/front/main/index.spec.js +++ b/modules/travel/front/main/index.spec.js @@ -12,29 +12,38 @@ describe('Travel Component vnTravel', () => { describe('fetchParams()', () => { it('should return a range of dates with passed scope days', () => { - /** - * Calculates the difference in days between two dates, it also - * accounts for cases where the two dates in question span a - * daylight saving time (DST) change. - * - * @param {Date} a The start date - * @param {Date} b The end date - * @return {Number} The difference in days - */ - function diffInDays(a, b) { - const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate()); - const utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate()); - const msInDay = 86400 * 1000; - return Math.floor((utc2 - utc1) / msInDay); - } + let params = controller.fetchParams({ + scopeDays: 2 + }); + const shippedFrom = new Date(); + shippedFrom.setHours(0, 0, 0, 0); + const shippedTo = new Date(shippedFrom.getTime()); + shippedTo.setDate(shippedTo.getDate() + params.scopeDays); + shippedTo.setHours(23, 59, 59, 999); - let params = controller.fetchParams({scopeDays: 2}); - const diff = diffInDays( - params.shippedFrom, - new Date(params.shippedTo.getTime() + 1) - ); + const expectedParams = { + shippedFrom, + scopeDays: params.scopeDays, + shippedTo + }; - expect(diff).toEqual(3); + expect(params).toEqual(expectedParams); + }); + + it('should return default value for scope days', () => { + let params = controller.fetchParams({ + scopeDays: 1 + }); + + expect(params.scopeDays).toEqual(1); + }); + + it('should return the given scope days', () => { + let params = controller.fetchParams({ + scopeDays: 2 + }); + + expect(params.scopeDays).toEqual(2); }); }); }); diff --git a/modules/travel/front/search-panel/index.html b/modules/travel/front/search-panel/index.html index afc041f66d..8e7f4140d2 100644 --- a/modules/travel/front/search-panel/index.html +++ b/modules/travel/front/search-panel/index.html @@ -1,6 +1,6 @@
-
- + + - + - + - - - - - - - +
+ + + + + + Or + + + + + +
+ - + - + diff --git a/modules/travel/front/search-panel/index.js b/modules/travel/front/search-panel/index.js index 8aa25e594d..877d4f9d3e 100644 --- a/modules/travel/front/search-panel/index.js +++ b/modules/travel/front/search-panel/index.js @@ -1,7 +1,43 @@ import ngModule from '../module'; import SearchPanel from 'core/components/searchbar/search-panel'; +class Controller extends SearchPanel { + constructor($, $element) { + super($, $element); + this.filter = this.$.filter; + } + + get shippedFrom() { + return this._shippedFrom; + } + + set shippedFrom(value) { + this._shippedFrom = value; + this.filter.scopeDays = null; + } + + get shippedTo() { + return this._shippedTo; + } + + set shippedTo(value) { + this._shippedTo = value; + this.filter.scopeDays = null; + } + + get scopeDays() { + return this._scopeDays; + } + + set scopeDays(value) { + this._scopeDays = value; + + this.filter.shippedFrom = null; + this.filter.shippedTo = null; + } +} + ngModule.vnComponent('vnTravelSearchPanel', { template: require('./index.html'), - controller: SearchPanel + controller: Controller }); diff --git a/modules/travel/front/search-panel/index.spec.js b/modules/travel/front/search-panel/index.spec.js new file mode 100644 index 0000000000..a1f3c36b31 --- /dev/null +++ b/modules/travel/front/search-panel/index.spec.js @@ -0,0 +1,48 @@ +import './index'; + +describe('Travel Component vnTravelSearchPanel', () => { + let controller; + + beforeEach(ngModule('travel')); + + beforeEach(inject($componentController => { + controller = $componentController('vnTravelSearchPanel', {$element: null}); + controller.$t = () => {}; + controller.filter = {}; + })); + + describe('shippedFrom() setter', () => { + it('should clear the scope days when setting the from property', () => { + controller.filter.scopeDays = 1; + + controller.shippedFrom = new Date(); + + expect(controller.filter.scopeDays).toBeNull(); + expect(controller.shippedFrom).toBeDefined(); + }); + }); + + describe('shippedTo() setter', () => { + it('should clear the scope days when setting the to property', () => { + controller.filter.scopeDays = 1; + + controller.shippedTo = new Date(); + + expect(controller.filter.scopeDays).toBeNull(); + expect(controller.shippedTo).toBeDefined(); + }); + }); + + describe('scopeDays() setter', () => { + it('should clear the date range when setting the scopeDays property', () => { + controller.filter.shippedFrom = new Date(); + controller.filter.shippedTo = new Date(); + + controller.scopeDays = 1; + + expect(controller.filter.shippedFrom).toBeNull(); + expect(controller.filter.shippedTo).toBeNull(); + expect(controller.scopeDays).toBeDefined(); + }); + }); +}); diff --git a/modules/worker/back/methods/worker-dms/filter.js b/modules/worker/back/methods/worker-dms/filter.js index 553cf2a25b..82216f956a 100644 --- a/modules/worker/back/methods/worker-dms/filter.js +++ b/modules/worker/back/methods/worker-dms/filter.js @@ -28,7 +28,7 @@ module.exports = Self => { const account = await Self.app.models.Account.findById(userId); const stmt = new ParameterizedSQL( - `SELECT d.id dmsFk, d.reference, d.description, d.file, d.created + `SELECT d.id dmsFk, d.reference, d.description, d.file, d.created, d.hardCopyNumber, d.hasFile FROM workerDocument wd JOIN dms d ON d.id = wd.document JOIN dmsType dt ON dt.id = d.dmsTypeFk diff --git a/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js b/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js index 540a7ab8eb..97637d197b 100644 --- a/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js +++ b/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js @@ -26,11 +26,11 @@ module.exports = Self => { const workerModel = Self.app.models.Worker; const targetTimeEntry = await Self.findById(id); - const isSubordinate = await workerModel.isSubordinate(ctx, targetTimeEntry.userFk); - const isHHRR = await Self.app.models.Account.hasRole(currentUserId, 'hr'); + const isTeamBoss = await Self.app.models.Account.hasRole(currentUserId, 'teamBoss'); + const isHimself = currentUserId == targetTimeEntry.userFk; - const notAllowed = isSubordinate === false || (isSubordinate && currentUserId == targetTimeEntry.userFk && !isHHRR); + const notAllowed = isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss); if (notAllowed) throw new UserError(`You don't have enough privileges`); diff --git a/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js b/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js index 5e37329886..0f055bdc52 100644 --- a/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js +++ b/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js @@ -5,6 +5,8 @@ describe('workerTimeControl add/delete timeEntry()', () => { const HHRRId = 37; const teamBossId = 13; const employeeId = 1; + const salesPersonId = 106; + const salesBossId = 19; let activeCtx = { accessToken: {userId: 50}, }; @@ -85,13 +87,13 @@ describe('workerTimeControl add/delete timeEntry()', () => { }); it('should try but fail to delete his own time entry', async() => { - activeCtx.accessToken.userId = teamBossId; + activeCtx.accessToken.userId = salesBossId; let error; let todayAtSeven = new Date(); todayAtSeven.setHours(19, 30, 0, 0); let data = { - workerFk: teamBossId, + workerFk: salesPersonId, timed: todayAtSeven }; @@ -100,6 +102,7 @@ describe('workerTimeControl add/delete timeEntry()', () => { createdTimeEntry = await app.models.WorkerTimeControl.findById(timeEntry.id); try { + activeCtx.accessToken.userId = salesPersonId; await app.models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id); } catch (e) { error = e; @@ -110,6 +113,30 @@ describe('workerTimeControl add/delete timeEntry()', () => { expect(error.message).toBe(`You don't have enough privileges`); }); + it('should delete the created time entry for the team boss as himself', async() => { + activeCtx.accessToken.userId = teamBossId; + + let todayAtFive = new Date(); + todayAtFive.setHours(17, 30, 0, 0); + + let data = { + workerFk: teamBossId, + timed: todayAtFive + }; + + timeEntry = await app.models.WorkerTimeControl.addTimeEntry(ctx, data); + + createdTimeEntry = await app.models.WorkerTimeControl.findById(timeEntry.id); + + expect(createdTimeEntry).toBeDefined(); + + await app.models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id); + + createdTimeEntry = await app.models.WorkerTimeControl.findById(timeEntry.id); + + expect(createdTimeEntry).toBeNull(); + }); + it('should delete the created time entry for the team boss as HHRR', async() => { activeCtx.accessToken.userId = HHRRId; diff --git a/modules/worker/back/models/department.json b/modules/worker/back/models/department.json index 31ebbb09a4..7d6f7a7be6 100644 --- a/modules/worker/back/models/department.json +++ b/modules/worker/back/models/department.json @@ -9,28 +9,31 @@ "properties": { "id": { "id": true, - "type": "Number" + "type": "number" + }, + "code": { + "type": "string" }, "name": { - "type": "String" + "type": "string" }, "parentFk": { - "type": "Number" + "type": "number" }, "lft": { - "type": "Number" + "type": "number" }, "rgt": { - "type": "Number" + "type": "number" }, "sons": { - "type": "Number" + "type": "number" }, "chatName": { - "type": "String" + "type": "string" }, "notificationEmail": { - "type": "String" + "type": "string" } } } diff --git a/modules/worker/front/descriptor/index.js b/modules/worker/front/descriptor/index.js index c5dc1ea2c8..260d3f6121 100644 --- a/modules/worker/front/descriptor/index.js +++ b/modules/worker/front/descriptor/index.js @@ -57,7 +57,7 @@ class Controller extends Descriptor { onUploadResponse() { const timestamp = new Date().getTime(); const src = this.$rootScope.imagePath('user', '520x520', this.worker.id); - const zoomSrc = this.$rootScope.imagePath('user', '1600x900', this.worker.id); + const zoomSrc = this.$rootScope.imagePath('user', '1600x1600', this.worker.id); const newSrc = `${src}&t=${timestamp}`; const newZoomSrc = `${zoomSrc}&t=${timestamp}`; diff --git a/modules/worker/front/dms/edit/index.html b/modules/worker/front/dms/edit/index.html index 13bf6f953a..2ac96851c1 100644 --- a/modules/worker/front/dms/edit/index.html +++ b/modules/worker/front/dms/edit/index.html @@ -68,7 +68,7 @@ - diff --git a/modules/worker/front/dms/index/index.html b/modules/worker/front/dms/index/index.html index d6e1bc25c8..6ad1cffd88 100644 --- a/modules/worker/front/dms/index/index.html +++ b/modules/worker/front/dms/index/index.html @@ -15,6 +15,7 @@ Id + Order Reference Description Original @@ -28,6 +29,12 @@ {{::document.dmsFk}} + + + {{::document.hardCopyNumber}} + + {{::document.reference}} @@ -40,7 +47,7 @@ diff --git a/modules/worker/front/dms/index/index.js b/modules/worker/front/dms/index/index.js index e67240a733..9bb3c896a3 100644 --- a/modules/worker/front/dms/index/index.js +++ b/modules/worker/front/dms/index/index.js @@ -6,42 +6,6 @@ class Controller extends Component { constructor($element, $, vnFile) { super($element, $); this.vnFile = vnFile; - this.filter = { - include: { - relation: 'dms', - scope: { - fields: [ - 'dmsTypeFk', - 'reference', - 'hardCopyNumber', - 'workerFk', - 'description', - 'hasFile', - 'file', - 'created', - ], - include: [ - { - relation: 'dmsType', - scope: { - fields: ['name'] - } - }, { - relation: 'worker', - scope: { - fields: ['userFk'], - include: { - relation: 'user', - scope: { - fields: ['nickname'] - } - }, - } - } - ] - }, - } - }; } deleteDms(index) { diff --git a/modules/zone/back/models/zone-event.js b/modules/zone/back/models/zone-event.js index d4fad8e965..6af031a239 100644 --- a/modules/zone/back/models/zone-event.js +++ b/modules/zone/back/models/zone-event.js @@ -1,5 +1,3 @@ -const app = require('vn-loopback/server/server'); - module.exports = Self => { Self.validate('range', function(err) { if (this.type == 'range' diff --git a/package-lock.json b/package-lock.json index ff41351411..861c917d09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5893,7 +5893,7 @@ }, "util": { "version": "0.10.3", - "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -6864,7 +6864,7 @@ "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { "cache-base": "^1.0.1", @@ -7185,7 +7185,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -7376,7 +7376,7 @@ "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "dev": true, "requires": { "collection-visit": "^1.0.0", @@ -7584,7 +7584,7 @@ "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -10021,7 +10021,7 @@ }, "file-loader": { "version": "1.1.11", - "resolved": "http://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", "dev": true, "requires": { @@ -10143,11 +10143,6 @@ "parse-filepath": "^1.0.1" } }, - "first-chunk-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-0.1.0.tgz", - "integrity": "sha1-dV0+wU1JqG49L8wIvurVwMornAo=" - }, "flagged-respawn": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", @@ -11207,7 +11202,7 @@ "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", "dev": true, "requires": { "global-prefix": "^1.0.1", @@ -13100,9 +13095,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "internal-ip": { "version": "4.3.0", @@ -13394,7 +13389,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { "isobject": "^3.0.1" @@ -13478,7 +13473,8 @@ "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true }, "is-valid-glob": { "version": "1.0.0", @@ -22352,7 +22348,7 @@ "dependencies": { "jsesc": { "version": "0.5.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true } @@ -22694,7 +22690,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { @@ -22908,7 +22904,7 @@ "dependencies": { "source-map": { "version": "0.4.4", - "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { @@ -23369,7 +23365,7 @@ "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { "define-property": "^1.0.0", @@ -23420,7 +23416,7 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { "kind-of": "^3.2.0" @@ -23438,40 +23434,43 @@ } }, "soap": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/soap/-/soap-0.26.0.tgz", - "integrity": "sha512-tTS3lnGl6lfjQQuJgNnWOgC0Xa6qYQSwl2G7DX3kCdGmek/FTNmHDM/7icKP1KBMFfCrKpAWEbZiGefa92SCYw==", + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/soap/-/soap-0.35.0.tgz", + "integrity": "sha512-nRzW37ZdsdPKW8AtRKj6ibK+xVqgN8HFeowf+7NiJUtrHUbdiES3pFtRN0ZNU4q9Z1c75Epg77+9ENrtx9ulTw==", "requires": { - "bluebird": "^3.5.0", - "concat-stream": "^1.5.1", - "debug": "^2.6.9", - "ejs": "~2.5.5", - "finalhandler": "^1.0.3", + "debug": "^4.1.1", + "get-stream": "^6.0.0", "httpntlm": "^1.5.2", - "lodash": "^4.17.5", + "lodash": "^4.17.19", "request": ">=2.9.0", "sax": ">=0.6", - "serve-static": "^1.11.1", - "strip-bom": "~0.3.1", - "uuid": "^3.1.0", - "xml-crypto": "~0.8.0" + "strip-bom": "^3.0.0", + "uuid": "^8.3.0", + "xml-crypto": "^2.0.0" }, "dependencies": { - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "ms": "2.1.2" } }, - "ejs": { - "version": "2.5.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.9.tgz", - "integrity": "sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ==" + "get-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" } } }, @@ -23704,7 +23703,7 @@ "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", "dev": true, "requires": { "extend-shallow": "^3.0.0" @@ -23958,13 +23957,9 @@ } }, "strip-bom": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-0.3.1.tgz", - "integrity": "sha1-noo57/RW/5q8LwWfXyIluw8/fKU=", - "requires": { - "first-chunk-stream": "^0.1.0", - "is-utf8": "^0.2.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" }, "strip-eof": { "version": "1.0.0", @@ -25006,7 +25001,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" @@ -25088,7 +25083,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -26779,12 +26774,12 @@ "dev": true }, "xml-crypto": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-0.8.5.tgz", - "integrity": "sha1-K7z7PrM/OoKiGLgiv2craxwg5Tg=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-2.0.0.tgz", + "integrity": "sha512-/a04qr7RpONRZHOxROZ6iIHItdsQQjN3sj8lJkYDDss8tAkEaAs0VrFjb3tlhmS5snQru5lTs9/5ISSMdPDHlg==", "requires": { - "xmldom": "=0.1.19", - "xpath.js": ">=0.0.3" + "xmldom": "0.1.27", + "xpath": "0.0.27" } }, "xml-name-validator": { @@ -26811,7 +26806,7 @@ }, "xmlbuilder": { "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" }, "xmlchars": { @@ -26826,14 +26821,14 @@ "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=" }, "xmldom": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.19.tgz", - "integrity": "sha1-Yx/Ad3bv2EEYvyUXGzftTQdaCrw=" + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", + "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=" }, - "xpath.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xpath.js/-/xpath.js-1.1.0.tgz", - "integrity": "sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ==" + "xpath": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.27.tgz", + "integrity": "sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ==" }, "xtend": { "version": "1.0.3", diff --git a/package.json b/package.json index 0bb835dd85..0e1bc8e32c 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "require-yaml": "0.0.1", "sharp": "^0.25.4", "smbhash": "0.0.1", - "soap": "^0.26.0", + "soap": "^0.35.0", "strong-error-handler": "^2.3.2", "uuid": "^3.3.3", "vn-loopback": "file:./loopback",