Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 5334-editDepartment

This commit is contained in:
Carlos Satorres 2023-05-30 08:05:17 +02:00
commit 9ee653dbd1
60 changed files with 336 additions and 179 deletions

View File

@ -67,7 +67,7 @@ module.exports = Self => {
if (!image) return false;
const hasReadRole = models.ImageCollection.hasReadRole(ctx, collection);
const hasReadRole = await models.ImageCollection.hasReadRole(ctx, collection);
if (!hasReadRole)
throw new UserError(`You don't have enough privileges`);

View File

@ -9,10 +9,11 @@ module.exports = Self => {
* @return {boolean} True for user with read privileges
*/
Self.hasReadRole = async(ctx, name, options) => {
const collection = await Self.findOne({where: {name}}, {
const collection = await Self.findOne({
include: {
relation: 'readRole'
}
},
where: {name}
}, options);
return await hasRole(ctx, collection, options);

View File

@ -27,7 +27,6 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp
('Client', 'summary', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateUser', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'campaignMetricsPdf', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'campaignMetricsEmail', '*', 'ALLOW', 'ROLE', 'employee'),

View File

@ -0,0 +1,121 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Ticket', 'editDiscount', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Ticket', 'editDiscount', 'WRITE', 'ALLOW', 'ROLE', 'salesPerson'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'salesAssistant'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'deliveryBoss'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'buyer'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'claimManager'),
('Ticket', 'deleteTicketWithPartPrepared', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Ticket', 'editZone', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss'),
('State', 'editableStates', 'READ', 'ALLOW', 'ROLE', 'employee'),
('State', 'seeEditableStates', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('State', 'seeEditableStates', 'READ', 'ALLOW', 'ROLE', 'production'),
('State', 'isSomeEditable', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('State', 'isAllEditable', 'READ', 'ALLOW', 'ROLE', 'production'),
('State', 'isAllEditable', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('Agency', 'seeExpired', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('Agency', 'seeExpired', 'READ', 'ALLOW', 'ROLE', 'productionBoss'),
('Claim', 'createAfterDeadline', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Client', 'editAddressLogifloraAllowed', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Client', 'editFiscalDataWithoutTaxDataCheck', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Client', 'editVerifiedDataWithoutTaxDataCheck', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Client', 'editCredit', 'WRITE', 'ALLOW', 'ROLE', 'financialBoss'),
('Client', 'isNotEditableCredit', 'WRITE', 'ALLOW', 'ROLE', 'financialBoss'),
('InvoiceOut', 'canCreatePdf', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'),
('Supplier', 'editPayMethodCheck', 'WRITE', 'ALLOW', 'ROLE', 'financial'),
('Worker', 'isTeamBoss', 'WRITE', 'ALLOW', 'ROLE', 'teamBoss'),
('Worker', 'forceIsSubordinate', 'READ', 'ALLOW', 'ROLE', 'hr'),
('Claim', 'editState', 'WRITE', 'ALLOW', 'ROLE', 'claimManager');
DELETE FROM `salix`.`ACL`
WHERE
model = 'Claim'
AND property = '*'
AND accessType = '*';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Claim', 'find', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'findById', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'findOne', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'getSummary', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'updateClaim', 'WRITE', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'regularizeClaim', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'updateClaimDestination', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'downloadFile', 'READ', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'filter', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'logs', 'READ', 'ALLOW', 'ROLE', 'claimManager');
DELETE FROM `salix`.`ACL`
WHERE
model = 'Ticket'
AND property = '*'
AND accessType = '*';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Ticket', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getVolume', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getTotalVolume', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'summary', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'priceDifference', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'componentUpdate', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'new', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'isEditable', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'setDeleted', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'restore', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getSales', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getSalesPersonMana', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'filter', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'makeInvoice', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'updateEditableTicket', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'updateDiscount', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'transferSales', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'sendSms', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'isLocked', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'freightCost', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getComponentsSum', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'updateAttributes', 'WRITE', 'ALLOW', 'ROLE', 'delivery'), -- Change Priority in Route tickets
('Ticket', 'deliveryNoteCsv', 'READ', 'ALLOW', 'ROLE', 'employee');
DELETE FROM `salix`.`ACL`
WHERE
model = 'State'
AND property = '*'
AND accessType = 'READ';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('State', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('State', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
('State', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee');
DELETE FROM `salix`.`ACL`
WHERE
model = 'Worker'
AND property = '*'
AND accessType = 'READ';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Worker', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'filter', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'getWorkedHours', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'active', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'activeWithRole', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'uploadFile', 'WRITE', 'ALLOW', 'ROLE', 'hr'),
('Worker', 'contracts', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'holidays', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'activeContract', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'activeWithInheritedRole', 'READ', 'ALLOW', 'ROLE', 'employee');
DELETE FROM `salix`.`ACL`
WHERE model = 'Client'
AND property = 'updateUser'
AND accessType = '*';

View File

@ -625,6 +625,7 @@ export default {
selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check',
secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[ng-model="sale.checked"]',
thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[ng-model="sale.checked"]',
fourthSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(4) vn-check[ng-model="sale.checked"]',
deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]',
transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]',
moveToTicketInput: 'form vn-input-number[ng-model="$ctrl.transfer.ticketId"] input',

View File

@ -251,7 +251,6 @@ describe('Ticket Edit sale path', () => {
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
await page.waitToClick(selectors.globalItems.acceptButton);
await page.waitToClick(selectors.globalItems.acceptButton);
await page.waitForState('claim.card.basicData');
});

View File

@ -17,7 +17,7 @@ describe('Claim summary path', () => {
});
it('should navigate to the target claim summary section', async() => {
await page.loginAndModule('employee', 'claim');
await page.loginAndModule('salesPerson', 'claim');
await page.accessToSearchResult(claimId);
await page.waitForState('claim.card.summary');
});

View File

@ -16,7 +16,7 @@ describe('Claim descriptor path', () => {
});
it('should now navigate to the target claim summary section', async() => {
await page.loginAndModule('employee', 'claim');
await page.loginAndModule('salesPerson', 'claim');
await page.accessToSearchResult(claimId);
await page.waitForState('claim.card.summary');
});

View File

@ -7,11 +7,13 @@ vn-descriptor-content {
.photo {
position: relative;
width: 100%;
text-align: center;
overflow: hidden;
& > img[ng-src] {
min-height: 16em;
display: block;
max-width: 100%;
height: 256px;
}

View File

@ -171,5 +171,7 @@
"Added observation": "Added observation",
"Comment added to client": "Comment added to client",
"This ticket is already a refund": "This ticket is already a refund",
"A claim with that sale already exists": "A claim with that sale already exists"
"A claim with that sale already exists": "A claim with that sale already exists",
"Can't transfer claimed sales": "Can't transfer claimed sales",
"Invalid quantity": "Invalid quantity"
}

View File

@ -59,12 +59,14 @@ module.exports = Self => {
const landedPlusWeek = new Date(ticket.landed);
landedPlusWeek.setDate(landedPlusWeek.getDate() + 7);
const hasClaimManagerRole = await models.VnUser.hasRole(userId, 'claimManager', myOptions);
const isClaimable = landedPlusWeek >= Date.vnNew();
const canCreateClaimAfterDeadline =
await models.ACL.checkAccessAcl(ctx, 'Claim', 'createAfterDeadline', 'WRITE');
if (ticket.isDeleted)
throw new UserError(`You can't create a claim for a removed ticket`);
if (!isClaimable && !hasClaimManagerRole)
if (!isClaimable && !canCreateClaimAfterDeadline)
throw new UserError(`You can't create a claim from a ticket delivered more than seven days ago`);
const newClaim = await Self.create({

View File

@ -46,7 +46,6 @@ module.exports = Self => {
Self.updateClaim = async(ctx, id, options) => {
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
const args = ctx.args;
let tx;
const myOptions = {};
@ -81,9 +80,9 @@ module.exports = Self => {
if (args.claimStateFk) {
const canEditOldState = await models.ClaimState.isEditable(ctx, claim.claimStateFk, myOptions);
const canEditNewState = await models.ClaimState.isEditable(ctx, args.claimStateFk, myOptions);
const isClaimManager = await models.VnUser.hasRole(userId, 'claimManager', myOptions);
const canEditState = await models.ACL.checkAccessAcl(ctx, 'Claim', 'editState', 'WRITE');
if (!canEditOldState || !canEditNewState || changedHasToPickUp && !isClaimManager)
if (!canEditOldState || !canEditNewState || changedHasToPickUp && !canEditState)
throw new UserError(`You don't have enough privileges to change that field`);
}

View File

@ -87,15 +87,15 @@ module.exports = function(Self) {
Self.updateAddress = async(ctx, clientId, addressId, options) => {
const models = Self.app.models;
const args = ctx.args;
const userId = ctx.req.accessToken.userId;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const isSalesAssistant = await models.VnUser.hasRole(userId, 'salesAssistant', myOptions);
const canEditAddressLogifloraAllowed =
await models.ACL.checkAccessAcl(ctx, 'Client', 'editAddressLogifloraAllowed');
if (args.isLogifloraAllowed && !isSalesAssistant)
if (args.isLogifloraAllowed && !canEditAddressLogifloraAllowed)
throw new UserError(`You don't have enough privileges`);
const address = await models.Address.findOne({

View File

@ -131,9 +131,10 @@ module.exports = Self => {
myOptions.transaction = tx;
}
try {
const isSalesAssistant = await models.VnUser.hasRole(userId, 'salesAssistant', myOptions);
const canEditNotTaxDataChecked =
await models.ACL.checkAccessAcl(ctx, 'Client', 'editFiscalDataWithoutTaxDataCheck', 'WRITE');
const client = await models.Client.findById(clientId, null, myOptions);
if (!isSalesAssistant && client.isTaxDataChecked)
if (!canEditNotTaxDataChecked && client.isTaxDataChecked)
throw new UserError(`Not enough privileges to edit a client with verified data`);
// Sage data validation
const taxDataChecked = args.isTaxDataChecked;

View File

@ -2,6 +2,7 @@ const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('updateUser', {
description: 'Updates the user information',
accessType: 'WRITE',
accepts: [
{
arg: 'id',
@ -32,7 +33,6 @@ module.exports = Self => {
Self.updateUser = async function(ctx, id, options) {
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
let tx;
const myOptions = {};
@ -45,9 +45,8 @@ module.exports = Self => {
}
try {
const isSalesPerson = await models.VnUser.hasRole(userId, 'salesPerson', myOptions);
if (!isSalesPerson)
const canEdit = await models.ACL.checkAccessAcl(ctx, 'Client', 'updateUser', 'WRITE');
if (!canEdit)
throw new UserError(`Not enough privileges to edit a client`);
const isClient = await models.Client.findById(id, null, myOptions);

View File

@ -218,9 +218,9 @@ module.exports = Self => {
const models = Self.app.models;
const loopBackContext = LoopBackContext.getCurrentContext();
const userId = loopBackContext.active.accessToken.userId;
const accessToken = {req: loopBackContext.active.accessToken};
const isSalesAssistant = await models.VnUser.hasRole(userId, 'salesAssistant', ctx.options);
const editVerifiedDataWithoutTaxDataChecked = models.ACL.checkAccessAcl(accessToken, 'Client', 'editVerifiedDataWithoutTaxDataCheck', 'WRITE');
const hasChanges = orgData && changes;
const isTaxDataChecked = hasChanges && (changes.isTaxDataChecked || orgData.isTaxDataChecked);
@ -232,8 +232,8 @@ module.exports = Self => {
const sageTransactionType = hasChanges && (changes.sageTransactionTypeFk || orgData.sageTransactionTypeFk);
const sageTransactionTypeChanged = hasChanges && orgData.sageTransactionTypeFk != sageTransactionType;
const cantEditVerifiedData = isTaxDataCheckedChanged && !isSalesAssistant;
const cantChangeSageData = (sageTaxTypeChanged || sageTransactionTypeChanged) && !isSalesAssistant;
const cantEditVerifiedData = isTaxDataCheckedChanged && !editVerifiedDataWithoutTaxDataChecked;
const cantChangeSageData = (sageTaxTypeChanged || sageTransactionTypeChanged) && !editVerifiedDataWithoutTaxDataChecked;
if (cantEditVerifiedData || cantChangeSageData)
throw new UserError(`You don't have enough privileges`);
@ -401,9 +401,10 @@ module.exports = Self => {
Self.changeCredit = async function changeCredit(ctx, finalState, changes) {
const models = Self.app.models;
const userId = ctx.options.accessToken.userId;
const accessToken = {req: {accessToken: ctx.options.accessToken} };
const isFinancialBoss = await models.VnUser.hasRole(userId, 'financialBoss', ctx.options);
if (!isFinancialBoss) {
const canEditCredit = await models.ACL.checkAccessAcl(accessToken, 'Client', 'editCredit', 'WRITE');
if (!canEditCredit) {
const lastCredit = await models.ClientCredit.findOne({
where: {
clientFk: finalState.id
@ -412,10 +413,9 @@ module.exports = Self => {
}, ctx.options);
const lastAmount = lastCredit && lastCredit.amount;
const lastWorkerId = lastCredit && lastCredit.workerFk;
const lastWorkerIsFinancialBoss = await models.VnUser.hasRole(lastWorkerId, 'financialBoss', ctx.options);
const lastCreditIsNotEditable = !await models.ACL.checkAccessAcl(accessToken, 'Client', 'isNotEditableCredit', 'WRITE');
if (lastAmount == 0 && lastWorkerIsFinancialBoss)
if (lastAmount == 0 && lastCreditIsNotEditable)
throw new UserError(`You can't change the credit set to zero from a financialBoss`);
const creditLimits = await models.ClientCreditLimit.find({

View File

@ -2,6 +2,11 @@
vn-id="watcher"
data="$ctrl.dms">
</vn-watcher>
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form
name="form"
ng-submit="$ctrl.onSubmit()"
@ -29,7 +34,7 @@
<vn-autocomplete vn-one required="true"
label="Warehouse"
ng-model="$ctrl.dms.warehouseId"
url="Warehouses"
data="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>

View File

@ -5,6 +5,11 @@
form="form"
save="patch">
</vn-watcher>
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form name="form" ng-submit="watcher.submit()" class="vn-w-md">
<vn-card class="vn-pa-lg">
<vn-horizontal>
@ -152,14 +157,14 @@
<vn-autocomplete
label="Warehouse Out"
ng-model="$ctrl.travelFilterParams.warehouseOutFk"
url="Warehouses"
data="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
<vn-autocomplete
label="Warehouse In"
ng-model="$ctrl.travelFilterParams.warehouseInFk"
url="Warehouses"
data="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>

View File

@ -25,7 +25,6 @@ module.exports = Self => {
Self.createPdf = async function(ctx, id, options) {
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
if (process.env.NODE_ENV == 'test')
throw new UserError(`Action not allowed on the test environment`);
@ -43,9 +42,9 @@ module.exports = Self => {
try {
const invoiceOut = await Self.findById(id, null, myOptions);
const hasInvoicing = await models.VnUser.hasRole(userId, 'invoicing', myOptions);
const canCreatePdf = await models.ACL.checkAccessAcl(ctx, 'InvoiceOut', 'canCreatePdf', 'WRITE');
if (invoiceOut.hasPdf && !hasInvoicing)
if (invoiceOut.hasPdf && !canCreatePdf)
throw new UserError(`You don't have enough privileges`);
await invoiceOut.updateAttributes({

View File

@ -1,3 +1,8 @@
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<vn-descriptor-content
module="item"
description="$ctrl.item.name"
@ -108,7 +113,9 @@
<vn-autocomplete
label="Warehouse"
ng-model="$ctrl.warehouseFk"
url="Warehouses">
data="warehouses"
show-field="name"
value="id">
</vn-autocomplete>
</tpl-body>
<tpl-buttons>

View File

@ -1,4 +1,9 @@
<div class="search-panel">
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
<vn-horizontal class="vn-px-lg vn-pt-lg">
<vn-textfield
@ -35,7 +40,9 @@
vn-one
label="Warehouse"
ng-model="filter.warehouseFk"
url="Warehouses">
data="warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal class="vn-px-lg">

View File

@ -1,4 +1,9 @@
<div class="search-panel">
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
<vn-horizontal class="vn-px-lg vn-pt-lg">
<vn-textfield
@ -83,7 +88,7 @@
vn-one
label="Warehouse"
ng-model="filter.warehouseFk"
url="Warehouses">
data="Warehouses">
</vn-autocomplete>
<vn-autocomplete
vn-one

View File

@ -1,4 +1,9 @@
<div class="search-panel">
<vn-crud-model
auto-load="true"
url="Agencies"
data="agencies">
</vn-crud-model>
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
<vn-horizontal class="vn-px-lg vn-pt-lg">
<vn-textfield

View File

@ -1,4 +1,9 @@
<div class="search-panel">
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
<vn-horizontal class="vn-px-lg vn-pt-lg">
<vn-textfield
@ -79,7 +84,7 @@
vn-one
label="Warehouse"
ng-model="filter.warehouseFk"
url="Warehouses"
data="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>

View File

@ -99,18 +99,20 @@ module.exports = Self => {
Self.observe('before save', async function(ctx) {
if (ctx.isNewInstance) return;
const loopbackContext = LoopBackContext.getCurrentContext();
const changes = ctx.data || ctx.instance;
const orgData = ctx.currentInstance;
const userId = loopbackContext.active.accessToken.userId;
const loopBackContext = LoopBackContext.getCurrentContext();
const accessToken = {req: loopBackContext.active.accessToken};
const editPayMethodCheck =
await Self.app.models.ACL.checkAccessAcl(accessToken, 'Supplier', 'editPayMethodCheck', 'WRITE');
const isNotFinancial = !await Self.app.models.VnUser.hasRole(userId, 'financial');
const isPayMethodChecked = changes.isPayMethodChecked || orgData.isPayMethodChecked;
const hasChanges = orgData && changes;
const isPayMethodCheckedChanged = hasChanges
&& orgData.isPayMethodChecked != isPayMethodChecked;
if (isNotFinancial && isPayMethodCheckedChanged)
if (!editPayMethodCheck && isPayMethodCheckedChanged)
throw new UserError('You can not modify is pay method checked');
});

View File

@ -64,7 +64,7 @@ describe('sale updateQuantity()', () => {
try {
const options = {transaction: tx};
const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, options);
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
expect(isRoleAdvanced).toEqual(true);

View File

@ -64,7 +64,7 @@ module.exports = Self => {
const sale = await models.Sale.findById(id, filter, myOptions);
const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, myOptions);
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
if (newQuantity > sale.quantity && !isRoleAdvanced)
throw new UserError('The new quantity should be smaller than the old one');

View File

@ -19,13 +19,11 @@ module.exports = Self => {
Self.editableStates = async(ctx, filter, options) => {
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
const myOptions = {...(options || {})};
const isProduction = await models.VnUser.hasRole(userId, 'production', myOptions);
const isAdministrative = await models.VnUser.hasRole(userId, 'administrative', myOptions);
const seeEditableStates = await models.ACL.checkAccessAcl(ctx, 'State', 'seeEditableStates', 'READ');
if (!isProduction && !isAdministrative)
if (!seeEditableStates)
filter = mergeFilters(filter, {where: {alertLevel: 0}});
const states = await models.State.find(filter, myOptions);

View File

@ -19,22 +19,23 @@ module.exports = Self => {
});
Self.isEditable = async(ctx, stateId, options) => {
const accessToken = ctx.req.accessToken;
const models = Self.app.models;
const userId = accessToken.userId;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const isProduction = await models.VnUser.hasRole(userId, 'production', myOptions);
const isSalesPerson = await models.VnUser.hasRole(userId, 'salesPerson', myOptions);
const isAdministrative = await models.VnUser.hasRole(userId, 'administrative', myOptions);
const isAllEditable = await models.ACL.checkAccessAcl(ctx, 'State', 'isAllEditable', 'READ');
const state = await models.State.findById(stateId, null, myOptions);
const isSomeEditable = (
await models.ACL.checkAccessAcl(ctx, 'State', 'isSomeEditable', 'READ')
&& (
state.code == 'PICKER_DESIGNED' || state.code == 'PRINTED'
)
);
const salesPersonAllowed = (isSalesPerson && (state.code == 'PICKER_DESIGNED' || state.code == 'PRINTED'));
const isAllowed = isProduction || isAdministrative || salesPersonAllowed || state.alertLevel == 0;
const isAllowed = isAllEditable || isSomeEditable || state.alertLevel == 0;
return isAllowed;
};
};

View File

@ -121,8 +121,8 @@ module.exports = Self => {
if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`);
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
if (!isDeliveryBoss) {
const editZone = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editZone', 'WRITE');
if (!editZone) {
const zoneShipped = await models.Agency.getShipped(
ctx,
args.landed,

View File

@ -30,7 +30,7 @@ module.exports = Self => {
where: {ticketFk: id}
}, myOptions);
const isRoleAdvanced = await models.Ticket.isRoleAdvanced(ctx, myOptions);
const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*');
const alertLevel = state ? state.alertLevel : null;
const ticket = await models.Ticket.findById(id, {

View File

@ -1,32 +0,0 @@
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.VnUser.hasRole(userId, 'salesAssistant', myOptions);
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
const isBuyer = await models.VnUser.hasRole(userId, 'buyer', myOptions);
const isClaimManager = await models.VnUser.hasRole(userId, 'claimManager', myOptions);
const isRoleAdvanced = isSalesAssistant || isDeliveryBoss || isBuyer || isClaimManager;
return isRoleAdvanced;
};
};

View File

@ -60,7 +60,6 @@ module.exports = Self => {
Self.priceDifference = async(ctx, options) => {
const args = ctx.args;
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
const myOptions = {};
let tx;
@ -78,8 +77,8 @@ module.exports = Self => {
if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`);
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
if (!isDeliveryBoss) {
const editZone = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editZone', 'WRITE');
if (!editZone) {
const zoneShipped = await models.Agency.getShipped(
ctx,
args.landed,

View File

@ -39,7 +39,6 @@ module.exports = Self => {
const ticketToDelete = await models.Ticket.findById(id, {fields: ['isDeleted']}, myOptions);
if (ticketToDelete.isDeleted) return false;
const userId = ctx.req.accessToken.userId;
const isEditable = await Self.isEditable(ctx, id, myOptions);
if (!isEditable)
@ -54,7 +53,8 @@ module.exports = Self => {
throw new UserError($t('Tickets with associated refunds', {id: ticketRefunds[0].id}));
// Check if has sales with shelving
const isSalesAssistant = await models.VnUser.hasRole(userId, 'salesAssistant', myOptions);
const canDeleteTicketWithPartPrepared =
await models.ACL.checkAccessAcl(ctx, 'Ticket', 'deleteTicketWithPartPrepared', 'WRITE');
const sales = await models.Sale.find({
include: {relation: 'itemShelvingSale'},
where: {ticketFk: id}
@ -63,7 +63,7 @@ module.exports = Self => {
return sale.itemShelvingSale();
});
if (hasItemShelvingSales && !isSalesAssistant)
if (hasItemShelvingSales && !canDeleteTicketWithPartPrepared)
throw new UserError(`You cannot delete a ticket that part of it is being prepared`);
// Check for existing claim

View File

@ -3,6 +3,7 @@ let UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('transferSales', {
description: 'Transfer sales to a new or a given ticket',
accessType: 'WRITE',
accepts: [{
arg: 'id',
type: 'number',

View File

@ -85,17 +85,14 @@ module.exports = Self => {
const userId = ctx.req.accessToken.userId;
const isLocked = await models.Ticket.isLocked(id, myOptions);
const roles = await models.VnUser.getRoles(userId, myOptions);
const hasAllowedRoles = roles.filter(role =>
role == 'salesPerson' || role == 'claimManager'
);
const canEditDiscount = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'editDiscount');
const state = await Self.app.models.TicketState.findOne({
where: {ticketFk: id}
}, myOptions);
const alertLevel = state ? state.alertLevel : null;
if (isLocked || (!hasAllowedRoles && alertLevel > 0))
if (isLocked || (!canEditDiscount && alertLevel > 0))
throw new UserError(`The sales of this ticket can't be modified`);
const usesMana = await models.Sale.usesMana(ctx, myOptions);

View File

@ -36,7 +36,6 @@ module.exports = function(Self) {
require('../methods/ticket/getTicketsFuture')(Self);
require('../methods/ticket/merge')(Self);
require('../methods/ticket/getTicketsAdvance')(Self);
require('../methods/ticket/isRoleAdvanced')(Self);
require('../methods/ticket/collectionLabel')(Self);
require('../methods/ticket/expeditionPalletLabel')(Self);
require('../methods/ticket/saveSign')(Self);

View File

@ -1,4 +1,9 @@
<div class="search-panel">
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
<vn-horizontal class="vn-px-lg vn-pt-lg">
<vn-date-picker
@ -49,7 +54,9 @@
vn-one
label="Warehouse"
ng-model="filter.warehouseFk"
url="Warehouses"
data="warehouses"
show-field="name"
value-field="id"
required="true">
</vn-autocomplete>
</vn-horizontal>

View File

@ -4,6 +4,11 @@
order="name"
auto-load="true">
</vn-crud-model>
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form name="form">
<vn-card class="vn-w-md vn-pa-lg">
<vn-horizontal>
@ -25,7 +30,7 @@
</vn-autocomplete>
<vn-autocomplete vn-one
required="true"
url="Warehouses"
data="Warehouses"
label="Warehouse"
show-field="name"
value-field="id"

View File

@ -2,6 +2,11 @@
vn-id="watcher"
data="$ctrl.dms">
</vn-watcher>
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form
name="form"
ng-submit="$ctrl.onSubmit()"
@ -29,7 +34,7 @@
<vn-autocomplete vn-one required="true"
label="Warehouse"
ng-model="$ctrl.dms.warehouseId"
url="Warehouses"
data="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>

View File

@ -1,4 +1,9 @@
<div class="search-panel">
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
<vn-horizontal class="vn-px-lg vn-pt-lg">
<vn-date-picker
@ -83,7 +88,9 @@
vn-one
label="Warehouse"
ng-model="filter.warehouseFk"
url="Warehouses"
data="warehouses"
show-field="name"
value-field="id"
required="true">
</vn-autocomplete>
</vn-horizontal>

View File

@ -491,7 +491,7 @@
<vn-confirm
vn-id="claimSure"
message="Do you want to create a claim?"
on-accept="$ctrl.createClaim()">
on-accept="$ctrl.onCreateClaimAccepted()">
</vn-confirm>
<vn-menu vn-id="moreOptions">
@ -513,7 +513,7 @@
</vn-item>
<vn-item translate
name="claim"
ng-click="claimSure.show()"
ng-click="$ctrl.createClaim()"
ng-if="$ctrl.isClaimable">
Add claim
</vn-item>

View File

@ -203,7 +203,7 @@ class Controller extends Section {
if (pastDays >= this.ticketConfig[0].daysForWarningClaim)
this.$.claimConfirm.show();
else
this.onCreateClaimAccepted();
this.$.claimSure.show();
}
onCreateClaimAccepted() {

View File

@ -1,4 +1,9 @@
<div class="search-panel">
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
<vn-horizontal class="vn-px-lg vn-pt-lg">
<vn-textfield
@ -102,7 +107,7 @@
vn-one
label="Warehouse"
ng-model="filter.warehouseFk"
url="Warehouses">
data="Warehouses">
</vn-autocomplete>
<vn-autocomplete
vn-one

View File

@ -1,4 +1,9 @@
<div class="search-panel">
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form ng-submit="$ctrl.onSearch()">
<vn-horizontal>
<vn-textfield
@ -52,14 +57,14 @@
<vn-autocomplete vn-one
label="Warehouse Out"
ng-model="filter.warehouseOutFk"
url="Warehouses"
data="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
<vn-autocomplete vn-one
label="Warehouse In"
ng-model="filter.warehouseInFk"
url="Warehouses"
data="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('worker-dms downloadFile()', () => {
let dmsId = 4;
@ -6,7 +6,7 @@ describe('worker-dms downloadFile()', () => {
it('should return a response for an employee with text content-type', async() => {
let workerId = 1106;
let ctx = {req: {accessToken: {userId: workerId}}};
const result = await app.models.WorkerDms.downloadFile(ctx, dmsId);
const result = await models.WorkerDms.downloadFile(ctx, dmsId);
expect(result[1]).toEqual('text/plain');
});
@ -17,7 +17,7 @@ describe('worker-dms downloadFile()', () => {
let error;
try {
await app.models.WorkerDms.downloadFile(ctx, dmsId);
await models.WorkerDms.downloadFile(ctx, dmsId);
} catch (e) {
error = e;
}

View File

@ -40,10 +40,10 @@ module.exports = Self => {
Object.assign(myOptions, options);
const isSubordinate = await models.Worker.isSubordinate(ctx, workerId, myOptions);
const isTeamBoss = await models.VnUser.hasRole(currentUserId, 'teamBoss', myOptions);
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
const isHimself = currentUserId == workerId;
if (isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss))
if (!isSubordinate || (isSubordinate && isHimself && !isTeamBoss))
throw new UserError(`You don't have enough privileges`);
query = `CALL vn.workerTimeControl_clockIn(?,?,?)`;

View File

@ -32,7 +32,7 @@ module.exports = Self => {
const targetTimeEntry = await Self.findById(id, null, myOptions);
const isSubordinate = await models.Worker.isSubordinate(ctx, targetTimeEntry.userFk, myOptions);
const isTeamBoss = await models.VnUser.hasRole(currentUserId, 'teamBoss', myOptions);
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
const isHimself = currentUserId == targetTimeEntry.userFk;
if (isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss))

View File

@ -38,7 +38,7 @@ module.exports = Self => {
const targetTimeEntry = await Self.findById(id, null, myOptions);
const isSubordinate = await models.Worker.isSubordinate(ctx, targetTimeEntry.userFk, myOptions);
const isTeamBoss = await models.VnUser.hasRole(currentUserId, 'teamBoss', myOptions);
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
const isHimself = currentUserId == targetTimeEntry.userFk;
const notAllowed = isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss);

View File

@ -53,7 +53,7 @@ module.exports = Self => {
try {
const isSubordinate = await models.Worker.isSubordinate(ctx, id, myOptions);
const isTeamBoss = await models.VnUser.hasRole(userId, 'teamBoss', myOptions);
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
if (!isSubordinate || (isSubordinate && userId == id && !isTeamBoss))
throw new UserError(`You don't have enough privileges`);

View File

@ -40,7 +40,7 @@ module.exports = Self => {
try {
const isSubordinate = await models.Worker.isSubordinate(ctx, id, myOptions);
const isTeamBoss = await models.VnUser.hasRole(userId, 'teamBoss', myOptions);
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
if (!isSubordinate || (isSubordinate && userId == id && !isTeamBoss))
throw new UserError(`You don't have enough privileges`);

View File

@ -25,22 +25,15 @@ module.exports = Self => {
Self.isSubordinate = async(ctx, id, options) => {
const models = Self.app.models;
const myUserId = ctx.req.accessToken.userId;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const mySubordinates = await Self.mySubordinates(ctx, myOptions);
const isSubordinate = mySubordinates.find(subordinate => {
return subordinate.workerFk == id;
});
const isSubordinate = mySubordinates.some(subordinate => subordinate.workerFk == id);
const forceIsSubordinate = await models.ACL.checkAccessAcl(ctx, 'Worker', 'forceIsSubordinate', 'READ');
const isHr = await models.VnUser.hasRole(myUserId, 'hr', myOptions);
if (isHr || isSubordinate)
return true;
return false;
return forceIsSubordinate || isSubordinate;
};
};

View File

@ -30,7 +30,7 @@ module.exports = Self => {
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
const isSubordinate = await models.Worker.isSubordinate(ctx, id);
const isTeamBoss = await models.VnUser.hasRole(userId, 'teamBoss');
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
if (!isSubordinate || (isSubordinate && userId == id && !isTeamBoss))
throw new UserError(`You don't have enough privileges`);

View File

@ -3,6 +3,11 @@
vn-id="watcher"
data="$ctrl.dms">
</vn-watcher>
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form
name="form"
ng-submit="$ctrl.onSubmit()"

View File

@ -17,6 +17,7 @@ describe('Client', () => {
$element = $compile(`<vn-worker-dms-create></vn-worker-dms-create>`)($rootScope);
controller = $element.controller('vnWorkerDmsCreate');
controller._worker = {id: 1101, name: 'Bruce wayne'};
$httpBackend.whenRoute('GET', `Warehouses?filter=%7B%7D`).respond([{$oldData: {}}]);
}));
describe('worker() setter', () => {

View File

@ -2,6 +2,11 @@
vn-id="watcher"
data="$ctrl.dms">
</vn-watcher>
<vn-crud-model
auto-load="true"
url="Warehouses"
data="warehouses">
</vn-crud-model>
<form
name="form"
ng-submit="$ctrl.onSubmit()"
@ -29,7 +34,7 @@
<vn-autocomplete vn-one required="true"
label="Warehouse"
ng-model="$ctrl.dms.warehouseId"
url="Warehouses"
data="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>

View File

@ -35,19 +35,13 @@ module.exports = Self => {
});
Self.getLanded = async(ctx, shipped, addressFk, agencyModeFk, warehouseFk, options) => {
const models = Self.app.models;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const userId = ctx.req.accessToken.userId;
const models = Self.app.models;
const roles = await models.VnUser.getRoles(userId);
const canSeeExpired = roles.filter(role =>
role == 'productionBoss' || role == 'administrative'
);
let showExpired = false;
if (canSeeExpired.length) showExpired = true;
const canSeeExpired = await models.ACL.checkAccessAcl(ctx, 'Agency', 'seeExpired', 'READ');
const stmts = [];
stmts.push(new ParameterizedSQL(
@ -56,7 +50,7 @@ module.exports = Self => {
addressFk,
agencyModeFk,
warehouseFk,
showExpired
canSeeExpired
]
));

View File

@ -24,7 +24,6 @@ module.exports = Self => {
if (typeof options == 'object')
Object.assign(myOptions, options);
const userId = ctx.req.accessToken.userId;
const conn = Self.dataSource.connector;
const models = Self.app.models;
const where = filter.where;
@ -36,10 +35,7 @@ module.exports = Self => {
&& where.agencyModeFk && where.warehouseFk;
if (filterByAvailability) {
const roles = await models.VnUser.getRoles(userId, myOptions);
const canSeeExpired = roles.filter(role =>
role == 'productionBoss' || role == 'administrative'
);
const canSeeExpired = await models.ACL.checkAccessAcl(ctx, 'Agency', 'seeExpired');
let showExpired = false;
if (canSeeExpired.length) showExpired = true;