From 543fbf3c0a322e9b586ed3caf8194c1491753235 Mon Sep 17 00:00:00 2001 From: jorgep Date: Tue, 25 Jul 2023 15:35:08 +0200 Subject: [PATCH] refs #5929 isEditableOrThrow created, tests passed --- loopback/locale/en.json | 6 +- loopback/locale/es.json | 7 +- modules/ticket/back/methods/ticket/addSale.js | 5 +- .../back/methods/ticket/componentUpdate.js | 6 +- .../ticket/back/methods/ticket/isEditable.js | 52 +-------- .../back/methods/ticket/isEditableOrThrow.js | 49 ++++++++ .../back/methods/ticket/priceDifference.js | 7 +- .../methods/ticket/recalculateComponents.js | 6 +- .../ticket/back/methods/ticket/setDeleted.js | 5 +- .../back/methods/ticket/specs/addSale.spec.js | 2 +- .../methods/ticket/specs/isEditable.spec.js | 109 ++++-------------- .../ticket/specs/isEditableOrThrow.spec.js | 100 ++++++++++++++++ .../ticket/specs/priceDifference.spec.js | 3 +- .../specs/recalculateComponents.spec.js | 3 +- .../ticket/specs/transferClient.spec.js | 2 +- .../ticket/specs/transferSales.spec.js | 2 +- .../back/methods/ticket/transferClient.js | 6 +- .../back/methods/ticket/transferSales.js | 6 +- modules/ticket/back/models/ticket-methods.js | 1 + 19 files changed, 203 insertions(+), 174 deletions(-) create mode 100644 modules/ticket/back/methods/ticket/isEditableOrThrow.js create mode 100644 modules/ticket/back/methods/ticket/specs/isEditableOrThrow.spec.js diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 030afbe9e..135bb2be9 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -178,5 +178,9 @@ "The renew period has not been exceeded": "The renew period has not been exceeded", "You can not use the same password": "You can not use the same password", "Valid priorities": "Valid priorities: %d", - "Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}" + "Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}", + "You don't have enough privileges.": "You don't have enough privileges.", + "This ticket is locked.": "This ticket is locked.", + "This ticket is not editable.": "This ticket is not editable.", + "The ticket doesn't exist.": "The ticket doesn't exist." } diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 942cc74c7..ac62d62e1 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -308,7 +308,8 @@ "The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias", "You cannot assign/remove an alias that you are not assigned to": "No puede asignar/eliminar un alias que no tenga asignado", "This invoice has a linked vehicle.": "Esta factura tiene un vehiculo vinculado", - "You don't have enough privileges.": "You don't have enough privileges.", - "This ticket is locked.": "This ticket is locked.", - "This ticket is not editable.": "This ticket is not editable." + "You don't have enough privileges.": "No tienes suficientes permisos.", + "This ticket is locked.": "Este ticket está bloqueado.", + "This ticket is not editable.": "Este ticket no es editable.", + "The ticket doesn't exist.": "No existe el ticket." } \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/addSale.js b/modules/ticket/back/methods/ticket/addSale.js index 2cd02a8a4..9a3e32a7e 100644 --- a/modules/ticket/back/methods/ticket/addSale.js +++ b/modules/ticket/back/methods/ticket/addSale.js @@ -1,4 +1,3 @@ - const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { @@ -47,9 +46,7 @@ module.exports = Self => { } try { - const isEditable = await models.Ticket.isEditable(ctx, id, myOptions); - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + const isEditable = await models.Ticket.isEditableOrThrow(ctx, id, myOptions); const item = await models.Item.findById(itemId, null, myOptions); const ticket = await models.Ticket.findById(id, { diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index 48aee36d4..eadbf65c2 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -1,4 +1,3 @@ -const UserError = require('vn-loopback/util/user-error'); const loggable = require('vn-loopback/util/log'); module.exports = Self => { @@ -116,10 +115,7 @@ module.exports = Self => { const userId = ctx.req.accessToken.userId; const models = Self.app.models; const $t = ctx.req.__; // $translate - const isEditable = await models.Ticket.isEditable(ctx, args.id, myOptions); - - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + const isEditable = await models.Ticket.isEditableOrThrow(ctx, args.id, myOptions); const editZone = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editZone', 'WRITE'); if (!editZone) { diff --git a/modules/ticket/back/methods/ticket/isEditable.js b/modules/ticket/back/methods/ticket/isEditable.js index 967988214..f657cd5e3 100644 --- a/modules/ticket/back/methods/ticket/isEditable.js +++ b/modules/ticket/back/methods/ticket/isEditable.js @@ -1,5 +1,3 @@ -const UserError = require('vn-loopback/util/user-error'); - module.exports = Self => { Self.remoteMethodCtx('isEditable', { description: 'Check if a ticket is editable', @@ -22,50 +20,12 @@ module.exports = Self => { }); Self.isEditable = async(ctx, id, options) => { - const models = Self.app.models; - const myOptions = {}; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - const state = await models.TicketState.findOne({ - where: {ticketFk: id} - }, myOptions); - - const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*'); - const canEditWeeklyTicket = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'canEditWeekly', 'WRITE'); - const alertLevel = state ? state.alertLevel : null; - const ticket = await models.Ticket.findById(id, { - fields: ['clientFk'], - include: [{ - relation: 'client', - scope: { - include: { - relation: 'type' - } - } - }] - }, 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) - throw new UserError(`The ticket doesn't exist.`); - - if (!isEditable && !isRoleAdvanced) - throw new UserError(`This ticket is not editable.`); - - if (isLocked) - throw new UserError(`This ticket is locked.`); - - if (isWeekly && !canEditWeeklyTicket) - throw new UserError(`You don't have enough privileges.`); - + try { + await Self.isEditableOrThrow(ctx, id, options); + } catch (e) { + if (e.name === 'ForbiddenError') return false; + throw e; + } return true; }; }; diff --git a/modules/ticket/back/methods/ticket/isEditableOrThrow.js b/modules/ticket/back/methods/ticket/isEditableOrThrow.js new file mode 100644 index 000000000..6a8bafa2c --- /dev/null +++ b/modules/ticket/back/methods/ticket/isEditableOrThrow.js @@ -0,0 +1,49 @@ +const ForbiddenError = require('vn-loopback/util/forbiddenError'); + +module.exports = Self => { + Self.isEditableOrThrow = async(ctx, id, options) => { + const models = Self.app.models; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const state = await models.TicketState.findOne({ + where: {ticketFk: id} + }, myOptions); + + const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*'); + const canEditWeeklyTicket = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'canEditWeekly', 'WRITE'); + const alertLevel = state ? state.alertLevel : null; + const ticket = await models.Ticket.findById(id, { + fields: ['clientFk'], + include: [{ + relation: 'client', + scope: { + include: { + relation: 'type' + } + } + }] + }, 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) + throw new ForbiddenError(`The ticket doesn't exist.`); + + if (!isEditable && !isRoleAdvanced) + throw new ForbiddenError(`This ticket is not editable.`); + + if (isLocked) + throw new ForbiddenError(`This ticket is locked.`); + + if (isWeekly && !canEditWeeklyTicket) + throw new ForbiddenError(`You don't have enough privileges.`); + }; +}; diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index 42a71f1c8..754646b03 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -1,5 +1,3 @@ -const UserError = require('vn-loopback/util/user-error'); - module.exports = Self => { Self.remoteMethodCtx('priceDifference', { description: 'Returns sales with price difference if the ticket is editable', @@ -72,10 +70,7 @@ module.exports = Self => { } try { - const isEditable = await Self.isEditable(ctx, args.id, myOptions); - - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + const isEditable = await Self.isEditableOrThrow(ctx, args.id, myOptions); const editZone = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editZone', 'WRITE'); if (!editZone) { diff --git a/modules/ticket/back/methods/ticket/recalculateComponents.js b/modules/ticket/back/methods/ticket/recalculateComponents.js index eb9c8a72e..78c44bab3 100644 --- a/modules/ticket/back/methods/ticket/recalculateComponents.js +++ b/modules/ticket/back/methods/ticket/recalculateComponents.js @@ -1,4 +1,3 @@ -const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('recalculateComponents', { description: 'Calculates the price of a sale and its components', @@ -33,10 +32,7 @@ module.exports = Self => { } try { - const isEditable = await Self.isEditable(ctx, id, myOptions); - - if (!isEditable) - throw new UserError(`The current ticket can't be modified`); + const isEditable = await Self.isEditableOrThrow(ctx, id, myOptions); const recalculation = await Self.rawSql('CALL vn.ticket_recalcComponents(?, NULL)', [id], myOptions); diff --git a/modules/ticket/back/methods/ticket/setDeleted.js b/modules/ticket/back/methods/ticket/setDeleted.js index 878cce056..6485f198e 100644 --- a/modules/ticket/back/methods/ticket/setDeleted.js +++ b/modules/ticket/back/methods/ticket/setDeleted.js @@ -39,10 +39,7 @@ module.exports = Self => { const ticketToDelete = await models.Ticket.findById(id, {fields: ['isDeleted']}, myOptions); if (ticketToDelete.isDeleted) return false; - const isEditable = await Self.isEditable(ctx, id, myOptions); - - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + const isEditable = await Self.isEditableOrThrow(ctx, id, myOptions); // Check if ticket has refunds const ticketRefunds = await models.TicketRefund.find({ diff --git a/modules/ticket/back/methods/ticket/specs/addSale.spec.js b/modules/ticket/back/methods/ticket/specs/addSale.spec.js index 2e568716a..b1ecb133b 100644 --- a/modules/ticket/back/methods/ticket/specs/addSale.spec.js +++ b/modules/ticket/back/methods/ticket/specs/addSale.spec.js @@ -97,6 +97,6 @@ describe('ticket addSale()', () => { error = e; } - expect(error.message).toEqual(`The sales of this ticket can't be modified`); + expect(error.message).toEqual(`This ticket is locked.`); }); }); diff --git a/modules/ticket/back/methods/ticket/specs/isEditable.spec.js b/modules/ticket/back/methods/ticket/specs/isEditable.spec.js index 043445c28..301745ed3 100644 --- a/modules/ticket/back/methods/ticket/specs/isEditable.spec.js +++ b/modules/ticket/back/methods/ticket/specs/isEditable.spec.js @@ -1,100 +1,37 @@ const models = require('vn-loopback/server/server').models; -describe('ticket isEditable()', () => { - it('should throw an error as the ticket does not exist', async() => { - const tx = await models.Ticket.beginTransaction({}); - let error; - try { - const options = {transaction: tx}; - const ctx = { - req: {accessToken: {userId: 9}} - }; - - await models.Ticket.isEditable(ctx, 9999, options); - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toEqual(`The ticket doesn't exist.`); - }); - - it('should throw an error as this ticket is not editable', async() => { - const tx = await models.Ticket.beginTransaction({}); - let error; - - try { - const options = {transaction: tx}; - const ctx = { - req: {accessToken: {userId: 1}} - }; - - await models.Ticket.isEditable(ctx, 8, options); - await tx.rollback(); - } catch (e) { - error = e; - await tx.rollback(); - } - - expect(error.message).toEqual(`This ticket is not editable.`); - }); - - it('should throw an error as this ticket is locked.', async() => { - const tx = await models.Ticket.beginTransaction({}); - let error; - try { - const options = {transaction: tx}; - const ctx = { - req: {accessToken: {userId: 18}} - }; - - await models.Ticket.isEditable(ctx, 19, options); - - await tx.rollback(); - } catch (e) { - error = e; - await tx.rollback(); - } - - expect(error.message).toEqual(`This ticket is locked.`); - }); - - it('should throw an error as you do not have enough privileges.', async() => { - const tx = await models.Ticket.beginTransaction({}); - let error; - 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) { - error = e; - await tx.rollback(); - } - - expect(error.message).toEqual(`You don't have enough privileges.`); - }); - - it('should be able to edit a ticket weekly', async() => { +describe('isEditable()', () => { + it('should return false if It is able to edit', async() => { const tx = await models.Ticket.beginTransaction({}); let result; + try { const options = {transaction: tx}; const ctx = {req: {accessToken: {userId: 35}}}; - - result = await models.Ticket.isEditable(ctx, 15, options); + result = await models.Ticket.isEditable(ctx, 5, options); await tx.rollback(); - } catch (e) { + } catch (error) { await tx.rollback(); throw e; } - expect(result).toEqual(true); + expect(result).toBeFalse(); + }); + + it('should return true if It is able to edit', async() => { + const tx = await models.Ticket.beginTransaction({}); + let result; + + try { + const options = {transaction: tx}; + const ctx = {req: {accessToken: {userId: 35}}}; + result = await models.Ticket.isEditable(ctx, 15, options); + await tx.rollback(); + } catch (error) { + await tx.rollback(); + throw e; + } + + expect(result).toBeTrue(); }); }); diff --git a/modules/ticket/back/methods/ticket/specs/isEditableOrThrow.spec.js b/modules/ticket/back/methods/ticket/specs/isEditableOrThrow.spec.js new file mode 100644 index 000000000..b65ed64a1 --- /dev/null +++ b/modules/ticket/back/methods/ticket/specs/isEditableOrThrow.spec.js @@ -0,0 +1,100 @@ +const models = require('vn-loopback/server/server').models; + +describe('ticket isEditableOrThrow()', () => { + it('should throw an error as the ticket does not exist', async() => { + const tx = await models.Ticket.beginTransaction({}); + let error; + try { + const options = {transaction: tx}; + const ctx = { + req: {accessToken: {userId: 9}} + }; + + await models.Ticket.isEditableOrThrow(ctx, 9999, options); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toEqual(`The ticket doesn't exist.`); + }); + + it('should throw an error as this ticket is not editable', async() => { + const tx = await models.Ticket.beginTransaction({}); + let error; + + try { + const options = {transaction: tx}; + const ctx = { + req: {accessToken: {userId: 1}} + }; + + await models.Ticket.isEditableOrThrow(ctx, 8, options); + await tx.rollback(); + } catch (e) { + error = e; + await tx.rollback(); + } + + expect(error.message).toEqual(`This ticket is not editable.`); + }); + + it('should throw an error as this ticket is locked.', async() => { + const tx = await models.Ticket.beginTransaction({}); + let error; + try { + const options = {transaction: tx}; + const ctx = { + req: {accessToken: {userId: 18}} + }; + + await models.Ticket.isEditableOrThrow(ctx, 19, options); + + await tx.rollback(); + } catch (e) { + error = e; + await tx.rollback(); + } + + expect(error.message).toEqual(`This ticket is locked.`); + }); + + it('should throw an error as you do not have enough privileges.', async() => { + const tx = await models.Ticket.beginTransaction({}); + let error; + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 1}}}; + + const result = await models.Ticket.isEditableOrThrow(ctx, 15, options); + + expect(result).toEqual(false); + + await tx.rollback(); + } catch (e) { + error = e; + await tx.rollback(); + } + + expect(error.message).toEqual(`You don't have enough privileges.`); + }); + + it('should return undefined if It can be edited', async() => { + const tx = await models.Ticket.beginTransaction({}); + let result; + try { + const options = {transaction: tx}; + const ctx = {req: {accessToken: {userId: 35}}}; + + result = await models.Ticket.isEditableOrThrow(ctx, 15, options); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + + expect(result).toBeUndefined(); + }); +}); diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js index cc54353ef..d01f0c1bb 100644 --- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js +++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js @@ -1,5 +1,6 @@ const models = require('vn-loopback/server/server').models; const UserError = require('vn-loopback/util/user-error'); +const ForbiddenError = require('vn-loopback/util/forbiddenError'); describe('sale priceDifference()', () => { it('should return ticket price differences', async() => { @@ -59,7 +60,7 @@ describe('sale priceDifference()', () => { await tx.rollback(); } - expect(error).toEqual(new UserError(`The sales of this ticket can't be modified`)); + expect(error).toEqual(new ForbiddenError(`This ticket is not editable.`)); }); it('should return ticket movable', async() => { diff --git a/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js b/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js index ed10d114f..383c2c6d5 100644 --- a/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js +++ b/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js @@ -1,4 +1,5 @@ const models = require('vn-loopback/server/server').models; +const ForbiddenError = require('vn-loopback/util/forbiddenError'); describe('ticket recalculateComponents()', () => { const ticketId = 11; @@ -38,6 +39,6 @@ describe('ticket recalculateComponents()', () => { error = e; } - expect(error).toEqual(new Error(`The current ticket can't be modified`)); + expect(error).toEqual(new ForbiddenError(`This ticket is locked.`)); }); }); diff --git a/modules/ticket/back/methods/ticket/specs/transferClient.spec.js b/modules/ticket/back/methods/ticket/specs/transferClient.spec.js index ed10e5159..c09c20083 100644 --- a/modules/ticket/back/methods/ticket/specs/transferClient.spec.js +++ b/modules/ticket/back/methods/ticket/specs/transferClient.spec.js @@ -23,7 +23,7 @@ describe('Ticket transferClient()', () => { error = e; } - expect(error.message).toEqual(`The current ticket can't be modified`); + expect(error.message).toEqual(`This ticket is locked.`); }); it('should be assigned a different clientFk', async() => { diff --git a/modules/ticket/back/methods/ticket/specs/transferSales.spec.js b/modules/ticket/back/methods/ticket/specs/transferSales.spec.js index 562688917..ef92e88c0 100644 --- a/modules/ticket/back/methods/ticket/specs/transferSales.spec.js +++ b/modules/ticket/back/methods/ticket/specs/transferSales.spec.js @@ -33,7 +33,7 @@ describe('sale transferSales()', () => { error = e; } - expect(error.message).toEqual(`The sales of this ticket can't be modified`); + expect(error.message).toEqual(`This ticket is not editable.`); }); it('should throw an error if the receiving ticket is not editable', async() => { diff --git a/modules/ticket/back/methods/ticket/transferClient.js b/modules/ticket/back/methods/ticket/transferClient.js index 04c153bd2..c87ad4881 100644 --- a/modules/ticket/back/methods/ticket/transferClient.js +++ b/modules/ticket/back/methods/ticket/transferClient.js @@ -1,4 +1,3 @@ -const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('transferClient', { description: 'Transfering ticket to another client', @@ -29,10 +28,7 @@ module.exports = Self => { if (typeof options == 'object') Object.assign(myOptions, options); - const isEditable = await Self.isEditable(ctx, id, myOptions); - - if (!isEditable) - throw new UserError(`The current ticket can't be modified`); + const isEditable = await Self.isEditableOrThrow(ctx, id, myOptions); const ticket = await models.Ticket.findById( id, diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js index 0eee50d5f..bd99920db 100644 --- a/modules/ticket/back/methods/ticket/transferSales.js +++ b/modules/ticket/back/methods/ticket/transferSales.js @@ -1,4 +1,4 @@ -let UserError = require('vn-loopback/util/user-error'); +const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('transferSales', { @@ -48,9 +48,7 @@ module.exports = Self => { } try { - const isEditable = await models.Ticket.isEditable(ctx, id, myOptions); - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + const isEditable = await models.Ticket.isEditableOrThrow(ctx, id, myOptions); if (ticketId) { const isReceiverEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions); diff --git a/modules/ticket/back/models/ticket-methods.js b/modules/ticket/back/models/ticket-methods.js index b432c9f6b..c37337253 100644 --- a/modules/ticket/back/models/ticket-methods.js +++ b/modules/ticket/back/models/ticket-methods.js @@ -6,6 +6,7 @@ module.exports = function(Self) { require('../methods/ticket/componentUpdate')(Self); require('../methods/ticket/new')(Self); require('../methods/ticket/isEditable')(Self); + require('../methods/ticket/isEditableOrThrow')(Self); require('../methods/ticket/setDeleted')(Self); require('../methods/ticket/restore')(Self); require('../methods/ticket/getSales')(Self);