salix/modules/ticket/back/methods/ticket/transferSales.js

208 lines
7.5 KiB
JavaScript

let UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('transferSales', {
description: 'Transfer sales to a new or a given ticket',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'Origin ticket id',
http: {source: 'path'}
},
{
arg: 'ticketId',
type: 'number',
description: 'Destination ticket id',
required: false
},
{
arg: 'sales',
type: ['object'],
description: 'The sales to transfer',
required: true
}],
returns: {
type: 'object',
root: true
},
http: {
path: `/:id/transferSales`,
verb: 'POST'
}
});
Self.transferSales = async(ctx, id, ticketId, sales, options) => {
const userId = ctx.req.accessToken.userId;
const models = Self.app.models;
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const isEditable = await models.Ticket.isEditable(ctx, id, myOptions);
if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`);
if (ticketId) {
const isReceiverEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions);
if (!isReceiverEditable)
throw new UserError(`The sales of the receiver ticket can't be modified`);
}
const originalTicket = await models.Ticket.findById(id, null, myOptions);
const originalSales = await models.Sale.find({
where: {ticketFk: id}
}, myOptions);
if (!ticketId) {
const ticket = await models.Ticket.findById(id);
const canCreateTicket = await models.Client.canCreateTicket(ticket.clientFk);
if (!canCreateTicket)
throw new UserError(`You can't create a ticket for a inactive client`);
ticketId = await cloneTicket(originalTicket, myOptions);
}
const map = new Map();
for (const sale of originalSales)
map.set(sale.id, sale);
const saleIds = sales.map(sale => sale.id);
const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}});
if (hasClaimedSales)
throw new UserError(`Can't transfer claimed sales`);
for (const sale of sales) {
const originalSale = map.get(sale.id);
const originalSaleData = { // <-- Loopback modifies original instance on save
itemFk: originalSale.itemFk,
quantity: originalSale.quantity,
concept: originalSale.concept,
ticketFk: originalSale.ticketFk
};
if (sale.quantity == originalSale.quantity) {
query = `UPDATE sale
SET ticketFk = ?
WHERE id = ?`;
await Self.rawSql(query, [ticketId, sale.id], myOptions);
} else if (sale.quantity != originalSale.quantity) {
await transferPartialSale(
ticketId, originalSale, sale, myOptions);
}
// Log to original ticket
await models.TicketLog.create({
originFk: id,
userFk: userId,
action: 'update',
changedModel: 'Sale',
changedModelId: sale.id,
oldInstance: {
item: originalSaleData.itemFk,
quantity: originalSaleData.quantity,
concept: originalSaleData.concept,
ticket: originalSaleData.ticketFk
},
newInstance: {
item: sale.itemFk,
quantity: sale.quantity,
concept: sale.concept,
ticket: ticketId
}
}, myOptions);
// Log to destination ticket
await models.TicketLog.create({
originFk: ticketId,
userFk: userId,
action: 'update',
changedModel: 'Sale',
changedModelId: sale.id,
oldInstance: {
item: originalSaleData.itemFk,
quantity: originalSaleData.quantity,
concept: originalSaleData.concept,
ticket: originalSaleData.ticketFk
},
newInstance: {
item: sale.itemFk,
quantity: sale.quantity,
concept: sale.concept,
ticket: ticketId
}
}, myOptions);
}
const isTicketEmpty = await models.Ticket.isEmpty(id, myOptions);
if (isTicketEmpty) {
await originalTicket.updateAttributes({
isDeleted: true
}, myOptions);
}
if (tx) await tx.commit();
return {id: ticketId};
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
async function cloneTicket(ticket, options) {
query = `CALL vn.ticket_Clone(?, @result);
SELECT @result newTicketId;`;
let result = await Self.rawSql(query, [
ticket.id
], options);
return result[1][0].newTicketId;
}
async function transferPartialSale(ticketId, originalSale, sale, options) {
const models = Self.app.models;
if (sale.quantity > originalSale.quantity)
throw new UserError('Invalid quantity');
// Update original sale
const rest = originalSale.quantity - sale.quantity;
query = `UPDATE sale
SET quantity = ?
WHERE id = ?`;
await Self.rawSql(query, [rest, sale.id], options);
// Clone sale with new quantity
query = `INSERT INTO sale (itemFk, ticketFk, concept, quantity, originalQuantity, price, discount, priceFixed,
reserved, isPicked, isPriceFixed, isAdded)
SELECT itemFk, ?, concept, ?, originalQuantity, price, discount, priceFixed,
reserved, isPicked, isPriceFixed, isAdded
FROM sale
WHERE id = ?`;
await Self.rawSql(query, [ticketId, sale.quantity, sale.id], options);
const [lastInsertedSale] = await Self.rawSql('SELECT LAST_INSERT_ID() AS id', null, options);
// Clone sale components
const saleComponents = await models.SaleComponent.find({
where: {saleFk: sale.id}
}, options);
const newComponents = saleComponents.map(component => {
component.saleFk = lastInsertedSale.id;
return component;
});
await models.SaleComponent.create(newComponents, options);
}
};