const UserError = require('vn-loopback/util/user-error'); const LoopBackContext = require('loopback-context'); module.exports = Self => { require('../methods/sale/getClaimableFromTicket')(Self); require('../methods/sale/reserve')(Self); require('../methods/sale/deleteSales')(Self); require('../methods/sale/updatePrice')(Self); require('../methods/sale/updateQuantity')(Self); require('../methods/sale/updateConcept')(Self); require('../methods/sale/recalculatePrice')(Self); require('../methods/sale/canEdit')(Self); require('../methods/sale/usesMana')(Self); require('../methods/sale/clone')(Self); require('../methods/sale/getFromSectorCollection')(Self); Self.validatesPresenceOf('concept', { message: `Concept cannot be blank` }); Self.observe('before save', async ctx => { const models = Self.app.models; const changes = ctx.data || ctx.instance; const instance = ctx.currentInstance; const newQuantity = changes?.quantity; if (newQuantity == null) return; const loopBackContext = LoopBackContext.getCurrentContext(); ctx.req = loopBackContext.active; const ticketId = changes?.ticketFk || instance?.ticketFk; const itemId = changes?.itemFk || instance?.itemFk; const oldQuantity = instance?.quantity ?? null; const quantityAdded = newQuantity - oldQuantity; const isReduction = oldQuantity && newQuantity <= oldQuantity; const ticket = await models.Ticket.findById( ticketId, { fields: ['id', 'clientFk', 'warehouseFk', 'addressFk', 'agencyModeFk', 'shipped', 'landed'], include: { relation: 'client', scope: { fields: ['id', 'typeFk'], include: { relation: 'type', scope: { fields: ['code', 'description'] } } } } }, ctx.options); if (ticket?.client()?.typeFk === 'loses') return; const isRefund = await models.TicketRefund.findOne({ fields: ['id'], where: {refundTicketFk: ticketId} }, ctx.options); if (isRefund) return; if (newQuantity < 0) throw new UserError('You can only add negative amounts in refund tickets'); const item = await models.Item.findOne({ fields: ['family'], where: {id: itemId}, }, ctx.options); if (item.family == 'EMB') return; if (await models.ACL.checkAccessAcl(ctx, 'Sale', 'isInPreparing', '*')) return; await models.Sale.rawSql(`CALL catalog_calcFromItem(?,?,?,?)`, [ ticket.landed, ticket.addressFk, ticket.agencyModeFk, itemId ], ctx.options); const [itemInfo] = await models.Sale.rawSql(`SELECT available FROM tmp.ticketCalculateItem`, null, ctx.options); const available = itemInfo?.available; if ((!isReduction && !available) || available < quantityAdded) throw new UserError(`This item is not available`); if (await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*')) return; const itemMinimalQuantity = await models.ItemMinimumQuantity.find({ fields: ['quantity', 'warehouseFk'], where: { itemFk: itemId, started: {lte: ticket.shipped}, or: [ {ended: {gte: ticket.shipped}}, {ended: null} ], // eslint-disable-next-line no-dupe-keys or: [ {warehouseFk: ticket.warehouseFk}, {warehouseFk: null} ] }, }, ctx.options); const minQuantity = itemMinimalQuantity.reduce((selected, item) => { if (item.warehouseFk === ticket.warehouseFk) return item; if (item.warehouseFk === null && !selected) return item; return selected; }, null); if (newQuantity < minQuantity?.quantity && newQuantity != available) throw new UserError('The amount cannot be less than the minimum'); if (ctx.isNewInstance || isReduction) return; const [saleGrouping] = await models.Sale.rawSql(` SELECT t.price newPrice FROM tmp.ticketComponentPrice t ORDER BY (t.grouping <= ?) DESC, t.grouping ASC LIMIT 1`, [quantityAdded], ctx.options); await models.Sale.rawSql(` DROP TEMPORARY TABLE IF EXISTS tmp.ticketCalculateItem, tmp.ticketComponentPrice, tmp.ticketComponent, tmp.ticketLot, tmp.zoneGetShipped; `, null, ctx.options); if (!saleGrouping?.newPrice || saleGrouping.newPrice > instance.price) throw new UserError('The price of the item changed'); }); };