From d86aa5535c0866315c51e732ccf5ebe0e96ffb9c Mon Sep 17 00:00:00 2001 From: carlosjr Date: Tue, 4 Jan 2022 16:16:39 +0100 Subject: [PATCH 1/7] refactor(createFromSales): now claimManager can claim any time --- .../back/methods/claim/createFromSales.js | 3 +- .../claim/specs/createFromSales.spec.js | 31 +++++++++++++++++++ modules/ticket/front/sale/index.js | 4 ++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/modules/claim/back/methods/claim/createFromSales.js b/modules/claim/back/methods/claim/createFromSales.js index cdbce865b..ba7bda71d 100644 --- a/modules/claim/back/methods/claim/createFromSales.js +++ b/modules/claim/back/methods/claim/createFromSales.js @@ -59,11 +59,12 @@ module.exports = Self => { const landedPlusWeek = new Date(ticket.landed); landedPlusWeek.setDate(landedPlusWeek.getDate() + 7); + const hasClaimManagerRole = await models.Account.hasRole(userId, 'claimManager', myOptions); const isClaimable = landedPlusWeek >= new Date(); if (ticket.isDeleted) throw new UserError(`You can't create a claim for a removed ticket`); - if (!isClaimable) + if (!isClaimable && !hasClaimManagerRole) throw new UserError(`You can't create a claim from a ticket delivered more than seven days ago`); const newClaim = await Self.create({ diff --git a/modules/claim/back/methods/claim/specs/createFromSales.spec.js b/modules/claim/back/methods/claim/specs/createFromSales.spec.js index 8a48b8613..097dcc0d9 100644 --- a/modules/claim/back/methods/claim/specs/createFromSales.spec.js +++ b/modules/claim/back/methods/claim/specs/createFromSales.spec.js @@ -46,9 +46,40 @@ describe('Claim createFromSales()', () => { } }); + it('should be able to create a claim for a ticket delivered more than seven days ago as claimManager', async() => { + const tx = await models.Claim.beginTransaction({}); + const claimManagerId = 72; + activeCtx.accessToken.userId = claimManagerId; + + try { + const options = {transaction: tx}; + + const todayMinusEightDays = new Date(); + todayMinusEightDays.setDate(todayMinusEightDays.getDate() - 8); + + const ticket = await models.Ticket.findById(ticketId, options); + await ticket.updateAttribute('landed', todayMinusEightDays, options); + + const claim = await models.Claim.createFromSales(ctx, ticketId, newSale, options); + + expect(claim.ticketFk).toEqual(ticketId); + + const claimBeginning = await models.ClaimBeginning.findOne({where: {claimFk: claim.id}}, options); + + expect(claimBeginning.saleFk).toEqual(newSale[0].id); + expect(claimBeginning.quantity).toEqual(newSale[0].quantity); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + it('should not be able to create a claim for a ticket delivered more than seven days ago', async() => { const tx = await models.Claim.beginTransaction({}); + activeCtx.accessToken.userId = 1; let error; try { diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js index 9d0f71eb8..54167ce96 100644 --- a/modules/ticket/front/sale/index.js +++ b/modules/ticket/front/sale/index.js @@ -40,7 +40,9 @@ class Controller extends Section { const landedPlusWeek = new Date(this.ticket.landed); landedPlusWeek.setDate(landedPlusWeek.getDate() + 7); - return landedPlusWeek >= new Date(); + const hasClaimManagerRole = this.aclService.hasAny(['claimManager']); + + return landedPlusWeek >= new Date() || hasClaimManagerRole; } return false; } From 961dc100ccc8c312aa30d47fe909e19e8da31752 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 5 Jan 2022 12:44:18 +0100 Subject: [PATCH 2/7] feat(client): add isWorker condition in hasBusinessType --- modules/client/back/models/client.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 7ab8bb477..dc32ac2c0 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -55,13 +55,16 @@ module.exports = Self => { with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/ }); - Self.validate('businessTypeFk', hasBusinessType, { + Self.validateAsync('businessTypeFk', hasBusinessType, { message: `The type of business must be filled in basic data` }); - function hasBusinessType(err) { - if (!this.businessTypeFk) + async function hasBusinessType(err, done) { + const isWorker = await Self.app.models.UserAccount.findById(this.id); + + if (!this.businessTypeFk && !isWorker) err(); + done(); } Self.validatesLengthOf('postcode', { From ed84aa46bd15364b6e0a31b8e4b03792c5f76849 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 5 Jan 2022 14:29:03 +0100 Subject: [PATCH 3/7] feat(client): add more condition for businessType Validation --- modules/client/back/models/client.js | 45 +++++++++++++++------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index dc32ac2c0..ea87a49ee 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -55,18 +55,6 @@ module.exports = Self => { with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/ }); - Self.validateAsync('businessTypeFk', hasBusinessType, { - message: `The type of business must be filled in basic data` - }); - - async function hasBusinessType(err, done) { - const isWorker = await Self.app.models.UserAccount.findById(this.id); - - if (!this.businessTypeFk && !isWorker) - err(); - done(); - } - Self.validatesLengthOf('postcode', { allowNull: true, allowBlank: true, @@ -192,6 +180,24 @@ module.exports = Self => { return regexp.test(value); } + Self.observe('before save', async ctx => { + const changes = ctx.data || ctx.instance; + const orgData = ctx.currentInstance; + const hasChanges = orgData && changes; + + const businessTypeFk = changes && changes.businessTypeFk || orgData && orgData.businessTypeFk; + + const isTaxDataChecked = changes && changes.isTaxDataChecked || orgData && orgData.isTaxDataChecked; + const isTaxDataCheckedChanged = hasChanges && orgData.isTaxDataChecked != isTaxDataChecked; + + let isWorker = false; + if (!ctx.isNewInstance) + isWorker = await Self.app.models.UserAccount.findById(orgData.id); + + if (!businessTypeFk && !isTaxDataChecked && !isTaxDataCheckedChanged && !isWorker) + throw new UserError(`The type of business must be filled in basic data`); + }); + Self.observe('before save', async function(ctx) { const changes = ctx.data || ctx.instance; const orgData = ctx.currentInstance; @@ -209,7 +215,7 @@ module.exports = Self => { && orgData.isTaxDataChecked != isTaxDataChecked; if ((socialNameChanged || dataCheckedChanged) && !isAlpha(socialName)) - throw new UserError('The socialName has an invalid format'); + throw new UserError(`The socialName has an invalid format`); if (changes.salesPerson === null) { changes.credit = 0; @@ -377,14 +383,11 @@ module.exports = Self => { throw new UserError(`You don't have enough privileges to set this credit amount`); } - const client = await models.Client.findById(finalState.id, null, ctx.options); - if (client.businessTypeFk) { - await models.ClientCredit.create({ - amount: changes.credit, - clientFk: finalState.id, - workerFk: userId - }, ctx.options); - } + await models.ClientCredit.create({ + amount: changes.credit, + clientFk: finalState.id, + workerFk: userId + }, ctx.options); }; const app = require('vn-loopback/server/server'); From e1c91954955ae8414be792f2f95341ad039b92d0 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 5 Jan 2022 14:53:29 +0100 Subject: [PATCH 4/7] update condition --- modules/client/back/models/client.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index ea87a49ee..06453da36 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -183,18 +183,15 @@ module.exports = Self => { Self.observe('before save', async ctx => { const changes = ctx.data || ctx.instance; const orgData = ctx.currentInstance; - const hasChanges = orgData && changes; const businessTypeFk = changes && changes.businessTypeFk || orgData && orgData.businessTypeFk; - const isTaxDataChecked = changes && changes.isTaxDataChecked || orgData && orgData.isTaxDataChecked; - const isTaxDataCheckedChanged = hasChanges && orgData.isTaxDataChecked != isTaxDataChecked; let isWorker = false; if (!ctx.isNewInstance) isWorker = await Self.app.models.UserAccount.findById(orgData.id); - if (!businessTypeFk && !isTaxDataChecked && !isTaxDataCheckedChanged && !isWorker) + if (!businessTypeFk && !isTaxDataChecked && !isWorker) throw new UserError(`The type of business must be filled in basic data`); }); From 2279b3d9ab42953b90b6a8a3dd006404e90b1a29 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Jan 2022 15:17:21 +0100 Subject: [PATCH 5/7] Prevent businessTypeFk validation for other invalid fields --- modules/client/back/models/client.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 06453da36..0c378ec25 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -184,15 +184,17 @@ module.exports = Self => { const changes = ctx.data || ctx.instance; const orgData = ctx.currentInstance; - const businessTypeFk = changes && changes.businessTypeFk || orgData && orgData.businessTypeFk; - const isTaxDataChecked = changes && changes.isTaxDataChecked || orgData && orgData.isTaxDataChecked; + if (!ctx.isNewInstance) { + const businessTypeFk = changes && changes.businessTypeFk || orgData && orgData.businessTypeFk; + const isTaxDataChecked = changes && changes.isTaxDataChecked || orgData && orgData.isTaxDataChecked; + const changedFields = Object.keys(changes); + const hasChangedOtherFields = changedFields.some(key => key !== 'businessTypeFk'); - let isWorker = false; - if (!ctx.isNewInstance) - isWorker = await Self.app.models.UserAccount.findById(orgData.id); + const isWorker = await Self.app.models.UserAccount.findById(orgData.id); - if (!businessTypeFk && !isTaxDataChecked && !isWorker) - throw new UserError(`The type of business must be filled in basic data`); + if (!businessTypeFk && !isTaxDataChecked && !isWorker && !hasChangedOtherFields) + throw new UserError(`The type of business must be filled in basic data`); + } }); Self.observe('before save', async function(ctx) { From 4e6d8d17f542b25dffa9247ce69828c0990e9f3b Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Jan 2022 15:41:26 +0100 Subject: [PATCH 6/7] Throw invalid businessType for new clients --- modules/client/back/models/client.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 0c378ec25..bb6a8d863 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -184,17 +184,26 @@ module.exports = Self => { const changes = ctx.data || ctx.instance; const orgData = ctx.currentInstance; + const businessTypeFk = changes && changes.businessTypeFk || orgData && orgData.businessTypeFk; + const isTaxDataChecked = changes && changes.isTaxDataChecked || orgData && orgData.isTaxDataChecked; + + let invalidBusinessType = false; if (!ctx.isNewInstance) { - const businessTypeFk = changes && changes.businessTypeFk || orgData && orgData.businessTypeFk; - const isTaxDataChecked = changes && changes.isTaxDataChecked || orgData && orgData.isTaxDataChecked; + const isWorker = await Self.app.models.UserAccount.findById(orgData.id); const changedFields = Object.keys(changes); const hasChangedOtherFields = changedFields.some(key => key !== 'businessTypeFk'); - const isWorker = await Self.app.models.UserAccount.findById(orgData.id); - if (!businessTypeFk && !isTaxDataChecked && !isWorker && !hasChangedOtherFields) - throw new UserError(`The type of business must be filled in basic data`); + invalidBusinessType = true; } + + if (ctx.isNewInstance) { + if (!businessTypeFk && !isTaxDataChecked) + invalidBusinessType = true; + } + + if (invalidBusinessType) + throw new UserError(`The type of business must be filled in basic data`); }); Self.observe('before save', async function(ctx) { From c24df3ade9f49db3b67aeca9ffa8627cbf294465 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Jan 2022 16:23:58 +0100 Subject: [PATCH 7/7] Updated translations --- loopback/locale/es.json | 2 +- modules/client/back/models/client.js | 2 +- modules/supplier/back/models/supplier.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index dc662e8d3..cff5f652e 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -102,7 +102,7 @@ "Weekday cannot be blank": "El día de la semana no puede quedar en blanco", "You can't delete a confirmed order": "No puedes borrar un pedido confirmado", "Can't create stowaway for this ticket": "No se puede crear un polizon para este ticket", - "The socialName has an invalid format": "El nombre fiscal tiene un formato incorrecto", + "The social name has an invalid format": "El nombre fiscal tiene un formato incorrecto", "Invalid quantity": "Cantidad invalida", "This postal code is not valid": "This postal code is not valid", "is invalid": "is invalid", diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index bb6a8d863..3dc1e1f8d 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -223,7 +223,7 @@ module.exports = Self => { && orgData.isTaxDataChecked != isTaxDataChecked; if ((socialNameChanged || dataCheckedChanged) && !isAlpha(socialName)) - throw new UserError(`The socialName has an invalid format`); + throw new UserError(`The social name has an invalid format`); if (changes.salesPerson === null) { changes.credit = 0; diff --git a/modules/supplier/back/models/supplier.js b/modules/supplier/back/models/supplier.js index 2912a3577..f8b096b30 100644 --- a/modules/supplier/back/models/supplier.js +++ b/modules/supplier/back/models/supplier.js @@ -114,6 +114,6 @@ module.exports = Self => { && orgData.socialName != socialName; if ((socialNameChanged) && !isAlpha(socialName)) - throw new UserError('The socialName has an invalid format'); + throw new UserError('The social name has an invalid format'); }); };