From 31aafc071945c2d6e84760d92b1173d7495790a3 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 10 Aug 2022 09:11:38 +0200 Subject: [PATCH 01/69] feat: add inserts in printQueue --- db/dump/fixtures.sql | 4 ++ .../methods/invoiceOut/globalInvoicing.js | 41 +++++++++++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index e7232edd30..638f191f37 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2642,3 +2642,7 @@ INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`) VALUES (1, 9); + +INSERT INTO `vn`.`report` (`id`, `name`) + VALUES + (3, 'invoice'); \ No newline at end of file diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index 7f2cbb4420..14d6913cbc 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -79,6 +79,13 @@ module.exports = Self => { const minShipped = new Date(); minShipped.setFullYear(minShipped.getFullYear() - 1); + if (args.fromClientId = args.toClientId) { + minShipped.setFullYear(2021); + minShipped.setMonth(1); + minShipped.setDate(1); + minShipped.setHours(0, 0, 0, 0); + } + // Packaging liquidation const vIsAllInvoiceable = false; const clientsWithPackaging = await getClientsWithPackaging(ctx, myOptions); @@ -138,8 +145,34 @@ module.exports = Self => { if (newInvoice.id) { await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); - query = `INSERT IGNORE INTO invoiceOut_queue(invoiceFk) VALUES(?)`; - await Self.rawSql(query, [newInvoice.id], myOptions); + // query = `INSERT IGNORE INTO invoiceOut_queue(invoiceFk) VALUES(?)`; + // await Self.rawSql(query, [newInvoice.id], myOptions); + + query = `SELECT id FROM vn.report WHERE name ='invoice'`; + const [reportFk] = await Self.rawSql(query, null, myOptions); + + query = `SELECT ref FROM vn.invoiceOut WHERE id = ?`; + const [invoiceRef] = await Self.rawSql(query, [newInvoice.id], myOptions); + + // Print invoice + const args = { + invoiceOutFk: newInvoice.id, + refFk: invoiceRef.ref, + hasToForcePdf: true, + email: '' + }; + + const userId = ctx.req.accessToken.userId; + + query = `INSERT INTO vn.printQueue (priorityFk, reportFk, workerFk, printerFk) VALUES (?, ?, ?, NULL)`; + await Self.rawSql(query, [2, reportFk.id, userId], myOptions); // La prioridad de donde se la saca? 'adPriorityBelowNormal' + + const [lastInsertedPrintQueue] = await Self.rawSql('SELECT LAST_INSERT_ID() AS id', null, myOptions); + + for (let key in args) { + query = `INSERT INTO vn.printQueueArgs (printQueueFk, name, value) VALUES (?, ?, ?)`; + await Self.rawSql(query, [lastInsertedPrintQueue.id, key, args[key]], myOptions); + } invoicesIds.push(newInvoice.id); } @@ -192,8 +225,10 @@ module.exports = Self => { const query = `SELECT DISTINCT clientFk AS id FROM ticket t JOIN ticketPackaging tp ON t.id = tp.ticketFk + JOIN client c ON c.id = t.clientFk WHERE t.shipped BETWEEN '2017-11-21' AND ? - AND t.clientFk BETWEEN ? AND ?`; + AND t.clientFk BETWEEN ? AND ? + AND c.isActive`; return models.InvoiceOut.rawSql(query, [ args.maxShipped, args.fromClientId, From f3df373f70aded877b2cbeae261b75ace5cacba8 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 10 Aug 2022 13:23:50 +0200 Subject: [PATCH 02/69] delete: unnecessary code --- .../methods/invoiceOut/globalInvoicing.js | 30 ++----------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index 14d6913cbc..dba05ed857 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -145,34 +145,8 @@ module.exports = Self => { if (newInvoice.id) { await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); - // query = `INSERT IGNORE INTO invoiceOut_queue(invoiceFk) VALUES(?)`; - // await Self.rawSql(query, [newInvoice.id], myOptions); - - query = `SELECT id FROM vn.report WHERE name ='invoice'`; - const [reportFk] = await Self.rawSql(query, null, myOptions); - - query = `SELECT ref FROM vn.invoiceOut WHERE id = ?`; - const [invoiceRef] = await Self.rawSql(query, [newInvoice.id], myOptions); - - // Print invoice - const args = { - invoiceOutFk: newInvoice.id, - refFk: invoiceRef.ref, - hasToForcePdf: true, - email: '' - }; - - const userId = ctx.req.accessToken.userId; - - query = `INSERT INTO vn.printQueue (priorityFk, reportFk, workerFk, printerFk) VALUES (?, ?, ?, NULL)`; - await Self.rawSql(query, [2, reportFk.id, userId], myOptions); // La prioridad de donde se la saca? 'adPriorityBelowNormal' - - const [lastInsertedPrintQueue] = await Self.rawSql('SELECT LAST_INSERT_ID() AS id', null, myOptions); - - for (let key in args) { - query = `INSERT INTO vn.printQueueArgs (printQueueFk, name, value) VALUES (?, ?, ?)`; - await Self.rawSql(query, [lastInsertedPrintQueue.id, key, args[key]], myOptions); - } + query = `INSERT IGNORE INTO invoiceOut_queue(invoiceFk) VALUES(?)`; + await Self.rawSql(query, [newInvoice.id], myOptions); invoicesIds.push(newInvoice.id); } From fe8ae164eb503f4025b927aa137c992a95dce6ed Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 4 Oct 2022 13:22:11 +0200 Subject: [PATCH 03/69] refactor(ticket): isEditable, canEdit --- back/methods/account/aclFunc.js | 33 +++++++++++++++++++ back/models/account.js | 3 +- db/dump/fixtures.sql | 6 ++++ modules/ticket/back/methods/sale/canEdit.js | 24 ++++++++++---- .../ticket/back/methods/sale/deleteSales.js | 3 +- .../back/methods/sale/recalculatePrice.js | 7 ++-- modules/ticket/back/methods/sale/reserve.js | 3 +- .../back/methods/sale/specs/canEdit.spec.js | 6 ++-- .../ticket/back/methods/ticket/isEditable.js | 24 ++++++-------- .../back/methods/ticket/isRoleAdvanced.js | 32 ++++++++++++++++++ modules/ticket/back/model-config.json | 3 ++ modules/ticket/back/models/sale-cloned.json | 26 +++++++++++++++ modules/ticket/back/models/ticket.js | 1 + 13 files changed, 141 insertions(+), 30 deletions(-) create mode 100644 back/methods/account/aclFunc.js create mode 100644 modules/ticket/back/methods/ticket/isRoleAdvanced.js create mode 100644 modules/ticket/back/models/sale-cloned.json diff --git a/back/methods/account/aclFunc.js b/back/methods/account/aclFunc.js new file mode 100644 index 0000000000..47dcd6f7a8 --- /dev/null +++ b/back/methods/account/aclFunc.js @@ -0,0 +1,33 @@ +module.exports = Self => { + Self.remoteMethodCtx('aclFunc', { + description: 'Get the user information and permissions', + accepts: [ + { + arg: 'property', + type: 'String', + description: 'The user name or email', + required: true + } + ], + returns: { + type: 'Object', + root: true + }, + http: { + path: `/aclFunc`, + verb: 'GET' + } + }); + + Self.aclFunc = async function(ctx, property) { + const userId = ctx.req.accessToken.userId; + const models = Self.app.models; + + const [acl] = await Self.rawSql( + `SELECT a.principalId + FROM salix.ACL a + WHERE a.property = ?`, [property]); + + return await models.Account.hasRole(userId, acl.principalId); + }; +}; diff --git a/back/models/account.js b/back/models/account.js index ba703c68d7..5b101eef76 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -7,6 +7,7 @@ module.exports = Self => { require('../methods/account/change-password')(Self); require('../methods/account/set-password')(Self); require('../methods/account/validate-token')(Self); + require('../methods/account/aclFunc')(Self); // Validations @@ -77,7 +78,7 @@ module.exports = Self => { `SELECT r.name FROM account.user u JOIN account.roleRole rr ON rr.role = u.role - JOIN account.role r ON r.id = rr.inheritsFrom + JOIN account.role r ON r.id = rr.inheritsFrom WHERE u.id = ?`, [userId], options); let roles = []; diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 1f66a53cfc..fd78a5401d 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2651,3 +2651,9 @@ INSERT INTO `vn`.`collection` (`id`, `created`, `workerFk`, `stateFk`, `itemPack INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `level`, `wagon`, `smartTagFk`, `usedShelves`, `itemCount`, `liters`) VALUES (9, 3, util.VN_NOW(), NULL, 0, NULL, NULL, NULL, NULL); + +INSERT INTO salix.ACL +(model, property, accessType, permission, principalType, principalId) +VALUES +('Sale', 'editTracked', 'WRITE', 'ALLOW', 'ROLE', 'production'), +('Sale', 'editCloned', 'WRITE', 'ALLOW', 'ROLE', 'production'); diff --git a/modules/ticket/back/methods/sale/canEdit.js b/modules/ticket/back/methods/sale/canEdit.js index 4e0fc5f8bf..f359b19e41 100644 --- a/modules/ticket/back/methods/sale/canEdit.js +++ b/modules/ticket/back/methods/sale/canEdit.js @@ -1,3 +1,5 @@ +const UserError = require('vn-loopback/util/user-error'); + module.exports = Self => { Self.remoteMethodCtx('canEdit', { description: 'Check if all the received sales are aditable', @@ -25,16 +27,26 @@ module.exports = Self => { if (typeof options == 'object') Object.assign(myOptions, options); - const idsCollection = sales.map(sale => sale.id); - - const saleTracking = await models.SaleTracking.find({where: {saleFk: {inq: idsCollection}}}, myOptions); + /* const firstSale = await models.Sale.findById(sales[0], null, myOptions); + const isTicketEditable = await models.Ticket.isEditable(ctx, firstSale.ticketFk, myOptions); + if (!isTicketEditable) + throw new UserError(`The sales of this ticket can't be modified`);*/ + const saleTracking = await models.SaleTracking.find({where: {saleFk: {inq: sales}}}, myOptions); const hasSaleTracking = saleTracking.length; - const isProductionRole = await models.Account.hasRole(userId, 'production', myOptions); + const saleCloned = await models.SaleCloned.find({where: {saleClonedFk: {inq: sales}}}, myOptions); + const hasSaleCloned = saleCloned.length; - const canEdit = (isProductionRole || !hasSaleTracking); + /* const isProductionRole = await models.Account.hasRole(userId, 'production', myOptions); + const canEdit = (isProductionRole || !hasSaleTracking);// && (isRole || !hasSaleCloned); - return canEdit; + const isRole = await models.Account.hasRole(userId, 'developer', myOptions);*/ + const editTracked = await models.Account.aclFunc(ctx, 'editTracked'); + const editCloned = await models.Account.aclFunc(ctx, 'editCloned'); + console.log(editTracked); + const canEdit = (editTracked || !hasSaleTracking) && (editCloned || !hasSaleCloned); + + return canEdit;// && isTicketEditable; }; }; diff --git a/modules/ticket/back/methods/sale/deleteSales.js b/modules/ticket/back/methods/sale/deleteSales.js index c1359569d7..7036821e9c 100644 --- a/modules/ticket/back/methods/sale/deleteSales.js +++ b/modules/ticket/back/methods/sale/deleteSales.js @@ -41,7 +41,8 @@ module.exports = Self => { } try { - const canEditSales = await models.Sale.canEdit(ctx, sales, myOptions); + const saleIds = sales.map(sale => sale.id); + const canEditSales = await models.Sale.canEdit(ctx, saleIds, myOptions); const ticket = await models.Ticket.findById(ticketId, { include: { diff --git a/modules/ticket/back/methods/sale/recalculatePrice.js b/modules/ticket/back/methods/sale/recalculatePrice.js index 59c7d3535c..cbe59cad2d 100644 --- a/modules/ticket/back/methods/sale/recalculatePrice.js +++ b/modules/ticket/back/methods/sale/recalculatePrice.js @@ -1,4 +1,5 @@ const UserError = require('vn-loopback/util/user-error'); + module.exports = Self => { Self.remoteMethodCtx('recalculatePrice', { description: 'Calculates the price of sales and its components', @@ -34,15 +35,13 @@ module.exports = Self => { } try { - const salesIds = []; - for (let sale of sales) - salesIds.push(sale.id); + const salesIds = sales.map(sale => sale.id); const isEditable = await models.Ticket.isEditable(ctx, sales[0].ticketFk, myOptions); if (!isEditable) throw new UserError(`The sales of this ticket can't be modified`); - const canEditSale = await models.Sale.canEdit(ctx, sales, myOptions); + const canEditSale = await models.Sale.canEdit(ctx, salesIds, myOptions); if (!canEditSale) throw new UserError(`Sale(s) blocked, please contact production`); diff --git a/modules/ticket/back/methods/sale/reserve.js b/modules/ticket/back/methods/sale/reserve.js index b368f6fc3d..c3e9ac30f2 100644 --- a/modules/ticket/back/methods/sale/reserve.js +++ b/modules/ticket/back/methods/sale/reserve.js @@ -53,7 +53,8 @@ module.exports = Self => { if (!isTicketEditable) throw new UserError(`The sales of this ticket can't be modified`); - const canEditSale = await models.Sale.canEdit(ctx, sales, myOptions); + const salesIds = sales.map(sale => sale.id); + const canEditSale = await models.Sale.canEdit(ctx, salesIds, myOptions); if (!canEditSale) throw new UserError(`Sale(s) blocked, please contact production`); diff --git a/modules/ticket/back/methods/sale/specs/canEdit.spec.js b/modules/ticket/back/methods/sale/specs/canEdit.spec.js index 4f6747257e..667ce98da3 100644 --- a/modules/ticket/back/methods/sale/specs/canEdit.spec.js +++ b/modules/ticket/back/methods/sale/specs/canEdit.spec.js @@ -10,7 +10,7 @@ describe('sale canEdit()', () => { const productionUserID = 49; const ctx = {req: {accessToken: {userId: productionUserID}}}; - const sales = [{id: 3}]; + const sales = [3]; const result = await models.Sale.canEdit(ctx, sales, options); @@ -32,7 +32,7 @@ describe('sale canEdit()', () => { const salesPersonUserID = 18; const ctx = {req: {accessToken: {userId: salesPersonUserID}}}; - const sales = [{id: 10}]; + const sales = [10]; const result = await models.Sale.canEdit(ctx, sales, options); @@ -54,7 +54,7 @@ describe('sale canEdit()', () => { const salesPersonUserID = 18; const ctx = {req: {accessToken: {userId: salesPersonUserID}}}; - const sales = [{id: 3}]; + const sales = [3]; const result = await models.Sale.canEdit(ctx, sales, options); diff --git a/modules/ticket/back/methods/ticket/isEditable.js b/modules/ticket/back/methods/ticket/isEditable.js index 5b9a397a1b..bdd18d7de4 100644 --- a/modules/ticket/back/methods/ticket/isEditable.js +++ b/modules/ticket/back/methods/ticket/isEditable.js @@ -20,24 +20,20 @@ module.exports = Self => { }); Self.isEditable = async(ctx, id, options) => { - const userId = ctx.req.accessToken.userId; + const models = Self.app.models; const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); - let state = await Self.app.models.TicketState.findOne({ + const state = await models.TicketState.findOne({ where: {ticketFk: id} }, myOptions); - const isSalesAssistant = await Self.app.models.Account.hasRole(userId, 'salesAssistant', myOptions); - const isDeliveryBoss = await Self.app.models.Account.hasRole(userId, 'deliveryBoss', myOptions); - const isBuyer = await Self.app.models.Account.hasRole(userId, 'buyer', myOptions); + const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, myOptions); - const isValidRole = isSalesAssistant || isDeliveryBoss || isBuyer; - - let alertLevel = state ? state.alertLevel : null; - let ticket = await Self.app.models.Ticket.findById(id, { + const alertLevel = state ? state.alertLevel : null; + const ticket = await models.Ticket.findById(id, { fields: ['clientFk'], include: [{ relation: 'client', @@ -48,15 +44,15 @@ module.exports = Self => { } }] }, myOptions); - const isLocked = await Self.app.models.Ticket.isLocked(id, myOptions); + const isLocked = await models.Ticket.isLocked(id, myOptions); const alertLevelGreaterThanZero = (alertLevel && alertLevel > 0); const isNormalClient = ticket && ticket.client().type().code == 'normal'; - const validAlertAndRoleNormalClient = (alertLevelGreaterThanZero && isNormalClient && !isValidRole); + const isEditable = !(alertLevelGreaterThanZero && isNormalClient); - if (!ticket || validAlertAndRoleNormalClient || isLocked) - return false; + if (ticket && (isEditable || isRoleAdvanced) && !isLocked) + return true; - return true; + return false; }; }; diff --git a/modules/ticket/back/methods/ticket/isRoleAdvanced.js b/modules/ticket/back/methods/ticket/isRoleAdvanced.js new file mode 100644 index 0000000000..7c5c8ed86f --- /dev/null +++ b/modules/ticket/back/methods/ticket/isRoleAdvanced.js @@ -0,0 +1,32 @@ +module.exports = Self => { + Self.remoteMethodCtx('isRoleAdvanced', { + description: 'Check if a ticket is editable', + accessType: 'READ', + returns: { + type: 'boolean', + root: true + }, + http: { + path: `/isRoleAdvanced`, + verb: 'GET' + } + }); + + Self.isRoleAdvanced = async(ctx, options) => { + const models = Self.app.models; + const userId = ctx.req.accessToken.userId; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', myOptions); + const isDeliveryBoss = await models.Account.hasRole(userId, 'deliveryBoss', myOptions); + const isBuyer = await models.Account.hasRole(userId, 'buyer', myOptions); + const isClaimManager = await models.Account.hasRole(userId, 'claimManager', myOptions); + + const isRoleAdvanced = isSalesAssistant || isDeliveryBoss || isBuyer || isClaimManager; + + return isRoleAdvanced; + }; +}; diff --git a/modules/ticket/back/model-config.json b/modules/ticket/back/model-config.json index 8a6ac0c004..032cc88949 100644 --- a/modules/ticket/back/model-config.json +++ b/modules/ticket/back/model-config.json @@ -29,6 +29,9 @@ "SaleChecked": { "dataSource": "vn" }, + "SaleCloned": { + "dataSource": "vn" + }, "SaleComponent": { "dataSource": "vn" }, diff --git a/modules/ticket/back/models/sale-cloned.json b/modules/ticket/back/models/sale-cloned.json new file mode 100644 index 0000000000..eb0641684e --- /dev/null +++ b/modules/ticket/back/models/sale-cloned.json @@ -0,0 +1,26 @@ +{ + "name": "SaleCloned", + "base": "VnModel", + "options": { + "mysql": { + "table": "saleCloned" + } + }, + "properties": { + "saleClonedFk": { + "id": true + } + }, + "relations": { + "saleOriginal": { + "type": "belongsTo", + "model": "Sale", + "foreignKey": "saleOriginalFk" + }, + "saleCloned": { + "type": "belongsTo", + "model": "Sale", + "foreignKey": "saleClonedFk" + } + } +} diff --git a/modules/ticket/back/models/ticket.js b/modules/ticket/back/models/ticket.js index 47d105824e..7f5984f504 100644 --- a/modules/ticket/back/models/ticket.js +++ b/modules/ticket/back/models/ticket.js @@ -28,6 +28,7 @@ module.exports = Self => { require('../methods/ticket/freightCost')(Self); require('../methods/ticket/getComponentsSum')(Self); require('../methods/ticket/refund')(Self); + require('../methods/ticket/isRoleAdvanced')(Self); Self.observe('before save', async function(ctx) { const loopBackContext = LoopBackContext.getCurrentContext(); From 5f39249edb68aa45c37ec55722c717a47ff50758 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 4 Oct 2022 15:02:00 +0200 Subject: [PATCH 04/69] fix(ticket): canEdit use aclFunc --- modules/ticket/back/methods/sale/canEdit.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/modules/ticket/back/methods/sale/canEdit.js b/modules/ticket/back/methods/sale/canEdit.js index f359b19e41..94c2fc19a9 100644 --- a/modules/ticket/back/methods/sale/canEdit.js +++ b/modules/ticket/back/methods/sale/canEdit.js @@ -14,23 +14,22 @@ module.exports = Self => { root: true }, http: { - path: `/isEditable`, + path: `/canEdit`, verb: 'get' } }); Self.canEdit = async(ctx, sales, options) => { const models = Self.app.models; - const userId = ctx.req.accessToken.userId; const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); - /* const firstSale = await models.Sale.findById(sales[0], null, myOptions); + const firstSale = await models.Sale.findById(sales[0], null, myOptions); const isTicketEditable = await models.Ticket.isEditable(ctx, firstSale.ticketFk, myOptions); if (!isTicketEditable) - throw new UserError(`The sales of this ticket can't be modified`);*/ + throw new UserError(`The sales of this ticket can't be modified`); const saleTracking = await models.SaleTracking.find({where: {saleFk: {inq: sales}}}, myOptions); const hasSaleTracking = saleTracking.length; @@ -38,15 +37,11 @@ module.exports = Self => { const saleCloned = await models.SaleCloned.find({where: {saleClonedFk: {inq: sales}}}, myOptions); const hasSaleCloned = saleCloned.length; - /* const isProductionRole = await models.Account.hasRole(userId, 'production', myOptions); - const canEdit = (isProductionRole || !hasSaleTracking);// && (isRole || !hasSaleCloned); + const canEditTracked = await models.Account.aclFunc(ctx, 'editTracked'); + const canEditCloned = await models.Account.aclFunc(ctx, 'editCloned'); - const isRole = await models.Account.hasRole(userId, 'developer', myOptions);*/ - const editTracked = await models.Account.aclFunc(ctx, 'editTracked'); - const editCloned = await models.Account.aclFunc(ctx, 'editCloned'); - console.log(editTracked); - const canEdit = (editTracked || !hasSaleTracking) && (editCloned || !hasSaleCloned); + const canEdit = (canEditTracked || !hasSaleTracking) && (canEditCloned || !hasSaleCloned); - return canEdit;// && isTicketEditable; + return canEdit; }; }; From 994cf7ccf0e3d55116188b84bbb80cdb3b5d2687 Mon Sep 17 00:00:00 2001 From: vicent Date: Tue, 4 Oct 2022 15:04:27 +0200 Subject: [PATCH 05/69] fix: '==' by '=' --- modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index dba05ed857..6279f90b6f 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -41,7 +41,6 @@ module.exports = Self => { Self.globalInvoicing = async(ctx, options) => { const args = ctx.args; - let tx; const myOptions = {}; @@ -79,7 +78,7 @@ module.exports = Self => { const minShipped = new Date(); minShipped.setFullYear(minShipped.getFullYear() - 1); - if (args.fromClientId = args.toClientId) { + if (args.fromClientId == args.toClientId) { minShipped.setFullYear(2021); minShipped.setMonth(1); minShipped.setDate(1); From 9d482f7dfdd6d7193e42f99140d757aeb5f6dcb4 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 5 Oct 2022 15:13:36 +0200 Subject: [PATCH 06/69] test(ticket): fix tests and add funcionalityAcl --- back/methods/account/aclFunc.js | 33 ---------- back/methods/account/funcionalityAcl.js | 40 +++++++++++++ back/models/funcionalityAcl.json | 24 ++++++++ .../10490-august/00-funcionalityAcl.sql | 7 +++ db/dump/fixtures.sql | 26 ++++---- modules/ticket/back/methods/sale/canEdit.js | 4 +- .../back/methods/sale/specs/canEdit.spec.js | 52 ++++++++++++++-- .../methods/sale/specs/updateConcept.spec.js | 2 +- .../methods/sale/specs/updateQuantity.spec.js | 60 ++++++++++++++++--- .../back/methods/sale/updateQuantity.js | 12 ++-- modules/ticket/back/models/ticket-methods.js | 1 + 11 files changed, 197 insertions(+), 64 deletions(-) delete mode 100644 back/methods/account/aclFunc.js create mode 100644 back/methods/account/funcionalityAcl.js create mode 100644 back/models/funcionalityAcl.json create mode 100644 db/changes/10490-august/00-funcionalityAcl.sql diff --git a/back/methods/account/aclFunc.js b/back/methods/account/aclFunc.js deleted file mode 100644 index 47dcd6f7a8..0000000000 --- a/back/methods/account/aclFunc.js +++ /dev/null @@ -1,33 +0,0 @@ -module.exports = Self => { - Self.remoteMethodCtx('aclFunc', { - description: 'Get the user information and permissions', - accepts: [ - { - arg: 'property', - type: 'String', - description: 'The user name or email', - required: true - } - ], - returns: { - type: 'Object', - root: true - }, - http: { - path: `/aclFunc`, - verb: 'GET' - } - }); - - Self.aclFunc = async function(ctx, property) { - const userId = ctx.req.accessToken.userId; - const models = Self.app.models; - - const [acl] = await Self.rawSql( - `SELECT a.principalId - FROM salix.ACL a - WHERE a.property = ?`, [property]); - - return await models.Account.hasRole(userId, acl.principalId); - }; -}; diff --git a/back/methods/account/funcionalityAcl.js b/back/methods/account/funcionalityAcl.js new file mode 100644 index 0000000000..3a5e09720d --- /dev/null +++ b/back/methods/account/funcionalityAcl.js @@ -0,0 +1,40 @@ +module.exports = Self => { + Self.remoteMethod('funcionalityAcl', { + description: 'Return if user has permissions', + accepts: [ + { + arg: 'model', + type: 'String', + description: 'The model', + required: true + }, + { + arg: 'property', + type: 'String', + description: 'The property', + required: true + } + ], + returns: { + type: 'Object', + root: true + }, + http: { + path: `/funcionalityAcl`, + verb: 'GET' + } + }); + + Self.funcionalityAcl = async function(ctx, model, property) { + const userId = ctx.req.accessToken.userId; + const models = Self.app.models; + + const [acl] = await Self.rawSql( + `SELECT f.role + FROM salix.funcionalityAcl f + WHERE f.model = ? + AND f.property = ?`, [model, property]); + + return await models.Account.hasRole(userId, acl.role); + }; +}; diff --git a/back/models/funcionalityAcl.json b/back/models/funcionalityAcl.json new file mode 100644 index 0000000000..840c4f6f3a --- /dev/null +++ b/back/models/funcionalityAcl.json @@ -0,0 +1,24 @@ +{ + "name": "FuncionalityAcl", + "base": "VnModel", + "options": { + "mysql": { + "table": "salix.funcionalityAcl" + } + }, + "properties": { + "id": { + "type": "number", + "id": true + }, + "model": { + "type": "string" + }, + "property": { + "type": "string" + }, + "role": { + "type": "string" + } + } +} diff --git a/db/changes/10490-august/00-funcionalityAcl.sql b/db/changes/10490-august/00-funcionalityAcl.sql new file mode 100644 index 0000000000..889a92c48d --- /dev/null +++ b/db/changes/10490-august/00-funcionalityAcl.sql @@ -0,0 +1,7 @@ +CREATE TABLE `funcionalityAcl` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `model` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL, + `property` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL, + `role` varchar(45) COLLATE utf8mb3_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`) + ) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index a09755479d..cde9345efa 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -14,10 +14,10 @@ INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`) ('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66); INSERT INTO `salix`.`printConfig` (`id`, `itRecipient`, `incidencesEmail`) - VALUES + VALUES (1, 'it@gotamcity.com', 'incidences@gotamcity.com'); -INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`) +INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`) VALUES ('1', '6'); @@ -1146,10 +1146,11 @@ INSERT INTO `vncontrol`.`accion`(`accion_id`, `accion`) INSERT INTO `vn`.`saleTracking`(`saleFk`, `isChecked`, `created`, `originalQuantity`, `workerFk`, `actionFk`, `id`, `stateFk`) VALUES - (1, 0, util.VN_CURDATE(), 5, 55, 3, 1, 14), - (1, 1, util.VN_CURDATE(), 5, 54, 3, 2, 8), - (2, 1, util.VN_CURDATE(), 10, 40, 4, 3, 8), - (3, 1, util.VN_CURDATE(), 2, 40, 4, 4, 8); + (1, 0, util.VN_CURDATE(), 5, 55, 3, 1, 14), + (1, 1, util.VN_CURDATE(), 5, 54, 3, 2, 8), + (2, 1, util.VN_CURDATE(), 10, 40, 4, 3, 8), + (3, 1, util.VN_CURDATE(), 2, 40, 4, 4, 8), + (31, 1, util.VN_CURDATE(), -5, 40, 4, 5, 8); INSERT INTO `vn`.`itemBarcode`(`id`, `itemFk`, `code`) VALUES @@ -2664,8 +2665,11 @@ INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `lev VALUES (9, 3, util.VN_NOW(), NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO salix.ACL -(model, property, accessType, permission, principalType, principalId) -VALUES -('Sale', 'editTracked', 'WRITE', 'ALLOW', 'ROLE', 'production'), -('Sale', 'editCloned', 'WRITE', 'ALLOW', 'ROLE', 'production'); +INSERT INTO `salix`.`funcionalityAcl` (`model`, `property`, `role`) + VALUES + ('Sale', 'editTracked', 'production'), + ('Sale', 'editCloned', 'production'); + +INSERT INTO `vn`.`saleCloned` (`saleClonedFk`, `saleOriginalFk`) + VALUES + ('26', '25'); diff --git a/modules/ticket/back/methods/sale/canEdit.js b/modules/ticket/back/methods/sale/canEdit.js index 94c2fc19a9..1b9e471ef8 100644 --- a/modules/ticket/back/methods/sale/canEdit.js +++ b/modules/ticket/back/methods/sale/canEdit.js @@ -37,8 +37,8 @@ module.exports = Self => { const saleCloned = await models.SaleCloned.find({where: {saleClonedFk: {inq: sales}}}, myOptions); const hasSaleCloned = saleCloned.length; - const canEditTracked = await models.Account.aclFunc(ctx, 'editTracked'); - const canEditCloned = await models.Account.aclFunc(ctx, 'editCloned'); + const canEditTracked = await models.Account.funcionalityAcl(ctx, 'Sale', 'editTracked'); + const canEditCloned = await models.Account.funcionalityAcl(ctx, 'Sale', 'editCloned'); const canEdit = (canEditTracked || !hasSaleTracking) && (canEditCloned || !hasSaleCloned); diff --git a/modules/ticket/back/methods/sale/specs/canEdit.spec.js b/modules/ticket/back/methods/sale/specs/canEdit.spec.js index 667ce98da3..9533d64641 100644 --- a/modules/ticket/back/methods/sale/specs/canEdit.spec.js +++ b/modules/ticket/back/methods/sale/specs/canEdit.spec.js @@ -10,7 +10,7 @@ describe('sale canEdit()', () => { const productionUserID = 49; const ctx = {req: {accessToken: {userId: productionUserID}}}; - const sales = [3]; + const sales = [25]; const result = await models.Sale.canEdit(ctx, sales, options); @@ -51,10 +51,10 @@ describe('sale canEdit()', () => { try { const options = {transaction: tx}; - const salesPersonUserID = 18; - const ctx = {req: {accessToken: {userId: salesPersonUserID}}}; + const buyerId = 35; + const ctx = {req: {accessToken: {userId: buyerId}}}; - const sales = [3]; + const sales = [31]; const result = await models.Sale.canEdit(ctx, sales, options); @@ -66,4 +66,48 @@ describe('sale canEdit()', () => { throw e; } }); + + it('should return false if any of the sales is cloned', async() => { + const tx = await models.Sale.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const buyerId = 35; + const ctx = {req: {accessToken: {userId: buyerId}}}; + + const sales = [26]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(false); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return true if any of the sales is cloned and has the correct role', async() => { + const tx = await models.Sale.beginTransaction({}); + // modify? + try { + const options = {transaction: tx}; + + const productionId = 49; + const ctx = {req: {accessToken: {userId: productionId}}}; + + const sales = [26]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); }); diff --git a/modules/ticket/back/methods/sale/specs/updateConcept.spec.js b/modules/ticket/back/methods/sale/specs/updateConcept.spec.js index 01f610d36d..0e7e9bf0fa 100644 --- a/modules/ticket/back/methods/sale/specs/updateConcept.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateConcept.spec.js @@ -2,7 +2,7 @@ const models = require('vn-loopback/server/server').models; describe('sale updateConcept()', () => { const ctx = {req: {accessToken: {userId: 9}}}; - const saleId = 1; + const saleId = 25; it('should throw if ID was undefined', async() => { const tx = await models.Sale.beginTransaction({}); diff --git a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js index 4c961faab5..bf139ab115 100644 --- a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js @@ -28,13 +28,20 @@ describe('sale updateQuantity()', () => { }); it('should throw an error if the quantity is greater than it should be', async() => { + const ctx = { + req: { + accessToken: {userId: 1}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; const tx = await models.Sale.beginTransaction({}); let error; try { const options = {transaction: tx}; - await models.Sale.updateQuantity(ctx, 1, 99, options); + await models.Sale.updateQuantity(ctx, 17, 99, options); await tx.rollback(); } catch (e) { @@ -45,21 +52,60 @@ describe('sale updateQuantity()', () => { expect(error).toEqual(new Error('The new quantity should be smaller than the old one')); }); - it('should update the quantity of a given sale current line', async() => { + it('should add quantity if the quantity is greater than it should be and is role advanced', async() => { const tx = await models.Sale.beginTransaction({}); + const saleId = 17; + const buyerId = 35; + const ctx = { + req: { + accessToken: {userId: buyerId}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; try { const options = {transaction: tx}; - const originalLine = await models.Sale.findOne({where: {id: 1}, fields: ['quantity']}, options); + const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, options); - expect(originalLine.quantity).toEqual(5); + expect(isRoleAdvanced).toEqual(true); - await models.Sale.updateQuantity(ctx, 1, 4, options); + const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options); - const modifiedLine = await models.Sale.findOne({where: {id: 1}, fields: ['quantity']}, options); + expect(originalLine.quantity).toEqual(30); - expect(modifiedLine.quantity).toEqual(4); + const newQuantity = originalLine.quantity + 1; + await models.Sale.updateQuantity(ctx, saleId, newQuantity, options); + + const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options); + + expect(modifiedLine.quantity).toEqual(newQuantity); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should update the quantity of a given sale current line', async() => { + const tx = await models.Sale.beginTransaction({}); + const saleId = 25; + const newQuantity = 4; + + try { + const options = {transaction: tx}; + + const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options); + + expect(originalLine.quantity).toEqual(20); + + await models.Sale.updateQuantity(ctx, saleId, newQuantity, options); + + const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, options); + + expect(modifiedLine.quantity).toEqual(newQuantity); await tx.rollback(); } catch (e) { diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js index 24e3736f37..f3bc0ca380 100644 --- a/modules/ticket/back/methods/sale/updateQuantity.js +++ b/modules/ticket/back/methods/sale/updateQuantity.js @@ -41,14 +41,13 @@ module.exports = Self => { } try { - const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions); - - if (!canEditSale) - throw new UserError(`Sale(s) blocked, please contact production`); - if (isNaN(newQuantity)) throw new UserError(`The value should be a number`); + const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions); + if (!canEditSale) + throw new UserError(`Sale(s) blocked, please contact production`); + const filter = { include: { relation: 'ticket', @@ -70,7 +69,8 @@ module.exports = Self => { const sale = await models.Sale.findById(id, filter, myOptions); - if (newQuantity > sale.quantity) + const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, myOptions); + if (newQuantity > sale.quantity && !isRoleAdvanced) throw new UserError('The new quantity should be smaller than the old one'); const oldQuantity = sale.quantity; diff --git a/modules/ticket/back/models/ticket-methods.js b/modules/ticket/back/models/ticket-methods.js index 9255e52e62..8ab1845d96 100644 --- a/modules/ticket/back/models/ticket-methods.js +++ b/modules/ticket/back/models/ticket-methods.js @@ -33,4 +33,5 @@ module.exports = function(Self) { require('../methods/ticket/closeByTicket')(Self); require('../methods/ticket/closeByAgency')(Self); require('../methods/ticket/closeByRoute')(Self); + require('../methods/ticket/isRoleAdvanced')(Self); }; From c29625f079c50a56a30308d9d8cdd45157209401 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 6 Oct 2022 15:04:27 +0200 Subject: [PATCH 07/69] fix: funcionalityAcl --- back/methods/account/funcionalityAcl.js | 20 +++++++++++++------ back/model-config.json | 3 +++ back/models/account.js | 2 +- .../10490-august/00-funcionalityAcl.sql | 10 ++++++++-- db/dump/fixtures.sql | 5 ----- .../back/methods/sale/specs/canEdit.spec.js | 2 +- 6 files changed, 27 insertions(+), 15 deletions(-) diff --git a/back/methods/account/funcionalityAcl.js b/back/methods/account/funcionalityAcl.js index 3a5e09720d..ae73dee0b8 100644 --- a/back/methods/account/funcionalityAcl.js +++ b/back/methods/account/funcionalityAcl.js @@ -29,12 +29,20 @@ module.exports = Self => { const userId = ctx.req.accessToken.userId; const models = Self.app.models; - const [acl] = await Self.rawSql( - `SELECT f.role - FROM salix.funcionalityAcl f - WHERE f.model = ? - AND f.property = ?`, [model, property]); + const acls = await models.FuncionalityAcl.find({ + where: { + model: model, + property: property + } + }); - return await models.Account.hasRole(userId, acl.role); + const hasPermissions = acls.filter(async acl => { + console.log('FILTER: '); + acl.role && await models.Account.hasRole(userId, acl.role); + }); + console.log(hasPermissions); + if (hasPermissions) + return true; + return false; }; }; diff --git a/back/model-config.json b/back/model-config.json index 830a78fd42..c351969552 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -53,6 +53,9 @@ "EmailUser": { "dataSource": "vn" }, + "FuncionalityAcl": { + "dataSource": "vn" + }, "Image": { "dataSource": "vn" }, diff --git a/back/models/account.js b/back/models/account.js index 5b101eef76..368f154bce 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -7,7 +7,7 @@ module.exports = Self => { require('../methods/account/change-password')(Self); require('../methods/account/set-password')(Self); require('../methods/account/validate-token')(Self); - require('../methods/account/aclFunc')(Self); + require('../methods/account/funcionalityAcl')(Self); // Validations diff --git a/db/changes/10490-august/00-funcionalityAcl.sql b/db/changes/10490-august/00-funcionalityAcl.sql index 889a92c48d..b525803279 100644 --- a/db/changes/10490-august/00-funcionalityAcl.sql +++ b/db/changes/10490-august/00-funcionalityAcl.sql @@ -1,7 +1,13 @@ -CREATE TABLE `funcionalityAcl` ( +CREATE TABLE `salix`.`funcionalityAcl` ( `id` int(11) NOT NULL AUTO_INCREMENT, `model` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL, `property` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL, `role` varchar(45) COLLATE utf8mb3_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`) - ) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci +) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; + + +INSERT INTO `salix`.`funcionalityAcl` (`model`, `property`, `role`) + VALUES + ('Sale', 'editTracked', 'production'), + ('Sale', 'editCloned', NULL); diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index cde9345efa..fb31c08a56 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2665,11 +2665,6 @@ INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `lev VALUES (9, 3, util.VN_NOW(), NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `salix`.`funcionalityAcl` (`model`, `property`, `role`) - VALUES - ('Sale', 'editTracked', 'production'), - ('Sale', 'editCloned', 'production'); - INSERT INTO `vn`.`saleCloned` (`saleClonedFk`, `saleOriginalFk`) VALUES ('26', '25'); diff --git a/modules/ticket/back/methods/sale/specs/canEdit.spec.js b/modules/ticket/back/methods/sale/specs/canEdit.spec.js index 9533d64641..1fe63f33c8 100644 --- a/modules/ticket/back/methods/sale/specs/canEdit.spec.js +++ b/modules/ticket/back/methods/sale/specs/canEdit.spec.js @@ -91,7 +91,7 @@ describe('sale canEdit()', () => { it('should return true if any of the sales is cloned and has the correct role', async() => { const tx = await models.Sale.beginTransaction({}); - // modify? + try { const options = {transaction: tx}; From d5592d6a0f4a22f4cc3dfa1ad36712d63810ff55 Mon Sep 17 00:00:00 2001 From: jgallego Date: Thu, 6 Oct 2022 15:19:55 +0200 Subject: [PATCH 08/69] sin toClientId --- .../methods/invoiceOut/globalInvoicing.js | 24 ++++++++++--------- .../front/index/global-invoicing/index.js | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index 4a20b81a20..71a10b1b87 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -21,7 +21,8 @@ module.exports = Self => { { arg: 'toClientId', type: 'number', - description: 'The maximum client id' + description: 'The maximum client id', + required: false }, { arg: 'companyFk', @@ -77,13 +78,10 @@ module.exports = Self => { const minShipped = new Date(); minShipped.setFullYear(minShipped.getFullYear() - 1); - - if (args.fromClientId == args.toClientId) { - minShipped.setFullYear(2021); - minShipped.setMonth(1); - minShipped.setDate(1); - minShipped.setHours(0, 0, 0, 0); - } + minShipped.setMonth(1); + minShipped.setDate(1); + minShipped.setHours(0, 0, 0, 0); + // Packaging liquidation const vIsAllInvoiceable = false; @@ -200,11 +198,13 @@ module.exports = Self => { JOIN ticketPackaging tp ON t.id = tp.ticketFk JOIN client c ON c.id = t.clientFk WHERE t.shipped BETWEEN '2017-11-21' AND ? - AND t.clientFk BETWEEN ? AND ? + AND t.clientFk >= ? + AND (t.clientFk <= ? OR ? IS NULL) AND c.isActive`; return models.InvoiceOut.rawSql(query, [ args.maxShipped, args.fromClientId, + args.toClientId, args.toClientId ], options); } @@ -233,15 +233,17 @@ module.exports = Self => { LEFT JOIN ticketService ts ON ts.ticketFk = t.id JOIN address a ON a.id = t.addressFk JOIN client c ON c.id = t.clientFk - WHERE ISNULL(t.refFk) AND c.id BETWEEN ? AND ? + WHERE ISNULL(t.refFk) AND c.id >= ? + AND (t.clientFk <= ? OR ? IS NULL) AND t.shipped BETWEEN ? AND util.dayEnd(?) AND t.companyFk = ? AND c.hasToInvoice - AND c.isTaxDataChecked + AND c.isTaxDataChecked AND c.isActive GROUP BY c.id, IF(c.hasToInvoiceByAddress,a.id,TRUE) HAVING sumAmount > 0`; return models.InvoiceOut.rawSql(query, [ args.fromClientId, args.toClientId, + args.toClientId, minShipped, args.maxShipped, args.companyFk diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index 5e522f23d4..1b1ae5ec9d 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -54,7 +54,7 @@ class Controller extends Dialog { if (!this.invoice.invoiceDate || !this.invoice.maxShipped) throw new Error('Invoice date and the max date should be filled'); - if (!this.invoice.fromClientId || !this.invoice.toClientId) + if (!this.invoice.fromClientId) throw new Error('Choose a valid clients range'); this.isInvoicing = true; From 3da948f3f9f1873c54f940e9960cf1b1b0f3cf04 Mon Sep 17 00:00:00 2001 From: vicent Date: Fri, 7 Oct 2022 09:17:14 +0200 Subject: [PATCH 09/69] refactor: delete unnecessary lines --- modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index 71a10b1b87..dae6a0c330 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -81,7 +81,6 @@ module.exports = Self => { minShipped.setMonth(1); minShipped.setDate(1); minShipped.setHours(0, 0, 0, 0); - // Packaging liquidation const vIsAllInvoiceable = false; From 8130cf9e6a7d2583f10af4ed46c5d1cf733e0fac Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 10 Oct 2022 12:40:10 +0200 Subject: [PATCH 10/69] feat: separate globalInvoicing in 2 parts --- db/changes/10491-august/00-aclInvoiceOut.sql | 3 + .../methods/invoiceOut/clientToInvoice.js | 173 ++++++++++++ .../methods/invoiceOut/globalInvoicing.js | 253 +++++------------- modules/invoiceOut/back/models/invoice-out.js | 1 + .../front/index/global-invoicing/index.html | 2 + .../front/index/global-invoicing/index.js | 14 +- 6 files changed, 255 insertions(+), 191 deletions(-) create mode 100644 db/changes/10491-august/00-aclInvoiceOut.sql create mode 100644 modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js diff --git a/db/changes/10491-august/00-aclInvoiceOut.sql b/db/changes/10491-august/00-aclInvoiceOut.sql new file mode 100644 index 0000000000..b129b72018 --- /dev/null +++ b/db/changes/10491-august/00-aclInvoiceOut.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('InvoiceOut', 'clientToInvoice', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'); \ No newline at end of file diff --git a/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js new file mode 100644 index 0000000000..16c999e73a --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js @@ -0,0 +1,173 @@ +module.exports = Self => { + Self.remoteMethodCtx('clientToInvoice', { + description: 'Get the clients to make global invoicing', + accessType: 'WRITE', + accepts: [ + { + arg: 'invoiceDate', + type: 'date', + description: 'The invoice date' + }, + { + arg: 'maxShipped', + type: 'date', + description: 'The maximum shipped date' + }, + { + arg: 'fromClientId', + type: 'number', + description: 'The minimum client id' + }, + { + arg: 'toClientId', + type: 'number', + description: 'The maximum client id', + required: false + }, + { + arg: 'companyFk', + type: 'number', + description: 'The company id to invoice' + } + ], + returns: { + type: 'object', + root: true + }, + http: { + path: '/clientToInvoice', + verb: 'POST' + } + }); + + Self.clientToInvoice = async(ctx, options) => { + const args = ctx.args; + let tx; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + const clientToInvoideIds = []; + let query; + try { + query = ` + SELECT MAX(issued) issued + FROM vn.invoiceOut io + JOIN vn.time t ON t.dated = io.issued + WHERE io.serial = 'A' + AND t.year = YEAR(?) + AND io.companyFk = ?`; + const [maxIssued] = await Self.rawSql(query, [ + args.invoiceDate, + args.companyFk + ], myOptions); + + const maxSerialDate = maxIssued.issued || args.invoiceDate; + if (args.invoiceDate < maxSerialDate) + args.invoiceDate = maxSerialDate; + + if (args.invoiceDate < args.maxShipped) + args.maxShipped = args.invoiceDate; + + const minShipped = new Date(); + minShipped.setFullYear(minShipped.getFullYear() - 1); + minShipped.setMonth(1); + minShipped.setDate(1); + minShipped.setHours(0, 0, 0, 0); + + // Packaging liquidation + const vIsAllInvoiceable = false; + const clientsWithPackaging = await getClientsWithPackaging(ctx, myOptions); + for (let client of clientsWithPackaging) { + await Self.rawSql('CALL packageInvoicing(?, ?, ?, ?, @newTicket)', [ + client.id, + args.invoiceDate, + args.companyFk, + vIsAllInvoiceable + ], myOptions); + } + + const invoiceableClients = await getInvoiceableClients(ctx, myOptions); + + if (!invoiceableClients.length) return; + + const clientToInvoiceIds = invoiceableClients.map(invoiceableClient => invoiceableClient.id); + const dataArr = new Set(clientToInvoiceIds); + const clientNotRepeatedIds = [...dataArr]; + + if (tx) await tx.commit(); + + console.log(invoiceableClients, clientToInvoiceIds, clientNotRepeatedIds); + return clientNotRepeatedIds; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; + + async function getClientsWithPackaging(ctx, options) { + const models = Self.app.models; + const args = ctx.args; + const query = `SELECT DISTINCT clientFk AS id + FROM ticket t + JOIN ticketPackaging tp ON t.id = tp.ticketFk + JOIN client c ON c.id = t.clientFk + WHERE t.shipped BETWEEN '2017-11-21' AND ? + AND t.clientFk >= ? + AND (t.clientFk <= ? OR ? IS NULL) + AND c.isActive`; + return models.InvoiceOut.rawSql(query, [ + args.maxShipped, + args.fromClientId, + args.toClientId, + args.toClientId + ], options); + } + + async function getInvoiceableClients(ctx, options) { + const models = Self.app.models; + const args = ctx.args; + const minShipped = new Date(); + minShipped.setFullYear(minShipped.getFullYear() - 1); + + const query = `SELECT + c.id, + SUM(IFNULL + ( + s.quantity * + s.price * (100-s.discount)/100, + 0) + + IFNULL(ts.quantity * ts.price,0) + ) AS sumAmount, + c.hasToInvoiceByAddress, + c.email, + c.isToBeMailed, + a.id addressFk + FROM ticket t + LEFT JOIN sale s ON s.ticketFk = t.id + LEFT JOIN ticketService ts ON ts.ticketFk = t.id + JOIN address a ON a.id = t.addressFk + JOIN client c ON c.id = t.clientFk + WHERE ISNULL(t.refFk) AND c.id >= ? + AND (t.clientFk <= ? OR ? IS NULL) + AND t.shipped BETWEEN ? AND util.dayEnd(?) + AND t.companyFk = ? AND c.hasToInvoice + AND c.isTaxDataChecked AND c.isActive + GROUP BY c.id, IF(c.hasToInvoiceByAddress,a.id,TRUE) HAVING sumAmount > 0`; + + return models.InvoiceOut.rawSql(query, [ + args.fromClientId, + args.toClientId, + args.toClientId, + minShipped, + args.maxShipped, + args.companyFk + ], options); + } +}; diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index dae6a0c330..bee79746a3 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -1,35 +1,13 @@ module.exports = Self => { Self.remoteMethodCtx('globalInvoicing', { - description: 'Make a global invoice', + description: 'Make a global invoice of a client', accessType: 'WRITE', - accepts: [ - { - arg: 'invoiceDate', - type: 'date', - description: 'The invoice date' - }, - { - arg: 'maxShipped', - type: 'date', - description: 'The maximum shipped date' - }, - { - arg: 'fromClientId', - type: 'number', - description: 'The minimum client id' - }, - { - arg: 'toClientId', - type: 'number', - description: 'The maximum client id', - required: false - }, - { - arg: 'companyFk', - type: 'number', - description: 'The company id to invoice' - } - ], + accepts: [{ + arg: 'clientId', + type: 'number', + description: 'The client id to invoice', + required: true + }], returns: { type: 'object', root: true @@ -40,10 +18,10 @@ module.exports = Self => { } }); - Self.globalInvoicing = async(ctx, options) => { - const args = ctx.args; - let tx; + Self.globalInvoicing = async(ctx, clientId, options) => { + const models = Self.app.models; const myOptions = {}; + let tx; if (typeof options == 'object') Object.assign(myOptions, options); @@ -55,108 +33,65 @@ module.exports = Self => { const invoicesIds = []; const failedClients = []; - let query; try { - query = ` - SELECT MAX(issued) issued - FROM vn.invoiceOut io - JOIN vn.time t ON t.dated = io.issued - WHERE io.serial = 'A' - AND t.year = YEAR(?) - AND io.companyFk = ?`; - const [maxIssued] = await Self.rawSql(query, [ - args.invoiceDate, - args.companyFk - ], myOptions); - - const maxSerialDate = maxIssued.issued || args.invoiceDate; - if (args.invoiceDate < maxSerialDate) - args.invoiceDate = maxSerialDate; - - if (args.invoiceDate < args.maxShipped) - args.maxShipped = args.invoiceDate; - - const minShipped = new Date(); - minShipped.setFullYear(minShipped.getFullYear() - 1); - minShipped.setMonth(1); - minShipped.setDate(1); - minShipped.setHours(0, 0, 0, 0); - - // Packaging liquidation - const vIsAllInvoiceable = false; - const clientsWithPackaging = await getClientsWithPackaging(ctx, myOptions); - for (let client of clientsWithPackaging) { - await Self.rawSql('CALL packageInvoicing(?, ?, ?, ?, @newTicket)', [ - client.id, - args.invoiceDate, - args.companyFk, - vIsAllInvoiceable - ], myOptions); - } - - const invoiceableClients = await getInvoiceableClients(ctx, myOptions); - - if (!invoiceableClients.length) return; - - for (let client of invoiceableClients) { - try { - if (client.hasToInvoiceByAddress) { - await Self.rawSql('CALL ticketToInvoiceByAddress(?, ?, ?, ?)', [ - minShipped, - args.maxShipped, - client.addressFk, - args.companyFk - ], myOptions); - } else { - await Self.rawSql('CALL invoiceFromClient(?, ?, ?)', [ - args.maxShipped, - client.id, - args.companyFk - ], myOptions); - } - - // Make invoice - const isSpanishCompany = await getIsSpanishCompany(args.companyFk, myOptions); - - // Validates ticket nagative base - const hasAnyNegativeBase = await getNegativeBase(myOptions); - if (hasAnyNegativeBase && isSpanishCompany) - continue; - - query = `SELECT invoiceSerial(?, ?, ?) AS serial`; - const [invoiceSerial] = await Self.rawSql(query, [ + const client = await models.Client.findById(clientId, { + fields: ['id', 'hasToInvoiceByAddress', 'addressFk'] + }, myOptions); + try { + if (client.hasToInvoiceByAddress) { + await Self.rawSql('CALL ticketToInvoiceByAddress(?, ?, ?, ?)', [ + minShipped, + args.maxShipped, + client.addressFk, + args.companyFk + ], myOptions); + } else { + await Self.rawSql('CALL invoiceFromClient(?, ?, ?)', [ + args.maxShipped, client.id, - args.companyFk, - 'G' + args.companyFk ], myOptions); - const serialLetter = invoiceSerial.serial; - - query = `CALL invoiceOut_new(?, ?, NULL, @invoiceId)`; - await Self.rawSql(query, [ - serialLetter, - args.invoiceDate - ], myOptions); - - const [newInvoice] = await Self.rawSql(`SELECT @invoiceId id`, null, myOptions); - if (newInvoice.id) { - await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); - - query = `INSERT IGNORE INTO invoiceOutQueue(invoiceFk) VALUES(?)`; - await Self.rawSql(query, [newInvoice.id], myOptions); - - invoicesIds.push(newInvoice.id); - } - } catch (e) { - failedClients.push({ - id: client.id, - stacktrace: e - }); - continue; } - } - if (failedClients.length > 0) - await notifyFailures(ctx, failedClients, myOptions); + // Make invoice + const isSpanishCompany = await getIsSpanishCompany(args.companyFk, myOptions); + + // Validates ticket nagative base + const hasAnyNegativeBase = await getNegativeBase(myOptions); + if (hasAnyNegativeBase && isSpanishCompany) + return notifyFailures(ctx, failedClients, myOptions); // continue + + query = `SELECT invoiceSerial(?, ?, ?) AS serial`; + const [invoiceSerial] = await Self.rawSql(query, [ + client.id, + args.companyFk, + 'G' + ], myOptions); + const serialLetter = invoiceSerial.serial; + + query = `CALL invoiceOut_new(?, ?, NULL, @invoiceId)`; + await Self.rawSql(query, [ + serialLetter, + args.invoiceDate + ], myOptions); + + const [newInvoice] = await Self.rawSql(`SELECT @invoiceId id`, null, myOptions); + if (newInvoice.id) { + await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); + + query = `INSERT IGNORE INTO invoiceOutQueue(invoiceFk) VALUES(?)`; + await Self.rawSql(query, [newInvoice.id], myOptions); + + invoicesIds.push(newInvoice.id); + } + } catch (e) { + failedClients.push({ + id: client.id, + stacktrace: e + }); + return notifyFailures(ctx, failedClients, myOptions); // continue + } + // } if (tx) await tx.commit(); } catch (e) { @@ -189,66 +124,6 @@ module.exports = Self => { return supplierCompany && supplierCompany.total; } - async function getClientsWithPackaging(ctx, options) { - const models = Self.app.models; - const args = ctx.args; - const query = `SELECT DISTINCT clientFk AS id - FROM ticket t - JOIN ticketPackaging tp ON t.id = tp.ticketFk - JOIN client c ON c.id = t.clientFk - WHERE t.shipped BETWEEN '2017-11-21' AND ? - AND t.clientFk >= ? - AND (t.clientFk <= ? OR ? IS NULL) - AND c.isActive`; - return models.InvoiceOut.rawSql(query, [ - args.maxShipped, - args.fromClientId, - args.toClientId, - args.toClientId - ], options); - } - - async function getInvoiceableClients(ctx, options) { - const models = Self.app.models; - const args = ctx.args; - const minShipped = new Date(); - minShipped.setFullYear(minShipped.getFullYear() - 1); - - const query = `SELECT - c.id, - SUM(IFNULL - ( - s.quantity * - s.price * (100-s.discount)/100, - 0) - + IFNULL(ts.quantity * ts.price,0) - ) AS sumAmount, - c.hasToInvoiceByAddress, - c.email, - c.isToBeMailed, - a.id addressFk - FROM ticket t - LEFT JOIN sale s ON s.ticketFk = t.id - LEFT JOIN ticketService ts ON ts.ticketFk = t.id - JOIN address a ON a.id = t.addressFk - JOIN client c ON c.id = t.clientFk - WHERE ISNULL(t.refFk) AND c.id >= ? - AND (t.clientFk <= ? OR ? IS NULL) - AND t.shipped BETWEEN ? AND util.dayEnd(?) - AND t.companyFk = ? AND c.hasToInvoice - AND c.isTaxDataChecked AND c.isActive - GROUP BY c.id, IF(c.hasToInvoiceByAddress,a.id,TRUE) HAVING sumAmount > 0`; - - return models.InvoiceOut.rawSql(query, [ - args.fromClientId, - args.toClientId, - args.toClientId, - minShipped, - args.maxShipped, - args.companyFk - ], options); - } - async function notifyFailures(ctx, failedClients, options) { const models = Self.app.models; const userId = ctx.req.accessToken.userId; diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index 5af64de2b1..7ac1246cfc 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -7,6 +7,7 @@ module.exports = Self => { require('../methods/invoiceOut/book')(Self); require('../methods/invoiceOut/createPdf')(Self); require('../methods/invoiceOut/createManualInvoice')(Self); + require('../methods/invoiceOut/clientToInvoice')(Self); require('../methods/invoiceOut/globalInvoicing')(Self); require('../methods/invoiceOut/refund')(Self); require('../methods/invoiceOut/invoiceEmail')(Self); diff --git a/modules/invoiceOut/front/index/global-invoicing/index.html b/modules/invoiceOut/front/index/global-invoicing/index.html index 3d245b8d8e..dbb780b7ca 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.html +++ b/modules/invoiceOut/front/index/global-invoicing/index.html @@ -20,6 +20,8 @@ Adding invoices to queue... + {{$ctrl.lastClientId}} + {{::$ctrl.lastClientId || 'Vacío'}} diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index 1b1ae5ec9d..66c2e698a2 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -58,8 +58,18 @@ class Controller extends Dialog { throw new Error('Choose a valid clients range'); this.isInvoicing = true; - return this.$http.post(`InvoiceOuts/globalInvoicing`, this.invoice) - .then(() => super.responseHandler(response)) + return this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) + .then(res => { + this.lastClientId = res.data[res.data.length - 1]; + console.log(this.lastClientId); + }) + // .then(() => { + // for (let clientId of res.data) { + // const params = {clientId: clientId}; + // this.$http.post(`InvoiceOuts/globalInvoicing`, params); + // } + // }) + // .then(() => super.responseHandler(response)) .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) .finally(() => this.isInvoicing = false); } catch (e) { From 376d46b67ec22278a303894449537ce81cac9182 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 10 Oct 2022 13:06:49 +0200 Subject: [PATCH 11/69] feat(canEdit): integrate isWeekly and adapt back tests and e2e --- ...ncionalityAcl.js => hasFuncionalityAcl.js} | 15 ++-- back/models/account.js | 2 +- .../00-funcionalityAcl.sql | 8 +- db/changes/10491-august/delete.keep | 0 db/dump/fixtures.sql | 5 +- db/export-data.sh | 1 + e2e/paths/05-ticket/09_weekly.spec.js | 4 +- loopback/locale/en.json | 3 +- modules/ticket/back/methods/sale/canEdit.js | 14 +++- .../back/methods/sale/specs/canEdit.spec.js | 74 ++++++++++++++++++- .../ticket-weekly/specs/filter.spec.js | 2 +- 11 files changed, 103 insertions(+), 25 deletions(-) rename back/methods/account/{funcionalityAcl.js => hasFuncionalityAcl.js} (71%) rename db/changes/{10490-august => 10491-august}/00-funcionalityAcl.sql (60%) delete mode 100644 db/changes/10491-august/delete.keep diff --git a/back/methods/account/funcionalityAcl.js b/back/methods/account/hasFuncionalityAcl.js similarity index 71% rename from back/methods/account/funcionalityAcl.js rename to back/methods/account/hasFuncionalityAcl.js index ae73dee0b8..d6224fffcb 100644 --- a/back/methods/account/funcionalityAcl.js +++ b/back/methods/account/hasFuncionalityAcl.js @@ -1,5 +1,5 @@ module.exports = Self => { - Self.remoteMethod('funcionalityAcl', { + Self.remoteMethod('hasFuncionalityAcl', { description: 'Return if user has permissions', accepts: [ { @@ -20,12 +20,12 @@ module.exports = Self => { root: true }, http: { - path: `/funcionalityAcl`, + path: `/hasFuncionalityAcl`, verb: 'GET' } }); - Self.funcionalityAcl = async function(ctx, model, property) { + Self.hasFuncionalityAcl = async function(ctx, model, property) { const userId = ctx.req.accessToken.userId; const models = Self.app.models; @@ -36,11 +36,10 @@ module.exports = Self => { } }); - const hasPermissions = acls.filter(async acl => { - console.log('FILTER: '); - acl.role && await models.Account.hasRole(userId, acl.role); - }); - console.log(hasPermissions); + let hasPermissions; + for (let acl of acls) + if (!hasPermissions) hasPermissions = await models.Account.hasRole(userId, acl.role); + if (hasPermissions) return true; return false; diff --git a/back/models/account.js b/back/models/account.js index f824ed8986..7d7fa9fe38 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -7,7 +7,7 @@ module.exports = Self => { require('../methods/account/change-password')(Self); require('../methods/account/set-password')(Self); require('../methods/account/validate-token')(Self); - require('../methods/account/funcionalityAcl')(Self); + require('../methods/account/hasFuncionalityAcl')(Self); require('../methods/account/privileges')(Self); // Validations diff --git a/db/changes/10490-august/00-funcionalityAcl.sql b/db/changes/10491-august/00-funcionalityAcl.sql similarity index 60% rename from db/changes/10490-august/00-funcionalityAcl.sql rename to db/changes/10491-august/00-funcionalityAcl.sql index b525803279..02f3dbcc43 100644 --- a/db/changes/10490-august/00-funcionalityAcl.sql +++ b/db/changes/10491-august/00-funcionalityAcl.sql @@ -3,11 +3,13 @@ CREATE TABLE `salix`.`funcionalityAcl` ( `model` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL, `property` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL, `role` varchar(45) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; + PRIMARY KEY (`id`), + CONSTRAINT `role_FK` FOREIGN KEY (`role`) REFERENCES `account`.`role` (`name`) ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; INSERT INTO `salix`.`funcionalityAcl` (`model`, `property`, `role`) VALUES ('Sale', 'editTracked', 'production'), - ('Sale', 'editCloned', NULL); + ('Sale', 'editCloned', 66); + ('Sale', 'editWeekly', 66); diff --git a/db/changes/10491-august/delete.keep b/db/changes/10491-august/delete.keep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 4bd4dd96b0..fa76f6f842 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1357,7 +1357,8 @@ INSERT INTO `vn`.`ticketWeekly`(`ticketFk`, `weekDay`) (2, 1), (3, 2), (4, 4), - (5, 6); + (5, 6), + (14, 6); INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyModeFk`, `m3`, `kg`,`ref`, `totalEntries`, `cargoSupplierFk`) VALUES @@ -2667,7 +2668,7 @@ INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `lev INSERT INTO `vn`.`saleCloned` (`saleClonedFk`, `saleOriginalFk`) VALUES - ('26', '25'); + ('27', '25'); UPDATE `account`.`user` SET `hasGrant` = 1 diff --git a/db/export-data.sh b/db/export-data.sh index bbbeb7152b..7252267ba8 100755 --- a/db/export-data.sh +++ b/db/export-data.sh @@ -34,6 +34,7 @@ TABLES=( salix ACL fieldAcl + funcionalityAcl module defaultViewConfig ) diff --git a/e2e/paths/05-ticket/09_weekly.spec.js b/e2e/paths/05-ticket/09_weekly.spec.js index d04138ee5f..0ba57aa9dc 100644 --- a/e2e/paths/05-ticket/09_weekly.spec.js +++ b/e2e/paths/05-ticket/09_weekly.spec.js @@ -19,7 +19,7 @@ describe('Ticket descriptor path', () => { it('should count the amount of tickets in the turns section', async() => { const result = await page.countElement(selectors.ticketsIndex.weeklyTicket); - expect(result).toEqual(5); + expect(result).toEqual(6); }); it('should go back to the ticket index then search and access a ticket summary', async() => { @@ -104,7 +104,7 @@ describe('Ticket descriptor path', () => { await page.doSearch(); const nResults = await page.countElement(selectors.ticketsIndex.searchWeeklyResult); - expect(nResults).toEqual(5); + expect(nResults).toEqual(6); }); it('should update the agency then remove it afterwards', async() => { diff --git a/loopback/locale/en.json b/loopback/locale/en.json index e5a0fae322..6d2faf6044 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -133,5 +133,6 @@ "Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h.", "Password does not meet requirements": "Password does not meet requirements", "You don't have privileges to change the zone": "You don't have privileges to change the zone or for these parameters there are more than one shipping options, talk to agencies", - "Not enough privileges to edit a client": "Not enough privileges to edit a client" + "Not enough privileges to edit a client": "Not enough privileges to edit a client", + "Sale(s) blocked, please contact production": "Sale(s) blocked, please contact production" } \ No newline at end of file diff --git a/modules/ticket/back/methods/sale/canEdit.js b/modules/ticket/back/methods/sale/canEdit.js index 1b9e471ef8..c0cd4b7019 100644 --- a/modules/ticket/back/methods/sale/canEdit.js +++ b/modules/ticket/back/methods/sale/canEdit.js @@ -37,10 +37,18 @@ module.exports = Self => { const saleCloned = await models.SaleCloned.find({where: {saleClonedFk: {inq: sales}}}, myOptions); const hasSaleCloned = saleCloned.length; - const canEditTracked = await models.Account.funcionalityAcl(ctx, 'Sale', 'editTracked'); - const canEditCloned = await models.Account.funcionalityAcl(ctx, 'Sale', 'editCloned'); + const isTicketWeekly = + await models.TicketWeekly.findOne({where: {ticketFk: firstSale.ticketFk}}, myOptions); - const canEdit = (canEditTracked || !hasSaleTracking) && (canEditCloned || !hasSaleCloned); + const canEditTracked = await models.Account.hasFuncionalityAcl(ctx, 'Sale', 'editTracked'); + const canEditCloned = await models.Account.hasFuncionalityAcl(ctx, 'Sale', 'editCloned'); + const canEditWeekly = await models.Account.hasFuncionalityAcl(ctx, 'Ticket', 'editWeekly'); + + const shouldEditTracked = canEditTracked || !hasSaleTracking; + const shouldEditCloned = canEditCloned || !hasSaleCloned; + const shouldEditWeekly = canEditWeekly || !isTicketWeekly; + + const canEdit = shouldEditTracked && shouldEditCloned && shouldEditWeekly; return canEdit; }; diff --git a/modules/ticket/back/methods/sale/specs/canEdit.spec.js b/modules/ticket/back/methods/sale/specs/canEdit.spec.js index 1fe63f33c8..7d89471f63 100644 --- a/modules/ticket/back/methods/sale/specs/canEdit.spec.js +++ b/modules/ticket/back/methods/sale/specs/canEdit.spec.js @@ -76,7 +76,7 @@ describe('sale canEdit()', () => { const buyerId = 35; const ctx = {req: {accessToken: {userId: buyerId}}}; - const sales = [26]; + const sales = [27]; const result = await models.Sale.canEdit(ctx, sales, options); @@ -91,14 +91,80 @@ describe('sale canEdit()', () => { it('should return true if any of the sales is cloned and has the correct role', async() => { const tx = await models.Sale.beginTransaction({}); + const roleEnabled = await models.FuncionalityAcl.findOne({ + where: { + model: 'Sale', + property: 'editCloned' + } + }); + if (!roleEnabled || !roleEnabled.role) return; try { const options = {transaction: tx}; - const productionId = 49; - const ctx = {req: {accessToken: {userId: productionId}}}; + const roleId = await models.Role.findOne({ + where: { + name: roleEnabled.role + } + }); + const ctx = {req: {accessToken: {userId: roleId}}}; - const sales = [26]; + const sales = [27]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return false if any of the sales is of ticket weekly', async() => { + const tx = await models.Sale.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const employeeId = 1; + const ctx = {req: {accessToken: {userId: employeeId}}}; + + const sales = [33]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(false); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return true if any of the sales is of ticketWeekly and has the correct role', async() => { + const tx = await models.Sale.beginTransaction({}); + const roleEnabled = await models.FuncionalityAcl.findOne({ + where: { + model: 'Sale', + property: 'editWeekly' + } + }); + if (!roleEnabled || !roleEnabled.role) return; + + try { + const options = {transaction: tx}; + + const roleId = await models.Role.findOne({ + where: { + name: roleEnabled.role + } + }); + const ctx = {req: {accessToken: {userId: roleId}}}; + + const sales = [33]; const result = await models.Sale.canEdit(ctx, sales, options); diff --git a/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js b/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js index 411bbe014d..2587b66576 100644 --- a/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js +++ b/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js @@ -17,7 +17,7 @@ describe('ticket-weekly filter()', () => { const firstRow = result[0]; expect(firstRow.ticketFk).toEqual(1); - expect(result.length).toEqual(5); + expect(result.length).toEqual(6); await tx.rollback(); } catch (e) { From 99271f275f7b25c823b8bacd2cfc5689357b5862 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 10 Oct 2022 13:26:38 +0200 Subject: [PATCH 12/69] remove unnecessary isEditable --- modules/ticket/back/methods/sale/deleteSales.js | 10 +++------- modules/ticket/back/methods/sale/recalculatePrice.js | 4 ---- modules/ticket/back/methods/sale/reserve.js | 6 +----- modules/ticket/back/methods/sale/updatePrice.js | 5 ----- 4 files changed, 4 insertions(+), 21 deletions(-) diff --git a/modules/ticket/back/methods/sale/deleteSales.js b/modules/ticket/back/methods/sale/deleteSales.js index 7036821e9c..c045b91971 100644 --- a/modules/ticket/back/methods/sale/deleteSales.js +++ b/modules/ticket/back/methods/sale/deleteSales.js @@ -42,7 +42,10 @@ module.exports = Self => { try { const saleIds = sales.map(sale => sale.id); + const canEditSales = await models.Sale.canEdit(ctx, saleIds, myOptions); + if (!canEditSales) + throw new UserError(`Sale(s) blocked, please contact production`); const ticket = await models.Ticket.findById(ticketId, { include: { @@ -58,13 +61,6 @@ module.exports = Self => { } }, myOptions); - const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions); - if (!isTicketEditable) - throw new UserError(`The sales of this ticket can't be modified`); - - if (!canEditSales) - throw new UserError(`Sale(s) blocked, please contact production`); - const promises = []; let deletions = ''; for (let sale of sales) { diff --git a/modules/ticket/back/methods/sale/recalculatePrice.js b/modules/ticket/back/methods/sale/recalculatePrice.js index cbe59cad2d..38c68d7f62 100644 --- a/modules/ticket/back/methods/sale/recalculatePrice.js +++ b/modules/ticket/back/methods/sale/recalculatePrice.js @@ -37,10 +37,6 @@ module.exports = Self => { try { const salesIds = sales.map(sale => sale.id); - const isEditable = await models.Ticket.isEditable(ctx, sales[0].ticketFk, myOptions); - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); - const canEditSale = await models.Sale.canEdit(ctx, salesIds, myOptions); if (!canEditSale) throw new UserError(`Sale(s) blocked, please contact production`); diff --git a/modules/ticket/back/methods/sale/reserve.js b/modules/ticket/back/methods/sale/reserve.js index c3e9ac30f2..648e6de237 100644 --- a/modules/ticket/back/methods/sale/reserve.js +++ b/modules/ticket/back/methods/sale/reserve.js @@ -49,13 +49,9 @@ module.exports = Self => { } try { - const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions); - if (!isTicketEditable) - throw new UserError(`The sales of this ticket can't be modified`); - const salesIds = sales.map(sale => sale.id); - const canEditSale = await models.Sale.canEdit(ctx, salesIds, myOptions); + const canEditSale = await models.Sale.canEdit(ctx, salesIds, myOptions); if (!canEditSale) throw new UserError(`Sale(s) blocked, please contact production`); diff --git a/modules/ticket/back/methods/sale/updatePrice.js b/modules/ticket/back/methods/sale/updatePrice.js index bbd9d154db..cca73fef1e 100644 --- a/modules/ticket/back/methods/sale/updatePrice.js +++ b/modules/ticket/back/methods/sale/updatePrice.js @@ -66,12 +66,7 @@ module.exports = Self => { const sale = await models.Sale.findById(id, filter, myOptions); - const isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk, myOptions); - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); - const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions); - if (!canEditSale) throw new UserError(`Sale(s) blocked, please contact production`); From 53f78a98d274ac1f74d2d20a54676343a6c0087c Mon Sep 17 00:00:00 2001 From: vicent Date: Tue, 11 Oct 2022 10:04:13 +0200 Subject: [PATCH 13/69] feat: update message while globalInvoicing --- .../front/index/global-invoicing/index.html | 4 +--- .../front/index/global-invoicing/index.js | 18 ++++++++---------- .../front/index/global-invoicing/locale/es.yml | 3 ++- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/modules/invoiceOut/front/index/global-invoicing/index.html b/modules/invoiceOut/front/index/global-invoicing/index.html index dbb780b7ca..d7b4c3604d 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.html +++ b/modules/invoiceOut/front/index/global-invoicing/index.html @@ -19,9 +19,7 @@ ng-if="$ctrl.isInvoicing"> - Adding invoices to queue... - {{$ctrl.lastClientId}} - {{::$ctrl.lastClientId || 'Vacío'}} + {{$ctrl.currentClientId}} {{$ctrl.$t('of')}} {{$ctrl.lastClientId}} diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index 66c2e698a2..fea1094ce5 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -57,19 +57,17 @@ class Controller extends Dialog { if (!this.invoice.fromClientId) throw new Error('Choose a valid clients range'); - this.isInvoicing = true; return this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) - .then(res => { + .then(async res => { this.lastClientId = res.data[res.data.length - 1]; - console.log(this.lastClientId); + this.isInvoicing = true; + for (let clientId of res.data) { + this.currentClientId = clientId; + const params = {clientId: clientId}; + await this.$http.post(`InvoiceOuts/globalInvoicing`, params); + } }) - // .then(() => { - // for (let clientId of res.data) { - // const params = {clientId: clientId}; - // this.$http.post(`InvoiceOuts/globalInvoicing`, params); - // } - // }) - // .then(() => super.responseHandler(response)) + .then(() => super.responseHandler(response)) .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) .finally(() => this.isInvoicing = false); } catch (e) { diff --git a/modules/invoiceOut/front/index/global-invoicing/locale/es.yml b/modules/invoiceOut/front/index/global-invoicing/locale/es.yml index 1a6e15656c..2089743076 100644 --- a/modules/invoiceOut/front/index/global-invoicing/locale/es.yml +++ b/modules/invoiceOut/front/index/global-invoicing/locale/es.yml @@ -6,4 +6,5 @@ Invoice date: Fecha de factura From client: Desde el cliente To client: Hasta el cliente Invoice date and the max date should be filled: La fecha de factura y la fecha límite deben rellenarse -Choose a valid clients range: Selecciona un rango válido de clientes \ No newline at end of file +Choose a valid clients range: Selecciona un rango válido de clientes +of: de \ No newline at end of file From 0d785695fe311fecf198891e7efe8be0a375211e Mon Sep 17 00:00:00 2001 From: vicent Date: Tue, 11 Oct 2022 12:24:06 +0200 Subject: [PATCH 14/69] feat: invoicing by (clientFk, addressFk) --- .../methods/invoiceOut/clientToInvoice.js | 18 ++++--- .../methods/invoiceOut/globalInvoicing.js | 54 ++++++++++++++++--- .../front/index/global-invoicing/index.js | 13 +++-- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js index 16c999e73a..5466f22ace 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js +++ b/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js @@ -53,7 +53,6 @@ module.exports = Self => { myOptions.transaction = tx; } - const clientToInvoideIds = []; let query; try { query = ` @@ -97,14 +96,21 @@ module.exports = Self => { if (!invoiceableClients.length) return; - const clientToInvoiceIds = invoiceableClients.map(invoiceableClient => invoiceableClient.id); - const dataArr = new Set(clientToInvoiceIds); - const clientNotRepeatedIds = [...dataArr]; + const clientAndAddress = invoiceableClients.map( + invoiceableClient => [invoiceableClient.id, invoiceableClient.addressFk] + ); if (tx) await tx.commit(); - console.log(invoiceableClients, clientToInvoiceIds, clientNotRepeatedIds); - return clientNotRepeatedIds; + return { + clientAndAddressIds: clientAndAddress, + invoiceDate: args.invoiceDate, + maxShipped: args.maxShipped, + fromClientId: args.fromClientId, + toClientId: args.toClientId, + companyFk: args.companyFk, + minShipped: minShipped + }; } catch (e) { if (tx) await tx.rollback(); throw e; diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index bee79746a3..a90a986c38 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -7,6 +7,43 @@ module.exports = Self => { type: 'number', description: 'The client id to invoice', required: true + }, + { + arg: 'addressId', + type: 'number', + description: 'The address id to invoice', + required: true + }, + { + arg: 'invoiceDate', + type: 'date', + description: 'The invoice date' + }, + { + arg: 'maxShipped', + type: 'date', + description: 'The maximum shipped date' + }, + { + arg: 'fromClientId', + type: 'number', + description: 'The minimum client id' + }, + { + arg: 'toClientId', + type: 'number', + description: 'The maximum client id', + required: false + }, + { + arg: 'companyFk', + type: 'number', + description: 'The company id to invoice' + }, + { + arg: 'minShipped', + type: 'date', + description: 'The company id to invoice' }], returns: { type: 'object', @@ -18,7 +55,8 @@ module.exports = Self => { } }); - Self.globalInvoicing = async(ctx, clientId, options) => { + Self.globalInvoicing = async(ctx, options) => { + const args = ctx.args; const models = Self.app.models; const myOptions = {}; let tx; @@ -34,15 +72,16 @@ module.exports = Self => { const invoicesIds = []; const failedClients = []; try { - const client = await models.Client.findById(clientId, { - fields: ['id', 'hasToInvoiceByAddress', 'addressFk'] + // const addresses = await models.Address.find({where: {clientFk: args.clientId}}, myOptions); + const client = await models.Client.findById(args.clientId, { + fields: ['id', 'hasToInvoiceByAddress'] }, myOptions); try { if (client.hasToInvoiceByAddress) { await Self.rawSql('CALL ticketToInvoiceByAddress(?, ?, ?, ?)', [ - minShipped, + args.minShipped, args.maxShipped, - client.addressFk, + args.addressId, args.companyFk ], myOptions); } else { @@ -59,7 +98,7 @@ module.exports = Self => { // Validates ticket nagative base const hasAnyNegativeBase = await getNegativeBase(myOptions); if (hasAnyNegativeBase && isSpanishCompany) - return notifyFailures(ctx, failedClients, myOptions); // continue + return tx.rollback(); // continue query = `SELECT invoiceSerial(?, ?, ?) AS serial`; const [invoiceSerial] = await Self.rawSql(query, [ @@ -89,9 +128,8 @@ module.exports = Self => { id: client.id, stacktrace: e }); - return notifyFailures(ctx, failedClients, myOptions); // continue + await notifyFailures(ctx, failedClients, myOptions); // continue } - // } if (tx) await tx.commit(); } catch (e) { diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index fea1094ce5..30d965e9f2 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -59,12 +59,15 @@ class Controller extends Dialog { return this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) .then(async res => { - this.lastClientId = res.data[res.data.length - 1]; + const clientAndAddressIds = res.data.clientAndAddressIds; + if (!clientAndAddressIds) return super.responseHandler(response); + this.lastClientId = clientAndAddressIds[clientAndAddressIds.length - 1][0]; this.isInvoicing = true; - for (let clientId of res.data) { - this.currentClientId = clientId; - const params = {clientId: clientId}; - await this.$http.post(`InvoiceOuts/globalInvoicing`, params); + for (let clientAndAddresId of clientAndAddressIds) { + this.currentClientId = clientAndAddresId[0]; + res.data.clientId = clientAndAddresId[0]; + res.data.addressId = clientAndAddresId[1]; + await this.$http.post(`InvoiceOuts/globalInvoicing`, res.data); } }) .then(() => super.responseHandler(response)) From 50ec41decefb975e0900cafbe6596eb44596f042 Mon Sep 17 00:00:00 2001 From: vicent Date: Thu, 13 Oct 2022 15:01:15 +0200 Subject: [PATCH 15/69] refator: cancel request --- .../methods/invoiceOut/clientToInvoice.js | 41 +++++++++------ .../methods/invoiceOut/globalInvoicing.js | 18 ++++--- .../front/index/global-invoicing/index.html | 10 ++-- .../front/index/global-invoicing/index.js | 50 ++++++++++++++----- .../index/global-invoicing/locale/es.yml | 3 +- 5 files changed, 82 insertions(+), 40 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js index 5466f22ace..cb2bfece7b 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js +++ b/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js @@ -30,10 +30,14 @@ module.exports = Self => { description: 'The company id to invoice' } ], - returns: { - type: 'object', - root: true + returns: [{ + arg: 'clientsAndAddresses', + type: ['object'] }, + { + arg: 'invoice', + type: 'object' + }], http: { path: '/clientToInvoice', verb: 'POST' @@ -94,23 +98,30 @@ module.exports = Self => { const invoiceableClients = await getInvoiceableClients(ctx, myOptions); - if (!invoiceableClients.length) return; + if (!invoiceableClients) return; - const clientAndAddress = invoiceableClients.map( - invoiceableClient => [invoiceableClient.id, invoiceableClient.addressFk] + const clientsAndAddresses = invoiceableClients.map(invoiceableClient => { + return { + clientId: invoiceableClient.id, + addressId: invoiceableClient.addressFk + + }; + } ); if (tx) await tx.commit(); - return { - clientAndAddressIds: clientAndAddress, - invoiceDate: args.invoiceDate, - maxShipped: args.maxShipped, - fromClientId: args.fromClientId, - toClientId: args.toClientId, - companyFk: args.companyFk, - minShipped: minShipped - }; + return [ + clientsAndAddresses, + { + invoiceDate: args.invoiceDate, + maxShipped: args.maxShipped, + fromClientId: args.fromClientId, + toClientId: args.toClientId, + companyFk: args.companyFk, + minShipped: minShipped + } + ]; } catch (e) { if (tx) await tx.rollback(); throw e; diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index a90a986c38..8728a52788 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -1,6 +1,6 @@ module.exports = Self => { Self.remoteMethodCtx('globalInvoicing', { - description: 'Make a global invoice of a client', + description: 'Make a invoice of a client', accessType: 'WRITE', accepts: [{ arg: 'clientId', @@ -17,17 +17,20 @@ module.exports = Self => { { arg: 'invoiceDate', type: 'date', - description: 'The invoice date' + description: 'The invoice date', + required: true }, { arg: 'maxShipped', type: 'date', - description: 'The maximum shipped date' + description: 'The maximum shipped date', + required: true }, { arg: 'fromClientId', type: 'number', - description: 'The minimum client id' + description: 'The minimum client id', + required: true }, { arg: 'toClientId', @@ -38,12 +41,14 @@ module.exports = Self => { { arg: 'companyFk', type: 'number', - description: 'The company id to invoice' + description: 'The company id to invoice', + required: true }, { arg: 'minShipped', type: 'date', - description: 'The company id to invoice' + description: 'The company id to invoice', + required: true }], returns: { type: 'object', @@ -72,7 +77,6 @@ module.exports = Self => { const invoicesIds = []; const failedClients = []; try { - // const addresses = await models.Address.find({where: {clientFk: args.clientId}}, myOptions); const client = await models.Client.findById(args.clientId, { fields: ['id', 'hasToInvoiceByAddress'] }, myOptions); diff --git a/modules/invoiceOut/front/index/global-invoicing/index.html b/modules/invoiceOut/front/index/global-invoicing/index.html index d7b4c3604d..a6c7661f53 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.html +++ b/modules/invoiceOut/front/index/global-invoicing/index.html @@ -16,10 +16,12 @@
+ ng-if="$ctrl.lastClientId"> - - {{$ctrl.currentClientId}} {{$ctrl.$t('of')}} {{$ctrl.lastClientId}} +
+ {{'Id Client' | translate}}: {{$ctrl.currentClientId}} + {{'of' | translate}} {{::$ctrl.lastClientId}} +
@@ -66,5 +68,5 @@ - + {{$ctrl.isInvoicing}} \ No newline at end of file diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index 30d965e9f2..a74cf76107 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -6,7 +6,7 @@ class Controller extends Dialog { constructor($element, $, $transclude) { super($element, $, $transclude); - this.isInvoicing = false; + this.lastClientId = null; this.invoice = { maxShipped: new Date() }; @@ -46,7 +46,7 @@ class Controller extends Dialog { this.invoice.companyFk = value; } - responseHandler(response) { + async responseHandler(response) { try { if (response !== 'accept') return super.responseHandler(response); @@ -57,25 +57,49 @@ class Controller extends Dialog { if (!this.invoice.fromClientId) throw new Error('Choose a valid clients range'); + this.on('close', () => { + if (this.canceler) this.canceler.resolve(); + this.vnApp.showSuccess(this.$t('Data saved!')); + }); + return this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) .then(async res => { - const clientAndAddressIds = res.data.clientAndAddressIds; - if (!clientAndAddressIds) return super.responseHandler(response); - this.lastClientId = clientAndAddressIds[clientAndAddressIds.length - 1][0]; - this.isInvoicing = true; - for (let clientAndAddresId of clientAndAddressIds) { - this.currentClientId = clientAndAddresId[0]; - res.data.clientId = clientAndAddresId[0]; - res.data.addressId = clientAndAddresId[1]; - await this.$http.post(`InvoiceOuts/globalInvoicing`, res.data); + const clientsAndAddresses = res.data.clientsAndAddresses; + const invoice = res.data.invoice; + + if (!clientsAndAddresses.length) return super.responseHandler(response); + this.lastClientId = clientsAndAddresses[clientsAndAddresses.length - 1].clientId; + this.$.invoiceButton.setAttribute('disabled', true); + for (let clientAndAddress of clientsAndAddresses) { + this.currentClientId = clientAndAddress.clientId; + const params = { + clientId: clientAndAddress.clientId, + addressId: clientAndAddress.addressId, + invoiceDate: invoice.invoiceDate, + maxShipped: invoice.maxShipped, + fromClientId: invoice.fromClientId, + toClientId: invoice.toClientId, + companyFk: invoice.companyFk, + minShipped: invoice.minShipped, + + }; + this.canceler = this.$q.defer(); + const options = { + timeout: this.canceler.promise + }; + await this.$http.post(`InvoiceOuts/globalInvoicing`, params, options); } }) .then(() => super.responseHandler(response)) .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) - .finally(() => this.isInvoicing = false); + .finally(() => { + this.lastClientId = null; + this.$.invoiceButton.removeAttribute('disabled'); + }); } catch (e) { this.vnApp.showError(this.$t(e.message)); - this.isInvoicing = false; + this.lastClientId = null; + this.$.invoiceButton.removeAttribute('disabled'); return false; } } diff --git a/modules/invoiceOut/front/index/global-invoicing/locale/es.yml b/modules/invoiceOut/front/index/global-invoicing/locale/es.yml index 2089743076..6245ee2089 100644 --- a/modules/invoiceOut/front/index/global-invoicing/locale/es.yml +++ b/modules/invoiceOut/front/index/global-invoicing/locale/es.yml @@ -7,4 +7,5 @@ From client: Desde el cliente To client: Hasta el cliente Invoice date and the max date should be filled: La fecha de factura y la fecha límite deben rellenarse Choose a valid clients range: Selecciona un rango válido de clientes -of: de \ No newline at end of file +of: de +Id Client: Id Cliente \ No newline at end of file From 5918b3e0dfc3bc3c7868664fb71090366ba8820a Mon Sep 17 00:00:00 2001 From: vicent Date: Fri, 14 Oct 2022 09:30:09 +0200 Subject: [PATCH 16/69] refactor: juan changes --- .../invoiceOut/front/index/global-invoicing/index.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index a74cf76107..2dc4de3cbd 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -62,6 +62,7 @@ class Controller extends Dialog { this.vnApp.showSuccess(this.$t('Data saved!')); }); + this.$.invoiceButton.disabled = true; return this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) .then(async res => { const clientsAndAddresses = res.data.clientsAndAddresses; @@ -69,7 +70,6 @@ class Controller extends Dialog { if (!clientsAndAddresses.length) return super.responseHandler(response); this.lastClientId = clientsAndAddresses[clientsAndAddresses.length - 1].clientId; - this.$.invoiceButton.setAttribute('disabled', true); for (let clientAndAddress of clientsAndAddresses) { this.currentClientId = clientAndAddress.clientId; const params = { @@ -93,13 +93,14 @@ class Controller extends Dialog { .then(() => super.responseHandler(response)) .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) .finally(() => { - this.lastClientId = null; - this.$.invoiceButton.removeAttribute('disabled'); + this.lastClientId = null; // unificar en una función + this.$.invoiceButton.disabled = false; // unificar en una función }); } catch (e) { this.vnApp.showError(this.$t(e.message)); - this.lastClientId = null; - this.$.invoiceButton.removeAttribute('disabled'); + this.lastClientId = null; // unificar en una función + this.$.invoiceButton.disabled = false; // unificar en una función + throw e; return false; } } From 15ba6681afd112b91b68ccc8b299b1d0b7d5907b Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 17 Oct 2022 09:49:47 +0200 Subject: [PATCH 17/69] refator: code unified --- .../back/methods/invoiceOut/globalInvoicing.js | 4 ++-- .../front/index/global-invoicing/index.js | 16 +++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index 8728a52788..b9d4b1e329 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -102,7 +102,7 @@ module.exports = Self => { // Validates ticket nagative base const hasAnyNegativeBase = await getNegativeBase(myOptions); if (hasAnyNegativeBase && isSpanishCompany) - return tx.rollback(); // continue + return tx.rollback(); query = `SELECT invoiceSerial(?, ?, ?) AS serial`; const [invoiceSerial] = await Self.rawSql(query, [ @@ -132,7 +132,7 @@ module.exports = Self => { id: client.id, stacktrace: e }); - await notifyFailures(ctx, failedClients, myOptions); // continue + await notifyFailures(ctx, failedClients, myOptions); } if (tx) await tx.commit(); diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index 2dc4de3cbd..74a4f562f9 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -5,8 +5,6 @@ import './style.scss'; class Controller extends Dialog { constructor($element, $, $transclude) { super($element, $, $transclude); - - this.lastClientId = null; this.invoice = { maxShipped: new Date() }; @@ -46,6 +44,11 @@ class Controller extends Dialog { this.invoice.companyFk = value; } + restartValues() { + this.lastClientId = null; + this.$.invoiceButton.disabled = false; + } + async responseHandler(response) { try { if (response !== 'accept') @@ -92,15 +95,10 @@ class Controller extends Dialog { }) .then(() => super.responseHandler(response)) .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) - .finally(() => { - this.lastClientId = null; // unificar en una función - this.$.invoiceButton.disabled = false; // unificar en una función - }); + .finally(() => this.restartValues()); } catch (e) { + this.restartValues(); this.vnApp.showError(this.$t(e.message)); - this.lastClientId = null; // unificar en una función - this.$.invoiceButton.disabled = false; // unificar en una función - throw e; return false; } } From 6924b05c8a45dc05044a67e8c3c271ed32875b58 Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 17 Oct 2022 10:19:07 +0200 Subject: [PATCH 18/69] feat: add radio button --- .../back/methods/invoiceOut/globalInvoicing.js | 2 +- .../front/index/global-invoicing/index.html | 12 ++++++++++++ .../invoiceOut/front/index/global-invoicing/index.js | 3 +++ .../front/index/global-invoicing/locale/es.yml | 4 +++- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index b9d4b1e329..6aa2ecc076 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -36,7 +36,7 @@ module.exports = Self => { arg: 'toClientId', type: 'number', description: 'The maximum client id', - required: false + required: true }, { arg: 'companyFk', diff --git a/modules/invoiceOut/front/index/global-invoicing/index.html b/modules/invoiceOut/front/index/global-invoicing/index.html index a6c7661f53..7f96397f55 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.html +++ b/modules/invoiceOut/front/index/global-invoicing/index.html @@ -37,6 +37,18 @@ + + + + + + { const clientsAndAddresses = res.data.clientsAndAddresses; diff --git a/modules/invoiceOut/front/index/global-invoicing/locale/es.yml b/modules/invoiceOut/front/index/global-invoicing/locale/es.yml index 6245ee2089..8ac2cc13a2 100644 --- a/modules/invoiceOut/front/index/global-invoicing/locale/es.yml +++ b/modules/invoiceOut/front/index/global-invoicing/locale/es.yml @@ -8,4 +8,6 @@ To client: Hasta el cliente Invoice date and the max date should be filled: La fecha de factura y la fecha límite deben rellenarse Choose a valid clients range: Selecciona un rango válido de clientes of: de -Id Client: Id Cliente \ No newline at end of file +Id Client: Id Cliente +All clients: Todos los clientes +Clients range: Rango de clientes \ No newline at end of file From 33092acee755b5e752400f2ecd9628a2ac735c2a Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 17 Oct 2022 11:42:05 +0200 Subject: [PATCH 19/69] refactor: delete unnecessary code --- .../methods/invoiceOut/globalInvoicing.js | 37 ++++++------------- .../front/index/global-invoicing/index.js | 2 - 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index 6aa2ecc076..270d1c2f96 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -26,18 +26,6 @@ module.exports = Self => { description: 'The maximum shipped date', required: true }, - { - arg: 'fromClientId', - type: 'number', - description: 'The minimum client id', - required: true - }, - { - arg: 'toClientId', - type: 'number', - description: 'The maximum client id', - required: true - }, { arg: 'companyFk', type: 'number', @@ -47,7 +35,7 @@ module.exports = Self => { { arg: 'minShipped', type: 'date', - description: 'The company id to invoice', + description: 'The minium shupped date', required: true }], returns: { @@ -74,13 +62,14 @@ module.exports = Self => { myOptions.transaction = tx; } - const invoicesIds = []; - const failedClients = []; + let invoiceId; try { const client = await models.Client.findById(args.clientId, { fields: ['id', 'hasToInvoiceByAddress'] }, myOptions); try { + throw new Error(`Pq lo digo yo`); + if (client.hasToInvoiceByAddress) { await Self.rawSql('CALL ticketToInvoiceByAddress(?, ?, ?, ?)', [ args.minShipped, @@ -125,14 +114,14 @@ module.exports = Self => { query = `INSERT IGNORE INTO invoiceOutQueue(invoiceFk) VALUES(?)`; await Self.rawSql(query, [newInvoice.id], myOptions); - invoicesIds.push(newInvoice.id); + invoiceId = newInvoice.id; } } catch (e) { - failedClients.push({ + const failedClient = { id: client.id, stacktrace: e - }); - await notifyFailures(ctx, failedClients, myOptions); + }; + await notifyFailures(ctx, failedClient, myOptions); } if (tx) await tx.commit(); @@ -141,7 +130,7 @@ module.exports = Self => { throw e; } - return invoicesIds; + return invoiceId; }; async function getNegativeBase(options) { @@ -166,7 +155,7 @@ module.exports = Self => { return supplierCompany && supplierCompany.total; } - async function notifyFailures(ctx, failedClients, options) { + async function notifyFailures(ctx, failedClient, options) { const models = Self.app.models; const userId = ctx.req.accessToken.userId; const $t = ctx.req.__; // $translate @@ -175,10 +164,8 @@ module.exports = Self => { const subject = $t('Global invoicing failed'); let body = $t(`Wasn't able to invoice the following clients`) + ':

'; - for (client of failedClients) { - body += `ID: ${client.id} -
${client.stacktrace}

`; - } + body += `ID: ${failedClient.id} +
${failedClient.stacktrace}

`; await Self.rawSql(` INSERT INTO vn.mail (sender, replyTo, sent, subject, body) diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index a7b263fc05..4ef2ed8e06 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -83,8 +83,6 @@ class Controller extends Dialog { addressId: clientAndAddress.addressId, invoiceDate: invoice.invoiceDate, maxShipped: invoice.maxShipped, - fromClientId: invoice.fromClientId, - toClientId: invoice.toClientId, companyFk: invoice.companyFk, minShipped: invoice.minShipped, From e5fd6adfe553a8692846161bf3beacfcd59a908e Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 17 Oct 2022 11:43:01 +0200 Subject: [PATCH 20/69] fix: delete throw error --- .../back/methods/invoiceOut/specs/globalInvoicing.spec.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js index f7546b72e9..eeef08e1ff 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js @@ -4,6 +4,7 @@ describe('InvoiceOut globalInvoicing()', () => { const userId = 1; const companyFk = 442; const clientId = 1101; + const addressId = 1; const invoicedTicketId = 8; const invoiceSerial = 'A'; const activeCtx = { @@ -22,11 +23,12 @@ describe('InvoiceOut globalInvoicing()', () => { try { ctx.args = { + clientId: clientId, + addressId: addressId, invoiceDate: new Date(), maxShipped: new Date(), - fromClientId: clientId, - toClientId: 1106, - companyFk: companyFk + companyFk: companyFk, + minShipped: new Date() }; const result = await models.InvoiceOut.globalInvoicing(ctx, options); const ticket = await models.Ticket.findById(invoicedTicketId, null, options); From dd10b79441bd688b25564f22a90441303fda31c2 Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 17 Oct 2022 11:43:26 +0200 Subject: [PATCH 21/69] delete: throw error --- modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index 270d1c2f96..d74199799a 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -68,8 +68,6 @@ module.exports = Self => { fields: ['id', 'hasToInvoiceByAddress'] }, myOptions); try { - throw new Error(`Pq lo digo yo`); - if (client.hasToInvoiceByAddress) { await Self.rawSql('CALL ticketToInvoiceByAddress(?, ?, ?, ?)', [ args.minShipped, From 2d1b48280c58b8f0c626ae9b0e611ef5e814dd13 Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 17 Oct 2022 11:53:29 +0200 Subject: [PATCH 22/69] fix: backTest --- .../invoiceOut/specs/globalInvoicing.spec.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js index eeef08e1ff..bd6a07baa7 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js @@ -2,9 +2,14 @@ const models = require('vn-loopback/server/server').models; describe('InvoiceOut globalInvoicing()', () => { const userId = 1; - const companyFk = 442; const clientId = 1101; - const addressId = 1; + const addressId = 121; + const companyFk = 442; + const minShipped = new Date(); + minShipped.setFullYear(minShipped.getFullYear() - 1); + minShipped.setMonth(1); + minShipped.setDate(1); + minShipped.setHours(0, 0, 0, 0); const invoicedTicketId = 8; const invoiceSerial = 'A'; const activeCtx = { @@ -28,12 +33,12 @@ describe('InvoiceOut globalInvoicing()', () => { invoiceDate: new Date(), maxShipped: new Date(), companyFk: companyFk, - minShipped: new Date() + minShipped: minShipped }; const result = await models.InvoiceOut.globalInvoicing(ctx, options); const ticket = await models.Ticket.findById(invoicedTicketId, null, options); - expect(result.length).toBeGreaterThan(0); + expect(result).toBeGreaterThan(0); expect(ticket.refFk).toContain(invoiceSerial); await tx.rollback(); From 86d24ffede6b430e7923d66f77d73244a8dc71d7 Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 17 Oct 2022 13:02:03 +0200 Subject: [PATCH 23/69] refactor code --- .../invoiceOut/back/methods/invoiceOut/clientToInvoice.js | 3 +-- modules/invoiceOut/front/index/global-invoicing/index.js | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js index cb2bfece7b..a0578897a0 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js +++ b/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js @@ -21,8 +21,7 @@ module.exports = Self => { { arg: 'toClientId', type: 'number', - description: 'The maximum client id', - required: false + description: 'The maximum client id' }, { arg: 'companyFk', diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index 4ef2ed8e06..e311f6b020 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -58,7 +58,7 @@ class Controller extends Dialog { if (!this.invoice.invoiceDate || !this.invoice.maxShipped) throw new Error('Invoice date and the max date should be filled'); - if (!this.invoice.fromClientId) + if (!this.invoice.fromClientId || !this.invoice.toClientId) throw new Error('Choose a valid clients range'); this.on('close', () => { @@ -71,11 +71,11 @@ class Controller extends Dialog { return this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) .then(async res => { - const clientsAndAddresses = res.data.clientsAndAddresses; const invoice = res.data.invoice; - + const clientsAndAddresses = res.data.clientsAndAddresses; if (!clientsAndAddresses.length) return super.responseHandler(response); this.lastClientId = clientsAndAddresses[clientsAndAddresses.length - 1].clientId; + for (let clientAndAddress of clientsAndAddresses) { this.currentClientId = clientAndAddress.clientId; const params = { @@ -98,8 +98,8 @@ class Controller extends Dialog { .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) .finally(() => this.restartValues()); } catch (e) { - this.restartValues(); this.vnApp.showError(this.$t(e.message)); + this.restartValues(); return false; } } From 8ab6a50c73bd93e952ee4e5981d8d9ad3336278c Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 17 Oct 2022 13:02:19 +0200 Subject: [PATCH 24/69] try to fix frontTest --- .../index/global-invoicing/index.spec.js | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/modules/invoiceOut/front/index/global-invoicing/index.spec.js b/modules/invoiceOut/front/index/global-invoicing/index.spec.js index 916364007f..1e5ed3a998 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.spec.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.spec.js @@ -19,6 +19,7 @@ describe('InvoiceOut', () => { } }; controller = $componentController('vnInvoiceOutGlobalInvoicing', {$element, $scope, $transclude}); + controller.$.invoiceButton = {disabled: false}; })); describe('getMinClientId()', () => { @@ -86,14 +87,39 @@ describe('InvoiceOut', () => { it('should make an http POST query and then call to the showSuccess() method', () => { jest.spyOn(controller.vnApp, 'showSuccess'); - + const filter = { + order: 'id DESC', + limit: 1 + }; + const minShipped = new Date(); + minShipped.setFullYear(minShipped.getFullYear() - 1); + minShipped.setMonth(1); + minShipped.setDate(1); + minShipped.setHours(0, 0, 0, 0); controller.invoice = { invoiceDate: new Date(), maxShipped: new Date(), fromClientId: 1101, - toClientId: 1101 + toClientId: 1101, + companyFk: 442, + minShipped: minShipped + }; + const response = { + clientsAndAddresses: [{clientId: 1101, addressId: 121}], + invoice: controller.invoice + }; + const expectedParams = { + clientId: 1101, + addressId: 121, + invoiceDate: new Date(), + maxShipped: new Date(), + companyFk: 442, + minShipped: minShipped }; + const serializedParams = $httpParamSerializer({filter}); + $httpBackend.expectGET(`Clients/findOne?${serializedParams}`).respond(200, {id: 1112}); + $httpBackend.expect('POST', `InvoiceOuts/clientToInvoice`).respond(response); $httpBackend.expect('POST', `InvoiceOuts/globalInvoicing`).respond({id: 1}); controller.responseHandler('accept'); $httpBackend.flush(); From f95f977b69a4b72f5122107425f603b113aacae9 Mon Sep 17 00:00:00 2001 From: vicent Date: Tue, 18 Oct 2022 10:04:53 +0200 Subject: [PATCH 25/69] fix: backTest --- .../methods/invoiceOut/specs/globalInvoicing.spec.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js index bd6a07baa7..3f359dfb57 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js @@ -10,7 +10,6 @@ describe('InvoiceOut globalInvoicing()', () => { minShipped.setMonth(1); minShipped.setDate(1); minShipped.setHours(0, 0, 0, 0); - const invoicedTicketId = 8; const invoiceSerial = 'A'; const activeCtx = { accessToken: {userId: userId}, @@ -35,11 +34,14 @@ describe('InvoiceOut globalInvoicing()', () => { companyFk: companyFk, minShipped: minShipped }; - const result = await models.InvoiceOut.globalInvoicing(ctx, options); - const ticket = await models.Ticket.findById(invoicedTicketId, null, options); + const invoiceOutId = await models.InvoiceOut.globalInvoicing(ctx, options); + const invoiceOut = await models.InvoiceOut.findById(invoiceOutId, null, options); + const [firstTicket] = await models.Ticket.find({ + where: {refFk: invoiceOut.ref} + }, options); - expect(result).toBeGreaterThan(0); - expect(ticket.refFk).toContain(invoiceSerial); + expect(invoiceOutId).toBeGreaterThan(0); + expect(firstTicket.refFk).toContain(invoiceSerial); await tx.rollback(); } catch (e) { From a5ceee07e94bd012cfdf256f4e3e38cd7c78c570 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 18 Oct 2022 11:50:16 +0200 Subject: [PATCH 26/69] use loopback --- back/methods/account/hasFuncionalityAcl.js | 47 ------------------- back/models/account.js | 1 - db/changes/10491-august/00-editTrackedACL.sql | 3 ++ .../10491-august/00-funcionalityAcl.sql | 15 ------ modules/ticket/back/methods/sale/canEdit.js | 28 +++++++++-- .../back/methods/sale/specs/canEdit.spec.js | 12 ++--- .../back/methods/sale/specs/reserve.spec.js | 6 +-- 7 files changed, 36 insertions(+), 76 deletions(-) delete mode 100644 back/methods/account/hasFuncionalityAcl.js create mode 100644 db/changes/10491-august/00-editTrackedACL.sql delete mode 100644 db/changes/10491-august/00-funcionalityAcl.sql diff --git a/back/methods/account/hasFuncionalityAcl.js b/back/methods/account/hasFuncionalityAcl.js deleted file mode 100644 index d6224fffcb..0000000000 --- a/back/methods/account/hasFuncionalityAcl.js +++ /dev/null @@ -1,47 +0,0 @@ -module.exports = Self => { - Self.remoteMethod('hasFuncionalityAcl', { - description: 'Return if user has permissions', - accepts: [ - { - arg: 'model', - type: 'String', - description: 'The model', - required: true - }, - { - arg: 'property', - type: 'String', - description: 'The property', - required: true - } - ], - returns: { - type: 'Object', - root: true - }, - http: { - path: `/hasFuncionalityAcl`, - verb: 'GET' - } - }); - - Self.hasFuncionalityAcl = async function(ctx, model, property) { - const userId = ctx.req.accessToken.userId; - const models = Self.app.models; - - const acls = await models.FuncionalityAcl.find({ - where: { - model: model, - property: property - } - }); - - let hasPermissions; - for (let acl of acls) - if (!hasPermissions) hasPermissions = await models.Account.hasRole(userId, acl.role); - - if (hasPermissions) - return true; - return false; - }; -}; diff --git a/back/models/account.js b/back/models/account.js index 7d7fa9fe38..f74052b5c9 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -7,7 +7,6 @@ module.exports = Self => { require('../methods/account/change-password')(Self); require('../methods/account/set-password')(Self); require('../methods/account/validate-token')(Self); - require('../methods/account/hasFuncionalityAcl')(Self); require('../methods/account/privileges')(Self); // Validations diff --git a/db/changes/10491-august/00-editTrackedACL.sql b/db/changes/10491-august/00-editTrackedACL.sql new file mode 100644 index 0000000000..37d24ac814 --- /dev/null +++ b/db/changes/10491-august/00-editTrackedACL.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('Sale', 'editTracked', 'READ', 'ALLOW', 'ROLE', 'production'); diff --git a/db/changes/10491-august/00-funcionalityAcl.sql b/db/changes/10491-august/00-funcionalityAcl.sql deleted file mode 100644 index 02f3dbcc43..0000000000 --- a/db/changes/10491-august/00-funcionalityAcl.sql +++ /dev/null @@ -1,15 +0,0 @@ -CREATE TABLE `salix`.`funcionalityAcl` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `model` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `property` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `role` varchar(45) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `role_FK` FOREIGN KEY (`role`) REFERENCES `account`.`role` (`name`) ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; - - -INSERT INTO `salix`.`funcionalityAcl` (`model`, `property`, `role`) - VALUES - ('Sale', 'editTracked', 'production'), - ('Sale', 'editCloned', 66); - ('Sale', 'editWeekly', 66); diff --git a/modules/ticket/back/methods/sale/canEdit.js b/modules/ticket/back/methods/sale/canEdit.js index c0cd4b7019..b1dab82a5d 100644 --- a/modules/ticket/back/methods/sale/canEdit.js +++ b/modules/ticket/back/methods/sale/canEdit.js @@ -40,16 +40,36 @@ module.exports = Self => { const isTicketWeekly = await models.TicketWeekly.findOne({where: {ticketFk: firstSale.ticketFk}}, myOptions); - const canEditTracked = await models.Account.hasFuncionalityAcl(ctx, 'Sale', 'editTracked'); - const canEditCloned = await models.Account.hasFuncionalityAcl(ctx, 'Sale', 'editCloned'); - const canEditWeekly = await models.Account.hasFuncionalityAcl(ctx, 'Ticket', 'editWeekly'); + // (principalType, principalId,model, property, accessType,callback); + // let canEditTracked = await models.ACL.checkPermission('ROLE', 'employee', 'Sale', 'updateConcept', '*'); + // let canEditTracked2 = await models.ACL.checkPermission('USER', 'developer', 'Sale', 'editTracked', 'READ'); + const array = ['editTracked']; + let canEditTracked3 = await models.ACL.checkAccessForContext({ + principals: [{ + type: 'ROLE', + id: 'employee' + }], + model: 'Sale', + property: 'editTracked', + methodNames: array, + accessType: 'READ' + }); + console.log(canEditTracked3); + // canEditTracked = await models.ACL.resolvePermission(canEditTracked); + // let canEditCloned = await models.ACL.checkPermission('ROLE', 'employee', 'Sale', 'editCloned', '*'); + // let canEditWeekly = await models.ACL.checkPermission('ROLE', 'employee', 'Ticket', 'editWeekly', '*'); + // console.log(canEditTracked, canEditTracked2); + console.log(canEditTracked3); const shouldEditTracked = canEditTracked || !hasSaleTracking; const shouldEditCloned = canEditCloned || !hasSaleCloned; const shouldEditWeekly = canEditWeekly || !isTicketWeekly; const canEdit = shouldEditTracked && shouldEditCloned && shouldEditWeekly; - return canEdit; + if (canEdit) + return true; + + return false; }; }; diff --git a/modules/ticket/back/methods/sale/specs/canEdit.spec.js b/modules/ticket/back/methods/sale/specs/canEdit.spec.js index 7d89471f63..1522ee7a31 100644 --- a/modules/ticket/back/methods/sale/specs/canEdit.spec.js +++ b/modules/ticket/back/methods/sale/specs/canEdit.spec.js @@ -91,20 +91,20 @@ describe('sale canEdit()', () => { it('should return true if any of the sales is cloned and has the correct role', async() => { const tx = await models.Sale.beginTransaction({}); - const roleEnabled = await models.FuncionalityAcl.findOne({ + const roleEnabled = await models.ACL.findOne({ where: { model: 'Sale', property: 'editCloned' } }); - if (!roleEnabled || !roleEnabled.role) return; + if (!roleEnabled || !roleEnabled.principalId) return; try { const options = {transaction: tx}; const roleId = await models.Role.findOne({ where: { - name: roleEnabled.role + name: roleEnabled.principalId } }); const ctx = {req: {accessToken: {userId: roleId}}}; @@ -146,20 +146,20 @@ describe('sale canEdit()', () => { it('should return true if any of the sales is of ticketWeekly and has the correct role', async() => { const tx = await models.Sale.beginTransaction({}); - const roleEnabled = await models.FuncionalityAcl.findOne({ + const roleEnabled = await models.ACL.findOne({ where: { model: 'Sale', property: 'editWeekly' } }); - if (!roleEnabled || !roleEnabled.role) return; + if (!roleEnabled || !roleEnabled.principalId) return; try { const options = {transaction: tx}; const roleId = await models.Role.findOne({ where: { - name: roleEnabled.role + name: roleEnabled.principalId } }); const ctx = {req: {accessToken: {userId: roleId}}}; diff --git a/modules/ticket/back/methods/sale/specs/reserve.spec.js b/modules/ticket/back/methods/sale/specs/reserve.spec.js index c4b3b4e5db..7c2d437151 100644 --- a/modules/ticket/back/methods/sale/specs/reserve.spec.js +++ b/modules/ticket/back/methods/sale/specs/reserve.spec.js @@ -1,9 +1,9 @@ const models = require('vn-loopback/server/server').models; -describe('sale reserve()', () => { +fdescribe('sale reserve()', () => { const ctx = { req: { - accessToken: {userId: 9}, + accessToken: {userId: 1}, headers: {origin: 'localhost:5000'}, __: () => {} } @@ -31,7 +31,7 @@ describe('sale reserve()', () => { expect(error).toEqual(new Error(`The sales of this ticket can't be modified`)); }); - it('should update the given sales of a ticket to reserved', async() => { + fit('should update the given sales of a ticket to reserved', async() => { const tx = await models.Sale.beginTransaction({}); try { From dc62841c3d72950e12717321d80144c3929a2890 Mon Sep 17 00:00:00 2001 From: vicent Date: Tue, 18 Oct 2022 14:46:40 +0200 Subject: [PATCH 27/69] refator: trying to delete async and await --- .../front/index/global-invoicing/index.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index e311f6b020..ef05c77843 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -50,6 +50,14 @@ class Controller extends Dialog { this.$.invoiceButton.disabled = false; } + invoice() { + const clientAndAddress = clientsAndAddresses[this.pos]; + return this.post(`InvoiceOuts/globalInvoicing`, params, options).then(() => { + this.pos++; + this.invoice(); + }); + } + async responseHandler(response) { try { if (response !== 'accept') @@ -69,7 +77,10 @@ class Controller extends Dialog { this.$.invoiceButton.disabled = true; if (this.clientsNumber == 'allClients') this.getMaxClientId(); - return this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) + this.pos = 0; + this.invoice(); + + this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) .then(async res => { const invoice = res.data.invoice; const clientsAndAddresses = res.data.clientsAndAddresses; @@ -91,7 +102,7 @@ class Controller extends Dialog { const options = { timeout: this.canceler.promise }; - await this.$http.post(`InvoiceOuts/globalInvoicing`, params, options); + await this.$http.post(`InvoiceOuts/globalInvoicing`, params, options).then(); } }) .then(() => super.responseHandler(response)) From 508decaf0bc5eaa4694c614b513d695f26bc8d73 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 19 Oct 2022 08:22:36 +0200 Subject: [PATCH 28/69] try --- modules/ticket/back/methods/sale/canEdit.js | 32 +++++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/modules/ticket/back/methods/sale/canEdit.js b/modules/ticket/back/methods/sale/canEdit.js index b1dab82a5d..4992a34990 100644 --- a/modules/ticket/back/methods/sale/canEdit.js +++ b/modules/ticket/back/methods/sale/canEdit.js @@ -1,4 +1,5 @@ const UserError = require('vn-loopback/util/user-error'); +const loopBackCtx = require('vn-loopback/server/server'); module.exports = Self => { Self.remoteMethodCtx('canEdit', { @@ -41,26 +42,45 @@ module.exports = Self => { await models.TicketWeekly.findOne({where: {ticketFk: firstSale.ticketFk}}, myOptions); // (principalType, principalId,model, property, accessType,callback); - // let canEditTracked = await models.ACL.checkPermission('ROLE', 'employee', 'Sale', 'updateConcept', '*'); + // let canEditTracked = await models.ACL.checkPermission('ROLE', 'employee', 'Sale', 'editTracked', 'WRITE'); + // let canEditTracked2 = await models.ACL.checkPermission('USER', 'developer', 'Sale', 'editTracked', 'READ'); const array = ['editTracked']; - let canEditTracked3 = await models.ACL.checkAccessForContext({ + const AccessContext = loopBackCtx.AccessContext; + const toFind = { principals: [{ type: 'ROLE', id: 'employee' }], model: 'Sale', property: 'editTracked', - methodNames: array, - accessType: 'READ' + methodNames: ['editTracked'], + accessType: 'WRITE' + }; + const newContext = new AccessContext(toFind); + newContext.methodNames = ['editTracked']; + + let canEditTracked3 = await models.ACL.checkAccessForContext(newContext); + + let canEditTracked4 = await models.ACL.checkAccessForContext({ + principals: [{ + type: 'ROLE', + id: 'developer' + }], + model: 'Sale', + property: 'editTracked', + methodName: 'editTracked', + methodNames: ['editTracked'], + accessType: 'WRITE' }); - console.log(canEditTracked3); + // console.log(canEditTracked); // canEditTracked = await models.ACL.resolvePermission(canEditTracked); // let canEditCloned = await models.ACL.checkPermission('ROLE', 'employee', 'Sale', 'editCloned', '*'); // let canEditWeekly = await models.ACL.checkPermission('ROLE', 'employee', 'Ticket', 'editWeekly', '*'); // console.log(canEditTracked, canEditTracked2); - console.log(canEditTracked3); + console.log('DENY: ', canEditTracked3.permission); + console.log('ALLOW: ', canEditTracked4.permission); const shouldEditTracked = canEditTracked || !hasSaleTracking; const shouldEditCloned = canEditCloned || !hasSaleCloned; const shouldEditWeekly = canEditWeekly || !isTicketWeekly; From 9d53360d50881ef016ab82d82753f9a538cf3c43 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 19 Oct 2022 13:59:57 +0200 Subject: [PATCH 29/69] feat: replaced await by recursive function --- .../front/index/global-invoicing/index.js | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index ef05c77843..46732cb669 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -50,15 +50,32 @@ class Controller extends Dialog { this.$.invoiceButton.disabled = false; } - invoice() { + invoiceOut(invoice, clientsAndAddresses) { const clientAndAddress = clientsAndAddresses[this.pos]; - return this.post(`InvoiceOuts/globalInvoicing`, params, options).then(() => { - this.pos++; - this.invoice(); - }); + if (!clientAndAddress) return; + this.currentClientId = clientAndAddress.clientId; + const params = { + clientId: clientAndAddress.clientId, + addressId: clientAndAddress.addressId, + invoiceDate: invoice.invoiceDate, + maxShipped: invoice.maxShipped, + companyFk: invoice.companyFk, + minShipped: invoice.minShipped, + + }; + this.canceler = this.$q.defer(); + const options = { + timeout: this.canceler.promise + }; + + return this.$http.post(`InvoiceOuts/globalInvoicing`, params, options) + .then(() => { + this.pos++; + return this.invoiceOut(invoice, clientsAndAddresses); + }); } - async responseHandler(response) { + responseHandler(response) { try { if (response !== 'accept') return super.responseHandler(response); @@ -77,33 +94,14 @@ class Controller extends Dialog { this.$.invoiceButton.disabled = true; if (this.clientsNumber == 'allClients') this.getMaxClientId(); - this.pos = 0; - this.invoice(); - this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) - .then(async res => { + .then(res => { const invoice = res.data.invoice; const clientsAndAddresses = res.data.clientsAndAddresses; if (!clientsAndAddresses.length) return super.responseHandler(response); this.lastClientId = clientsAndAddresses[clientsAndAddresses.length - 1].clientId; - - for (let clientAndAddress of clientsAndAddresses) { - this.currentClientId = clientAndAddress.clientId; - const params = { - clientId: clientAndAddress.clientId, - addressId: clientAndAddress.addressId, - invoiceDate: invoice.invoiceDate, - maxShipped: invoice.maxShipped, - companyFk: invoice.companyFk, - minShipped: invoice.minShipped, - - }; - this.canceler = this.$q.defer(); - const options = { - timeout: this.canceler.promise - }; - await this.$http.post(`InvoiceOuts/globalInvoicing`, params, options).then(); - } + this.pos = 0; + return this.invoiceOut(invoice, clientsAndAddresses); }) .then(() => super.responseHandler(response)) .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) From abd2d9a849ba76366f3b7c59f5c580d9fc2c43c8 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 19 Oct 2022 15:10:43 +0200 Subject: [PATCH 30/69] fix: e2e --- e2e/helpers/selectors.js | 1 + e2e/paths/09-invoice-out/04_globalInvoice.spec.js | 12 ++++++++++++ .../front/index/global-invoicing/index.spec.js | 8 -------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index cd6d39795b..a678da5839 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -954,6 +954,7 @@ export default { manualInvoiceTaxArea: 'vn-autocomplete[ng-model="$ctrl.invoice.taxArea"]', saveInvoice: 'button[response="accept"]', globalInvoiceForm: '.vn-invoice-out-global-invoicing', + globalInvoiceClientsRange: 'vn-radio[val="clientsRange"]', globalInvoiceDate: '[ng-model="$ctrl.invoice.invoiceDate"]', globalInvoiceFromClient: '[ng-model="$ctrl.invoice.fromClientId"]', globalInvoiceToClient: '[ng-model="$ctrl.invoice.toClientId"]', diff --git a/e2e/paths/09-invoice-out/04_globalInvoice.spec.js b/e2e/paths/09-invoice-out/04_globalInvoice.spec.js index b62c889db1..74efafd2da 100644 --- a/e2e/paths/09-invoice-out/04_globalInvoice.spec.js +++ b/e2e/paths/09-invoice-out/04_globalInvoice.spec.js @@ -33,6 +33,7 @@ describe('InvoiceOut global invoice path', () => { it('should create a global invoice for charles xavier today', async() => { await page.pickDate(selectors.invoiceOutIndex.globalInvoiceDate); + await page.waitToClick(selectors.invoiceOutIndex.globalInvoiceClientsRange); await page.autocompleteSearch(selectors.invoiceOutIndex.globalInvoiceFromClient, 'Petter Parker'); await page.autocompleteSearch(selectors.invoiceOutIndex.globalInvoiceToClient, 'Petter Parker'); await page.waitToClick(selectors.invoiceOutIndex.saveInvoice); @@ -48,4 +49,15 @@ describe('InvoiceOut global invoice path', () => { expect(currentInvoices).toBeGreaterThan(invoicesBefore); }); + + it('should create a global invoice for all clients today', async() => { + await page.waitToClick(selectors.invoiceOutIndex.createInvoice); + await page.waitToClick(selectors.invoiceOutIndex.createGlobalInvoice); + await page.waitForSelector(selectors.invoiceOutIndex.globalInvoiceForm); + await page.pickDate(selectors.invoiceOutIndex.globalInvoiceDate); + await page.waitToClick(selectors.invoiceOutIndex.saveInvoice); + const message = await page.waitForSnackbar(); + + expect(message.text).toContain('Data saved!'); + }); }); diff --git a/modules/invoiceOut/front/index/global-invoicing/index.spec.js b/modules/invoiceOut/front/index/global-invoicing/index.spec.js index 1e5ed3a998..6e3721f9e8 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.spec.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.spec.js @@ -108,14 +108,6 @@ describe('InvoiceOut', () => { clientsAndAddresses: [{clientId: 1101, addressId: 121}], invoice: controller.invoice }; - const expectedParams = { - clientId: 1101, - addressId: 121, - invoiceDate: new Date(), - maxShipped: new Date(), - companyFk: 442, - minShipped: minShipped - }; const serializedParams = $httpParamSerializer({filter}); $httpBackend.expectGET(`Clients/findOne?${serializedParams}`).respond(200, {id: 1112}); From 39f4445172f9f3487e7884c7f120087d760664c1 Mon Sep 17 00:00:00 2001 From: vicent Date: Thu, 20 Oct 2022 07:23:57 +0200 Subject: [PATCH 31/69] refator: endpoint name --- db/changes/10491-august/00-aclInvoiceOut.sql | 6 +++++- .../invoiceOut/{globalInvoicing.js => invoiceClient.js} | 6 +++--- .../{globalInvoicing.spec.js => invoiceClient.spec.js} | 4 ++-- modules/invoiceOut/back/models/invoice-out.js | 2 +- modules/invoiceOut/front/index/global-invoicing/index.js | 2 +- .../invoiceOut/front/index/global-invoicing/index.spec.js | 2 +- 6 files changed, 13 insertions(+), 9 deletions(-) rename modules/invoiceOut/back/methods/invoiceOut/{globalInvoicing.js => invoiceClient.js} (97%) rename modules/invoiceOut/back/methods/invoiceOut/specs/{globalInvoicing.spec.js => invoiceClient.spec.js} (91%) diff --git a/db/changes/10491-august/00-aclInvoiceOut.sql b/db/changes/10491-august/00-aclInvoiceOut.sql index b129b72018..bc2b87cdb3 100644 --- a/db/changes/10491-august/00-aclInvoiceOut.sql +++ b/db/changes/10491-august/00-aclInvoiceOut.sql @@ -1,3 +1,7 @@ INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES - ('InvoiceOut', 'clientToInvoice', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'); \ No newline at end of file + ('InvoiceOut', 'clientToInvoice', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'); + +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('InvoiceOut', 'invoiceClient', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'); \ No newline at end of file diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js similarity index 97% rename from modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js rename to modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js index d74199799a..ec32443446 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js @@ -1,5 +1,5 @@ module.exports = Self => { - Self.remoteMethodCtx('globalInvoicing', { + Self.remoteMethodCtx('invoiceClient', { description: 'Make a invoice of a client', accessType: 'WRITE', accepts: [{ @@ -43,12 +43,12 @@ module.exports = Self => { root: true }, http: { - path: '/globalInvoicing', + path: '/invoiceClient', verb: 'POST' } }); - Self.globalInvoicing = async(ctx, options) => { + Self.invoiceClient = async(ctx, options) => { const args = ctx.args; const models = Self.app.models; const myOptions = {}; diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js similarity index 91% rename from modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js rename to modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js index 3f359dfb57..f1f9b70372 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js @@ -1,6 +1,6 @@ const models = require('vn-loopback/server/server').models; -describe('InvoiceOut globalInvoicing()', () => { +describe('InvoiceOut invoiceClient()', () => { const userId = 1; const clientId = 1101; const addressId = 121; @@ -34,7 +34,7 @@ describe('InvoiceOut globalInvoicing()', () => { companyFk: companyFk, minShipped: minShipped }; - const invoiceOutId = await models.InvoiceOut.globalInvoicing(ctx, options); + const invoiceOutId = await models.InvoiceOut.invoiceClient(ctx, options); const invoiceOut = await models.InvoiceOut.findById(invoiceOutId, null, options); const [firstTicket] = await models.Ticket.find({ where: {refFk: invoiceOut.ref} diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index 7ac1246cfc..20d9af9391 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -8,7 +8,7 @@ module.exports = Self => { require('../methods/invoiceOut/createPdf')(Self); require('../methods/invoiceOut/createManualInvoice')(Self); require('../methods/invoiceOut/clientToInvoice')(Self); - require('../methods/invoiceOut/globalInvoicing')(Self); + require('../methods/invoiceOut/invoiceClient')(Self); require('../methods/invoiceOut/refund')(Self); require('../methods/invoiceOut/invoiceEmail')(Self); require('../methods/invoiceOut/exportationPdf')(Self); diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index 46732cb669..ffd5484e42 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -68,7 +68,7 @@ class Controller extends Dialog { timeout: this.canceler.promise }; - return this.$http.post(`InvoiceOuts/globalInvoicing`, params, options) + return this.$http.post(`InvoiceOuts/invoiceClient`, params, options) .then(() => { this.pos++; return this.invoiceOut(invoice, clientsAndAddresses); diff --git a/modules/invoiceOut/front/index/global-invoicing/index.spec.js b/modules/invoiceOut/front/index/global-invoicing/index.spec.js index 6e3721f9e8..04ea99e375 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.spec.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.spec.js @@ -112,7 +112,7 @@ describe('InvoiceOut', () => { const serializedParams = $httpParamSerializer({filter}); $httpBackend.expectGET(`Clients/findOne?${serializedParams}`).respond(200, {id: 1112}); $httpBackend.expect('POST', `InvoiceOuts/clientToInvoice`).respond(response); - $httpBackend.expect('POST', `InvoiceOuts/globalInvoicing`).respond({id: 1}); + $httpBackend.expect('POST', `InvoiceOuts/invoiceClient`).respond({id: 1}); controller.responseHandler('accept'); $httpBackend.flush(); From 2c98563cfabb8994a99e3ecbcc10e6f435ad8da8 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Thu, 20 Oct 2022 07:39:33 +0200 Subject: [PATCH 32/69] Add buttons to bottom-right --- modules/route/front/index/index.html | 50 +++++++++++++++------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/modules/route/front/index/index.html b/modules/route/front/index/index.html index 7a64a9affe..b3e520aead 100644 --- a/modules/route/front/index/index.html +++ b/modules/route/front/index/index.html @@ -7,29 +7,6 @@ model="model" options="$ctrl.smartTableOptions" expr-builder="$ctrl.exprBuilder(param, value)"> - -
- - - - - - - -
-
@@ -190,6 +167,33 @@ tooltip-position="left"> + + + + + + + + + + + + From 53112995bcf8223955ee1b254ba842ff9c7c7bf3 Mon Sep 17 00:00:00 2001 From: vicent Date: Thu, 20 Oct 2022 07:58:38 +0200 Subject: [PATCH 33/69] refactor: delete counter --- modules/invoiceOut/front/index/global-invoicing/index.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index ffd5484e42..1390f52e88 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -51,7 +51,7 @@ class Controller extends Dialog { } invoiceOut(invoice, clientsAndAddresses) { - const clientAndAddress = clientsAndAddresses[this.pos]; + const [clientAndAddress] = clientsAndAddresses; if (!clientAndAddress) return; this.currentClientId = clientAndAddress.clientId; const params = { @@ -70,7 +70,7 @@ class Controller extends Dialog { return this.$http.post(`InvoiceOuts/invoiceClient`, params, options) .then(() => { - this.pos++; + clientsAndAddresses.shift(); return this.invoiceOut(invoice, clientsAndAddresses); }); } @@ -100,7 +100,6 @@ class Controller extends Dialog { const clientsAndAddresses = res.data.clientsAndAddresses; if (!clientsAndAddresses.length) return super.responseHandler(response); this.lastClientId = clientsAndAddresses[clientsAndAddresses.length - 1].clientId; - this.pos = 0; return this.invoiceOut(invoice, clientsAndAddresses); }) .then(() => super.responseHandler(response)) From 8cbcb197bbd75b69c5f3aff54393725205a883e7 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Thu, 20 Oct 2022 08:14:11 +0200 Subject: [PATCH 34/69] fix downloadPDF wrong method --- modules/route/front/index/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/route/front/index/index.html b/modules/route/front/index/index.html index b3e520aead..cc76d22f21 100644 --- a/modules/route/front/index/index.html +++ b/modules/route/front/index/index.html @@ -180,7 +180,7 @@ From 28bd535e2b2590d665ba95d81a607aceddc54cbb Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Thu, 20 Oct 2022 15:04:25 +0200 Subject: [PATCH 35/69] Implemented SMS to route clients --- modules/route/back/methods/route/sendSms.js | 46 +++++++++++++ modules/route/back/models/route.js | 1 + modules/route/front/index.js | 1 + modules/route/front/index/index.html | 30 +++++++-- modules/route/front/index/index.js | 60 +++++++++++++++++ modules/route/front/index/locale/es.yml | 4 +- modules/route/front/sms/index.html | 45 +++++++++++++ modules/route/front/sms/index.js | 47 ++++++++++++++ modules/route/front/sms/index.spec.js | 71 +++++++++++++++++++++ modules/route/front/sms/locale/es.yml | 9 +++ modules/route/front/sms/style.scss | 5 ++ 11 files changed, 311 insertions(+), 8 deletions(-) create mode 100644 modules/route/back/methods/route/sendSms.js create mode 100644 modules/route/front/sms/index.html create mode 100644 modules/route/front/sms/index.js create mode 100644 modules/route/front/sms/index.spec.js create mode 100644 modules/route/front/sms/locale/es.yml create mode 100644 modules/route/front/sms/style.scss diff --git a/modules/route/back/methods/route/sendSms.js b/modules/route/back/methods/route/sendSms.js new file mode 100644 index 0000000000..9a93b040ef --- /dev/null +++ b/modules/route/back/methods/route/sendSms.js @@ -0,0 +1,46 @@ +/* eslint-disable no-console */ + +module.exports = Self => { + Self.remoteMethodCtx('sendSms', { + description: 'Sends a SMS to each client of the routes, each client only recieves the SMS once', + accessType: 'WRITE', + accepts: [{ + arg: 'id', + type: 'string', + required: true, + description: 'The routes Ids, is separated by commas', + http: {source: 'path'} + }, + { + arg: 'destination', + type: 'string', + description: 'A comma separated string of destinations', + required: true, + }, + { + arg: 'message', + type: 'string', + required: true, + }], + returns: { + type: 'object', + root: true + }, + http: { + path: `/:id/sendSms`, + verb: 'POST' + } + }); + + Self.sendSms = async(ctx, id, destination, message) => { + const targetClients = destination.split(','); + + const allSms = []; + for (let client of targetClients) { + let sms = await Self.app.models.Sms.send(ctx, client, message); + allSms.push(sms); + } + + return allSms; + }; +}; diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js index f5406728a9..08cabd30eb 100644 --- a/modules/route/back/models/route.js +++ b/modules/route/back/models/route.js @@ -12,6 +12,7 @@ module.exports = Self => { require('../methods/route/updateWorkCenter')(Self); require('../methods/route/driverRoutePdf')(Self); require('../methods/route/driverRouteEmail')(Self); + require('../methods/route/sendSms')(Self); Self.validate('kmStart', validateDistance, { message: 'Distance must be lesser than 1000' diff --git a/modules/route/front/index.js b/modules/route/front/index.js index 55cb745e1c..c43048df5a 100644 --- a/modules/route/front/index.js +++ b/modules/route/front/index.js @@ -15,3 +15,4 @@ import './agency-term/index'; import './agency-term/createInvoiceIn'; import './agency-term-search-panel'; import './ticket-popup'; +import './sms'; diff --git a/modules/route/front/index/index.html b/modules/route/front/index/index.html index cc76d22f21..e9785d9582 100644 --- a/modules/route/front/index/index.html +++ b/modules/route/front/index/index.html @@ -160,13 +160,6 @@ + + + + + e === ticket.clientFk).length > 0) + clientsFk.push(ticket.clientFk); + } + + for (let client of clientsFk) { + let currentClient = await this.$http.get(`Clients/${client}`); + clients.push(currentClient.data); + } + + let destination = ''; + let destinationFk = ''; + let routesId = ''; + + for (let client of clients) { + if (destination !== '') + destination = destination + ','; + if (destinationFk !== '') + destinationFk = destinationFk + ','; + destination = destination + client.phone; + destinationFk = destinationFk + client.id; + } + + for (let route of routes) { + if (routesId !== '') + routesId = routesId + ','; + routesId = routesId + route; + } + this.newSMS = Object.assign({ + routesId: routesId, + destinationFk: destinationFk, + destination: destination + }); + + this.$.sms.open(); + return true; + } catch (e) { + this.vnApp.showError(this.$t(e.message)); + return false; + } + } } Controller.$inject = ['$element', '$scope', 'vnReport']; diff --git a/modules/route/front/index/locale/es.yml b/modules/route/front/index/locale/es.yml index e4c5c8c55e..3db84d81e1 100644 --- a/modules/route/front/index/locale/es.yml +++ b/modules/route/front/index/locale/es.yml @@ -8,4 +8,6 @@ Hour finished: Hora fin Go to route: Ir a la ruta You must select a valid time: Debe seleccionar una hora válida You must select a valid date: Debe seleccionar una fecha válida -Mark as served: Marcar como servidas \ No newline at end of file +Mark as served: Marcar como servidas +Retrieving data from the routes: Recuperando datos de las rutas +Send SMS to all clients: Mandar sms a todos los clientes de las rutas \ No newline at end of file diff --git a/modules/route/front/sms/index.html b/modules/route/front/sms/index.html new file mode 100644 index 0000000000..4f86b346fd --- /dev/null +++ b/modules/route/front/sms/index.html @@ -0,0 +1,45 @@ + + +
+ + + + + + + + {{'Characters remaining' | translate}}: + + {{$ctrl.charactersRemaining()}} + + + +
+
+ + + + +
\ No newline at end of file diff --git a/modules/route/front/sms/index.js b/modules/route/front/sms/index.js new file mode 100644 index 0000000000..7013060716 --- /dev/null +++ b/modules/route/front/sms/index.js @@ -0,0 +1,47 @@ +import ngModule from '../module'; +import Component from 'core/lib/component'; +import './style.scss'; + +class Controller extends Component { + open() { + this.$.SMSDialog.show(); + } + + charactersRemaining() { + const element = this.$.message; + const value = element.input.value; + + const maxLength = 160; + const textAreaLength = new Blob([value]).size; + return maxLength - textAreaLength; + } + + onResponse() { + try { + if (!this.sms.destination) + throw new Error(`The destination can't be empty`); + if (!this.sms.message) + throw new Error(`The message can't be empty`); + if (this.charactersRemaining() < 0) + throw new Error(`The message it's too long`); + + this.$http.post(`Routes/${this.sms.routesId}/sendSms`, this.sms).then(res => { + this.vnApp.showMessage(this.$t('SMS sent!')); + + if (res.data) this.emit('send', {response: res.data}); + }); + } catch (e) { + this.vnApp.showError(this.$t(e.message)); + return false; + } + return true; + } +} + +ngModule.vnComponent('vnRouteSms', { + template: require('./index.html'), + controller: Controller, + bindings: { + sms: '<', + } +}); diff --git a/modules/route/front/sms/index.spec.js b/modules/route/front/sms/index.spec.js new file mode 100644 index 0000000000..b133db04dd --- /dev/null +++ b/modules/route/front/sms/index.spec.js @@ -0,0 +1,71 @@ +import './index'; + +describe('Ticket', () => { + describe('Component vnTicketSms', () => { + let controller; + let $httpBackend; + + beforeEach(ngModule('ticket')); + + beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => { + $httpBackend = _$httpBackend_; + let $scope = $rootScope.$new(); + const $element = angular.element(''); + controller = $componentController('vnTicketSms', {$element, $scope}); + controller.$.message = { + input: { + value: 'My SMS' + } + }; + })); + + describe('onResponse()', () => { + it('should perform a POST query and show a success snackbar', () => { + let params = {ticketId: 11, destinationFk: 1101, destination: 111111111, message: 'My SMS'}; + controller.sms = {ticketId: 11, destinationFk: 1101, destination: 111111111, message: 'My SMS'}; + + jest.spyOn(controller.vnApp, 'showMessage'); + $httpBackend.expect('POST', `Tickets/11/sendSms`, params).respond(200, params); + + controller.onResponse(); + $httpBackend.flush(); + + expect(controller.vnApp.showMessage).toHaveBeenCalledWith('SMS sent!'); + }); + + it('should call onResponse without the destination and show an error snackbar', () => { + controller.sms = {destinationFk: 1101, message: 'My SMS'}; + + jest.spyOn(controller.vnApp, 'showError'); + + controller.onResponse(); + + expect(controller.vnApp.showError).toHaveBeenCalledWith(`The destination can't be empty`); + }); + + it('should call onResponse without the message and show an error snackbar', () => { + controller.sms = {destinationFk: 1101, destination: 222222222}; + + jest.spyOn(controller.vnApp, 'showError'); + + controller.onResponse(); + + expect(controller.vnApp.showError).toHaveBeenCalledWith(`The message can't be empty`); + }); + }); + + describe('charactersRemaining()', () => { + it('should return the characters remaining in a element', () => { + controller.$.message = { + input: { + value: 'My message 0€' + } + }; + + let result = controller.charactersRemaining(); + + expect(result).toEqual(145); + }); + }); + }); +}); diff --git a/modules/route/front/sms/locale/es.yml b/modules/route/front/sms/locale/es.yml new file mode 100644 index 0000000000..4d60229213 --- /dev/null +++ b/modules/route/front/sms/locale/es.yml @@ -0,0 +1,9 @@ +Send SMS: Enviar SMS +Routes to notify: Rutas a notificar +Message: Mensaje +SMS sent!: ¡SMS enviado! +Characters remaining: Carácteres restantes +The destination can't be empty: El destinatario no puede estar vacio +The message can't be empty: El mensaje no puede estar vacio +The message it's too long: El mensaje es demasiado largo +Special characters like accents counts as a multiple: Carácteres especiales como los acentos cuentan como varios \ No newline at end of file diff --git a/modules/route/front/sms/style.scss b/modules/route/front/sms/style.scss new file mode 100644 index 0000000000..84571a5f42 --- /dev/null +++ b/modules/route/front/sms/style.scss @@ -0,0 +1,5 @@ +@import "variables"; + +.SMSDialog { + min-width: 400px +} \ No newline at end of file From ca53ec7c238a5cd2bc3f8807504063acd9126a33 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Thu, 20 Oct 2022 15:04:59 +0200 Subject: [PATCH 36/69] Changed the location of the function --- modules/route/back/methods/route/sendSms.js | 34 +++++------ modules/route/front/index/index.html | 66 +++++++-------------- modules/route/front/index/index.js | 60 ------------------- modules/route/front/sms/index.html | 13 +--- modules/route/front/sms/index.js | 2 +- modules/route/front/sms/locale/es.yml | 2 +- modules/route/front/tickets/index.html | 39 ++++++++---- modules/route/front/tickets/index.js | 31 ++++++++++ 8 files changed, 99 insertions(+), 148 deletions(-) diff --git a/modules/route/back/methods/route/sendSms.js b/modules/route/back/methods/route/sendSms.js index 9a93b040ef..fe881abd54 100644 --- a/modules/route/back/methods/route/sendSms.js +++ b/modules/route/back/methods/route/sendSms.js @@ -4,35 +4,29 @@ module.exports = Self => { Self.remoteMethodCtx('sendSms', { description: 'Sends a SMS to each client of the routes, each client only recieves the SMS once', accessType: 'WRITE', - accepts: [{ - arg: 'id', - type: 'string', - required: true, - description: 'The routes Ids, is separated by commas', - http: {source: 'path'} - }, - { - arg: 'destination', - type: 'string', - description: 'A comma separated string of destinations', - required: true, - }, - { - arg: 'message', - type: 'string', - required: true, - }], + accepts: [ + { + arg: 'destination', + type: 'string', + description: 'A comma separated string of destinations', + required: true, + }, + { + arg: 'message', + type: 'string', + required: true, + }], returns: { type: 'object', root: true }, http: { - path: `/:id/sendSms`, + path: `/sendSms`, verb: 'POST' } }); - Self.sendSms = async(ctx, id, destination, message) => { + Self.sendSms = async(ctx, destination, message) => { const targetClients = destination.split(','); const allSms = []; diff --git a/modules/route/front/index/index.html b/modules/route/front/index/index.html index e9785d9582..7a64a9affe 100644 --- a/modules/route/front/index/index.html +++ b/modules/route/front/index/index.html @@ -7,6 +7,29 @@ model="model" options="$ctrl.smartTableOptions" expr-builder="$ctrl.exprBuilder(param, value)"> + +
+ + + + + + + +
+
@@ -160,42 +183,6 @@ - - - - - e === ticket.clientFk).length > 0) - clientsFk.push(ticket.clientFk); - } - - for (let client of clientsFk) { - let currentClient = await this.$http.get(`Clients/${client}`); - clients.push(currentClient.data); - } - - let destination = ''; - let destinationFk = ''; - let routesId = ''; - - for (let client of clients) { - if (destination !== '') - destination = destination + ','; - if (destinationFk !== '') - destinationFk = destinationFk + ','; - destination = destination + client.phone; - destinationFk = destinationFk + client.id; - } - - for (let route of routes) { - if (routesId !== '') - routesId = routesId + ','; - routesId = routesId + route; - } - this.newSMS = Object.assign({ - routesId: routesId, - destinationFk: destinationFk, - destination: destination - }); - - this.$.sms.open(); - return true; - } catch (e) { - this.vnApp.showError(this.$t(e.message)); - return false; - } - } } Controller.$inject = ['$element', '$scope', 'vnReport']; diff --git a/modules/route/front/sms/index.html b/modules/route/front/sms/index.html index 4f86b346fd..0d7dd7c112 100644 --- a/modules/route/front/sms/index.html +++ b/modules/route/front/sms/index.html @@ -1,19 +1,10 @@ + message="Send SMS to the selected tickets">
- - + { + this.$http.post(`Routes/sendSms`, this.sms).then(res => { this.vnApp.showMessage(this.$t('SMS sent!')); if (res.data) this.emit('send', {response: res.data}); diff --git a/modules/route/front/sms/locale/es.yml b/modules/route/front/sms/locale/es.yml index 4d60229213..0168a6eb69 100644 --- a/modules/route/front/sms/locale/es.yml +++ b/modules/route/front/sms/locale/es.yml @@ -1,4 +1,4 @@ -Send SMS: Enviar SMS +Send SMS to the selected tickets: Enviar SMS a los tickets seleccionados Routes to notify: Rutas a notificar Message: Mensaje SMS sent!: ¡SMS enviado! diff --git a/modules/route/front/tickets/index.html b/modules/route/front/tickets/index.html index 1f91276e7e..29f5cd8610 100644 --- a/modules/route/front/tickets/index.html +++ b/modules/route/front/tickets/index.html @@ -29,13 +29,18 @@ disabled="!$ctrl.isChecked" ng-click="$ctrl.deletePriority()" vn-tooltip="Delete priority" - icon="filter_alt_off"> + icon="filter_alt"> + + @@ -149,19 +154,29 @@ route="$ctrl.$params" parent-reload="$ctrl.$.model.refresh()"> - - - + - \ No newline at end of file + + + + \ No newline at end of file diff --git a/modules/route/front/tickets/index.js b/modules/route/front/tickets/index.js index e78d9b8b78..80f8ad4f4d 100644 --- a/modules/route/front/tickets/index.js +++ b/modules/route/front/tickets/index.js @@ -161,6 +161,37 @@ class Controller extends Section { throw error; }); } + + async sendSms() { + try { + const clientsFk = []; + const clientsName = []; + const clients = []; + + const selectedTickets = this.getSelectedItems(this.$.$ctrl.tickets); + + for (let ticket of selectedTickets) { + clientsFk.push(ticket.clientFk); + let userContact = await this.$http.get(`Clients/${ticket.clientFk}`); + clientsName.push(userContact.data.name); + clients.push(userContact.data.phone); + } + + const destinationFk = String(clientsFk); + const destination = String(clients); + + this.newSMS = Object.assign({ + destinationFk: destinationFk, + destination: destination + }); + + this.$.sms.open(); + return true; + } catch (e) { + this.vnApp.showError(this.$t(e.message)); + return false; + } + } } ngModule.vnComponent('vnRouteTickets', { From b06f5b72468622606fa104164d14ce30d038124c Mon Sep 17 00:00:00 2001 From: vicent Date: Fri, 21 Oct 2022 10:06:34 +0200 Subject: [PATCH 37/69] feat: cuando seleccionas 'allClients' no tiene en cuenta el 'clientsRange' --- .../front/index/global-invoicing/index.html | 16 ++++++++++++++-- .../front/index/global-invoicing/index.js | 4 ++-- .../front/index/global-invoicing/locale/es.yml | 3 ++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/modules/invoiceOut/front/index/global-invoicing/index.html b/modules/invoiceOut/front/index/global-invoicing/index.html index 7f96397f55..c2d1c43040 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.html +++ b/modules/invoiceOut/front/index/global-invoicing/index.html @@ -13,7 +13,16 @@ url="Companies" data="companies" order="code"> - + +
+ +
+ {{'Calculating packages to invoice...' | translate}} +
+
+
@@ -40,7 +49,8 @@ + ng-model="$ctrl.clientsNumber" + ng-click="$ctrl.$onInit()"> @@ -62,6 +73,7 @@ url="Clients" label="To client" search-function="{or: [{id: $search}, {name: {like: '%'+$search+'%'}}]}" + order="id" show-field="name" value-field="id" ng-model="$ctrl.invoice.toClientId"> diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index 1390f52e88..39dc311376 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -92,10 +92,10 @@ class Controller extends Dialog { }); this.$.invoiceButton.disabled = true; - if (this.clientsNumber == 'allClients') this.getMaxClientId(); - + this.packageInvoicing = true; this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) .then(res => { + this.packageInvoicing = false; const invoice = res.data.invoice; const clientsAndAddresses = res.data.clientsAndAddresses; if (!clientsAndAddresses.length) return super.responseHandler(response); diff --git a/modules/invoiceOut/front/index/global-invoicing/locale/es.yml b/modules/invoiceOut/front/index/global-invoicing/locale/es.yml index 8ac2cc13a2..af151684f0 100644 --- a/modules/invoiceOut/front/index/global-invoicing/locale/es.yml +++ b/modules/invoiceOut/front/index/global-invoicing/locale/es.yml @@ -10,4 +10,5 @@ Choose a valid clients range: Selecciona un rango válido de clientes of: de Id Client: Id Cliente All clients: Todos los clientes -Clients range: Rango de clientes \ No newline at end of file +Clients range: Rango de clientes +Calculating packages to invoice...: Calculando paquetes a factura... \ No newline at end of file From 0f57a40aac1831c0b3a35b4d4f459a87e030ad09 Mon Sep 17 00:00:00 2001 From: vicent Date: Fri, 21 Oct 2022 10:50:18 +0200 Subject: [PATCH 38/69] fix: backTest --- .../invoiceOut/front/index/global-invoicing/index.spec.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/invoiceOut/front/index/global-invoicing/index.spec.js b/modules/invoiceOut/front/index/global-invoicing/index.spec.js index 04ea99e375..7dcc51e590 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.spec.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.spec.js @@ -87,10 +87,7 @@ describe('InvoiceOut', () => { it('should make an http POST query and then call to the showSuccess() method', () => { jest.spyOn(controller.vnApp, 'showSuccess'); - const filter = { - order: 'id DESC', - limit: 1 - }; + const minShipped = new Date(); minShipped.setFullYear(minShipped.getFullYear() - 1); minShipped.setMonth(1); @@ -109,8 +106,6 @@ describe('InvoiceOut', () => { invoice: controller.invoice }; - const serializedParams = $httpParamSerializer({filter}); - $httpBackend.expectGET(`Clients/findOne?${serializedParams}`).respond(200, {id: 1112}); $httpBackend.expect('POST', `InvoiceOuts/clientToInvoice`).respond(response); $httpBackend.expect('POST', `InvoiceOuts/invoiceClient`).respond({id: 1}); controller.responseHandler('accept'); From 5bf425d8e351724463338ea536f94e8fc25cfa58 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Mon, 24 Oct 2022 08:22:04 +0200 Subject: [PATCH 39/69] Front test and sms require client #4157 @1h30m --- modules/route/front/sms/index.spec.js | 14 +++++++------- modules/route/front/tickets/index.html | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/route/front/sms/index.spec.js b/modules/route/front/sms/index.spec.js index b133db04dd..42bf309315 100644 --- a/modules/route/front/sms/index.spec.js +++ b/modules/route/front/sms/index.spec.js @@ -1,17 +1,17 @@ import './index'; -describe('Ticket', () => { - describe('Component vnTicketSms', () => { +describe('Route', () => { + describe('Component vnRouteSms', () => { let controller; let $httpBackend; - beforeEach(ngModule('ticket')); + beforeEach(ngModule('route')); beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => { $httpBackend = _$httpBackend_; let $scope = $rootScope.$new(); const $element = angular.element(''); - controller = $componentController('vnTicketSms', {$element, $scope}); + controller = $componentController('vnRouteSms', {$element, $scope}); controller.$.message = { input: { value: 'My SMS' @@ -21,11 +21,11 @@ describe('Ticket', () => { describe('onResponse()', () => { it('should perform a POST query and show a success snackbar', () => { - let params = {ticketId: 11, destinationFk: 1101, destination: 111111111, message: 'My SMS'}; - controller.sms = {ticketId: 11, destinationFk: 1101, destination: 111111111, message: 'My SMS'}; + let params = {destinationFk: 1101, destination: 111111111, message: 'My SMS'}; + controller.sms = {destinationFk: 1101, destination: 111111111, message: 'My SMS'}; jest.spyOn(controller.vnApp, 'showMessage'); - $httpBackend.expect('POST', `Tickets/11/sendSms`, params).respond(200, params); + $httpBackend.expect('POST', `Routes/sendSms`, params).respond(200, params); controller.onResponse(); $httpBackend.flush(); diff --git a/modules/route/front/tickets/index.html b/modules/route/front/tickets/index.html index 29f5cd8610..a3d65772ad 100644 --- a/modules/route/front/tickets/index.html +++ b/modules/route/front/tickets/index.html @@ -37,6 +37,7 @@ icon="format_list_numbered"> From 3cfa56d610f3558ce8212475bdbd75ac22ef5cdb Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Tue, 25 Oct 2022 13:15:19 +0200 Subject: [PATCH 40/69] Add deliveryBoss ACL to the front --- modules/route/front/tickets/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/route/front/tickets/index.html b/modules/route/front/tickets/index.html index a3d65772ad..dae894ac77 100644 --- a/modules/route/front/tickets/index.html +++ b/modules/route/front/tickets/index.html @@ -37,6 +37,8 @@ icon="format_list_numbered"> Date: Tue, 25 Oct 2022 15:02:22 +0200 Subject: [PATCH 41/69] try --- db/changes/10491-august/00-editTrackedACL.sql | 2 +- modules/ticket/back/methods/sale/canEdit.js | 29 ++++++++----------- package.json | 2 +- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/db/changes/10491-august/00-editTrackedACL.sql b/db/changes/10491-august/00-editTrackedACL.sql index 37d24ac814..97394fffe0 100644 --- a/db/changes/10491-august/00-editTrackedACL.sql +++ b/db/changes/10491-august/00-editTrackedACL.sql @@ -1,3 +1,3 @@ INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES - ('Sale', 'editTracked', 'READ', 'ALLOW', 'ROLE', 'production'); + ('Sale', 'editTracked', 'WRITE', 'ALLOW', 'ROLE', 'production'); diff --git a/modules/ticket/back/methods/sale/canEdit.js b/modules/ticket/back/methods/sale/canEdit.js index 4992a34990..7a8523fb7f 100644 --- a/modules/ticket/back/methods/sale/canEdit.js +++ b/modules/ticket/back/methods/sale/canEdit.js @@ -27,25 +27,20 @@ module.exports = Self => { if (typeof options == 'object') Object.assign(myOptions, options); - const firstSale = await models.Sale.findById(sales[0], null, myOptions); - const isTicketEditable = await models.Ticket.isEditable(ctx, firstSale.ticketFk, myOptions); - if (!isTicketEditable) - throw new UserError(`The sales of this ticket can't be modified`); + console.log(ctx.req.accessToken); + const token = ctx.req.accessToken; + let canEditTracked = await models.ACL.checkAccessForToken(token, models.Sale, null, 'refund'); + // const newCtx = ctx; + // newCtx.property = 'refund'; + // newCtx.accessType = 'WRITE'; + // newCtx.methodNames = ['refund']; + // newCtx.model = await models.Sale; - const saleTracking = await models.SaleTracking.find({where: {saleFk: {inq: sales}}}, myOptions); - const hasSaleTracking = saleTracking.length; - - const saleCloned = await models.SaleCloned.find({where: {saleClonedFk: {inq: sales}}}, myOptions); - const hasSaleCloned = saleCloned.length; - - const isTicketWeekly = - await models.TicketWeekly.findOne({where: {ticketFk: firstSale.ticketFk}}, myOptions); - - // (principalType, principalId,model, property, accessType,callback); - // let canEditTracked = await models.ACL.checkPermission('ROLE', 'employee', 'Sale', 'editTracked', 'WRITE'); + // let canEditTracked = await models.ACL.checkAccessForContext(newCtx); + console.log(canEditTracked); // let canEditTracked2 = await models.ACL.checkPermission('USER', 'developer', 'Sale', 'editTracked', 'READ'); - const array = ['editTracked']; + /* const array = ['editTracked']; const AccessContext = loopBackCtx.AccessContext; const toFind = { principals: [{ @@ -90,6 +85,6 @@ module.exports = Self => { if (canEdit) return true; - return false; + return false;*/ }; }; diff --git a/package.json b/package.json index 26c164832a..abf7c9e4b1 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "jsdom": "^16.7.0", "jszip": "^3.10.0", "ldapjs": "^2.2.0", - "loopback": "^3.26.0", + "loopback": "^3.28.0", "loopback-boot": "3.3.1", "loopback-component-explorer": "^6.5.0", "loopback-component-storage": "3.6.1", From 350c516bb12c5589ca9cc9e96a67d4a2f779ca36 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 26 Oct 2022 10:36:41 +0200 Subject: [PATCH 42/69] =?UTF-8?q?feat:=20cancelar=20petici=C3=B3n=20cuando?= =?UTF-8?q?=20esta=20calculando=20el=20packaging?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/changes/10491-august/00-aclInvoiceOut.sql | 2 +- .../{clientToInvoice.js => clientsToInvoice.js} | 6 +++--- modules/invoiceOut/back/models/invoice-out.js | 2 +- .../front/index/global-invoicing/index.js | 15 ++++++++++----- .../front/index/global-invoicing/index.spec.js | 2 +- 5 files changed, 16 insertions(+), 11 deletions(-) rename modules/invoiceOut/back/methods/invoiceOut/{clientToInvoice.js => clientsToInvoice.js} (97%) diff --git a/db/changes/10491-august/00-aclInvoiceOut.sql b/db/changes/10491-august/00-aclInvoiceOut.sql index bc2b87cdb3..7715045b54 100644 --- a/db/changes/10491-august/00-aclInvoiceOut.sql +++ b/db/changes/10491-august/00-aclInvoiceOut.sql @@ -1,6 +1,6 @@ INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES - ('InvoiceOut', 'clientToInvoice', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'); + ('InvoiceOut', 'clientsToInvoice', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'); INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES diff --git a/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js similarity index 97% rename from modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js rename to modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js index a0578897a0..d42184ae59 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js +++ b/modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js @@ -1,5 +1,5 @@ module.exports = Self => { - Self.remoteMethodCtx('clientToInvoice', { + Self.remoteMethodCtx('clientsToInvoice', { description: 'Get the clients to make global invoicing', accessType: 'WRITE', accepts: [ @@ -38,12 +38,12 @@ module.exports = Self => { type: 'object' }], http: { - path: '/clientToInvoice', + path: '/clientsToInvoice', verb: 'POST' } }); - Self.clientToInvoice = async(ctx, options) => { + Self.clientsToInvoice = async(ctx, options) => { const args = ctx.args; let tx; const myOptions = {}; diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index 20d9af9391..d363ab8350 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -7,7 +7,7 @@ module.exports = Self => { require('../methods/invoiceOut/book')(Self); require('../methods/invoiceOut/createPdf')(Self); require('../methods/invoiceOut/createManualInvoice')(Self); - require('../methods/invoiceOut/clientToInvoice')(Self); + require('../methods/invoiceOut/clientsToInvoice')(Self); require('../methods/invoiceOut/invoiceClient')(Self); require('../methods/invoiceOut/refund')(Self); require('../methods/invoiceOut/invoiceEmail')(Self); diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index 39dc311376..f772a4936c 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -50,6 +50,11 @@ class Controller extends Dialog { this.$.invoiceButton.disabled = false; } + cancelRequest() { + this.canceler = this.$q.defer(); + return {timeout: this.canceler.promise}; + } + invoiceOut(invoice, clientsAndAddresses) { const [clientAndAddress] = clientsAndAddresses; if (!clientAndAddress) return; @@ -63,10 +68,8 @@ class Controller extends Dialog { minShipped: invoice.minShipped, }; - this.canceler = this.$q.defer(); - const options = { - timeout: this.canceler.promise - }; + + const options = this.cancelRequest(); return this.$http.post(`InvoiceOuts/invoiceClient`, params, options) .then(() => { @@ -93,7 +96,9 @@ class Controller extends Dialog { this.$.invoiceButton.disabled = true; this.packageInvoicing = true; - this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) + const options = this.cancelRequest(); + + this.$http.post(`InvoiceOuts/clientsToInvoice`, this.invoice, options) .then(res => { this.packageInvoicing = false; const invoice = res.data.invoice; diff --git a/modules/invoiceOut/front/index/global-invoicing/index.spec.js b/modules/invoiceOut/front/index/global-invoicing/index.spec.js index 7dcc51e590..e88b0b1d41 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.spec.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.spec.js @@ -106,7 +106,7 @@ describe('InvoiceOut', () => { invoice: controller.invoice }; - $httpBackend.expect('POST', `InvoiceOuts/clientToInvoice`).respond(response); + $httpBackend.expect('POST', `InvoiceOuts/clientsToInvoice`).respond(response); $httpBackend.expect('POST', `InvoiceOuts/invoiceClient`).respond({id: 1}); controller.responseHandler('accept'); $httpBackend.flush(); From b37c25788544f93806febaef0102dc37ab68a702 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 31 Oct 2022 14:13:06 +0100 Subject: [PATCH 43/69] feat(canEdit): use checkAccess --- .../00-editTrackedACL.sql | 4 +- loopback/server/boot/acl.js | 22 ++ modules/ticket/back/methods/sale/canEdit.js | 80 ++-- .../back/methods/sale/specs/canEdit.spec.js | 366 +++++++++++------- .../back/methods/sale/specs/reserve.spec.js | 4 +- .../ticket/specs/componentUpdate.spec.js | 8 +- 6 files changed, 281 insertions(+), 203 deletions(-) rename db/changes/{10491-august => 10500-november}/00-editTrackedACL.sql (52%) create mode 100644 loopback/server/boot/acl.js diff --git a/db/changes/10491-august/00-editTrackedACL.sql b/db/changes/10500-november/00-editTrackedACL.sql similarity index 52% rename from db/changes/10491-august/00-editTrackedACL.sql rename to db/changes/10500-november/00-editTrackedACL.sql index 97394fffe0..c661694242 100644 --- a/db/changes/10491-august/00-editTrackedACL.sql +++ b/db/changes/10500-november/00-editTrackedACL.sql @@ -1,3 +1,5 @@ INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES - ('Sale', 'editTracked', 'WRITE', 'ALLOW', 'ROLE', 'production'); + ('Sale', 'editTracked', 'WRITE', 'ALLOW', 'ROLE', 'production'), + ('Sale', 'editFloramondo', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'), + ('Ticket', 'editWeekly', 'WRITE', 'DENY', 'ROLE', '$authenticated'); diff --git a/loopback/server/boot/acl.js b/loopback/server/boot/acl.js new file mode 100644 index 0000000000..a230078336 --- /dev/null +++ b/loopback/server/boot/acl.js @@ -0,0 +1,22 @@ + +module.exports = function(app) { + app.models.ACL.checkAccess = async(ctx, modelId, property, accessType = '*') => { + const models = app.models; + const context = { + accessToken: ctx.req.accessToken, + model: models[modelId], + property: property, + modelId: modelId, + accessType: accessType, + sharedMethod: { + name: property, + aliases: [], + sharedClass: true + } + }; + + const acl = await models.ACL.checkAccessForContext(context); + + return acl.permission == 'ALLOW'; + }; +}; diff --git a/modules/ticket/back/methods/sale/canEdit.js b/modules/ticket/back/methods/sale/canEdit.js index 7a8523fb7f..afbf70638a 100644 --- a/modules/ticket/back/methods/sale/canEdit.js +++ b/modules/ticket/back/methods/sale/canEdit.js @@ -1,5 +1,4 @@ const UserError = require('vn-loopback/util/user-error'); -const loopBackCtx = require('vn-loopback/server/server'); module.exports = Self => { Self.remoteMethodCtx('canEdit', { @@ -7,7 +6,7 @@ module.exports = Self => { accessType: 'READ', accepts: [{ arg: 'sales', - type: ['object'], + type: ['number'], required: true }], returns: { @@ -16,7 +15,7 @@ module.exports = Self => { }, http: { path: `/canEdit`, - verb: 'get' + verb: 'GET' } }); @@ -27,64 +26,39 @@ module.exports = Self => { if (typeof options == 'object') Object.assign(myOptions, options); - console.log(ctx.req.accessToken); - const token = ctx.req.accessToken; - let canEditTracked = await models.ACL.checkAccessForToken(token, models.Sale, null, 'refund'); - // const newCtx = ctx; - // newCtx.property = 'refund'; - // newCtx.accessType = 'WRITE'; - // newCtx.methodNames = ['refund']; - // newCtx.model = await models.Sale; + const salesData = await models.Sale.find({ + fields: ['id', 'itemFk', 'ticketFk'], + where: {id: {inq: sales}}, + include: + { + relation: 'item', + scope: { + fields: ['id', 'isFloramondo'], + } + } + }, myOptions); - // let canEditTracked = await models.ACL.checkAccessForContext(newCtx); - console.log(canEditTracked); + const ticketId = salesData[0].ticketFk; - // let canEditTracked2 = await models.ACL.checkPermission('USER', 'developer', 'Sale', 'editTracked', 'READ'); - /* const array = ['editTracked']; - const AccessContext = loopBackCtx.AccessContext; - const toFind = { - principals: [{ - type: 'ROLE', - id: 'employee' - }], - model: 'Sale', - property: 'editTracked', - methodNames: ['editTracked'], - accessType: 'WRITE' - }; - const newContext = new AccessContext(toFind); - newContext.methodNames = ['editTracked']; + const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions); + if (!isTicketEditable) + throw new UserError(`The sales of this ticket can't be modified`); - let canEditTracked3 = await models.ACL.checkAccessForContext(newContext); + const hasSaleTracking = await models.SaleTracking.findOne({where: {saleFk: {inq: sales}}}, myOptions); + const hasSaleCloned = await models.SaleCloned.findOne({where: {saleClonedFk: {inq: sales}}}, myOptions); + const isTicketWeekly = await models.TicketWeekly.findOne({where: {ticketFk: ticketId}}, myOptions); + const hasSaleFloramondo = salesData.find(sale => sale.item().isFloramondo); - let canEditTracked4 = await models.ACL.checkAccessForContext({ - principals: [{ - type: 'ROLE', - id: 'developer' - }], - model: 'Sale', - property: 'editTracked', - methodName: 'editTracked', - methodNames: ['editTracked'], - accessType: 'WRITE' - }); - // console.log(canEditTracked); - // canEditTracked = await models.ACL.resolvePermission(canEditTracked); - // let canEditCloned = await models.ACL.checkPermission('ROLE', 'employee', 'Sale', 'editCloned', '*'); - // let canEditWeekly = await models.ACL.checkPermission('ROLE', 'employee', 'Ticket', 'editWeekly', '*'); + const canEditTracked = await models.ACL.checkAccess(ctx, 'Sale', 'editTracked'); + const canEditCloned = await models.ACL.checkAccess(ctx, 'Sale', 'editCloned'); + const canEditWeekly = await models.ACL.checkAccess(ctx, 'Ticket', 'editWeekly'); + const canEditFloramondo = await models.ACL.checkAccess(ctx, 'Sale', 'editFloramondo'); - // console.log(canEditTracked, canEditTracked2); - console.log('DENY: ', canEditTracked3.permission); - console.log('ALLOW: ', canEditTracked4.permission); const shouldEditTracked = canEditTracked || !hasSaleTracking; const shouldEditCloned = canEditCloned || !hasSaleCloned; const shouldEditWeekly = canEditWeekly || !isTicketWeekly; + const shouldEditFloramondo = canEditFloramondo || !hasSaleFloramondo; - const canEdit = shouldEditTracked && shouldEditCloned && shouldEditWeekly; - - if (canEdit) - return true; - - return false;*/ + return shouldEditTracked && shouldEditCloned && shouldEditWeekly && shouldEditFloramondo; }; }; diff --git a/modules/ticket/back/methods/sale/specs/canEdit.spec.js b/modules/ticket/back/methods/sale/specs/canEdit.spec.js index 1522ee7a31..4f66dcc874 100644 --- a/modules/ticket/back/methods/sale/specs/canEdit.spec.js +++ b/modules/ticket/back/methods/sale/specs/canEdit.spec.js @@ -1,179 +1,253 @@ const models = require('vn-loopback/server/server').models; describe('sale canEdit()', () => { - it('should return true if the role is production regardless of the saleTrackings', async() => { - const tx = await models.Sale.beginTransaction({}); + const employeeId = 1; - try { - const options = {transaction: tx}; + describe('sale editTracked', () => { + it('should return true if the role is production regardless of the saleTrackings', async() => { + const tx = await models.Sale.beginTransaction({}); - const productionUserID = 49; - const ctx = {req: {accessToken: {userId: productionUserID}}}; + try { + const options = {transaction: tx}; - const sales = [25]; + const productionUserID = 49; + const ctx = {req: {accessToken: {userId: productionUserID}}}; - const result = await models.Sale.canEdit(ctx, sales, options); + const sales = [25]; - expect(result).toEqual(true); + const result = await models.Sale.canEdit(ctx, sales, options); - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); + expect(result).toEqual(true); - it('should return true if the role is not production and none of the sales has saleTracking', async() => { - const tx = await models.Sale.beginTransaction({}); - - try { - const options = {transaction: tx}; - - const salesPersonUserID = 18; - const ctx = {req: {accessToken: {userId: salesPersonUserID}}}; - - const sales = [10]; - - const result = await models.Sale.canEdit(ctx, sales, options); - - expect(result).toEqual(true); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should return false if any of the sales has a saleTracking record', async() => { - const tx = await models.Sale.beginTransaction({}); - - try { - const options = {transaction: tx}; - - const buyerId = 35; - const ctx = {req: {accessToken: {userId: buyerId}}}; - - const sales = [31]; - - const result = await models.Sale.canEdit(ctx, sales, options); - - expect(result).toEqual(false); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should return false if any of the sales is cloned', async() => { - const tx = await models.Sale.beginTransaction({}); - - try { - const options = {transaction: tx}; - - const buyerId = 35; - const ctx = {req: {accessToken: {userId: buyerId}}}; - - const sales = [27]; - - const result = await models.Sale.canEdit(ctx, sales, options); - - expect(result).toEqual(false); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should return true if any of the sales is cloned and has the correct role', async() => { - const tx = await models.Sale.beginTransaction({}); - const roleEnabled = await models.ACL.findOne({ - where: { - model: 'Sale', - property: 'editCloned' + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; } }); - if (!roleEnabled || !roleEnabled.principalId) return; - try { - const options = {transaction: tx}; + it('should return true if the role is not production and none of the sales has saleTracking', async() => { + const tx = await models.Sale.beginTransaction({}); - const roleId = await models.Role.findOne({ - where: { - name: roleEnabled.principalId - } - }); - const ctx = {req: {accessToken: {userId: roleId}}}; + try { + const options = {transaction: tx}; - const sales = [27]; + const salesPersonUserID = 18; + const ctx = {req: {accessToken: {userId: salesPersonUserID}}}; - const result = await models.Sale.canEdit(ctx, sales, options); + const sales = [10]; - expect(result).toEqual(true); + const result = await models.Sale.canEdit(ctx, sales, options); - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); + expect(result).toEqual(true); - it('should return false if any of the sales is of ticket weekly', async() => { - const tx = await models.Sale.beginTransaction({}); - - try { - const options = {transaction: tx}; - - const employeeId = 1; - const ctx = {req: {accessToken: {userId: employeeId}}}; - - const sales = [33]; - - const result = await models.Sale.canEdit(ctx, sales, options); - - expect(result).toEqual(false); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should return true if any of the sales is of ticketWeekly and has the correct role', async() => { - const tx = await models.Sale.beginTransaction({}); - const roleEnabled = await models.ACL.findOne({ - where: { - model: 'Sale', - property: 'editWeekly' + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; } }); - if (!roleEnabled || !roleEnabled.principalId) return; - try { - const options = {transaction: tx}; + it('should return false if any of the sales has a saleTracking record', async() => { + const tx = await models.Sale.beginTransaction({}); - const roleId = await models.Role.findOne({ + try { + const options = {transaction: tx}; + + const buyerId = 35; + const ctx = {req: {accessToken: {userId: buyerId}}}; + + const sales = [31]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(false); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + }); + + describe('sale editCloned', () => { + it('should return false if any of the sales is cloned', async() => { + const tx = await models.Sale.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const buyerId = 35; + const ctx = {req: {accessToken: {userId: buyerId}}}; + + const sales = [27]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(false); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return true if any of the sales is cloned and has the correct role', async() => { + const tx = await models.Sale.beginTransaction({}); + const roleEnabled = await models.ACL.findOne({ where: { - name: roleEnabled.principalId + model: 'Sale', + property: 'editCloned', + permission: 'ALLOW' } }); - const ctx = {req: {accessToken: {userId: roleId}}}; + if (!roleEnabled || !roleEnabled.principalId) return await tx.rollback(); + try { + const options = {transaction: tx}; + + const role = await models.Role.findOne({ + where: { + name: roleEnabled.principalId + } + }); + const ctx = {req: {accessToken: {userId: role.id}}}; + + const sales = [27]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + }); + + describe('ticket editWeekly', () => { + it('should return false if any of the sales is of ticket weekly', async() => { + const tx = await models.Sale.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: employeeId}}}; + + const sales = [33]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(false); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return true if any of the sales is of ticketWeekly and has the correct role', async() => { + const tx = await models.Sale.beginTransaction({}); + const roleEnabled = await models.ACL.findOne({ + where: { + model: 'Ticket', + property: 'editWeekly', + permission: 'ALLOW' + } + }); + + if (!roleEnabled || !roleEnabled.principalId) return await tx.rollback(); + try { + const options = {transaction: tx}; + + const role = await models.Role.findOne({ + where: { + name: roleEnabled.principalId + } + }); + const ctx = {req: {accessToken: {userId: role.id}}}; + + const sales = [33]; + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + }); + + describe('sale editFloramondo', () => { + it('should return false if any of the sales isFloramondo', async() => { + const tx = await models.Sale.beginTransaction({}); const sales = [33]; - const result = await models.Sale.canEdit(ctx, sales, options); + try { + const options = {transaction: tx}; - expect(result).toEqual(true); + const ctx = {req: {accessToken: {userId: employeeId}}}; - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } + // For test + const saleToEdit = await models.Sale.findById(sales[0], null, options); + await saleToEdit.updateAttribute('itemFk', 9, options); + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(false); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return true if any of the sales is of isFloramondo and has the correct role', async() => { + const tx = await models.Sale.beginTransaction({}); + const sales = [32]; + + const roleEnabled = await models.ACL.findOne({ + where: { + model: 'Sale', + property: 'editFloramondo', + permission: 'ALLOW' + } + }); + + if (!roleEnabled || !roleEnabled.principalId) return await tx.rollback(); + + try { + const options = {transaction: tx}; + + const role = await models.Role.findOne({ + where: { + name: roleEnabled.principalId + } + }); + const ctx = {req: {accessToken: {userId: role.id}}}; + + // For test + const saleToEdit = await models.Sale.findById(sales[0], null, options); + await saleToEdit.updateAttribute('itemFk', 9, options); + + const result = await models.Sale.canEdit(ctx, sales, options); + + expect(result).toEqual(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); }); }); diff --git a/modules/ticket/back/methods/sale/specs/reserve.spec.js b/modules/ticket/back/methods/sale/specs/reserve.spec.js index 7c2d437151..7ab79f9c0a 100644 --- a/modules/ticket/back/methods/sale/specs/reserve.spec.js +++ b/modules/ticket/back/methods/sale/specs/reserve.spec.js @@ -1,6 +1,6 @@ const models = require('vn-loopback/server/server').models; -fdescribe('sale reserve()', () => { +describe('sale reserve()', () => { const ctx = { req: { accessToken: {userId: 1}, @@ -31,7 +31,7 @@ fdescribe('sale reserve()', () => { expect(error).toEqual(new Error(`The sales of this ticket can't be modified`)); }); - fit('should update the given sales of a ticket to reserved', async() => { + it('should update the given sales of a ticket to reserved', async() => { const tx = await models.Sale.beginTransaction({}); try { diff --git a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js index 2aa2a07c4c..49128ded8e 100644 --- a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js +++ b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js @@ -1,4 +1,5 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('ticket componentUpdate()', () => { const userID = 1101; @@ -175,10 +176,15 @@ describe('ticket componentUpdate()', () => { } } }; + + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: ctx.req + }); + const oldTicket = await models.Ticket.findById(ticketID, null, options); + await models.Ticket.componentUpdate(ctx, options); const [newTicketID] = await models.Ticket.rawSql('SELECT MAX(id) as id FROM ticket', null, options); - const oldTicket = await models.Ticket.findById(ticketID, null, options); const newTicket = await models.Ticket.findById(newTicketID.id, null, options); const newTicketSale = await models.Sale.findOne({where: {ticketFk: args.id}}, options); From ff5e601a1e37cf5813dfed3a8cb4346f026ea291 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Mon, 31 Oct 2022 14:43:31 +0100 Subject: [PATCH 44/69] Item islaid and test --- modules/item/back/methods/item/new.js | 10 ++++++++++ modules/item/back/methods/item/specs/new.spec.js | 10 ++++++++++ modules/item/back/models/item-type.json | 3 +++ 3 files changed, 23 insertions(+) diff --git a/modules/item/back/methods/item/new.js b/modules/item/back/methods/item/new.js index 0771b6b14a..26ec32a9a9 100644 --- a/modules/item/back/methods/item/new.js +++ b/modules/item/back/methods/item/new.js @@ -51,6 +51,16 @@ module.exports = Self => { const item = await models.Item.create(params, myOptions); + // set the item.isLaid to be the same as itemType.isLaid (itemType comes from item.typeFk) + + const itemType = await models.ItemType.findById(item.typeFk, myOptions); + + // Update the item with the new isLaid value + + item.isLaid = itemType.isLaid; + + await item.save(myOptions); + const typeTags = await models.ItemTypeTag.find({ where: {itemTypeFk: item.typeFk} }, myOptions); diff --git a/modules/item/back/methods/item/specs/new.spec.js b/modules/item/back/methods/item/specs/new.spec.js index 049ad0ff2e..b9dd8d3ace 100644 --- a/modules/item/back/methods/item/specs/new.spec.js +++ b/modules/item/back/methods/item/specs/new.spec.js @@ -15,6 +15,11 @@ describe('item new()', () => { }; let item = await models.Item.new(itemParams, options); + + let itemType = await models.ItemType.findById(item.typeFk, options); + + item.isLaid = itemType.isLaid; + const temporalNameTag = await models.Tag.findOne({where: {name: 'Nombre temporal'}}, options); const temporalName = await models.ItemTag.findOne({ @@ -26,9 +31,14 @@ describe('item new()', () => { item = await models.Item.findById(item.id, null, options); + itemType = await models.ItemType.findById(item.typeFk, options); + + item.isLaid = itemType.isLaid; + expect(item.intrastatFk).toEqual(5080000); expect(item.originFk).toEqual(1); expect(item.typeFk).toEqual(2); + expect(item.isLaid).toEqual(0); expect(item.name).toEqual('planta'); expect(temporalName.value).toEqual('planta'); diff --git a/modules/item/back/models/item-type.json b/modules/item/back/models/item-type.json index 74cdf3fc87..df80463e0d 100644 --- a/modules/item/back/models/item-type.json +++ b/modules/item/back/models/item-type.json @@ -26,6 +26,9 @@ }, "isUnconventionalSize": { "type": "number" + }, + "isLaid": { + "type": "number" } }, "relations": { From e7047e982f992b51889fc426e92562d0336012be Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 31 Oct 2022 15:07:22 +0100 Subject: [PATCH 45/69] fix e2e --- back/model-config.json | 3 --- back/models/funcionalityAcl.json | 24 --------------------- db/export-data.sh | 1 - loopback/server/boot/acl.js | 2 +- modules/ticket/back/methods/sale/canEdit.js | 8 +++---- 5 files changed, 5 insertions(+), 33 deletions(-) delete mode 100644 back/models/funcionalityAcl.json diff --git a/back/model-config.json b/back/model-config.json index dd35302a39..29676e979e 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -53,9 +53,6 @@ "EmailUser": { "dataSource": "vn" }, - "FuncionalityAcl": { - "dataSource": "vn" - }, "Image": { "dataSource": "vn" }, diff --git a/back/models/funcionalityAcl.json b/back/models/funcionalityAcl.json deleted file mode 100644 index 840c4f6f3a..0000000000 --- a/back/models/funcionalityAcl.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "FuncionalityAcl", - "base": "VnModel", - "options": { - "mysql": { - "table": "salix.funcionalityAcl" - } - }, - "properties": { - "id": { - "type": "number", - "id": true - }, - "model": { - "type": "string" - }, - "property": { - "type": "string" - }, - "role": { - "type": "string" - } - } -} diff --git a/db/export-data.sh b/db/export-data.sh index 7252267ba8..bbbeb7152b 100755 --- a/db/export-data.sh +++ b/db/export-data.sh @@ -34,7 +34,6 @@ TABLES=( salix ACL fieldAcl - funcionalityAcl module defaultViewConfig ) diff --git a/loopback/server/boot/acl.js b/loopback/server/boot/acl.js index a230078336..f9375e0c1d 100644 --- a/loopback/server/boot/acl.js +++ b/loopback/server/boot/acl.js @@ -1,6 +1,6 @@ module.exports = function(app) { - app.models.ACL.checkAccess = async(ctx, modelId, property, accessType = '*') => { + app.models.ACL.checkAccessAcl = async(ctx, modelId, property, accessType = '*') => { const models = app.models; const context = { accessToken: ctx.req.accessToken, diff --git a/modules/ticket/back/methods/sale/canEdit.js b/modules/ticket/back/methods/sale/canEdit.js index afbf70638a..bd6a56200b 100644 --- a/modules/ticket/back/methods/sale/canEdit.js +++ b/modules/ticket/back/methods/sale/canEdit.js @@ -49,10 +49,10 @@ module.exports = Self => { const isTicketWeekly = await models.TicketWeekly.findOne({where: {ticketFk: ticketId}}, myOptions); const hasSaleFloramondo = salesData.find(sale => sale.item().isFloramondo); - const canEditTracked = await models.ACL.checkAccess(ctx, 'Sale', 'editTracked'); - const canEditCloned = await models.ACL.checkAccess(ctx, 'Sale', 'editCloned'); - const canEditWeekly = await models.ACL.checkAccess(ctx, 'Ticket', 'editWeekly'); - const canEditFloramondo = await models.ACL.checkAccess(ctx, 'Sale', 'editFloramondo'); + const canEditTracked = await models.ACL.checkAccessAcl(ctx, 'Sale', 'editTracked'); + const canEditCloned = await models.ACL.checkAccessAcl(ctx, 'Sale', 'editCloned'); + const canEditWeekly = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editWeekly'); + const canEditFloramondo = await models.ACL.checkAccessAcl(ctx, 'Sale', 'editFloramondo'); const shouldEditTracked = canEditTracked || !hasSaleTracking; const shouldEditCloned = canEditCloned || !hasSaleCloned; From 7d7af6eb495e59599772c37b58278e762774a261 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Fri, 4 Nov 2022 07:42:21 +0100 Subject: [PATCH 46/69] Modified model to allow modifications to isLaid --- modules/item/back/models/item.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/item/back/models/item.json b/modules/item/back/models/item.json index 704c97434e..2f58c30a9b 100644 --- a/modules/item/back/models/item.json +++ b/modules/item/back/models/item.json @@ -143,6 +143,9 @@ }, "packingShelve": { "type": "number" + }, + "isLaid": { + "type": "boolean" } }, "relations": { From 11cf1ba414c13983be899f9b93c2bc838c21fced Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Fri, 4 Nov 2022 07:50:54 +0100 Subject: [PATCH 47/69] fix back test error --- modules/item/back/methods/item/specs/new.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/item/back/methods/item/specs/new.spec.js b/modules/item/back/methods/item/specs/new.spec.js index b9dd8d3ace..7364faa7d1 100644 --- a/modules/item/back/methods/item/specs/new.spec.js +++ b/modules/item/back/methods/item/specs/new.spec.js @@ -38,7 +38,7 @@ describe('item new()', () => { expect(item.intrastatFk).toEqual(5080000); expect(item.originFk).toEqual(1); expect(item.typeFk).toEqual(2); - expect(item.isLaid).toEqual(0); + expect(item.isLaid).toBeFalse(); expect(item.name).toEqual('planta'); expect(temporalName.value).toEqual('planta'); From 37292cee89db9578a6587cb6121d3fc19d05dabc Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Fri, 4 Nov 2022 08:12:46 +0100 Subject: [PATCH 48/69] remove comments --- modules/item/back/methods/item/new.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/item/back/methods/item/new.js b/modules/item/back/methods/item/new.js index 26ec32a9a9..d6a176b46c 100644 --- a/modules/item/back/methods/item/new.js +++ b/modules/item/back/methods/item/new.js @@ -51,12 +51,8 @@ module.exports = Self => { const item = await models.Item.create(params, myOptions); - // set the item.isLaid to be the same as itemType.isLaid (itemType comes from item.typeFk) - const itemType = await models.ItemType.findById(item.typeFk, myOptions); - // Update the item with the new isLaid value - item.isLaid = itemType.isLaid; await item.save(myOptions); From 03ec8e27e6628101674bde5102b7fb83ddfbfcdf Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Nov 2022 09:19:20 +0100 Subject: [PATCH 49/69] feat(ticket_isEditable): use ticketWeekly --- .../10500-november/00-editTrackedACL.sql | 3 +- db/dump/fixtures.sql | 8 +-- modules/ticket/back/methods/sale/canEdit.js | 5 +- .../back/methods/sale/specs/canEdit.spec.js | 70 ++----------------- .../ticket/back/methods/ticket/isEditable.js | 4 +- .../methods/ticket/specs/isEditable.spec.js | 19 +++++ 6 files changed, 33 insertions(+), 76 deletions(-) diff --git a/db/changes/10500-november/00-editTrackedACL.sql b/db/changes/10500-november/00-editTrackedACL.sql index c661694242..e768fb7c70 100644 --- a/db/changes/10500-november/00-editTrackedACL.sql +++ b/db/changes/10500-november/00-editTrackedACL.sql @@ -1,5 +1,4 @@ INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Sale', 'editTracked', 'WRITE', 'ALLOW', 'ROLE', 'production'), - ('Sale', 'editFloramondo', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'), - ('Ticket', 'editWeekly', 'WRITE', 'DENY', 'ROLE', '$authenticated'); + ('Sale', 'editFloramondo', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'); diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index d5500360c6..5db3bba63a 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -984,7 +984,7 @@ INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `pric (30, 4, 18, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()), (31, 2, 23, 'Melee weapon combat fist 15cm', -5, 7.08, 0, 0, 0, util.VN_CURDATE()), (32, 1, 24, 'Ranged weapon longbow 2m', -1, 8.07, 0, 0, 0, util.VN_CURDATE()), - (33, 5, 14, 'Ranged weapon pistol 9mm', 50, 1.79, 0, 0, 0, util.VN_CURDATE()); + (33, 5, 14, 'Ranged weapon pistol 9mm', 50, 1.79, 0, 0, 0, util.VN_CURDATE()); INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`) VALUES @@ -1358,7 +1358,7 @@ INSERT INTO `vn`.`ticketWeekly`(`ticketFk`, `weekDay`) (3, 2), (4, 4), (5, 6), - (14, 6); + (15, 6); INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyModeFk`, `m3`, `kg`,`ref`, `totalEntries`, `cargoSupplierFk`) VALUES @@ -2712,7 +2712,7 @@ INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `lev INSERT INTO `vn`.`saleCloned` (`saleClonedFk`, `saleOriginalFk`) VALUES - ('27', '25'); + (29, 25); UPDATE `account`.`user` SET `hasGrant` = 1 @@ -2720,4 +2720,4 @@ UPDATE `account`.`user` INSERT INTO `vn`.`osTicketConfig` (`id`, `host`, `user`, `password`, `oldStatus`, `newStatusId`, `day`, `comment`, `hostDb`, `userDb`, `passwordDb`, `portDb`, `responseType`, `fromEmailId`, `replyTo`) VALUES - (0, 'http://localhost:56596/scp', 'ostadmin', 'Admin1', 'open', 3, 60, 'Este CAU se ha cerrado automáticamente. Si el problema persiste responda a este mensaje.', 'localhost', 'osticket', 'osticket', 40003, 'reply', 1, 'all'); \ No newline at end of file + (0, 'http://localhost:56596/scp', 'ostadmin', 'Admin1', 'open', 3, 60, 'Este CAU se ha cerrado automáticamente. Si el problema persiste responda a este mensaje.', 'localhost', 'osticket', 'osticket', 40003, 'reply', 1, 'all'); diff --git a/modules/ticket/back/methods/sale/canEdit.js b/modules/ticket/back/methods/sale/canEdit.js index bd6a56200b..f44bd67438 100644 --- a/modules/ticket/back/methods/sale/canEdit.js +++ b/modules/ticket/back/methods/sale/canEdit.js @@ -46,19 +46,16 @@ module.exports = Self => { const hasSaleTracking = await models.SaleTracking.findOne({where: {saleFk: {inq: sales}}}, myOptions); const hasSaleCloned = await models.SaleCloned.findOne({where: {saleClonedFk: {inq: sales}}}, myOptions); - const isTicketWeekly = await models.TicketWeekly.findOne({where: {ticketFk: ticketId}}, myOptions); const hasSaleFloramondo = salesData.find(sale => sale.item().isFloramondo); const canEditTracked = await models.ACL.checkAccessAcl(ctx, 'Sale', 'editTracked'); const canEditCloned = await models.ACL.checkAccessAcl(ctx, 'Sale', 'editCloned'); - const canEditWeekly = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editWeekly'); const canEditFloramondo = await models.ACL.checkAccessAcl(ctx, 'Sale', 'editFloramondo'); const shouldEditTracked = canEditTracked || !hasSaleTracking; const shouldEditCloned = canEditCloned || !hasSaleCloned; - const shouldEditWeekly = canEditWeekly || !isTicketWeekly; const shouldEditFloramondo = canEditFloramondo || !hasSaleFloramondo; - return shouldEditTracked && shouldEditCloned && shouldEditWeekly && shouldEditFloramondo; + return shouldEditTracked && shouldEditCloned && shouldEditFloramondo; }; }; diff --git a/modules/ticket/back/methods/sale/specs/canEdit.spec.js b/modules/ticket/back/methods/sale/specs/canEdit.spec.js index 4f66dcc874..2aa873df56 100644 --- a/modules/ticket/back/methods/sale/specs/canEdit.spec.js +++ b/modules/ticket/back/methods/sale/specs/canEdit.spec.js @@ -72,6 +72,7 @@ describe('sale canEdit()', () => { }); describe('sale editCloned', () => { + const saleCloned = [29]; it('should return false if any of the sales is cloned', async() => { const tx = await models.Sale.beginTransaction({}); @@ -81,9 +82,7 @@ describe('sale canEdit()', () => { const buyerId = 35; const ctx = {req: {accessToken: {userId: buyerId}}}; - const sales = [27]; - - const result = await models.Sale.canEdit(ctx, sales, options); + const result = await models.Sale.canEdit(ctx, saleCloned, options); expect(result).toEqual(false); @@ -115,66 +114,7 @@ describe('sale canEdit()', () => { }); const ctx = {req: {accessToken: {userId: role.id}}}; - const sales = [27]; - - const result = await models.Sale.canEdit(ctx, sales, options); - - expect(result).toEqual(true); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - }); - - describe('ticket editWeekly', () => { - it('should return false if any of the sales is of ticket weekly', async() => { - const tx = await models.Sale.beginTransaction({}); - - try { - const options = {transaction: tx}; - - const ctx = {req: {accessToken: {userId: employeeId}}}; - - const sales = [33]; - - const result = await models.Sale.canEdit(ctx, sales, options); - - expect(result).toEqual(false); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should return true if any of the sales is of ticketWeekly and has the correct role', async() => { - const tx = await models.Sale.beginTransaction({}); - const roleEnabled = await models.ACL.findOne({ - where: { - model: 'Ticket', - property: 'editWeekly', - permission: 'ALLOW' - } - }); - - if (!roleEnabled || !roleEnabled.principalId) return await tx.rollback(); - try { - const options = {transaction: tx}; - - const role = await models.Role.findOne({ - where: { - name: roleEnabled.principalId - } - }); - const ctx = {req: {accessToken: {userId: role.id}}}; - - const sales = [33]; - - const result = await models.Sale.canEdit(ctx, sales, options); + const result = await models.Sale.canEdit(ctx, saleCloned, options); expect(result).toEqual(true); @@ -189,7 +129,7 @@ describe('sale canEdit()', () => { describe('sale editFloramondo', () => { it('should return false if any of the sales isFloramondo', async() => { const tx = await models.Sale.beginTransaction({}); - const sales = [33]; + const sales = [26]; try { const options = {transaction: tx}; @@ -213,7 +153,7 @@ describe('sale canEdit()', () => { it('should return true if any of the sales is of isFloramondo and has the correct role', async() => { const tx = await models.Sale.beginTransaction({}); - const sales = [32]; + const sales = [26]; const roleEnabled = await models.ACL.findOne({ where: { diff --git a/modules/ticket/back/methods/ticket/isEditable.js b/modules/ticket/back/methods/ticket/isEditable.js index bdd18d7de4..d8fbb86ce8 100644 --- a/modules/ticket/back/methods/ticket/isEditable.js +++ b/modules/ticket/back/methods/ticket/isEditable.js @@ -44,13 +44,15 @@ module.exports = Self => { } }] }, myOptions); + const isLocked = await models.Ticket.isLocked(id, myOptions); + const isWeekly = await models.TicketWeekly.findOne({where: {ticketFk: id}}, myOptions); const alertLevelGreaterThanZero = (alertLevel && alertLevel > 0); const isNormalClient = ticket && ticket.client().type().code == 'normal'; const isEditable = !(alertLevelGreaterThanZero && isNormalClient); - if (ticket && (isEditable || isRoleAdvanced) && !isLocked) + if (ticket && (isEditable || isRoleAdvanced) && !isLocked && !isWeekly) return true; return false; diff --git a/modules/ticket/back/methods/ticket/specs/isEditable.spec.js b/modules/ticket/back/methods/ticket/specs/isEditable.spec.js index adc2acdee5..7337017d6a 100644 --- a/modules/ticket/back/methods/ticket/specs/isEditable.spec.js +++ b/modules/ticket/back/methods/ticket/specs/isEditable.spec.js @@ -134,4 +134,23 @@ describe('ticket isEditable()', () => { expect(result).toEqual(false); }); + + it('should not be able to edit if is a ticket weekly', async() => { + const tx = await models.Ticket.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 1}}}; + + const result = await models.Ticket.isEditable(ctx, 15, options); + + expect(result).toEqual(false); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); }); From dbd0e77e12c5f5fc0bc620dea0e01d2421d42557 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 9 Nov 2022 09:14:32 +0100 Subject: [PATCH 50/69] feat: send mail with the invoice pdf --- .../back/methods/invoiceOut/invoiceClient.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js index ec32443446..c3ad9508a2 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js @@ -109,9 +109,6 @@ module.exports = Self => { if (newInvoice.id) { await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); - query = `INSERT IGNORE INTO invoiceOutQueue(invoiceFk) VALUES(?)`; - await Self.rawSql(query, [newInvoice.id], myOptions); - invoiceId = newInvoice.id; } } catch (e) { @@ -128,6 +125,21 @@ module.exports = Self => { throw e; } + const invoiceOut = await models.InvoiceOut.findById(invoiceId, { + include: { + relation: 'client' + } + }); + + try { + ctx.args = { + reference: invoiceOut.ref, + recipientId: invoiceOut.clientFk, + recipient: invoiceOut.client().email + }; + await models.InvoiceOut.invoiceEmail(ctx); + } catch (err) {} + return invoiceId; }; From 2ab475791c03a7b53bb187ac36fcc2e44eb3fc05 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 9 Nov 2022 09:16:58 +0100 Subject: [PATCH 51/69] refactor code --- .../back/methods/invoiceOut/invoiceClient.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js index c3ad9508a2..7c8742caae 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js @@ -130,13 +130,12 @@ module.exports = Self => { relation: 'client' } }); - + ctx.args = { + reference: invoiceOut.ref, + recipientId: invoiceOut.clientFk, + recipient: invoiceOut.client().email + }; try { - ctx.args = { - reference: invoiceOut.ref, - recipientId: invoiceOut.clientFk, - recipient: invoiceOut.client().email - }; await models.InvoiceOut.invoiceEmail(ctx); } catch (err) {} From 79e9edcee959f42044b7328932e5a5970a861f8c Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 9 Nov 2022 09:26:28 +0100 Subject: [PATCH 52/69] delete: old code --- .../00-deleteInvoiceOutQueue.sql | 1 + .../back/methods/invoiceOut/sendQueued.js | 133 ------------------ modules/invoiceOut/back/models/invoice-out.js | 1 - 3 files changed, 1 insertion(+), 134 deletions(-) create mode 100644 db/changes/10502-november/00-deleteInvoiceOutQueue.sql delete mode 100644 modules/invoiceOut/back/methods/invoiceOut/sendQueued.js diff --git a/db/changes/10502-november/00-deleteInvoiceOutQueue.sql b/db/changes/10502-november/00-deleteInvoiceOutQueue.sql new file mode 100644 index 0000000000..87a3059a09 --- /dev/null +++ b/db/changes/10502-november/00-deleteInvoiceOutQueue.sql @@ -0,0 +1 @@ +DROP TABLE `vn`.`invoiceOutQueue`; \ No newline at end of file diff --git a/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js b/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js deleted file mode 100644 index a1730ac818..0000000000 --- a/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js +++ /dev/null @@ -1,133 +0,0 @@ -const {Email, Report, storage} = require('vn-print'); - -module.exports = Self => { - Self.remoteMethod('sendQueued', { - description: 'Send all queued invoices', - accessType: 'WRITE', - accepts: [], - returns: { - type: 'object', - root: true - }, - http: { - path: '/send-queued', - verb: 'POST' - } - }); - - Self.sendQueued = async() => { - const invoices = await Self.rawSql(` - SELECT - io.id, - io.clientFk, - io.issued, - io.ref, - c.email recipient, - c.salesPersonFk, - c.isToBeMailed, - c.hasToInvoice, - co.hasDailyInvoice, - eu.email salesPersonEmail - FROM invoiceOutQueue ioq - JOIN invoiceOut io ON io.id = ioq.invoiceFk - JOIN client c ON c.id = io.clientFk - JOIN province p ON p.id = c.provinceFk - JOIN country co ON co.id = p.countryFk - LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk - WHERE status = ''`); - - let invoiceId; - for (const invoiceOut of invoices) { - try { - const tx = await Self.beginTransaction({}); - const myOptions = {transaction: tx}; - - invoiceId = invoiceOut.id; - - const args = { - reference: invoiceOut.ref, - recipientId: invoiceOut.clientFk, - recipient: invoiceOut.recipient, - replyTo: invoiceOut.salesPersonEmail - }; - - const invoiceReport = new Report('invoice', args); - const stream = await invoiceReport.toPdfStream(); - - const issued = invoiceOut.issued; - const year = issued.getFullYear().toString(); - const month = (issued.getMonth() + 1).toString(); - const day = issued.getDate().toString(); - - const fileName = `${year}${invoiceOut.ref}.pdf`; - - // Store invoice - storage.write(stream, { - type: 'invoice', - path: `${year}/${month}/${day}`, - fileName: fileName - }); - - await Self.rawSql(` - UPDATE invoiceOut - SET hasPdf = true - WHERE id = ?`, - [invoiceOut.id], myOptions); - - const isToBeMailed = invoiceOut.recipient && invoiceOut.salesPersonFk && invoiceOut.isToBeMailed; - - if (isToBeMailed) { - const mailOptions = { - overrideAttachments: true, - attachments: [] - }; - - const invoiceAttachment = { - filename: fileName, - content: stream - }; - - if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') { - const exportation = new Report('exportation', args); - const stream = await exportation.toPdfStream(); - const fileName = `CITES-${invoiceOut.ref}.pdf`; - - mailOptions.attachments.push({ - filename: fileName, - content: stream - }); - } - - mailOptions.attachments.push(invoiceAttachment); - - const email = new Email('invoice', args); - await email.send(mailOptions); - } - // Update queue status - const date = new Date(); - await Self.rawSql(` - UPDATE invoiceOutQueue - SET status = "printed", - printed = ? - WHERE invoiceFk = ?`, - [date, invoiceOut.id], myOptions); - - await tx.commit(); - } catch (error) { - await tx.rollback(); - - await Self.rawSql(` - UPDATE invoiceOutQueue - SET status = ? - WHERE invoiceFk = ?`, - [error.message, invoiceId]); - - throw e; - } - } - - return { - message: 'Success' - }; - }; -}; diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index 3648ba8498..88adae2ef0 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -13,7 +13,6 @@ module.exports = Self => { require('../methods/invoiceOut/refund')(Self); require('../methods/invoiceOut/invoiceEmail')(Self); require('../methods/invoiceOut/exportationPdf')(Self); - require('../methods/invoiceOut/sendQueued')(Self); require('../methods/invoiceOut/invoiceCsv')(Self); require('../methods/invoiceOut/invoiceCsvEmail')(Self); }; From 574f2757f4414ac2b062e322f29debd30f42a145 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 9 Nov 2022 10:19:27 +0100 Subject: [PATCH 53/69] refactor code --- .../back/methods/invoiceOut/invoiceClient.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js index 7c8742caae..6667b5f0eb 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js @@ -63,6 +63,7 @@ module.exports = Self => { } let invoiceId; + let invoiceOut; try { const client = await models.Client.findById(args.clientId, { fields: ['id', 'hasToInvoiceByAddress'] @@ -119,25 +120,24 @@ module.exports = Self => { await notifyFailures(ctx, failedClient, myOptions); } + invoiceOut = await models.InvoiceOut.findById(invoiceId, { + include: { + relation: 'client' + } + }, myOptions); + if (tx) await tx.commit(); } catch (e) { if (tx) await tx.rollback(); throw e; } - const invoiceOut = await models.InvoiceOut.findById(invoiceId, { - include: { - relation: 'client' - } - }); ctx.args = { reference: invoiceOut.ref, recipientId: invoiceOut.clientFk, recipient: invoiceOut.client().email }; - try { - await models.InvoiceOut.invoiceEmail(ctx); - } catch (err) {} + await models.InvoiceOut.invoiceEmail(ctx); return invoiceId; }; From 1ea5ffa6d30a33ccfc40d8c05727e6a69de220cf Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 9 Nov 2022 12:04:19 +0100 Subject: [PATCH 54/69] fix: backTest --- modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js | 4 +++- .../back/methods/invoiceOut/specs/invoiceClient.spec.js | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js index 6667b5f0eb..b04747d166 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js @@ -137,7 +137,9 @@ module.exports = Self => { recipientId: invoiceOut.clientFk, recipient: invoiceOut.client().email }; - await models.InvoiceOut.invoiceEmail(ctx); + try { + await models.InvoiceOut.invoiceEmail(ctx); + } catch (err) {} return invoiceId; }; diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js index f1f9b70372..fdf50cbd48 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js @@ -12,6 +12,9 @@ describe('InvoiceOut invoiceClient()', () => { minShipped.setHours(0, 0, 0, 0); const invoiceSerial = 'A'; const activeCtx = { + getLocale: () => { + return 'en'; + }, accessToken: {userId: userId}, __: value => { return value; From 0bd09ae366dd23b49c19a0f038b420f416357f05 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 9 Nov 2022 12:06:51 +0100 Subject: [PATCH 55/69] fix: delete unnecessary column --- modules/invoiceOut/front/index/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/invoiceOut/front/index/index.html b/modules/invoiceOut/front/index/index.html index 632dbf90bf..e2cf2120a3 100644 --- a/modules/invoiceOut/front/index/index.html +++ b/modules/invoiceOut/front/index/index.html @@ -30,7 +30,6 @@ Company Due date - From 638fd62aae298cf1349620d71f3b9b2cd671cdfd Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Thu, 10 Nov 2022 07:17:54 +0100 Subject: [PATCH 56/69] added requested changes, refs #4492 @40m --- modules/item/back/methods/item/new.js | 10 ++++------ modules/item/back/models/item-type.json | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/modules/item/back/methods/item/new.js b/modules/item/back/methods/item/new.js index d6a176b46c..fae37836fc 100644 --- a/modules/item/back/methods/item/new.js +++ b/modules/item/back/methods/item/new.js @@ -49,14 +49,12 @@ module.exports = Self => { const provisionalName = params.provisionalName; delete params.provisionalName; + const itemType = await models.ItemType.findById(params.typeFk, myOptions); + + params.isLaid = itemType.isLaid; + const item = await models.Item.create(params, myOptions); - const itemType = await models.ItemType.findById(item.typeFk, myOptions); - - item.isLaid = itemType.isLaid; - - await item.save(myOptions); - const typeTags = await models.ItemTypeTag.find({ where: {itemTypeFk: item.typeFk} }, myOptions); diff --git a/modules/item/back/models/item-type.json b/modules/item/back/models/item-type.json index df80463e0d..c5c920b2fe 100644 --- a/modules/item/back/models/item-type.json +++ b/modules/item/back/models/item-type.json @@ -28,7 +28,7 @@ "type": "number" }, "isLaid": { - "type": "number" + "type": "boolean" } }, "relations": { From 891cd6b474500e5984e093017554407c2eba8ce4 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Thu, 10 Nov 2022 07:23:08 +0100 Subject: [PATCH 57/69] Added requestes changes refs #4157 --- modules/route/back/methods/route/sendSms.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/route/back/methods/route/sendSms.js b/modules/route/back/methods/route/sendSms.js index fe881abd54..d1c3efa35b 100644 --- a/modules/route/back/methods/route/sendSms.js +++ b/modules/route/back/methods/route/sendSms.js @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ module.exports = Self => { Self.remoteMethodCtx('sendSms', { From 2704017486f065c2ab9cc2eb4cad80b4eb7f261b Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Thu, 10 Nov 2022 09:43:19 +0100 Subject: [PATCH 58/69] check default true --- modules/ticket/front/basic-data/step-two/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 6be455fc9e..85c55e863f 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -83,6 +83,7 @@
From 37d412bf3bbc254c00e03d7ced1f24d12f7134b8 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 10 Nov 2022 14:38:37 +0100 Subject: [PATCH 59/69] refactor: delete unnecessary test --- .../00-editTrackedACL.sql | 0 .../05-ticket/02_expeditions_and_log.spec.js | 2 +- .../methods/sale/specs/updateQuantity.spec.js | 18 ------------------ .../ticket/back/methods/sale/updateQuantity.js | 3 --- 4 files changed, 1 insertion(+), 22 deletions(-) rename db/changes/{10500-november => 10502-november}/00-editTrackedACL.sql (100%) diff --git a/db/changes/10500-november/00-editTrackedACL.sql b/db/changes/10502-november/00-editTrackedACL.sql similarity index 100% rename from db/changes/10500-november/00-editTrackedACL.sql rename to db/changes/10502-november/00-editTrackedACL.sql diff --git a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js index f970247e51..66df3e9e65 100644 --- a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js +++ b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js @@ -1,7 +1,7 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; -describe('Ticket expeditions and log path', () => { +fdescribe('Ticket expeditions and log path', () => { let browser; let page; diff --git a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js index bf139ab115..53a05cd7ee 100644 --- a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js @@ -9,24 +9,6 @@ describe('sale updateQuantity()', () => { } }; - it('should throw an error if the quantity is not a number', async() => { - const tx = await models.Sale.beginTransaction({}); - - let error; - try { - const options = {transaction: tx}; - - await models.Sale.updateQuantity(ctx, 1, 'wrong quantity!', options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error).toEqual(new Error('The value should be a number')); - }); - it('should throw an error if the quantity is greater than it should be', async() => { const ctx = { req: { diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js index f3bc0ca380..8cf0720ce0 100644 --- a/modules/ticket/back/methods/sale/updateQuantity.js +++ b/modules/ticket/back/methods/sale/updateQuantity.js @@ -41,9 +41,6 @@ module.exports = Self => { } try { - if (isNaN(newQuantity)) - throw new UserError(`The value should be a number`); - const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions); if (!canEditSale) throw new UserError(`Sale(s) blocked, please contact production`); From 01fe8c8997870a47110a759103945996ac304803 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Thu, 10 Nov 2022 14:53:08 +0100 Subject: [PATCH 60/69] requested changes --- modules/ticket/front/basic-data/step-two/index.html | 1 - modules/ticket/front/basic-data/step-two/index.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 85c55e863f..6be455fc9e 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -83,7 +83,6 @@
diff --git a/modules/ticket/front/basic-data/step-two/index.js b/modules/ticket/front/basic-data/step-two/index.js index c12647aa5c..32d6b2cd69 100644 --- a/modules/ticket/front/basic-data/step-two/index.js +++ b/modules/ticket/front/basic-data/step-two/index.js @@ -76,7 +76,7 @@ class Controller extends Component { haveNotNegatives = true; }); - this.ticket.withoutNegatives = false; + this.ticket.withoutNegatives = true; this.haveNegatives = (haveNegatives && haveNotNegatives && haveDifferences); } From 7e50f23563ddb9a96051aa98eba71a73585ded93 Mon Sep 17 00:00:00 2001 From: vicent Date: Fri, 11 Nov 2022 08:55:56 +0100 Subject: [PATCH 61/69] refacor code --- .../{10491-august => 10503-november}/00-aclInvoiceOut.sql | 0 .../00-deleteInvoiceOutQueue.sql | 0 db/dump/fixtures.sql | 4 ---- .../back/methods/invoiceOut/specs/invoiceClient.spec.js | 1 + print/templates/email/invoice/invoice.js | 3 ++- 5 files changed, 3 insertions(+), 5 deletions(-) rename db/changes/{10491-august => 10503-november}/00-aclInvoiceOut.sql (100%) rename db/changes/{10502-november => 10503-november}/00-deleteInvoiceOutQueue.sql (100%) diff --git a/db/changes/10491-august/00-aclInvoiceOut.sql b/db/changes/10503-november/00-aclInvoiceOut.sql similarity index 100% rename from db/changes/10491-august/00-aclInvoiceOut.sql rename to db/changes/10503-november/00-aclInvoiceOut.sql diff --git a/db/changes/10502-november/00-deleteInvoiceOutQueue.sql b/db/changes/10503-november/00-deleteInvoiceOutQueue.sql similarity index 100% rename from db/changes/10502-november/00-deleteInvoiceOutQueue.sql rename to db/changes/10503-november/00-deleteInvoiceOutQueue.sql diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index f7c7526ca0..29b75602b6 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2699,10 +2699,6 @@ INSERT INTO `util`.`notificationSubscription` (`notificationFk`, `userFk`) INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`) VALUES (1, 9); - -INSERT INTO `vn`.`report` (`id`, `name`) - VALUES - (3, 'invoice'); INSERT INTO `vn`.`productionConfig` (`isPreviousPreparationRequired`, `ticketPrintedMax`, `ticketTrolleyMax`, `rookieDays`, `notBuyingMonths`, `id`, `isZoneClosedByExpeditionActivated`, `maxNotReadyCollections`, `minTicketsToCloseZone`, `movingTicketDelRoute`, `defaultZone`, `defautlAgencyMode`, `hasUniqueCollectionTime`, `maxCollectionWithoutUser`, `pendingCollectionsOrder`, `pendingCollectionsAge`) VALUES diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js index fdf50cbd48..5f890de269 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js @@ -24,6 +24,7 @@ describe('InvoiceOut invoiceClient()', () => { it('should make a global invoicing', async() => { spyOn(models.InvoiceOut, 'createPdf').and.returnValue(new Promise(resolve => resolve(true))); + spyOn(models.InvoiceOut, 'invoiceEmail'); const tx = await models.InvoiceOut.beginTransaction({}); const options = {transaction: tx}; diff --git a/print/templates/email/invoice/invoice.js b/print/templates/email/invoice/invoice.js index 8d3dcaea73..4bf0f7d660 100755 --- a/print/templates/email/invoice/invoice.js +++ b/print/templates/email/invoice/invoice.js @@ -4,6 +4,7 @@ module.exports = { name: 'invoice', async serverPrefetch() { this.invoice = await this.fetchInvoice(this.reference); + console.log('this.invoice: ', this.invoice); }, methods: { fetchInvoice(reference) { @@ -15,7 +16,7 @@ module.exports = { }, props: { reference: { - type: Number, + type: String, required: true } } From a30f50ffe5c956c5c1e647b737d156670ae085d4 Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 14 Nov 2022 12:20:27 +0100 Subject: [PATCH 62/69] refactor: borrado console.log --- print/templates/email/invoice/invoice.js | 1 - 1 file changed, 1 deletion(-) diff --git a/print/templates/email/invoice/invoice.js b/print/templates/email/invoice/invoice.js index 4bf0f7d660..cb90e461fe 100755 --- a/print/templates/email/invoice/invoice.js +++ b/print/templates/email/invoice/invoice.js @@ -4,7 +4,6 @@ module.exports = { name: 'invoice', async serverPrefetch() { this.invoice = await this.fetchInvoice(this.reference); - console.log('this.invoice: ', this.invoice); }, methods: { fetchInvoice(reference) { From 386e304958743c90f9d82ea267023002231cdb28 Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 14 Nov 2022 14:52:08 +0100 Subject: [PATCH 63/69] =?UTF-8?q?fix:=20modelo=20incorreto=20para=20la=20t?= =?UTF-8?q?ransacci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../back/methods/invoiceOut/specs/downloadZip.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js index 7a9e184ea2..08f0497837 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js @@ -13,7 +13,7 @@ describe('InvoiceOut downloadZip()', () => { }; it('should return part of link to dowloand the zip', async() => { - const tx = await models.Order.beginTransaction({}); + const tx = await models.InvoiceOut.beginTransaction({}); try { const options = {transaction: tx}; @@ -30,7 +30,7 @@ describe('InvoiceOut downloadZip()', () => { }); it('should return an error if the size of the files is too large', async() => { - const tx = await models.Order.beginTransaction({}); + const tx = await models.InvoiceOut.beginTransaction({}); let error; try { From 216108a5760aca6692489feae6fb13ac2da46eca Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 14 Nov 2022 15:01:22 +0100 Subject: [PATCH 64/69] refactor --- modules/invoiceOut/front/index/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/invoiceOut/front/index/index.html b/modules/invoiceOut/front/index/index.html index 632dbf90bf..e2cf2120a3 100644 --- a/modules/invoiceOut/front/index/index.html +++ b/modules/invoiceOut/front/index/index.html @@ -30,7 +30,6 @@ Company Due date - From 0637050375af785da6f500dadef4c4edd7c706e5 Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 14 Nov 2022 15:11:33 +0100 Subject: [PATCH 65/69] fix: frontTest --- modules/ticket/front/expedition/index.spec.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/ticket/front/expedition/index.spec.js b/modules/ticket/front/expedition/index.spec.js index b95d64fa34..5a538b1c8b 100644 --- a/modules/ticket/front/expedition/index.spec.js +++ b/modules/ticket/front/expedition/index.spec.js @@ -76,9 +76,10 @@ describe('Ticket', () => { it('should make a query and then call to the $state go() method', () => { jest.spyOn(controller.$state, 'go').mockReturnThis(); + const landed = new Date(); const ticket = { clientFk: 1101, - landed: new Date(), + landed: landed, addressFk: 121, agencyModeFk: 1, warehouseFk: 1 @@ -90,7 +91,7 @@ describe('Ticket', () => { const expectedParams = { clientId: 1101, - landed: new Date(), + landed: landed, warehouseId: 1, addressId: 121, agencyModeId: 1, From 63142a886142e0598cc07e0b7cf56f691ed1aace Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 14 Nov 2022 15:16:21 +0100 Subject: [PATCH 66/69] refactor --- modules/invoiceOut/front/summary/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/invoiceOut/front/summary/index.html b/modules/invoiceOut/front/summary/index.html index a0d050efdd..b837751586 100644 --- a/modules/invoiceOut/front/summary/index.html +++ b/modules/invoiceOut/front/summary/index.html @@ -85,7 +85,7 @@ {{ticket.shipped | date: 'dd/MM/yyyy' | dashIfEmpty}} - {{ticket.totalWithVat | currency: 'EUR': 2}} + {{ticket.totalWithVat | currency: 'EUR': 2}} From 72400ebf02a52f1846def667a5a2fad707706f5e Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 15 Nov 2022 09:37:14 +0100 Subject: [PATCH 67/69] change folder db --- .vscode/settings.json | 22 +++++++------------ .../00-editTrackedACL.sql | 0 db/changes/10503-november/delete.keep | 0 3 files changed, 8 insertions(+), 14 deletions(-) rename db/changes/{10502-november => 10503-november}/00-editTrackedACL.sql (100%) delete mode 100644 db/changes/10503-november/delete.keep diff --git a/.vscode/settings.json b/.vscode/settings.json index c27d01a765..b5da1e8e69 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,14 +1,8 @@ -// Coloque su configuración en este archivo para sobrescribir la configuración predeterminada y de usuario. -{ - // Carácter predeterminado de final de línea. - "files.eol": "\n", - "editor.bracketPairColorization.enabled": true, - "editor.guides.bracketPairs": true, - "editor.formatOnSave": true, - "editor.defaultFormatter": "dbaeumer.vscode-eslint", - "editor.codeActionsOnSave": ["source.fixAll.eslint"], - "eslint.validate": [ - "javascript", - "json" - ] -} \ No newline at end of file +// Coloque su configuración en este archivo para sobrescribir la configuración predeterminada y de usuario. +{ + // Carácter predeterminado de final de línea. + "files.eol": "\n", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + } +} diff --git a/db/changes/10502-november/00-editTrackedACL.sql b/db/changes/10503-november/00-editTrackedACL.sql similarity index 100% rename from db/changes/10502-november/00-editTrackedACL.sql rename to db/changes/10503-november/00-editTrackedACL.sql diff --git a/db/changes/10503-november/delete.keep b/db/changes/10503-november/delete.keep deleted file mode 100644 index e69de29bb2..0000000000 From 174dd1fe5c71753f5188f52f66a86e0124603926 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 15 Nov 2022 10:00:21 +0100 Subject: [PATCH 68/69] feat(invoice): send invoice from stored PDF - closes #4811 --- .../back/methods/invoiceOut/invoiceEmail.js | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js index 83564e3abc..83cb848810 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js @@ -40,19 +40,40 @@ module.exports = Self => { } }); - Self.invoiceEmail = async ctx => { + Self.invoiceEmail = async(ctx, reference) => { const args = Object.assign({}, ctx.args); + const {InvoiceOut} = Self.app.models; const params = { recipient: args.recipient, lang: ctx.req.getLocale() }; + const invoiceOut = await InvoiceOut.findOne({ + where: { + ref: reference + } + }); + delete args.ctx; for (const param in args) params[param] = args[param]; const email = new Email('invoice', params); - return email.send(); + const [stream, ...headers] = await Self.download(ctx, invoiceOut.id); + const name = headers[1]; + const fileName = name.replace(/filename="(.*)"/gm, '$1'); + + const mailOptions = { + overrideAttachments: true, + attachments: [ + { + filename: fileName, + content: stream + } + ] + }; + + return email.send(mailOptions); }; }; From 925c3846227e406041e0b453d872378aa497ca72 Mon Sep 17 00:00:00 2001 From: Alex Moreno Date: Wed, 16 Nov 2022 06:36:35 +0000 Subject: [PATCH 69/69] Actualizar 'e2e/paths/05-ticket/02_expeditions_and_log.spec.js' remove focus --- e2e/paths/05-ticket/02_expeditions_and_log.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js index 66df3e9e65..f970247e51 100644 --- a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js +++ b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js @@ -1,7 +1,7 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; -fdescribe('Ticket expeditions and log path', () => { +describe('Ticket expeditions and log path', () => { let browser; let page;