refactor(ticket): isEditable, canEdit
gitea/salix/pipeline/head There was a failure building this commit Details

This commit is contained in:
Alex Moreno 2022-10-04 13:22:11 +02:00
parent e4b61f81a9
commit fe8ae164eb
13 changed files with 141 additions and 30 deletions

View File

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

View File

@ -7,6 +7,7 @@ module.exports = Self => {
require('../methods/account/change-password')(Self); require('../methods/account/change-password')(Self);
require('../methods/account/set-password')(Self); require('../methods/account/set-password')(Self);
require('../methods/account/validate-token')(Self); require('../methods/account/validate-token')(Self);
require('../methods/account/aclFunc')(Self);
// Validations // Validations

View File

@ -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`) INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `level`, `wagon`, `smartTagFk`, `usedShelves`, `itemCount`, `liters`)
VALUES VALUES
(9, 3, util.VN_NOW(), NULL, 0, NULL, NULL, NULL, NULL); (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');

View File

@ -1,3 +1,5 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('canEdit', { Self.remoteMethodCtx('canEdit', {
description: 'Check if all the received sales are aditable', description: 'Check if all the received sales are aditable',
@ -25,16 +27,26 @@ module.exports = Self => {
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
const idsCollection = sales.map(sale => sale.id); /* const firstSale = await models.Sale.findById(sales[0], null, myOptions);
const isTicketEditable = await models.Ticket.isEditable(ctx, firstSale.ticketFk, myOptions);
const saleTracking = await models.SaleTracking.find({where: {saleFk: {inq: idsCollection}}}, 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 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;
}; };
}; };

View File

@ -41,7 +41,8 @@ module.exports = Self => {
} }
try { 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, { const ticket = await models.Ticket.findById(ticketId, {
include: { include: {

View File

@ -1,4 +1,5 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('recalculatePrice', { Self.remoteMethodCtx('recalculatePrice', {
description: 'Calculates the price of sales and its components', description: 'Calculates the price of sales and its components',
@ -34,15 +35,13 @@ module.exports = Self => {
} }
try { try {
const salesIds = []; const salesIds = sales.map(sale => sale.id);
for (let sale of sales)
salesIds.push(sale.id);
const isEditable = await models.Ticket.isEditable(ctx, sales[0].ticketFk, myOptions); const isEditable = await models.Ticket.isEditable(ctx, sales[0].ticketFk, myOptions);
if (!isEditable) if (!isEditable)
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 canEditSale = await models.Sale.canEdit(ctx, sales, myOptions); const canEditSale = await models.Sale.canEdit(ctx, salesIds, myOptions);
if (!canEditSale) if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`); throw new UserError(`Sale(s) blocked, please contact production`);

View File

@ -53,7 +53,8 @@ module.exports = Self => {
if (!isTicketEditable) 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 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) if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`); throw new UserError(`Sale(s) blocked, please contact production`);

View File

@ -10,7 +10,7 @@ describe('sale canEdit()', () => {
const productionUserID = 49; const productionUserID = 49;
const ctx = {req: {accessToken: {userId: productionUserID}}}; const ctx = {req: {accessToken: {userId: productionUserID}}};
const sales = [{id: 3}]; const sales = [3];
const result = await models.Sale.canEdit(ctx, sales, options); const result = await models.Sale.canEdit(ctx, sales, options);
@ -32,7 +32,7 @@ describe('sale canEdit()', () => {
const salesPersonUserID = 18; const salesPersonUserID = 18;
const ctx = {req: {accessToken: {userId: salesPersonUserID}}}; const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
const sales = [{id: 10}]; const sales = [10];
const result = await models.Sale.canEdit(ctx, sales, options); const result = await models.Sale.canEdit(ctx, sales, options);
@ -54,7 +54,7 @@ describe('sale canEdit()', () => {
const salesPersonUserID = 18; const salesPersonUserID = 18;
const ctx = {req: {accessToken: {userId: salesPersonUserID}}}; const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
const sales = [{id: 3}]; const sales = [3];
const result = await models.Sale.canEdit(ctx, sales, options); const result = await models.Sale.canEdit(ctx, sales, options);

View File

@ -20,24 +20,20 @@ module.exports = Self => {
}); });
Self.isEditable = async(ctx, id, options) => { Self.isEditable = async(ctx, id, options) => {
const userId = ctx.req.accessToken.userId; const models = Self.app.models;
const myOptions = {}; const myOptions = {};
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
let state = await Self.app.models.TicketState.findOne({ const state = await models.TicketState.findOne({
where: {ticketFk: id} where: {ticketFk: id}
}, myOptions); }, myOptions);
const isSalesAssistant = await Self.app.models.Account.hasRole(userId, 'salesAssistant', myOptions); const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, myOptions);
const isDeliveryBoss = await Self.app.models.Account.hasRole(userId, 'deliveryBoss', myOptions);
const isBuyer = await Self.app.models.Account.hasRole(userId, 'buyer', myOptions);
const isValidRole = isSalesAssistant || isDeliveryBoss || isBuyer; const alertLevel = state ? state.alertLevel : null;
const ticket = await models.Ticket.findById(id, {
let alertLevel = state ? state.alertLevel : null;
let ticket = await Self.app.models.Ticket.findById(id, {
fields: ['clientFk'], fields: ['clientFk'],
include: [{ include: [{
relation: 'client', relation: 'client',
@ -48,15 +44,15 @@ module.exports = Self => {
} }
}] }]
}, myOptions); }, 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 alertLevelGreaterThanZero = (alertLevel && alertLevel > 0);
const isNormalClient = ticket && ticket.client().type().code == 'normal'; 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;
}; };
}; };

View File

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

View File

@ -29,6 +29,9 @@
"SaleChecked": { "SaleChecked": {
"dataSource": "vn" "dataSource": "vn"
}, },
"SaleCloned": {
"dataSource": "vn"
},
"SaleComponent": { "SaleComponent": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

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

View File

@ -28,6 +28,7 @@ module.exports = Self => {
require('../methods/ticket/freightCost')(Self); require('../methods/ticket/freightCost')(Self);
require('../methods/ticket/getComponentsSum')(Self); require('../methods/ticket/getComponentsSum')(Self);
require('../methods/ticket/refund')(Self); require('../methods/ticket/refund')(Self);
require('../methods/ticket/isRoleAdvanced')(Self);
Self.observe('before save', async function(ctx) { Self.observe('before save', async function(ctx) {
const loopBackContext = LoopBackContext.getCurrentContext(); const loopBackContext = LoopBackContext.getCurrentContext();