diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index 2484990ed..d77b0c26d 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -57,7 +57,14 @@
"The postcode doesn't exist. Please enter a correct one": "The postcode doesn't exist. Please enter a correct one",
"Can't create stowaway for this ticket": "Can't create stowaway for this ticket",
"Swift / BIC can't be empty": "Swift / BIC can't be empty",
- "Bought units from buy request": "Bought {{quantity}} units of {{concept}} [{{itemId}}]({{{urlItem}}}) for the ticket id [{{ticketId}}]({{{url}}})",
+ "Deleted sales from ticket": "I have deleted the following lines from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{deletions}}}",
+ "Added sale to ticket": "I have added the following line to the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}",
+ "Changed sale discount": "I have changed the following lines discounts from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
+ "Created claim": "I have created the claim [{{claimId}}]({{{claimUrl}}}) for the following lines from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
+ "Changed sale price": "I have changed the price of [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) from {{oldPrice}}€ ➔ *{{newPrice}}€* of the ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changed sale quantity": "I have changed the quantity of [{{itemId}} {{concept}}]({{{itemUrl}}}) from {{oldQuantity}} ➔ *{{newQuantity}}* of the ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changed sale reserved state": "I have changed the following lines reserved state from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
+ "Bought units from buy request": "Bought {{quantity}} units of [{{itemId}} {{concept}}]({{{urlItem}}}) for the ticket id [{{ticketId}}]({{{url}}})",
"MESSAGE_INSURANCE_CHANGE": "I have changed the insurence credit of client [{{clientName}} ({{clientId}})]({{{url}}}) to *{{credit}} €*",
"Changed client paymethod": "I have changed the pay method for client [{{clientName}} ({{clientId}})]({{{url}}})",
"Sent units from ticket": "I sent *{{quantity}}* units of [{{concept}} ({{itemId}})]({{{itemUrl}}}) to *\"{{nickname}}\"* coming from ticket id [{{ticketId}}]({{{ticketUrl}}})",
@@ -98,6 +105,9 @@
"Client assignment has changed": "I did change the salesperson ~*\"<{{previousWorkerName}}>\"*~ by *\"<{{currentWorkerName}}>\"* from the client [{{clientName}} ({{clientId}})]({{{url}}})",
"None": "None",
"error densidad = 0": "error densidad = 0",
+ "nickname": "nickname",
"This document already exists on this ticket": "This document already exists on this ticket",
- "serial non editable": "This serial doesn't allow to set a reference"
+ "State": "State",
+ "regular": "regular",
+ "reserved": "reserved"
}
\ No newline at end of file
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 1d73cbbf3..53213adae 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -54,7 +54,7 @@
"This address doesn't exist": "Este consignatario no existe",
"You can't create an order for a inactive client": "You can't create an order for a inactive client",
"You can't create an order for a client that doesn't has tax data verified": "You can't create an order for a client that doesn't has tax data verified",
- "You must delete the claim id %d first": "Antes debes borrar la reclamacion %d",
+ "You must delete the claim id %d first": "Antes debes borrar la reclamación %d",
"You don't have enough privileges": "No tienes suficientes permisos",
"Cannot check Equalization Tax in this NIF/CIF": "No se puede marcar RE en este NIF/CIF",
"You can't make changes on the basic data of an confirmed order or with rows": "No puedes cambiar los datos basicos de una orden con artículos",
@@ -122,7 +122,17 @@
"Swift / BIC can't be empty": "Swift / BIC no puede estar vacío",
"Customs agent is required for a non UEE member": "El agente de aduanas es requerido para los clientes extracomunitarios",
"Incoterms is required for a non UEE member": "El incoterms es requerido para los clientes extracomunitarios",
- "Bought units from buy request": "Se ha comprado {{quantity}} unidades de {{concept}} [{{itemId}}]({{{urlItem}}}) para el ticket id [{{ticketId}}]({{{url}}})",
+ "Deleted sales from ticket": "He eliminado las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{deletions}}}",
+ "Added sale to ticket": "He añadido la siguiente linea al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}",
+ "Changed sale discount": "He cambiado el descuento de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
+ "Created claim": "He creado la reclamación [{{claimId}}]({{{claimUrl}}}) de las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
+ "Changed sale price": "He cambiado el precio de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* del ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "Changed sale quantity": "He cambiado la cantidad de [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}* del ticket [{{ticketId}}]({{{ticketUrl}}})",
+ "State": "Estado",
+ "regular": "normal",
+ "reserved": "reservado",
+ "Changed sale reserved state": "He cambiado el estado reservado de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
+ "Bought units from buy request": "Se ha comprado {{quantity}} unidades de [{{itemId}} {{concept}}]({{{urlItem}}}) para el ticket id [{{ticketId}}]({{{url}}})",
"MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} ({{clientId}})]({{{url}}}) a *{{credit}} €*",
"Changed client paymethod": "He cambiado la forma de pago del cliente [{{clientName}} ({{clientId}})]({{{url}}})",
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})",
diff --git a/modules/claim/back/methods/claim/createFromSales.js b/modules/claim/back/methods/claim/createFromSales.js
index 2dd1b75c2..f22aabbf3 100644
--- a/modules/claim/back/methods/claim/createFromSales.js
+++ b/modules/claim/back/methods/claim/createFromSales.js
@@ -3,17 +3,20 @@ const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('createFromSales', {
description: 'Create a claim',
- accepts: [{
- arg: 'ticketId',
- type: 'Number',
- required: true,
- description: 'The origin ticket id'
- }, {
- arg: 'sales',
- type: ['Object'],
- required: true,
- description: 'The claimed sales'
- }],
+ accepts: [
+ {
+ arg: 'ticketId',
+ type: 'number',
+ required: true,
+ description: 'The origin ticket id'
+ },
+ {
+ arg: 'sales',
+ type: ['object'],
+ required: true,
+ description: 'The claimed sales'
+ }
+ ],
returns: {
type: 'object',
root: true
@@ -25,6 +28,7 @@ module.exports = Self => {
});
Self.createFromSales = async(ctx, ticketId, sales, options) => {
+ const $t = ctx.req.__; // $translate
const models = Self.app.models;
let tx;
const myOptions = {};
@@ -39,7 +43,20 @@ module.exports = Self => {
const userId = ctx.req.accessToken.userId;
try {
- const ticket = await models.Ticket.findById(ticketId, null, myOptions);
+ const ticket = await models.Ticket.findById(ticketId, {
+ include: {
+ relation: 'client',
+ scope: {
+ include: {
+ relation: 'salesPersonUser',
+ scope: {
+ fields: ['id', 'name']
+ }
+ }
+ }
+ }
+ }, myOptions);
+
if (ticket.isDeleted)
throw new UserError(`You can't create a claim for a removed ticket`);
@@ -49,6 +66,8 @@ module.exports = Self => {
ticketCreated: ticket.shipped,
workerFk: userId
}, myOptions);
+
+ let changesMade = '';
const promises = [];
for (const sale of sales) {
@@ -59,10 +78,25 @@ module.exports = Self => {
}, myOptions);
promises.push(newClaimBeginning);
+ changesMade += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity})`;
}
await Promise.all(promises);
+ const salesPerson = ticket.client().salesPersonUser();
+ if (salesPerson) {
+ const origin = ctx.req.headers.origin;
+
+ const message = $t('Created claim', {
+ claimId: newClaim.id,
+ ticketId: ticketId,
+ ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`,
+ claimUrl: `${origin}/#!/claim/${newClaim.id}/summary`,
+ changes: changesMade
+ });
+ await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
+ }
+
if (tx) await tx.commit();
return newClaim;
diff --git a/modules/claim/back/methods/claim/specs/createFromSales.spec.js b/modules/claim/back/methods/claim/specs/createFromSales.spec.js
index f08914025..849ccf8f5 100644
--- a/modules/claim/back/methods/claim/specs/createFromSales.spec.js
+++ b/modules/claim/back/methods/claim/specs/createFromSales.spec.js
@@ -7,7 +7,13 @@ describe('Claim createFromSales()', () => {
instance: 0,
quantity: 10
}];
- const ctx = {req: {accessToken: {userId: 1}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 1},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
it('should create a new claim', async() => {
const tx = await app.models.Claim.beginTransaction({});
diff --git a/modules/invoiceOut/front/summary/index.html b/modules/invoiceOut/front/summary/index.html
index 0406a39c5..924972299 100644
--- a/modules/invoiceOut/front/summary/index.html
+++ b/modules/invoiceOut/front/summary/index.html
@@ -1,6 +1,7 @@
diff --git a/modules/invoiceOut/front/summary/index.js b/modules/invoiceOut/front/summary/index.js
index 2446e986a..af0b5365e 100644
--- a/modules/invoiceOut/front/summary/index.js
+++ b/modules/invoiceOut/front/summary/index.js
@@ -7,7 +7,7 @@ class Controller extends Summary {
this._invoiceOut = value;
if (value && value.id) {
this.getSummary();
- this.getTickets();
+ this.$.ticketsModel.url = `InvoiceOuts/${this.invoiceOut.id}/getTickets`;
}
}
@@ -19,14 +19,6 @@ class Controller extends Summary {
return this.$http.get(`InvoiceOuts/${this.invoiceOut.id}/summary`)
.then(res => this.summary = res.data);
}
-
- getTickets() {
- this.$.$applyAsync(() => {
- const query = `InvoiceOuts/${this.invoiceOut.id}/getTickets`;
- this.$.ticketsModel.url = query;
- this.$.ticketsModel.refresh();
- });
- }
}
ngModule.vnComponent('vnInvoiceOutSummary', {
diff --git a/modules/invoiceOut/front/summary/index.spec.js b/modules/invoiceOut/front/summary/index.spec.js
index be6ad0a18..675cc02c3 100644
--- a/modules/invoiceOut/front/summary/index.spec.js
+++ b/modules/invoiceOut/front/summary/index.spec.js
@@ -27,17 +27,5 @@ describe('InvoiceOut', () => {
expect(controller.summary).toEqual('the data you are looking for');
});
});
-
- describe('getTickets()', () => {
- it('should perform a and then call to the ticketModel refresh() method', () => {
- jest.spyOn(controller.$.ticketsModel, 'refresh');
-
- controller.getTickets();
- $scope.$apply();
-
- expect(controller.$.ticketsModel.url).toEqual('InvoiceOuts/1/getTickets');
- expect(controller.$.ticketsModel.refresh).toHaveBeenCalledWith();
- });
- });
});
});
diff --git a/modules/ticket/back/methods/sale/deleteSales.js b/modules/ticket/back/methods/sale/deleteSales.js
index 31899a501..a604da858 100644
--- a/modules/ticket/back/methods/sale/deleteSales.js
+++ b/modules/ticket/back/methods/sale/deleteSales.js
@@ -6,18 +6,18 @@ module.exports = Self => {
accessType: 'WRITE',
accepts: [{
arg: 'sales',
- type: ['Object'],
+ type: ['object'],
required: true,
description: 'The sales to remove'
},
{
arg: 'ticketId',
- type: 'Number',
+ type: 'number',
required: true,
description: 'The ticket id'
}],
returns: {
- type: ['Object'],
+ type: ['object'],
root: true
},
http: {
@@ -27,10 +27,25 @@ module.exports = Self => {
});
Self.deleteSales = async(ctx, sales, ticketId) => {
+ const $t = ctx.req.__; // $translate
const models = Self.app.models;
const canEditSales = await models.Sale.canEdit(ctx, sales);
+ const ticket = await models.Ticket.findById(ticketId, {
+ include: {
+ relation: 'client',
+ scope: {
+ include: {
+ relation: 'salesPersonUser',
+ scope: {
+ fields: ['id', 'name']
+ }
+ }
+ }
+ }
+ });
+
const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId);
if (!isTicketEditable)
throw new UserError(`The sales of this ticket can't be modified`);
@@ -39,11 +54,26 @@ module.exports = Self => {
throw new UserError(`Sale(s) blocked, please contact production`);
const promises = [];
+ let deletions = '';
for (let sale of sales) {
const deletedSale = models.Sale.destroyById(sale.id);
+ deletions += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity})`;
+
promises.push(deletedSale);
}
+ const salesPerson = ticket.client().salesPersonUser();
+ if (salesPerson) {
+ const origin = ctx.req.headers.origin;
+
+ const message = $t('Deleted sales from ticket', {
+ ticketId: ticketId,
+ ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`,
+ deletions: deletions
+ });
+ await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
+ }
+
return Promise.all(promises);
};
};
diff --git a/modules/ticket/back/methods/sale/reserve.js b/modules/ticket/back/methods/sale/reserve.js
index 96c794e7c..639827fa7 100644
--- a/modules/ticket/back/methods/sale/reserve.js
+++ b/modules/ticket/back/methods/sale/reserve.js
@@ -5,24 +5,27 @@ module.exports = Self => {
Self.remoteMethodCtx('reserve', {
description: 'Change the state of a ticket',
accessType: 'WRITE',
- accepts: [{
- arg: 'ticketId',
- type: 'Number',
- required: true,
- description: 'The ticket id'
- }, {
- arg: 'sales',
- type: ['Object'],
- required: true,
- description: 'The sale to reserve'
- },
- {
- arg: 'reserved',
- type: 'Boolean',
- required: true
- }],
+ accepts: [
+ {
+ arg: 'ticketId',
+ type: 'number',
+ required: true,
+ description: 'The ticket id'
+ },
+ {
+ arg: 'sales',
+ type: ['object'],
+ required: true,
+ description: 'The sale to reserve'
+ },
+ {
+ arg: 'reserved',
+ type: 'boolean',
+ required: true
+ }
+ ],
returns: {
- type: ['Object'],
+ type: ['object'],
root: true
},
http: {
@@ -32,7 +35,9 @@ module.exports = Self => {
});
Self.reserve = async(ctx, ticketId, sales, reserved) => {
+ const $t = ctx.req.__; // $translate
const models = Self.app.models;
+
const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId);
if (!isTicketEditable)
throw new UserError(`The sales of this ticket can't be modified`);
@@ -42,12 +47,50 @@ module.exports = Self => {
if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`);
+ let changesMade = '';
const promises = [];
+
for (let sale of sales) {
- const reservedSale = models.Sale.update({id: sale.id}, {reserved: reserved});
- promises.push(reservedSale);
+ if (sale.reserved != reserved) {
+ const oldState = sale.reserved ? 'reserved' : 'regular';
+ const newState = reserved ? 'reserved' : 'regular';
+
+ const reservedSale = models.Sale.update({id: sale.id}, {reserved: reserved});
+
+ promises.push(reservedSale);
+
+ changesMade += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity}) ${$t('State')}: ${$t(oldState)} ➔ *${$t(newState)}*`;
+ }
}
- return Promise.all(promises);
+ const result = await Promise.all(promises);
+
+ const ticket = await models.Ticket.findById(ticketId, {
+ include: {
+ relation: 'client',
+ scope: {
+ include: {
+ relation: 'salesPersonUser',
+ scope: {
+ fields: ['id', 'name']
+ }
+ }
+ }
+ }
+ });
+
+ const salesPerson = ticket.client().salesPersonUser();
+ if (salesPerson) {
+ const origin = ctx.req.headers.origin;
+
+ const message = $t('Changed sale reserved state', {
+ ticketId: ticketId,
+ ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`,
+ changes: changesMade
+ });
+ await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
+ }
+
+ return result;
};
};
diff --git a/modules/ticket/back/methods/sale/specs/deleteSales.spec.js b/modules/ticket/back/methods/sale/specs/deleteSales.spec.js
index 22ac49452..aabc38375 100644
--- a/modules/ticket/back/methods/sale/specs/deleteSales.spec.js
+++ b/modules/ticket/back/methods/sale/specs/deleteSales.spec.js
@@ -17,7 +17,14 @@ describe('sale deleteSales()', () => {
});
it('should throw an error if the ticket of the given sales is not editable', async() => {
- let ctx = {req: {accessToken: {userId: 9}}};
+ let ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
+
let error;
const sales = [{id: 1, instance: 0}, {id: 2, instance: 1}];
@@ -33,7 +40,13 @@ describe('sale deleteSales()', () => {
});
it('should delete the sale', async() => {
- let ctx = {req: {accessToken: {userId: 9}}};
+ let ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
const sales = [{id: newSale.id, instance: 0}];
const ticketId = 16;
diff --git a/modules/ticket/back/methods/sale/specs/reserve.spec.js b/modules/ticket/back/methods/sale/specs/reserve.spec.js
index fce7bd95e..3752a2b6b 100644
--- a/modules/ticket/back/methods/sale/specs/reserve.spec.js
+++ b/modules/ticket/back/methods/sale/specs/reserve.spec.js
@@ -1,7 +1,14 @@
const app = require('vn-loopback/server/server');
describe('sale reserve()', () => {
- const ctx = {req: {accessToken: {userId: 9}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
+
afterAll(async done => {
let ctx = {req: {accessToken: {userId: 9}}};
let params = {
diff --git a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
index ec4376adb..ea8a65c27 100644
--- a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
+++ b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js
@@ -17,7 +17,13 @@ describe('sale updatePrice()', () => {
});
it('should throw an error if the ticket is not editable', async() => {
- let ctx = {req: {accessToken: {userId: 18}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 18},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
let immutableSaleId = 1;
let price = 5;
@@ -31,7 +37,14 @@ describe('sale updatePrice()', () => {
});
it('should return 0 if the price is an empty string', async() => {
- let ctx = {req: {accessToken: {userId: 18}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 18},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
+
let price = '';
await app.models.Sale.updatePrice(ctx, saleId, price);
@@ -46,7 +59,14 @@ describe('sale updatePrice()', () => {
});
it('should now set price as a number in a string', async() => {
- let ctx = {req: {accessToken: {userId: 18}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 18},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
+
let price = '8';
await app.models.Sale.updatePrice(ctx, saleId, price);
diff --git a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js
index 16221b55c..dabdac384 100644
--- a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js
+++ b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js
@@ -1,7 +1,13 @@
const app = require('vn-loopback/server/server');
describe('sale updateQuantity()', () => {
- const ctx = {req: {accessToken: {userId: 9}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
it('should throw an error if the quantity is not a number', async() => {
let error;
diff --git a/modules/ticket/back/methods/sale/updatePrice.js b/modules/ticket/back/methods/sale/updatePrice.js
index 2195c2b7b..cb86296c9 100644
--- a/modules/ticket/back/methods/sale/updatePrice.js
+++ b/modules/ticket/back/methods/sale/updatePrice.js
@@ -19,7 +19,7 @@ module.exports = Self => {
}
],
returns: {
- type: 'Number',
+ type: 'number',
root: true
},
http: {
@@ -29,29 +29,37 @@ module.exports = Self => {
});
Self.updatePrice = async(ctx, id, newPrice) => {
- let models = Self.app.models;
- let tx = await Self.beginTransaction({});
+ const $t = ctx.req.__; // $translate
+ const models = Self.app.models;
+ const tx = await Self.beginTransaction({});
try {
- let options = {transaction: tx};
+ const options = {transaction: tx};
- let filter = {
+ const filter = {
include: {
relation: 'ticket',
scope: {
include: {
relation: 'client',
scope: {
- fields: ['salesPersonFk']
+ fields: ['salesPersonFk'],
+ include: {
+ relation: 'salesPersonUser',
+ scope: {
+ fields: ['id', 'name']
+ }
+ }
}
},
fields: ['id', 'clientFk']
}
}
};
- let sale = await models.Sale.findById(id, filter, options);
- let isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk);
+ const sale = await models.Sale.findById(id, filter, options);
+
+ const isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk);
if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`);
@@ -60,21 +68,19 @@ module.exports = Self => {
if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`);
+ const oldPrice = sale.price;
const userId = ctx.req.accessToken.userId;
+ const usesMana = await models.WorkerMana.findOne({where: {workerFk: userId}, fields: 'amount'}, options);
+ const componentCode = usesMana ? 'mana' : 'buyerDiscount';
+ const discount = await models.Component.findOne({where: {code: componentCode}}, options);
+ const componentId = discount.id;
+ const componentValue = newPrice - sale.price;
- let usesMana = await models.WorkerMana.findOne({where: {workerFk: userId}, fields: 'amount'}, options);
-
- let componentCode = usesMana ? 'mana' : 'buyerDiscount';
-
- let discount = await models.Component.findOne({where: {code: componentCode}}, options);
- let componentId = discount.id;
- let componentValue = newPrice - sale.price;
-
- let where = {
+ const where = {
componentFk: componentId,
saleFk: id
};
- let saleComponent = await models.SaleComponent.findOne({where}, options);
+ const saleComponent = await models.SaleComponent.findOne({where}, options);
if (saleComponent) {
await models.SaleComponent.updateAll(where, {
@@ -92,6 +98,22 @@ module.exports = Self => {
query = `CALL vn.manaSpellersRequery(?)`;
await Self.rawSql(query, [userId], options);
+ const salesPerson = sale.ticket().client().salesPersonUser();
+ if (salesPerson) {
+ const origin = ctx.req.headers.origin;
+ const message = $t('Changed sale price', {
+ ticketId: sale.ticket().id,
+ itemId: sale.itemFk,
+ concept: sale.concept,
+ quantity: sale.quantity,
+ oldPrice: oldPrice,
+ newPrice: newPrice,
+ ticketUrl: `${origin}/#!/ticket/${sale.ticket().id}/sale`,
+ itemUrl: `${origin}/#!/item/${sale.itemFk}/summary`
+ });
+ await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
+ }
+
await tx.commit();
return sale;
diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js
index 00df49b9f..62e09f1f5 100644
--- a/modules/ticket/back/methods/sale/updateQuantity.js
+++ b/modules/ticket/back/methods/sale/updateQuantity.js
@@ -26,7 +26,8 @@ module.exports = Self => {
}
});
- Self.updateQuantity = async(ctx, id, quantity) => {
+ Self.updateQuantity = async(ctx, id, newQuantity) => {
+ const $t = ctx.req.__; // $translate
const models = Self.app.models;
const canEditSale = await models.Sale.canEdit(ctx, [id]);
@@ -34,13 +35,51 @@ module.exports = Self => {
if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`);
- if (isNaN(quantity))
+ if (isNaN(newQuantity))
throw new UserError(`The value should be a number`);
- let currentLine = await models.Sale.findOne({where: {id: id}});
- if (quantity > currentLine.quantity)
+ const filter = {
+ include: {
+ relation: 'ticket',
+ scope: {
+ include: {
+ relation: 'client',
+ scope: {
+ include: {
+ relation: 'salesPersonUser',
+ scope: {
+ fields: ['id', 'name']
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ const sale = await models.Sale.findById(id, filter);
+
+ if (newQuantity > sale.quantity)
throw new UserError('The new quantity should be smaller than the old one');
- return await currentLine.updateAttributes({quantity: quantity});
+ const oldQuantity = sale.quantity;
+ const result = await sale.updateAttributes({quantity: newQuantity});
+
+ const salesPerson = sale.ticket().client().salesPersonUser();
+ if (salesPerson) {
+ const origin = ctx.req.headers.origin;
+ const message = $t('Changed sale quantity', {
+ ticketId: sale.ticket().id,
+ itemId: sale.itemFk,
+ concept: sale.concept,
+ oldQuantity: oldQuantity,
+ newQuantity: newQuantity,
+ ticketUrl: `${origin}/#!/ticket/${sale.ticket().id}/sale`,
+ itemUrl: `${origin}/#!/item/${sale.itemFk}/summary`
+ });
+ await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
+ }
+
+ return result;
};
};
diff --git a/modules/ticket/back/methods/ticket/addSale.js b/modules/ticket/back/methods/ticket/addSale.js
index 365355df2..dc45e5de9 100644
--- a/modules/ticket/back/methods/ticket/addSale.js
+++ b/modules/ticket/back/methods/ticket/addSale.js
@@ -33,6 +33,7 @@ module.exports = Self => {
});
Self.addSale = async(ctx, id, itemId, quantity) => {
+ const $t = ctx.req.__; // $translate
const models = Self.app.models;
const isEditable = await models.Ticket.isEditable(ctx, id);
@@ -40,7 +41,19 @@ module.exports = Self => {
throw new UserError(`The sales of this ticket can't be modified`);
const item = await models.Item.findById(itemId);
- const ticket = await models.Ticket.findById(id);
+ const ticket = await models.Ticket.findById(id, {
+ include: {
+ relation: 'client',
+ scope: {
+ include: {
+ relation: 'salesPersonUser',
+ scope: {
+ fields: ['id', 'name']
+ }
+ }
+ }
+ }
+ });
const res = await models.Item.getVisibleAvailable(itemId, ticket.warehouseFk, ticket.shipped);
@@ -63,6 +76,20 @@ module.exports = Self => {
}
});
+ const addition = `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity})`;
+
+ const salesPerson = ticket.client().salesPersonUser();
+ if (salesPerson) {
+ const origin = ctx.req.headers.origin;
+
+ const message = $t('Added sale to ticket', {
+ ticketId: id,
+ ticketUrl: `${origin}/#!/ticket/${id}/sale`,
+ addition: addition
+ });
+ await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
+ }
+
return sale;
};
};
diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js
index b66179eb8..9ebd51bf4 100644
--- a/modules/ticket/back/methods/ticket/componentUpdate.js
+++ b/modules/ticket/back/methods/ticket/componentUpdate.js
@@ -230,7 +230,7 @@ module.exports = Self => {
ticketUrl: `${origin}/#!/ticket/${args.id}/sale`,
changes: changesMade
});
- await models.Chat.sendCheckingPresence(ctx, salesPersonId, message, myOptions);
+ await models.Chat.sendCheckingPresence(ctx, salesPersonId, message);
}
if (tx) await tx.commit();
diff --git a/modules/ticket/back/methods/ticket/specs/addSale.spec.js b/modules/ticket/back/methods/ticket/specs/addSale.spec.js
index c2650bf4b..9f6da7ed2 100644
--- a/modules/ticket/back/methods/ticket/specs/addSale.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/addSale.spec.js
@@ -12,7 +12,13 @@ describe('ticket addSale()', () => {
});
it('should create a new sale for the ticket with id 13', async() => {
- let ctx = {req: {accessToken: {userId: 9}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
const itemId = 4;
const quantity = 10;
newSale = await app.models.Ticket.addSale(ctx, ticketId, itemId, quantity);
@@ -21,7 +27,13 @@ describe('ticket addSale()', () => {
});
it('should not be able to add a sale if the item quantity is not available', async() => {
- let ctx = {req: {accessToken: {userId: 9}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
const itemId = 11;
const quantity = 10;
@@ -36,7 +48,13 @@ describe('ticket addSale()', () => {
});
it('should not be able to add a sale if the ticket is not editable', async() => {
- let ctx = {req: {accessToken: {userId: 9}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
const notEditableTicketId = 1;
const itemId = 4;
const quantity = 10;
diff --git a/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js b/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js
index 2e71842b4..406a3f3ee 100644
--- a/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js
@@ -35,7 +35,13 @@ describe('sale updateDiscount()', () => {
});
it('should throw an error if no sales were selected', async() => {
- let ctx = {req: {accessToken: {userId: 9}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
let error;
const ticketId = 11;
const sales = [];
@@ -51,7 +57,13 @@ describe('sale updateDiscount()', () => {
});
it('should throw an error if no sales belong to different tickets', async() => {
- let ctx = {req: {accessToken: {userId: 9}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
let error;
const ticketId = 11;
const sales = [1, 14];
@@ -67,7 +79,13 @@ describe('sale updateDiscount()', () => {
});
it('should throw an error if the ticket is invoiced already', async() => {
- let ctx = {req: {accessToken: {userId: 9}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
let error;
const ticketId = 1;
const sales = [1];
@@ -83,7 +101,13 @@ describe('sale updateDiscount()', () => {
});
it('should update the discount if the salesPerson has mana', async() => {
- let ctx = {req: {accessToken: {userId: 18}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 18},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
const ticketId = 11;
const sales = [originalSaleId];
const newDiscount = 100;
@@ -105,7 +129,13 @@ describe('sale updateDiscount()', () => {
});
it('should update the discount and add company discount component if the worker does not have mana', async() => {
- let ctx = {req: {accessToken: {userId: 9}}};
+ const ctx = {
+ req: {
+ accessToken: {userId: 9},
+ headers: {origin: 'localhost:5000'},
+ __: () => {}
+ }
+ };
const ticketId = 11;
const sales = [originalSaleId];
const newDiscount = 100;
diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js
index 1bebaae8d..c9424395d 100644
--- a/modules/ticket/back/methods/ticket/updateDiscount.js
+++ b/modules/ticket/back/methods/ticket/updateDiscount.js
@@ -17,7 +17,8 @@ module.exports = Self => {
description: 'The sales id',
type: ['number'],
required: true,
- }, {
+ },
+ {
arg: 'newDiscount',
description: 'The new discount',
type: 'number',
@@ -35,6 +36,7 @@ module.exports = Self => {
});
Self.updateDiscount = async(ctx, id, salesIds, newDiscount) => {
+ const $t = ctx.req.__; // $translate
const models = Self.app.models;
const tx = await Self.beginTransaction({});
@@ -59,7 +61,7 @@ module.exports = Self => {
}
};
- let sales = await models.Sale.find(filter, options);
+ const sales = await models.Sale.find(filter, options);
if (sales.length === 0)
throw new UserError('Please select at least one sale');
@@ -94,8 +96,11 @@ module.exports = Self => {
where: {code: componentCode}}, options);
const componentId = discountComponent.id;
- let promises = [];
+ const promises = [];
+ let changesMade = '';
+
for (let sale of sales) {
+ const oldDiscount = sale.discount;
const value = ((-sale.price * newDiscount) / 100);
const newComponent = models.SaleComponent.upsert({
saleFk: sale.id,
@@ -105,6 +110,7 @@ module.exports = Self => {
const updatedSale = sale.updateAttribute('discount', newDiscount, options);
promises.push(newComponent, updatedSale);
+ changesMade += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity}) ${oldDiscount}% ➔ *${newDiscount}%*`;
}
await Promise.all(promises);
@@ -112,6 +118,32 @@ module.exports = Self => {
const query = `call vn.manaSpellersRequery(?)`;
await Self.rawSql(query, [userId], options);
+ const ticket = await models.Ticket.findById(id, {
+ include: {
+ relation: 'client',
+ scope: {
+ include: {
+ relation: 'salesPersonUser',
+ scope: {
+ fields: ['id', 'name']
+ }
+ }
+ }
+ }
+ }, options);
+
+ const salesPerson = ticket.client().salesPersonUser();
+ if (salesPerson) {
+ const origin = ctx.req.headers.origin;
+
+ const message = $t('Changed sale discount', {
+ ticketId: id,
+ ticketUrl: `${origin}/#!/ticket/${id}/sale`,
+ changes: changesMade
+ });
+ await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
+ }
+
await tx.commit();
} catch (error) {
await tx.rollback();
diff --git a/modules/ticket/front/component/index.js b/modules/ticket/front/component/index.js
index 307f8af15..3f262f457 100644
--- a/modules/ticket/front/component/index.js
+++ b/modules/ticket/front/component/index.js
@@ -82,7 +82,10 @@ class Controller extends Section {
if (!this.ticket) return;
this.$http.get(`Tickets/${this.ticket.id}/getVolume`)
- .then(res => this.ticketVolume = res.data[0].volume);
+ .then(res => {
+ if (res.data.length)
+ this.ticketVolume = res.data[0].volume;
+ });
}
}
diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js
index 46cbe43c9..7e7654038 100644
--- a/modules/ticket/front/sale/index.js
+++ b/modules/ticket/front/sale/index.js
@@ -47,7 +47,13 @@ class Controller extends Section {
getMana() {
this.$http.get(`Tickets/${this.$params.id}/getSalesPersonMana`)
- .then(res => this.edit.mana = res.data);
+ .then(res => {
+ this.edit.mana = res.data;
+ this.$.$applyAsync(() => {
+ this.$.editDiscount.relocate();
+ this.$.editPricePopover.relocate();
+ });
+ });
}
/**
diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js
index e5368468a..169b41c5f 100644
--- a/modules/ticket/front/sale/index.spec.js
+++ b/modules/ticket/front/sale/index.spec.js
@@ -42,6 +42,8 @@ describe('Ticket', () => {
$scope.sms = {open: () => {}};
$scope.ticket = ticket;
$scope.model = crudModel;
+ $scope.editDiscount = {relocate: () => {}};
+ $scope.editPricePopover = {relocate: () => {}};
$httpBackend = _$httpBackend_;
Object.defineProperties($state.params, {
id: {