Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 5834-billingDataAutoFillBic

This commit is contained in:
Jorge Penadés 2023-07-26 13:39:42 +02:00
commit 7283945cf2
20 changed files with 192 additions and 207 deletions

View File

@ -0,0 +1,2 @@
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalType`,`principalId`)
VALUES ('Ticket','canEditWeekly','WRITE','ALLOW','ROLE','buyer');

View File

@ -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."
}

View File

@ -307,5 +307,9 @@
"Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}",
"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"
}
"This invoice has a linked vehicle.": "Esta factura tiene un vehiculo vinculado",
"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."
}

View File

@ -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`);
await models.Ticket.isEditableOrThrow(ctx, id, myOptions);
const item = await models.Item.findById(itemId, null, myOptions);
const ticket = await models.Ticket.findById(id, {

View File

@ -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`);
await models.Ticket.isEditableOrThrow(ctx, args.id, myOptions);
const editZone = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editZone', 'WRITE');
if (!editZone) {

View File

@ -20,41 +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 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 && (isEditable || isRoleAdvanced) && !isLocked && !isWeekly)
return true;
return false;
try {
await Self.isEditableOrThrow(ctx, id, options);
} catch (e) {
if (e.name === 'ForbiddenError') return false;
throw e;
}
return true;
};
};

View File

@ -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.`);
};
};

View File

@ -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`);
await Self.isEditableOrThrow(ctx, args.id, myOptions);
const editZone = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editZone', 'WRITE');
if (!editZone) {

View File

@ -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`);
await Self.isEditableOrThrow(ctx, id, myOptions);
const recalculation = await Self.rawSql('CALL vn.ticket_recalcComponents(?, NULL)', [id], myOptions);

View File

@ -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`);
await Self.isEditableOrThrow(ctx, id, myOptions);
// Check if ticket has refunds
const ticketRefunds = await models.TicketRefund.find({

View File

@ -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.`);
});
});

View File

@ -1,156 +1,37 @@
const models = require('vn-loopback/server/server').models;
describe('ticket isEditable()', () => {
it('should return false if the given ticket does not exist', 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: 9}}
};
result = await models.Ticket.isEditable(ctx, 9999, options);
const ctx = {req: {accessToken: {userId: 35}}};
result = await models.Ticket.isEditable(ctx, 5, options);
await tx.rollback();
} catch (e) {
} catch (error) {
await tx.rollback();
throw e;
}
expect(result).toEqual(false);
expect(result).toBeFalse();
});
it(`should return false if the given ticket isn't invoiced but isDeleted`, async() => {
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 deletedTicket = await models.Ticket.findOne({
where: {
invoiceOut: null,
isDeleted: true
},
fields: ['id']
});
const ctx = {
req: {accessToken: {userId: 9}}
};
result = await models.Ticket.isEditable(ctx, deletedTicket.id, options);
const ctx = {req: {accessToken: {userId: 35}}};
result = await models.Ticket.isEditable(ctx, 15, options);
await tx.rollback();
} catch (e) {
} catch (error) {
await tx.rollback();
throw e;
}
expect(result).toEqual(false);
});
it('should return true if the given ticket is editable', async() => {
const tx = await models.Ticket.beginTransaction({});
let result;
try {
const options = {transaction: tx};
const ctx = {
req: {accessToken: {userId: 9}}
};
result = await models.Ticket.isEditable(ctx, 16, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
expect(result).toEqual(true);
});
it('should not be able to edit a deleted or invoiced ticket even for salesAssistant', async() => {
const tx = await models.Ticket.beginTransaction({});
let result;
try {
const options = {transaction: tx};
const ctx = {
req: {accessToken: {userId: 21}}
};
result = await models.Ticket.isEditable(ctx, 19, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
expect(result).toEqual(false);
});
it('should not be able to edit a deleted or invoiced ticket even for productionBoss', async() => {
const tx = await models.Ticket.beginTransaction({});
let result;
try {
const options = {transaction: tx};
const ctx = {
req: {accessToken: {userId: 50}}
};
result = await models.Ticket.isEditable(ctx, 19, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
expect(result).toEqual(false);
});
it('should not be able to edit a deleted or invoiced ticket even for salesPerson', async() => {
const tx = await models.Ticket.beginTransaction({});
let result;
try {
const options = {transaction: tx};
const ctx = {
req: {accessToken: {userId: 18}}
};
result = await models.Ticket.isEditable(ctx, 19, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
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;
}
expect(result).toBeTrue();
});
});

View File

@ -0,0 +1,96 @@
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}}};
await models.Ticket.isEditableOrThrow(ctx, 15, options);
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();
});
});

View File

@ -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() => {

View File

@ -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.`));
});
});

View File

@ -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() => {

View File

@ -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() => {

View File

@ -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`);
await Self.isEditableOrThrow(ctx, id, myOptions);
const ticket = await models.Ticket.findById(
id,

View File

@ -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`);
await models.Ticket.isEditableOrThrow(ctx, id, myOptions);
if (ticketId) {
const isReceiverEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions);

View File

@ -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);