Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2142_e2e_entry_descriptor
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
43d57511e0
|
@ -784,6 +784,21 @@ export default {
|
||||||
ticketOne: 'vn-invoice-out-summary > vn-card > vn-horizontal > vn-auto > vn-table > div > vn-tbody > vn-tr:nth-child(1)',
|
ticketOne: 'vn-invoice-out-summary > vn-card > vn-horizontal > vn-auto > vn-table > div > vn-tbody > vn-tr:nth-child(1)',
|
||||||
ticketTwo: 'vn-invoice-out-summary > vn-card > vn-horizontal > vn-auto > vn-table > div > vn-tbody > vn-tr:nth-child(2)'
|
ticketTwo: 'vn-invoice-out-summary > vn-card > vn-horizontal > vn-auto > vn-table > div > vn-tbody > vn-tr:nth-child(2)'
|
||||||
},
|
},
|
||||||
|
travelBasicDada: {
|
||||||
|
reference: 'vn-travel-basic-data vn-textfield[ng-model="$ctrl.travel.ref"]',
|
||||||
|
agency: 'vn-travel-basic-data vn-autocomplete[ng-model="$ctrl.travel.agencyModeFk"]',
|
||||||
|
shippingDate: 'vn-travel-basic-data vn-date-picker[ng-model="$ctrl.travel.shipped"]',
|
||||||
|
deliveryDate: 'vn-travel-basic-data vn-date-picker[ng-model="$ctrl.travel.landed"]',
|
||||||
|
outputWarehouse: 'vn-travel-basic-data vn-autocomplete[ng-model="$ctrl.travel.warehouseOutFk"]',
|
||||||
|
inputWarehouse: 'vn-travel-basic-data vn-autocomplete[ng-model="$ctrl.travel.warehouseInFk"]',
|
||||||
|
delivered: 'vn-travel-basic-data vn-check[ng-model="$ctrl.travel.isDelivered"]',
|
||||||
|
received: 'vn-travel-basic-data vn-check[ng-model="$ctrl.travel.isReceived"]',
|
||||||
|
save: 'vn-travel-basic-data vn-submit[label="Save"]',
|
||||||
|
undoChanges: 'vn-travel-basic-data vn-button[label="Undo changes"]'
|
||||||
|
},
|
||||||
|
travelLog: {
|
||||||
|
firstLogFirstTD: 'vn-travel-log vn-tbody > vn-tr > vn-td:nth-child(1) > div'
|
||||||
|
},
|
||||||
travelThermograph: {
|
travelThermograph: {
|
||||||
add: 'vn-travel-thermograph-index vn-float-button[icon="add"]',
|
add: 'vn-travel-thermograph-index vn-float-button[icon="add"]',
|
||||||
thermographID: 'vn-travel-thermograph-create vn-autocomplete[ng-model="$ctrl.dms.thermographId"]',
|
thermographID: 'vn-travel-thermograph-create vn-autocomplete[ng-model="$ctrl.dms.thermographId"]',
|
||||||
|
|
|
@ -16,6 +16,12 @@ describe('Client Add notes path', () => {
|
||||||
await browser.close();
|
await browser.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`should reach the notes index`, async() => {
|
||||||
|
let url = await page.expectURL('/note');
|
||||||
|
|
||||||
|
expect(url).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it(`should click on the add note button`, async() => {
|
it(`should click on the add note button`, async() => {
|
||||||
await page.waitToClick(selectors.clientNotes.addNoteFloatButton);
|
await page.waitToClick(selectors.clientNotes.addNoteFloatButton);
|
||||||
let url = await page.expectURL('/note/create');
|
let url = await page.expectURL('/note/create');
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
import selectors from '../../helpers/selectors.js';
|
||||||
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
describe('Travel basic data path', () => {
|
||||||
|
let browser;
|
||||||
|
let page;
|
||||||
|
|
||||||
|
beforeAll(async() => {
|
||||||
|
browser = await getBrowser();
|
||||||
|
page = browser.page;
|
||||||
|
await page.loginAndModule('buyer', 'travel');
|
||||||
|
await page.accessToSearchResult('3');
|
||||||
|
await page.accessToSection('travel.card.basicData');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async() => {
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reach the thermograph section', async() => {
|
||||||
|
const result = await page.expectURL('/basic-data');
|
||||||
|
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set a wrong delivery date then receive an error on submit', async() => {
|
||||||
|
await page.datePicker(selectors.travelBasicDada.deliveryDate, -1, null);
|
||||||
|
await page.waitToClick(selectors.travelBasicDada.save);
|
||||||
|
const result = await page.waitForLastSnackbar();
|
||||||
|
|
||||||
|
expect(result).toEqual('Landing cannot be lesser than shipment');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should undo the changes', async() => {
|
||||||
|
await page.waitToClick(selectors.travelBasicDada.undoChanges);
|
||||||
|
await page.waitToClick(selectors.travelBasicDada.save);
|
||||||
|
const result = await page.waitForLastSnackbar();
|
||||||
|
|
||||||
|
expect(result).toEqual('No changes to save');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should now edit the whole form then save', async() => {
|
||||||
|
await page.clearInput(selectors.travelBasicDada.reference);
|
||||||
|
await page.write(selectors.travelBasicDada.reference, 'new reference!');
|
||||||
|
await page.autocompleteSearch(selectors.travelBasicDada.agency, 'Entanglement');
|
||||||
|
await page.autocompleteSearch(selectors.travelBasicDada.outputWarehouse, 'Warehouse Three');
|
||||||
|
await page.autocompleteSearch(selectors.travelBasicDada.inputWarehouse, 'Warehouse Four');
|
||||||
|
await page.waitToClick(selectors.travelBasicDada.delivered);
|
||||||
|
await page.waitToClick(selectors.travelBasicDada.received);
|
||||||
|
await page.waitToClick(selectors.travelBasicDada.save);
|
||||||
|
const result = await page.waitForLastSnackbar();
|
||||||
|
|
||||||
|
expect(result).toEqual('Data saved!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reload the section and check the reference was saved', async() => {
|
||||||
|
await page.reloadSection('travel.card.basicData');
|
||||||
|
const result = await page.waitToGetProperty(selectors.travelBasicDada.reference, 'value');
|
||||||
|
|
||||||
|
expect(result).toEqual('new reference!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check the agency was saved', async() => {
|
||||||
|
const result = await page.waitToGetProperty(selectors.travelBasicDada.agency, 'value');
|
||||||
|
|
||||||
|
expect(result).toEqual('Entanglement');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check the output warehouse date was saved', async() => {
|
||||||
|
const result = await page.waitToGetProperty(selectors.travelBasicDada.outputWarehouse, 'value');
|
||||||
|
|
||||||
|
expect(result).toEqual('Warehouse Three');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check the input warehouse date was saved', async() => {
|
||||||
|
const result = await page.waitToGetProperty(selectors.travelBasicDada.inputWarehouse, 'value');
|
||||||
|
|
||||||
|
expect(result).toEqual('Warehouse Four');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should check the delivered checkbox was saved even tho it doesn't make sense`, async() => {
|
||||||
|
await page.waitForClassPresent(selectors.travelBasicDada.delivered, 'checked');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should check the received checkbox was saved even tho it doesn't make sense`, async() => {
|
||||||
|
await page.waitForClassPresent(selectors.travelBasicDada.received, 'checked');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to the travel logs', async() => {
|
||||||
|
await page.accessToSection('travel.card.log');
|
||||||
|
const result = await page.expectURL('/log');
|
||||||
|
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check the 1st log contains details from the changes made', async() => {
|
||||||
|
const result = await page.waitToGetProperty(selectors.travelLog.firstLogFirstTD, 'innerText');
|
||||||
|
|
||||||
|
expect(result).toContain('new reference!');
|
||||||
|
});
|
||||||
|
});
|
|
@ -16,7 +16,7 @@ describe('Client isValidClient', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the isValidClient() method with an unexistant id and receive false', async() => {
|
it('should call the isValidClient() method with an unexistant id and receive false', async() => {
|
||||||
let id = 999999;
|
let id = 999;
|
||||||
let result = await app.models.Client.isValidClient(id);
|
let result = await app.models.Client.isValidClient(id);
|
||||||
|
|
||||||
expect(result).toBeFalsy();
|
expect(result).toBeFalsy();
|
||||||
|
|
|
@ -34,7 +34,7 @@ describe('ticket-request confirm()', () => {
|
||||||
expect(error.message).toEqual(`That item doesn't exists`);
|
expect(error.message).toEqual(`That item doesn't exists`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should throw an error if the item is not available`, async() => {
|
it('should throw an error if the item is not available', async() => {
|
||||||
const requestId = 5;
|
const requestId = 5;
|
||||||
const itemId = 4;
|
const itemId = 4;
|
||||||
const quantity = 99999;
|
const quantity = 99999;
|
||||||
|
|
|
@ -67,6 +67,10 @@ module.exports = Self => {
|
||||||
arg: 'problems',
|
arg: 'problems',
|
||||||
type: 'Boolean',
|
type: 'Boolean',
|
||||||
description: `Whether to show only tickets with problems`
|
description: `Whether to show only tickets with problems`
|
||||||
|
}, {
|
||||||
|
arg: 'pending',
|
||||||
|
type: 'Boolean',
|
||||||
|
description: `Whether to show only tickets with state 'Pending'`
|
||||||
}, {
|
}, {
|
||||||
arg: 'mine',
|
arg: 'mine',
|
||||||
type: 'Boolean',
|
type: 'Boolean',
|
||||||
|
@ -130,7 +134,7 @@ module.exports = Self => {
|
||||||
dateTo.setHours(23, 59, 0, 0);
|
dateTo.setHours(23, 59, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let where = buildFilter(ctx.args, (param, value) => {
|
const where = buildFilter(ctx.args, (param, value) => {
|
||||||
switch (param) {
|
switch (param) {
|
||||||
case 'search':
|
case 'search':
|
||||||
return /^\d+$/.test(value)
|
return /^\d+$/.test(value)
|
||||||
|
@ -155,6 +159,17 @@ module.exports = Self => {
|
||||||
return {'c.salesPersonFk': {inq: teamIds}};
|
return {'c.salesPersonFk': {inq: teamIds}};
|
||||||
case 'alertLevel':
|
case 'alertLevel':
|
||||||
return {'ts.alertLevel': value};
|
return {'ts.alertLevel': value};
|
||||||
|
case 'pending':
|
||||||
|
if (value) {
|
||||||
|
return {and: [
|
||||||
|
{'st.alertLevel': 0},
|
||||||
|
{'st.code': {neq: 'OK'}}
|
||||||
|
]};
|
||||||
|
} else {
|
||||||
|
return {and: [
|
||||||
|
{'st.alertLevel': {gt: 0}}
|
||||||
|
]};
|
||||||
|
}
|
||||||
case 'id':
|
case 'id':
|
||||||
case 'clientFk':
|
case 'clientFk':
|
||||||
case 'agencyModeFk':
|
case 'agencyModeFk':
|
||||||
|
@ -244,7 +259,6 @@ module.exports = Self => {
|
||||||
LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id
|
LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id
|
||||||
LEFT JOIN tmp.ticketTotal tt ON tt.ticketFk = f.id`);
|
LEFT JOIN tmp.ticketTotal tt ON tt.ticketFk = f.id`);
|
||||||
|
|
||||||
|
|
||||||
let condition;
|
let condition;
|
||||||
let hasProblem;
|
let hasProblem;
|
||||||
let range;
|
let range;
|
||||||
|
|
|
@ -32,7 +32,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
let alertLevel = state ? state.alertLevel : null;
|
let alertLevel = state ? state.alertLevel : null;
|
||||||
let ticket = await Self.app.models.Ticket.findById(id, {
|
let ticket = await Self.app.models.Ticket.findById(id, {
|
||||||
fields: ['isDeleted', 'clientFk', 'refFk'],
|
fields: ['clientFk'],
|
||||||
include: [{
|
include: [{
|
||||||
relation: 'client',
|
relation: 'client',
|
||||||
scope: {
|
scope: {
|
||||||
|
@ -42,13 +42,13 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
const isLocked = await Self.app.models.Ticket.isLocked(id);
|
||||||
|
|
||||||
const isDeleted = ticket && ticket.isDeleted;
|
const alertLevelGreaterThanZero = (alertLevel && alertLevel > 0);
|
||||||
const isOnDelivery = (alertLevel && alertLevel > 0);
|
|
||||||
const isNormalClient = ticket && ticket.client().type().code == 'normal';
|
const isNormalClient = ticket && ticket.client().type().code == 'normal';
|
||||||
const isInvoiced = ticket && ticket.refFk;
|
const validAlertAndRoleNormalClient = (alertLevelGreaterThanZero && isNormalClient && !isValidRole);
|
||||||
|
|
||||||
if (!ticket || isInvoiced || isDeleted || (isOnDelivery && isNormalClient && !isValidRole))
|
if (!ticket || validAlertAndRoleNormalClient || isLocked)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('isLocked', {
|
||||||
|
description: 'Check if a ticket is invoiced or deleted',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'the ticket id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: 'boolean',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/:id/isLocked`,
|
||||||
|
verb: 'get'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.isLocked = async id => {
|
||||||
|
const ticket = await Self.app.models.Ticket.findById(id, {
|
||||||
|
fields: ['isDeleted', 'refFk']
|
||||||
|
});
|
||||||
|
|
||||||
|
const isDeleted = ticket && ticket.isDeleted;
|
||||||
|
const isInvoiced = ticket && ticket.refFk;
|
||||||
|
|
||||||
|
if (!ticket || isInvoiced || isDeleted)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
};
|
|
@ -41,6 +41,34 @@ describe('ticket filter()', () => {
|
||||||
const firstRow = result[0];
|
const firstRow = result[0];
|
||||||
|
|
||||||
expect(result.length).toEqual(1);
|
expect(result.length).toEqual(1);
|
||||||
expect(firstRow.ticketFk).toEqual(11);
|
expect(firstRow.id).toEqual(11);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the tickets with grouped state "Pending" and not "Ok"', async() => {
|
||||||
|
const ctx = {req: {accessToken: {userId: 9}}, args: {pending: true}};
|
||||||
|
const filter = {};
|
||||||
|
const result = await app.models.Ticket.filter(ctx, filter);
|
||||||
|
const firstRow = result[0];
|
||||||
|
const secondRow = result[1];
|
||||||
|
const thirdRow = result[2];
|
||||||
|
|
||||||
|
expect(result.length).toEqual(3);
|
||||||
|
expect(firstRow.state).toEqual('Arreglar');
|
||||||
|
expect(secondRow.state).toEqual('Arreglar');
|
||||||
|
expect(thirdRow.state).toEqual('Arreglar');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the tickets that are not pending', async() => {
|
||||||
|
const ctx = {req: {accessToken: {userId: 9}}, args: {pending: false}};
|
||||||
|
const filter = {};
|
||||||
|
const result = await app.models.Ticket.filter(ctx, filter);
|
||||||
|
const firstRow = result[0];
|
||||||
|
const secondRow = result[1];
|
||||||
|
const thirdRow = result[2];
|
||||||
|
|
||||||
|
expect(result.length).toEqual(13);
|
||||||
|
expect(firstRow.state).toEqual('Entregado');
|
||||||
|
expect(secondRow.state).toEqual('Entregado');
|
||||||
|
expect(thirdRow.state).toEqual('Entregado');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
describe('ticket isEditable()', () => {
|
describe('ticket isEditable()', () => {
|
||||||
it('should return false if the given ticket is not editable', async() => {
|
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
|
||||||
let result = await app.models.Ticket.isEditable(ctx, 2);
|
|
||||||
|
|
||||||
expect(result).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return false if the given ticket does not exist', async() => {
|
it('should return false if the given ticket does not exist', async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
let ctx = {req: {accessToken: {userId: 9}}};
|
||||||
let result = await app.models.Ticket.isEditable(ctx, 99999);
|
let result = await app.models.Ticket.isEditable(ctx, 99999);
|
||||||
|
@ -15,37 +8,46 @@ describe('ticket isEditable()', () => {
|
||||||
expect(result).toEqual(false);
|
expect(result).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false if the given ticket isDeleted', async() => {
|
it(`should return false if the given ticket isn't invoiced but isDeleted`, async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
let ctx = {req: {accessToken: {userId: 9}}};
|
||||||
let result = await app.models.Ticket.isEditable(ctx, 19);
|
let deletedTicket = await app.models.Ticket.findOne({
|
||||||
|
where: {
|
||||||
|
invoiceOut: null,
|
||||||
|
isDeleted: true
|
||||||
|
},
|
||||||
|
fields: ['id']
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = await app.models.Ticket.isEditable(ctx, deletedTicket.id);
|
||||||
|
|
||||||
expect(result).toEqual(false);
|
expect(result).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true if the given ticket is editable', async() => {
|
it('should return true if the given ticket is editable', async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 9}}};
|
let ctx = {req: {accessToken: {userId: 9}}};
|
||||||
|
|
||||||
let result = await app.models.Ticket.isEditable(ctx, 16);
|
let result = await app.models.Ticket.isEditable(ctx, 16);
|
||||||
|
|
||||||
expect(result).toEqual(true);
|
expect(result).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to edit a deleted or invoiced ticket if the role is salesAssistant', async() => {
|
it('should not be able to edit a deleted or invoiced ticket even for salesAssistant', async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 21}}};
|
let ctx = {req: {accessToken: {userId: 21}}};
|
||||||
let result = await app.models.Ticket.isEditable(ctx, 8);
|
let result = await app.models.Ticket.isEditable(ctx, 19);
|
||||||
|
|
||||||
expect(result).toEqual(true);
|
expect(result).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to edit a deleted or invoiced ticket if the role is productionBoss', async() => {
|
it('should not be able to edit a deleted or invoiced ticket even for productionBoss', async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 50}}};
|
let ctx = {req: {accessToken: {userId: 50}}};
|
||||||
let result = await app.models.Ticket.isEditable(ctx, 8);
|
let result = await app.models.Ticket.isEditable(ctx, 19);
|
||||||
|
|
||||||
expect(result).toEqual(true);
|
expect(result).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be able to edit a deleted or invoiced ticket if the role is salesPerson', async() => {
|
it('should not be able to edit a deleted or invoiced ticket even for salesPerson', async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 18}}};
|
let ctx = {req: {accessToken: {userId: 18}}};
|
||||||
let result = await app.models.Ticket.isEditable(ctx, 8);
|
let result = await app.models.Ticket.isEditable(ctx, 19);
|
||||||
|
|
||||||
expect(result).toEqual(false);
|
expect(result).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('ticket isLocked()', () => {
|
||||||
|
it('should return true if the given ticket does not exist', async() => {
|
||||||
|
let result = await app.models.Ticket.isLocked(99999);
|
||||||
|
|
||||||
|
expect(result).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true if the given ticket is invoiced', async() => {
|
||||||
|
let invoicedTicket = await app.models.Ticket.findOne({
|
||||||
|
where: {invoiceOut: {neq: null}},
|
||||||
|
fields: ['id']
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = await app.models.Ticket.isLocked(invoicedTicket.id);
|
||||||
|
|
||||||
|
expect(result).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return true if the given ticket isn't invoiced but deleted`, async() => {
|
||||||
|
let deletedTicket = await app.models.Ticket.findOne({
|
||||||
|
where: {
|
||||||
|
invoiceOut: null,
|
||||||
|
isDeleted: true
|
||||||
|
},
|
||||||
|
fields: ['id']
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = await app.models.Ticket.isLocked(deletedTicket.id);
|
||||||
|
|
||||||
|
expect(result).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
|
@ -35,6 +35,7 @@ module.exports = Self => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.updateDiscount = async(ctx, id, salesIds, newDiscount) => {
|
Self.updateDiscount = async(ctx, id, salesIds, newDiscount) => {
|
||||||
|
const userId = ctx.req.accessToken.userId;
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const tx = await Self.beginTransaction({});
|
const tx = await Self.beginTransaction({});
|
||||||
|
|
||||||
|
@ -68,8 +69,14 @@ module.exports = Self => {
|
||||||
if (!allFromSameTicket)
|
if (!allFromSameTicket)
|
||||||
throw new UserError('All sales must belong to the same ticket');
|
throw new UserError('All sales must belong to the same ticket');
|
||||||
|
|
||||||
const isEditable = await models.Ticket.isEditable(ctx, id);
|
const isLocked = await models.Ticket.isLocked(id);
|
||||||
if (!isEditable)
|
const isSalesPerson = await models.Account.hasRole(userId, 'salesPerson');
|
||||||
|
const state = await Self.app.models.TicketState.findOne({
|
||||||
|
where: {ticketFk: id}
|
||||||
|
});
|
||||||
|
const alertLevel = state ? state.alertLevel : null;
|
||||||
|
|
||||||
|
if (isLocked || (!isSalesPerson && alertLevel > 0 ))
|
||||||
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 ticket = await models.Ticket.findById(id, {
|
const ticket = await models.Ticket.findById(id, {
|
||||||
|
|
|
@ -29,6 +29,7 @@ module.exports = Self => {
|
||||||
require('../methods/ticket/recalculateComponents')(Self);
|
require('../methods/ticket/recalculateComponents')(Self);
|
||||||
require('../methods/ticket/deleteStowaway')(Self);
|
require('../methods/ticket/deleteStowaway')(Self);
|
||||||
require('../methods/ticket/sendSms')(Self);
|
require('../methods/ticket/sendSms')(Self);
|
||||||
|
require('../methods/ticket/isLocked')(Self);
|
||||||
|
|
||||||
Self.observe('before save', async function(ctx) {
|
Self.observe('before save', async function(ctx) {
|
||||||
if (ctx.isNewInstance) return;
|
if (ctx.isNewInstance) return;
|
||||||
|
|
|
@ -165,8 +165,8 @@
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>
|
<vn-td number>
|
||||||
<span ng-class="{'link': $ctrl.isEditable}"
|
<span ng-class="{'link': !$ctrl.isLocked}"
|
||||||
title="{{$ctrl.isEditable ? 'Edit discount' : ''}}"
|
title="{{!$ctrl.isLocked ? 'Edit discount' : ''}}"
|
||||||
ng-click="$ctrl.showEditDiscountPopover($event, sale)">
|
ng-click="$ctrl.showEditDiscountPopover($event, sale)">
|
||||||
{{(sale.discount / 100) | percentage}}
|
{{(sale.discount / 100) | percentage}}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -46,6 +46,7 @@ class Controller {
|
||||||
set ticket(value) {
|
set ticket(value) {
|
||||||
this._ticket = value;
|
this._ticket = value;
|
||||||
this.isTicketEditable();
|
this.isTicketEditable();
|
||||||
|
this.isTicketLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
get sales() {
|
get sales() {
|
||||||
|
@ -354,7 +355,7 @@ class Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
showEditDiscountPopover(event, sale) {
|
showEditDiscountPopover(event, sale) {
|
||||||
if (!this.isEditable) return;
|
if (this.isLocked) return;
|
||||||
|
|
||||||
this.sale = sale;
|
this.sale = sale;
|
||||||
this.edit = [{
|
this.edit = [{
|
||||||
|
@ -540,6 +541,12 @@ class Controller {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isTicketLocked() {
|
||||||
|
this.$http.get(`Tickets/${this.$state.params.id}/isLocked`).then(res => {
|
||||||
|
this.isLocked = res.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
hasOneSaleSelected() {
|
hasOneSaleSelected() {
|
||||||
if (this.totalCheckedLines() === 1)
|
if (this.totalCheckedLines() === 1)
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -69,6 +69,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
$httpBackend.when('POST', `Claims/createFromSales`, {claim: claim, sales: sales}).respond(claim);
|
$httpBackend.when('POST', `Claims/createFromSales`, {claim: claim, sales: sales}).respond(claim);
|
||||||
$httpBackend.expect('POST', `Claims/createFromSales`).respond(claim);
|
$httpBackend.expect('POST', `Claims/createFromSales`).respond(claim);
|
||||||
controller.createClaim();
|
controller.createClaim();
|
||||||
|
@ -98,6 +99,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
let result = controller.checkedLines();
|
let result = controller.checkedLines();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
@ -116,6 +118,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.expectGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.expectGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.expectGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.expectGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
controller.onStateOkClick();
|
controller.onStateOkClick();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
@ -129,6 +132,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
controller.onStateChange(3);
|
controller.onStateChange(3);
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
});
|
});
|
||||||
|
@ -142,6 +146,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
controller.onRemoveLinesClick('accept');
|
controller.onRemoveLinesClick('accept');
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
@ -183,6 +188,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
controller.unmarkAsReserved(false);
|
controller.unmarkAsReserved(false);
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
});
|
});
|
||||||
|
@ -213,6 +219,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
controller.updateQuantity(sale);
|
controller.updateQuantity(sale);
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
@ -232,6 +239,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
controller.updateConcept(sale);
|
controller.updateConcept(sale);
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
@ -262,6 +270,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
controller.addSale(newSale);
|
controller.addSale(newSale);
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
@ -287,6 +296,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
controller.transferSales(13);
|
controller.transferSales(13);
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
@ -305,6 +315,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
controller.setTransferParams();
|
controller.setTransferParams();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
@ -330,6 +341,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
controller.newOrderFromTicket();
|
controller.newOrderFromTicket();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
@ -353,6 +365,7 @@ describe('Ticket', () => {
|
||||||
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
$httpBackend.whenGET(`Tickets/1/subtotal`).respond(200, 227.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
$httpBackend.whenGET(`Tickets/1/getVAT`).respond(200, 10.5);
|
||||||
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
$httpBackend.whenGET(`Tickets/1/isEditable`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/1/isLocked`).respond();
|
||||||
|
|
||||||
controller.calculateSalePrice();
|
controller.calculateSalePrice();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
|
@ -113,10 +113,16 @@
|
||||||
</vn-check>
|
</vn-check>
|
||||||
<vn-check
|
<vn-check
|
||||||
vn-one
|
vn-one
|
||||||
label="Problems"
|
label="With problems"
|
||||||
ng-model="filter.problems"
|
ng-model="filter.problems"
|
||||||
triple-state="true">
|
triple-state="true">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
|
<vn-check
|
||||||
|
vn-one
|
||||||
|
label="Pending"
|
||||||
|
ng-model="filter.pending"
|
||||||
|
triple-state="true">
|
||||||
|
</vn-check>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal class="vn-mt-lg">
|
<vn-horizontal class="vn-mt-lg">
|
||||||
<vn-submit label="Search"></vn-submit>
|
<vn-submit label="Search"></vn-submit>
|
||||||
|
|
|
@ -11,3 +11,5 @@ My team: Mi equipo
|
||||||
Order id: Id pedido
|
Order id: Id pedido
|
||||||
Grouped States: Estado agrupado
|
Grouped States: Estado agrupado
|
||||||
Days onward: Días adelante
|
Days onward: Días adelante
|
||||||
|
With problems: Con problemas
|
||||||
|
Pending: Pendientes
|
Loading…
Reference in New Issue