From 9c0334619d628ff419780642c77b335231f1c9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Andr=C3=A9s?= Date: Fri, 13 Oct 2023 11:56:50 +0200 Subject: [PATCH 1/4] refs #6199 --- loopback/locale/es.json | 3 ++- modules/item/back/models/item.json | 4 ++++ modules/ticket/back/methods/sale/updateQuantity.js | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 8c50cd9d8..d34c97d21 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -319,5 +319,6 @@ "The response is not a PDF": "La respuesta no es un PDF", "Ticket without Route": "Ticket sin ruta", "Booking completed": "Reserva completada", - "The ticket is in preparation": "El ticket [{{ticketId}}]({{{ticketUrl}}}) del comercial {{salesPersonId}} está en preparación" + "The ticket is in preparation": "El ticket [{{ticketId}}]({{{ticketUrl}}}) del comercial {{salesPersonId}} está en preparación", + "The amount cannot be less than the minimum": "La cantidad no puede ser menor que la cantidad mímina" } diff --git a/modules/item/back/models/item.json b/modules/item/back/models/item.json index e99dcd996..28f9648fb 100644 --- a/modules/item/back/models/item.json +++ b/modules/item/back/models/item.json @@ -154,6 +154,10 @@ "mysql":{ "columnName": "doPhoto" } + }, + "minQuantity": { + "type": "number", + "description": "Min quantity" } }, "relations": { diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js index edbc34e42..375928506 100644 --- a/modules/ticket/back/methods/sale/updateQuantity.js +++ b/modules/ticket/back/methods/sale/updateQuantity.js @@ -72,6 +72,15 @@ module.exports = Self => { where: {refundTicketFk: sale.ticketFk}, fields: ['id']} , myOptions); + + const item = await models.Item.findOne({ + where: {id: sale.itemFk}, + fields: ['minQuantity']} + , myOptions); + + if (newQuantity < item.minQuantity && !ticketRefund) + throw new UserError('The amount cannot be less than the minimum'); + if (newQuantity < 0 && !ticketRefund) throw new UserError('You can only add negative amounts in refund tickets'); From ab1cc34015686624bcb53a8b7eac620191cd52ca Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 13 Oct 2023 15:14:48 +0200 Subject: [PATCH 2/4] refs #6199 feat(sale): best quantity restriction --- .../back/methods/sale/updateQuantity.js | 22 +--------- modules/ticket/back/models/sale.js | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js index 375928506..ce7db5ffd 100644 --- a/modules/ticket/back/methods/sale/updateQuantity.js +++ b/modules/ticket/back/methods/sale/updateQuantity.js @@ -1,4 +1,4 @@ -let UserError = require('vn-loopback/util/user-error'); +const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('updateQuantity', { @@ -64,26 +64,6 @@ module.exports = Self => { const sale = await models.Sale.findById(id, filter, myOptions); - const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*'); - if (newQuantity > sale.quantity && !isRoleAdvanced) - throw new UserError('The new quantity should be smaller than the old one'); - - const ticketRefund = await models.TicketRefund.findOne({ - where: {refundTicketFk: sale.ticketFk}, - fields: ['id']} - , myOptions); - - const item = await models.Item.findOne({ - where: {id: sale.itemFk}, - fields: ['minQuantity']} - , myOptions); - - if (newQuantity < item.minQuantity && !ticketRefund) - throw new UserError('The amount cannot be less than the minimum'); - - if (newQuantity < 0 && !ticketRefund) - throw new UserError('You can only add negative amounts in refund tickets'); - const oldQuantity = sale.quantity; const result = await sale.updateAttributes({quantity: newQuantity}, myOptions); diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js index ae247fc24..556f35d60 100644 --- a/modules/ticket/back/models/sale.js +++ b/modules/ticket/back/models/sale.js @@ -1,3 +1,5 @@ +const UserError = require('vn-loopback/util/user-error'); + module.exports = Self => { require('../methods/sale/getClaimableFromTicket')(Self); require('../methods/sale/reserve')(Self); @@ -13,4 +15,43 @@ module.exports = 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; + console.log(ctx?.req?.accessToken, instance, changes); + const newQuantity = changes?.quantity; + if (newQuantity === null) return; + + const canEditQuantity = await models.ACL.checkAccessAcl(ctx, 'Sale', 'canForceQuantity', 'WRITE'); + if (canEditQuantity) return; + + const ticketId = changes?.ticketFk || instance?.ticketFk; + const itemId = changes?.itemFk || instance?.itemFk; + + const ticketRefund = await models.TicketRefund.findOne({ + where: {refundTicketFk: ticketId}, + fields: ['id']} + , ctx.options); + + const item = await models.Item.findOne({ + where: {id: itemId}, + fields: ['minQuantity']} + , ctx.options); + + if (newQuantity < item.minQuantity && !ticketRefund) + throw new UserError('The amount cannot be less than the minimum'); + + if (newQuantity < 0 && !ticketRefund) + throw new UserError('You can only add negative amounts in refund tickets'); + + const oldQuantity = instance?.quantity; + if (oldQuantity === null) return; + + const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*'); + if (newQuantity > oldQuantity && !isRoleAdvanced) + throw new UserError('The new quantity should be smaller than the old one'); + }); }; + From b769fa9bcf5ad8c99d2365742c78918783758c0d Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 16 Oct 2023 10:10:57 +0200 Subject: [PATCH 3/4] refs #6199 fix(sale_updateQuantity): if clientType is loses skip test: fix updateQuantity activeCtx and add test for minQuantity --- loopback/locale/en.json | 5 +- .../claim/specs/regularizeClaim.spec.js | 2 +- .../methods/sale/specs/updateQuantity.spec.js | 62 ++++++++++++++----- .../back/methods/sale/updateQuantity.js | 1 - modules/ticket/back/models/sale.js | 35 +++++++++-- 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 645a874e8..f61226e9e 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -189,5 +189,6 @@ "The sales do not exists": "The sales do not exists", "Ticket without Route": "Ticket without route", "Booking completed": "Booking complete", - "The ticket is in preparation": "The ticket [{{ticketId}}]({{{ticketUrl}}}) of the sales person {{salesPersonId}} is in preparation" -} + "The ticket is in preparation": "The ticket [{{ticketId}}]({{{ticketUrl}}}) of the sales person {{salesPersonId}} is in preparation", + "You can only add negative amounts in refund tickets": "You can only add negative amounts in refund tickets" +} \ No newline at end of file diff --git a/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js b/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js index 276843c32..95c356374 100644 --- a/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js +++ b/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js @@ -64,7 +64,7 @@ describe('claim regularizeClaim()', () => { claimEnds = await importTicket(ticketId, claimId, userId, options); - for (claimEnd of claimEnds) + for (const claimEnd of claimEnds) await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options); let claimBefore = await models.Claim.findById(claimId, null, options); diff --git a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js index 8064ea30b..bb58780e3 100644 --- a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js @@ -2,20 +2,6 @@ const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); describe('sale updateQuantity()', () => { - beforeAll(async() => { - const activeCtx = { - accessToken: {userId: 9}, - http: { - req: { - headers: {origin: 'http://localhost'} - } - } - }; - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ - active: activeCtx - }); - }); - const ctx = { req: { accessToken: {userId: 9}, @@ -23,6 +9,18 @@ describe('sale updateQuantity()', () => { __: () => {} } }; + function getActiveCtx(userId) { + return { + active: { + accessToken: {userId}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + } + }; + } it('should throw an error if the quantity is greater than it should be', async() => { const ctx = { @@ -32,6 +30,8 @@ describe('sale updateQuantity()', () => { __: () => {} } }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1)); + const tx = await models.Sale.beginTransaction({}); let error; @@ -50,6 +50,8 @@ describe('sale updateQuantity()', () => { }); it('should add quantity if the quantity is greater than it should be and is role advanced', async() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9)); + const tx = await models.Sale.beginTransaction({}); const saleId = 17; const buyerId = 35; @@ -87,6 +89,8 @@ describe('sale updateQuantity()', () => { }); it('should update the quantity of a given sale current line', async() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9)); + const tx = await models.Sale.beginTransaction({}); const saleId = 25; const newQuantity = 4; @@ -119,6 +123,8 @@ describe('sale updateQuantity()', () => { __: () => {} } }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1)); + const saleId = 17; const newQuantity = -10; @@ -140,6 +146,8 @@ describe('sale updateQuantity()', () => { }); it('should update a negative quantity when is a ticket refund', async() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9)); + const tx = await models.Sale.beginTransaction({}); const saleId = 13; const newQuantity = -10; @@ -159,4 +167,30 @@ describe('sale updateQuantity()', () => { throw e; } }); + + it('should throw an error if the quantity is less than the minimum quantity of the item', async() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9)); + + const tx = await models.Sale.beginTransaction({}); + const itemId = 2; + const saleId = 17; + const newQuantity = 29; + + let error; + try { + const options = {transaction: tx}; + + const item = await models.Item.findById(itemId, null, options); + await item.updateAttribute('minQuantity', 30, options); + + await models.Sale.updateQuantity(ctx, saleId, newQuantity, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toEqual(new Error('The amount cannot be less than the minimum')); + }); }); diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js index ce7db5ffd..55106f053 100644 --- a/modules/ticket/back/methods/sale/updateQuantity.js +++ b/modules/ticket/back/methods/sale/updateQuantity.js @@ -1,4 +1,3 @@ -const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('updateQuantity', { diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js index 556f35d60..bacc5ef44 100644 --- a/modules/ticket/back/models/sale.js +++ b/modules/ticket/back/models/sale.js @@ -1,4 +1,5 @@ const UserError = require('vn-loopback/util/user-error'); +const LoopBackContext = require('loopback-context'); module.exports = Self => { require('../methods/sale/getClaimableFromTicket')(Self); @@ -20,21 +21,46 @@ module.exports = Self => { const models = Self.app.models; const changes = ctx.data || ctx.instance; const instance = ctx.currentInstance; - console.log(ctx?.req?.accessToken, instance, changes); - const newQuantity = changes?.quantity; - if (newQuantity === null) return; + const newQuantity = changes?.quantity; + if (newQuantity == null) return; + + const loopBackContext = LoopBackContext.getCurrentContext(); + ctx.req = loopBackContext.active; const canEditQuantity = await models.ACL.checkAccessAcl(ctx, 'Sale', 'canForceQuantity', 'WRITE'); if (canEditQuantity) return; const ticketId = changes?.ticketFk || instance?.ticketFk; const itemId = changes?.itemFk || instance?.itemFk; + const ticket = await models.Ticket.findById( + ticketId, + { + fields: ['id', 'clientFk'], + include: { + relation: 'client', + scope: { + fields: ['id', 'clientTypeFk'], + include: { + relation: 'type', + scope: { + fields: ['code', 'description'] + } + } + } + } + }, + ctx.options); + if (ticket.client().type().code === 'loses') return; + const ticketRefund = await models.TicketRefund.findOne({ where: {refundTicketFk: ticketId}, fields: ['id']} , ctx.options); + if (newQuantity < 0 && !ticketRefund) + throw new UserError('You can only add negative amounts in refund tickets'); + const item = await models.Item.findOne({ where: {id: itemId}, fields: ['minQuantity']} @@ -43,9 +69,6 @@ module.exports = Self => { if (newQuantity < item.minQuantity && !ticketRefund) throw new UserError('The amount cannot be less than the minimum'); - if (newQuantity < 0 && !ticketRefund) - throw new UserError('You can only add negative amounts in refund tickets'); - const oldQuantity = instance?.quantity; if (oldQuantity === null) return; From f79e71161744cce480b88b1e07ec3cd1946ebe17 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 16 Oct 2023 10:19:33 +0200 Subject: [PATCH 4/4] refs #6199 test: updateQuantity refactor --- .../ticket/back/methods/sale/specs/updateQuantity.spec.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js index bb58780e3..6bf0a0d7e 100644 --- a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js @@ -174,14 +174,15 @@ describe('sale updateQuantity()', () => { const tx = await models.Sale.beginTransaction({}); const itemId = 2; const saleId = 17; - const newQuantity = 29; + const minQuantity = 30; + const newQuantity = minQuantity - 1; let error; try { const options = {transaction: tx}; const item = await models.Item.findById(itemId, null, options); - await item.updateAttribute('minQuantity', 30, options); + await item.updateAttribute('minQuantity', minQuantity, options); await models.Sale.updateQuantity(ctx, saleId, newQuantity, options);