3033-price_and_discount_ticket_sale_popover #707
|
@ -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}}})",
|
||||
|
@ -99,5 +106,8 @@
|
|||
"None": "None",
|
||||
"error densidad = 0": "error densidad = 0",
|
||||
"nickname": "nickname",
|
||||
"This document already exists on this ticket": "This document already exists on this ticket"
|
||||
"This document already exists on this ticket": "This document already exists on this ticket",
|
||||
"State": "State",
|
||||
"regular": "regular",
|
||||
"reserved": "reserved"
|
||||
}
|
|
@ -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}}})",
|
||||
|
|
|
@ -3,17 +3,20 @@ const UserError = require('vn-loopback/util/user-error');
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('createFromSales', {
|
||||
description: 'Create a claim',
|
||||
accepts: [{
|
||||
accepts: [
|
||||
{
|
||||
arg: 'ticketId',
|
||||
type: 'Number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The origin ticket id'
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'sales',
|
||||
type: ['Object'],
|
||||
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;
|
||||
|
|
|
@ -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({});
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,24 +5,27 @@ module.exports = Self => {
|
|||
Self.remoteMethodCtx('reserve', {
|
||||
description: 'Change the state of a ticket',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
accepts: [
|
||||
{
|
||||
arg: 'ticketId',
|
||||
type: 'Number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The ticket id'
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'sales',
|
||||
type: ['Object'],
|
||||
type: ['object'],
|
||||
required: true,
|
||||
description: 'The sale to reserve'
|
||||
},
|
||||
{
|
||||
arg: 'reserved',
|
||||
type: 'Boolean',
|
||||
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) {
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue