7182-workerDms_optimization #2946
|
@ -21,6 +21,7 @@ BEGIN
|
|||
t.clientFk,
|
||||
t.warehouseFk,
|
||||
ts.alertLevel,
|
||||
sub2.alertLevel futureAlertLevel,
|
||||
t.shipped,
|
||||
t.totalWithVat,
|
||||
sub2.shipped futureShipped,
|
||||
|
@ -47,6 +48,7 @@ BEGIN
|
|||
t.addressFk,
|
||||
t.id,
|
||||
t.shipped,
|
||||
ts.alertLevel,
|
||||
st.name state,
|
||||
st.code,
|
||||
st.classColor,
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
-- Place your SQL code here
|
||||
INSERT INTO salix.ACL
|
||||
SET model = 'Ticket',
|
||||
property = 'setWeight',
|
||||
accessType = 'WRITE',
|
||||
permission = 'ALLOW',
|
||||
principalType = 'ROLE',
|
||||
principalId = 'salesPerson';
|
||||
|
|
@ -687,8 +687,8 @@ export default {
|
|||
ticketFuture: {
|
||||
searchResult: 'vn-ticket-future tbody tr',
|
||||
openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
|
||||
originDated: 'vn-date-picker[label="Origin date"]',
|
||||
futureDated: 'vn-date-picker[label="Destination date"]',
|
||||
originScopeDays: 'vn-date-picker[label="Origin date"]',
|
||||
futureScopeDays: 'vn-date-picker[label="Destination date"]',
|
||||
linesMax: 'vn-textfield[label="Max Lines"]',
|
||||
litersMax: 'vn-textfield[label="Max Liters"]',
|
||||
ipt: 'vn-autocomplete[label="Origin IPT"]',
|
||||
|
|
|
@ -30,18 +30,18 @@ describe('Ticket Future path', () => {
|
|||
expect(message.text).toContain('warehouseFk is a required argument');
|
||||
|
||||
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
|
||||
await page.clearInput(selectors.ticketFuture.futureDated);
|
||||
await page.clearInput(selectors.ticketFuture.futureScopeDays);
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('futureDated is a required argument');
|
||||
expect(message.text).toContain('futureScopeDays is a required argument');
|
||||
|
||||
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
|
||||
await page.clearInput(selectors.ticketFuture.originDated);
|
||||
await page.clearInput(selectors.ticketFuture.originScopeDays);
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('originDated is a required argument');
|
||||
expect(message.text).toContain('originScopeDays is a required argument');
|
||||
|
||||
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
|
@ -71,7 +71,7 @@ describe('Ticket Future path', () => {
|
|||
await page.autocompleteSearch(selectors.ticketFuture.state, 'Free');
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
|
||||
expect(httpRequest).toContain('state=FREE');
|
||||
expect(httpRequest).toContain('state=0');
|
||||
|
||||
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
|
||||
|
||||
|
@ -80,7 +80,7 @@ describe('Ticket Future path', () => {
|
|||
await page.autocompleteSearch(selectors.ticketFuture.futureState, 'Free');
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
|
||||
expect(httpRequest).toContain('futureState=FREE');
|
||||
expect(httpRequest).toContain('futureState=0');
|
||||
|
||||
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
|
||||
await page.clearInput(selectors.ticketFuture.state);
|
||||
|
|
|
@ -372,5 +372,7 @@
|
|||
"The entry not have stickers": "La entrada no tiene etiquetas",
|
||||
"Too many records": "Demasiados registros",
|
||||
"Original invoice not found": "Factura original no encontrada",
|
||||
"The entry has no lines or does not exist": "La entrada no tiene lineas o no existe"
|
||||
"The entry has no lines or does not exist": "La entrada no tiene lineas o no existe",
|
||||
"Weight already set": "El peso ya está establecido",
|
||||
"This ticket is not allocated to your department": "Este ticket no está asignado a tu departamento"
|
||||
}
|
|
@ -9,13 +9,13 @@ module.exports = Self => {
|
|||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'originDated',
|
||||
arg: 'originScopeDays',
|
||||
type: 'date',
|
||||
description: 'The date in question',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
arg: 'futureDated',
|
||||
arg: 'futureScopeDays',
|
||||
type: 'date',
|
||||
description: 'The date to probe',
|
||||
required: true
|
||||
|
@ -129,9 +129,9 @@ module.exports = Self => {
|
|||
]
|
||||
};
|
||||
case 'state':
|
||||
return {'f.stateCode': {like: `%${value}%`}};
|
||||
return {'f.alertLevel': value};
|
||||
case 'futureState':
|
||||
return {'f.futureStateCode': {like: `%${value}%`}};
|
||||
return {'f.futureAlertLevel': value};
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -141,7 +141,7 @@ module.exports = Self => {
|
|||
|
||||
stmt = new ParameterizedSQL(
|
||||
`CALL vn.ticket_canbePostponed(?,?,?)`,
|
||||
[args.originDated, args.futureDated, args.warehouseFk]);
|
||||
[args.originScopeDays, args.futureScopeDays, args.warehouseFk]);
|
||||
|
||||
stmts.push(stmt);
|
||||
|
||||
|
@ -170,7 +170,7 @@ module.exports = Self => {
|
|||
LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = f.id
|
||||
`);
|
||||
|
||||
if (args.problems != undefined && (!args.originDated && !args.futureDated))
|
||||
if (args.problems != undefined && (!args.originScopeDays && !args.futureScopeDays))
|
||||
throw new UserError('Choose a date range or days forward');
|
||||
|
||||
let condition;
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('setWeight', {
|
||||
description: 'Sets weight of a ticket',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The ticket id',
|
||||
http: {source: 'path'}
|
||||
}, {
|
||||
arg: 'weight',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The weight value',
|
||||
}],
|
||||
returns: {
|
||||
type: 'Array',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/setWeight`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.setWeight = async(ctx, ticketId, weight, options) => {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const myOptions = {userId};
|
||||
let tx;
|
||||
|
||||
if (typeof options == 'object') Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
try {
|
||||
const ticket = await Self.findById(ticketId, null, myOptions);
|
||||
if (ticket.weight) throw new UserError('Weight already set');
|
||||
|
||||
const canEdit = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'updateAttributes');
|
||||
const client = await models.Client.findById(ticket.clientFk, {
|
||||
include: {relation: 'salesPersonUser'}},
|
||||
myOptions);
|
||||
|
||||
if (!canEdit) {
|
||||
const salesPersonUser = client.salesPersonUser();
|
||||
const workerDepartments = await models.WorkerDepartment.find({
|
||||
include: {relation: 'department'},
|
||||
where: {workerFk: {inq: [userId, salesPersonUser.id]}}
|
||||
}, myOptions);
|
||||
|
||||
if (
|
||||
workerDepartments.length == 2 &&
|
||||
workerDepartments[0].departmentFk != workerDepartments[1].departmentFk
|
||||
)
|
||||
throw new UserError('This ticket is not allocated to your department');
|
||||
}
|
||||
|
||||
await ticket.updateAttribute('weight', weight, myOptions);
|
||||
|
||||
const packedState = await models.State.findOne({where: {code: 'PACKED'}}, myOptions);
|
||||
const ticketState = await models.TicketState.findOne({where: {ticketFk: ticketId}}, myOptions);
|
||||
|
||||
const [{taxArea}] = await Self.rawSql('SELECT clientTaxArea(?,?) taxArea',
|
||||
[ticket.clientFk, ticket.warehouseFk], myOptions);
|
||||
|
||||
const isInvoiceable = ticketState.alertLevel >= packedState.alertLevel &&
|
||||
taxArea == 'WORLD' && client.hasDailyInvoice;
|
||||
|
||||
if (tx) await tx.commit();
|
||||
let invoiceIds = [];
|
||||
if (isInvoiceable) invoiceIds = [...await Self.invoiceTicketsAndPdf(ctx, [ticketId])];
|
||||
|
||||
return invoiceIds;
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -12,8 +12,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
};
|
||||
|
||||
|
@ -35,8 +35,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
problems: true
|
||||
};
|
||||
|
@ -60,8 +60,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
problems: false
|
||||
};
|
||||
|
@ -85,8 +85,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
problems: null
|
||||
};
|
||||
|
@ -110,8 +110,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
state: 'OK'
|
||||
};
|
||||
|
@ -135,8 +135,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
futureState: 'OK'
|
||||
};
|
||||
|
@ -160,8 +160,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
ipt: null
|
||||
};
|
||||
|
@ -185,8 +185,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
ipt: 'H'
|
||||
};
|
||||
|
@ -210,8 +210,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
futureIpt: null
|
||||
};
|
||||
|
@ -235,8 +235,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
futureIpt: 'H'
|
||||
};
|
||||
|
@ -260,8 +260,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
id: 13
|
||||
};
|
||||
|
@ -285,8 +285,8 @@ describe('ticket getTicketsFuture()', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const args = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: 1,
|
||||
futureId: 12
|
||||
};
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
const {models} = require('vn-loopback/server/server');
|
||||
|
||||
describe('ticket setWeight()', () => {
|
||||
const ctx = beforeAll.getCtx();
|
||||
beforeAll.mockLoopBackContext();
|
||||
let opts;
|
||||
let tx;
|
||||
const employeeId = 1;
|
||||
const administrativeId = 5;
|
||||
|
||||
beforeEach(async() => {
|
||||
opts = {transaction: tx};
|
||||
tx = await models.Ticket.beginTransaction({});
|
||||
opts.transaction = tx;
|
||||
ctx.req.accessToken.userId = administrativeId;
|
||||
});
|
||||
|
||||
afterEach(async() => await tx.rollback());
|
||||
|
||||
it('should throw an error if the weight is already set', async() => {
|
||||
try {
|
||||
const ticketId = 1;
|
||||
const weight = 10;
|
||||
|
||||
await models.Ticket.setWeight(ctx, ticketId, weight, opts);
|
||||
} catch (e) {
|
||||
expect(e.message).toEqual('Weight already set');
|
||||
}
|
||||
});
|
||||
|
||||
it('should set the weight of a ticket', async() => {
|
||||
const ticketId = 31;
|
||||
const weight = 15;
|
||||
|
||||
await models.Ticket.setWeight(ctx, ticketId, weight, opts);
|
||||
|
||||
const ticket = await models.Ticket.findById(ticketId, null, opts);
|
||||
|
||||
expect(ticket.weight).toEqual(weight);
|
||||
});
|
||||
|
||||
it('should throw an error if the user is not allocated to the same department', async() => {
|
||||
ctx.req.accessToken.userId = employeeId;
|
||||
try {
|
||||
const ticketId = 10;
|
||||
const weight = 20;
|
||||
|
||||
await models.Ticket.setWeight(ctx, ticketId, weight, opts);
|
||||
} catch (e) {
|
||||
expect(e.message).toEqual('This ticket is not allocated to your department');
|
||||
}
|
||||
});
|
||||
|
||||
it('should call invoiceTicketsAndPdf if the ticket is invoiceable', async() => {
|
||||
const ticketId = 10;
|
||||
const weight = 25;
|
||||
|
||||
spyOn(models.Client, 'findById').and.returnValue({
|
||||
hasDailyInvoice: true,
|
||||
salesPersonUser: () => ({id: 1})
|
||||
});
|
||||
spyOn(models.TicketState, 'findOne').and.returnValue({alertLevel: 3});
|
||||
spyOn(models.Ticket, 'rawSql').and.returnValue([{taxArea: 'WORLD'}]);
|
||||
spyOn(models.Ticket, 'invoiceTicketsAndPdf').and.returnValue([10]);
|
||||
|
||||
const invoiceIds = await models.Ticket.setWeight(ctx, ticketId, weight, opts);
|
||||
|
||||
expect(invoiceIds.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
|
@ -46,4 +46,5 @@ module.exports = function(Self) {
|
|||
require('../methods/ticket/invoiceTicketsAndPdf')(Self);
|
||||
require('../methods/ticket/docuwareDownload')(Self);
|
||||
require('../methods/ticket/myLastModified')(Self);
|
||||
require('../methods/ticket/setWeight')(Self);
|
||||
};
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
<vn-date-picker
|
||||
vn-one
|
||||
label="Origin date"
|
||||
ng-model="filter.originDated"
|
||||
ng-model="filter.originScopeDays"
|
||||
required="true">
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Destination date"
|
||||
ng-model="filter.futureDated"
|
||||
ng-model="filter.futureScopeDays"
|
||||
required="true">
|
||||
</vn-date-picker>
|
||||
</vn-horizontal>
|
||||
|
@ -59,7 +59,7 @@
|
|||
<vn-autocomplete vn-one
|
||||
data="$ctrl.groupedStates"
|
||||
label="Origin Grouped State"
|
||||
value-field="code"
|
||||
value-field="id"
|
||||
show-field="name"
|
||||
ng-model="filter.state">
|
||||
<tpl-item>
|
||||
|
@ -69,7 +69,7 @@
|
|||
<vn-autocomplete vn-one
|
||||
data="$ctrl.groupedStates"
|
||||
label="Destination Grouped State"
|
||||
value-field="code"
|
||||
value-field="id"
|
||||
show-field="name"
|
||||
ng-model="filter.futureState">
|
||||
<tpl-item>
|
||||
|
|
|
@ -65,8 +65,8 @@ export default class Controller extends Section {
|
|||
this.$http.get(`UserConfigs/getUserConfig`)
|
||||
.then(res => {
|
||||
this.filterParams = {
|
||||
originDated: today,
|
||||
futureDated: today,
|
||||
originScopeDays: today,
|
||||
futureScopeDays: today,
|
||||
warehouseFk: res.data.warehouseFk
|
||||
};
|
||||
this.$.model.applyFilter(null, this.filterParams);
|
||||
|
|
|
@ -4,3 +4,4 @@ Client phone: Tel. cliente
|
|||
Client mobile: Móv. cliente
|
||||
Go to the ticket: Ir al ticket
|
||||
Change state: Cambiar estado
|
||||
Weight: Peso
|
Loading…
Reference in New Issue