From e5d466b697e33513ea98b74b855f4c17877a8ba8 Mon Sep 17 00:00:00 2001 From: jorgep Date: Fri, 26 Jan 2024 08:30:43 +0100 Subject: [PATCH 1/7] fix: refs #6703 drop & replace sale refund by clone --- modules/ticket/back/methods/sale/clone.js | 28 +++++ modules/ticket/back/methods/sale/refund.js | 61 ----------- .../back/methods/sale/specs/refund.spec.js | 101 ------------------ modules/ticket/back/methods/ticket/refund.js | 2 +- modules/ticket/back/models/sale.js | 1 - 5 files changed, 29 insertions(+), 164 deletions(-) delete mode 100644 modules/ticket/back/methods/sale/refund.js delete mode 100644 modules/ticket/back/methods/sale/specs/refund.spec.js diff --git a/modules/ticket/back/methods/sale/clone.js b/modules/ticket/back/methods/sale/clone.js index f8eb4d143..8397499f7 100644 --- a/modules/ticket/back/methods/sale/clone.js +++ b/modules/ticket/back/methods/sale/clone.js @@ -1,4 +1,32 @@ module.exports = Self => { + Self.remoteMethodCtx('clone', { + description: 'Clone sales and services provided', + accessType: 'WRITE', + accepts: [ + { + arg: 'salesIds', + type: ['number'], + }, { + arg: 'servicesIds', + type: ['number'] + }, { + arg: 'withWarehouse', + type: 'boolean', + required: true + }, { + arg: 'negative', + type: 'boolean' + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/refund`, + verb: 'post' + } + }); Self.clone = async(ctx, salesIds, servicesIds, withWarehouse, negative, options) => { const models = Self.app.models; const myOptions = {}; diff --git a/modules/ticket/back/methods/sale/refund.js b/modules/ticket/back/methods/sale/refund.js deleted file mode 100644 index 19a8dfbb0..000000000 --- a/modules/ticket/back/methods/sale/refund.js +++ /dev/null @@ -1,61 +0,0 @@ -module.exports = Self => { - Self.remoteMethodCtx('refund', { - description: 'Create refund tickets with sales and services if provided', - accessType: 'WRITE', - accepts: [ - { - arg: 'salesIds', - type: ['number'], - }, - { - arg: 'servicesIds', - type: ['number'] - }, - { - arg: 'withWarehouse', - type: 'boolean', - required: true - } - ], - returns: { - type: ['object'], - root: true - }, - http: { - path: `/refund`, - verb: 'post' - } - }); - - Self.refund = async(ctx, salesIds, servicesIds, withWarehouse, options) => { - const models = Self.app.models; - const myOptions = {userId: ctx.req.accessToken.userId}; - let tx; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - if (!myOptions.transaction) { - tx = await Self.beginTransaction({}); - myOptions.transaction = tx; - } - - try { - const refundsTicket = await models.Sale.clone( - ctx, - salesIds, - servicesIds, - withWarehouse, - true, - myOptions - ); - - if (tx) await tx.commit(); - - return refundsTicket; - } catch (e) { - if (tx) await tx.rollback(); - throw e; - } - }; -}; diff --git a/modules/ticket/back/methods/sale/specs/refund.spec.js b/modules/ticket/back/methods/sale/specs/refund.spec.js deleted file mode 100644 index ab5e1e281..000000000 --- a/modules/ticket/back/methods/sale/specs/refund.spec.js +++ /dev/null @@ -1,101 +0,0 @@ -const models = require('vn-loopback/server/server').models; -const LoopBackContext = require('loopback-context'); - -describe('Sale refund()', () => { - const userId = 5; - const ctx = {req: {accessToken: userId}, args: {}}; - const activeCtx = { - accessToken: {userId}, - }; - const servicesIds = [3]; - const withWarehouse = true; - - beforeEach(() => { - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ - active: activeCtx - }); - }); - - it('should create ticket with the selected lines', async() => { - const tx = await models.Sale.beginTransaction({}); - const salesIds = [7, 8]; - - try { - const options = {transaction: tx}; - - const refundedTickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options); - - expect(refundedTickets).toBeDefined(); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should create one ticket for each unique ticketFk in the sales', async() => { - const tx = await models.Sale.beginTransaction({}); - const salesIds = [6, 7]; - - try { - const options = {transaction: tx}; - const ticketsBefore = await models.Ticket.find({}, options); - - const tickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options); - - const refundedTicket = await getTicketRefund(tickets[0].id, options); - const ticketsAfter = await models.Ticket.find({}, options); - const salesLength = refundedTicket.ticketSales().length; - const componentsLength = refundedTicket.ticketSales()[0].components().length; - - expect(refundedTicket).toBeDefined(); - expect(salesLength).toEqual(1); - expect(ticketsBefore.length).toEqual(ticketsAfter.length - 2); - expect(componentsLength).toEqual(4); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should create a ticket without sales', async() => { - const servicesIds = [4]; - const tx = await models.Sale.beginTransaction({}); - const options = {transaction: tx}; - try { - const tickets = await models.Sale.refund(ctx, null, servicesIds, withWarehouse, options); - const refundedTicket = await getTicketRefund(tickets[0].id, options); - - expect(refundedTicket).toBeDefined(); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); -}); - -async function getTicketRefund(id, options) { - return models.Ticket.findOne({ - where: { - id - }, - include: [ - { - relation: 'ticketSales', - scope: { - include: { - relation: 'components' - } - } - }, - { - relation: 'ticketServices', - } - ] - }, options); -} diff --git a/modules/ticket/back/methods/ticket/refund.js b/modules/ticket/back/methods/ticket/refund.js index 4fed02260..b07995453 100644 --- a/modules/ticket/back/methods/ticket/refund.js +++ b/modules/ticket/back/methods/ticket/refund.js @@ -45,7 +45,7 @@ module.exports = Self => { const services = await models.TicketService.find(filter, myOptions); const servicesIds = services.map(service => service.id); - const refundedTickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, myOptions); + const refundedTickets = await models.Sale.clone(ctx, salesIds, servicesIds, withWarehouse, true, myOptions); if (tx) await tx.commit(); diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js index dd092573d..30fb74b75 100644 --- a/modules/ticket/back/models/sale.js +++ b/modules/ticket/back/models/sale.js @@ -9,7 +9,6 @@ module.exports = Self => { require('../methods/sale/updateQuantity')(Self); require('../methods/sale/updateConcept')(Self); require('../methods/sale/recalculatePrice')(Self); - require('../methods/sale/refund')(Self); require('../methods/sale/canEdit')(Self); require('../methods/sale/usesMana')(Self); require('../methods/sale/clone')(Self); From 4fc780967f17256d49ea0cf5724219bb4dfc7f08 Mon Sep 17 00:00:00 2001 From: jorgep Date: Fri, 26 Jan 2024 15:32:50 +0100 Subject: [PATCH 2/7] fix: refs #6703 tests --- db/changes/240601/00-cloneAcl.sql | 4 ++++ modules/ticket/back/methods/sale/clone.js | 4 ++-- modules/ticket/back/methods/ticket/refund.js | 2 +- modules/ticket/front/sale/index.js | 2 +- modules/ticket/front/sale/index.spec.js | 2 +- modules/ticket/front/services/index.js | 2 +- 6 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 db/changes/240601/00-cloneAcl.sql diff --git a/db/changes/240601/00-cloneAcl.sql b/db/changes/240601/00-cloneAcl.sql new file mode 100644 index 000000000..bc6e22ee0 --- /dev/null +++ b/db/changes/240601/00-cloneAcl.sql @@ -0,0 +1,4 @@ +UPDATE salix.ACL + SET property='clone' + WHERE model = 'Sale' + AND property = 'refund' \ No newline at end of file diff --git a/modules/ticket/back/methods/sale/clone.js b/modules/ticket/back/methods/sale/clone.js index 8397499f7..77c40d8a0 100644 --- a/modules/ticket/back/methods/sale/clone.js +++ b/modules/ticket/back/methods/sale/clone.js @@ -23,8 +23,8 @@ module.exports = Self => { root: true }, http: { - path: `/refund`, - verb: 'post' + path: `/clone`, + verb: 'POST' } }); Self.clone = async(ctx, salesIds, servicesIds, withWarehouse, negative, options) => { diff --git a/modules/ticket/back/methods/ticket/refund.js b/modules/ticket/back/methods/ticket/refund.js index b07995453..7365f34df 100644 --- a/modules/ticket/back/methods/ticket/refund.js +++ b/modules/ticket/back/methods/ticket/refund.js @@ -20,7 +20,7 @@ module.exports = Self => { }, http: { path: `/refund`, - verb: 'post' + verb: 'POST' } }); diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js index ed6d9b10a..ce6aad5ed 100644 --- a/modules/ticket/front/sale/index.js +++ b/modules/ticket/front/sale/index.js @@ -524,7 +524,7 @@ class Controller extends Section { const salesIds = sales.map(sale => sale.id); const params = {salesIds: salesIds, withWarehouse: withWarehouse}; - const query = 'Sales/refund'; + const query = 'Sales/clone'; this.$http.post(query, params).then(res => { const [refundTicket] = res.data; this.vnApp.showSuccess(this.$t('The following refund ticket have been created', { diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js index 36be32f52..6b1da108e 100644 --- a/modules/ticket/front/sale/index.spec.js +++ b/modules/ticket/front/sale/index.spec.js @@ -729,7 +729,7 @@ describe('Ticket', () => { salesIds: [1, 4], }; const refundTicket = {id: 99}; - $httpBackend.expect('POST', 'Sales/refund', params).respond(200, [refundTicket]); + $httpBackend.expect('POST', 'Sales/clone', params).respond(200, [refundTicket]); controller.createRefund(); $httpBackend.flush(); diff --git a/modules/ticket/front/services/index.js b/modules/ticket/front/services/index.js index d8c209ea4..08a76f9ba 100644 --- a/modules/ticket/front/services/index.js +++ b/modules/ticket/front/services/index.js @@ -56,7 +56,7 @@ class Controller extends Section { if (!this.checkeds.length) return; const params = {servicesIds: this.checkeds, withWarehouse: false}; - const query = 'Sales/refund'; + const query = 'Sales/clone'; this.$http.post(query, params).then(res => { const refundTicket = res.data; this.vnApp.showSuccess(this.$t('The following refund ticket have been created', { From 9b8c58ba7d4f95bcfc84b07f1ffd93f1753a6b9a Mon Sep 17 00:00:00 2001 From: carlossa Date: Mon, 29 Jan 2024 16:00:24 +0100 Subject: [PATCH 3/7] refs #6270 makeInvoice --- .../ticket/back/methods/ticket/makeInvoice.js | 9 ++++- modules/ticket/front/descriptor-menu/index.js | 40 ++++++++++--------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/modules/ticket/back/methods/ticket/makeInvoice.js b/modules/ticket/back/methods/ticket/makeInvoice.js index 83222a4ee..1fcbd4130 100644 --- a/modules/ticket/back/methods/ticket/makeInvoice.js +++ b/modules/ticket/back/methods/ticket/makeInvoice.js @@ -110,7 +110,14 @@ module.exports = function(Self) { if (tx) await tx.commit(); - return resultInvoice.id; + const notificationInfo = { + clientName: firstTicket.clientFk.name, + clientEmail: firstTicket.clientFk.email, + ticketId: resultInvoice.id, + url: ctx.req.headers.referer + }; + + return {invoiceId: resultInvoice.id, notificationInfo}; } catch (e) { if (tx) await tx.rollback(); throw e; diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js index cd819e623..4e33d2c43 100644 --- a/modules/ticket/front/descriptor-menu/index.js +++ b/modules/ticket/front/descriptor-menu/index.js @@ -248,26 +248,30 @@ class Controller extends Section { if (this.ticket.address.incotermsFk && !this.ticket.weight && !force) return this.$.withoutWeightConfirmation.show(); - const client = this.ticket.client; - if (client.hasElectronicInvoice) { - this.$http.post(`NotificationQueues`, { - notificationFk: 'invoice-electronic', - authorFk: client.id, - params: JSON.stringify( - { - 'name': client.name, - 'email': client.email, - 'ticketId': this.id, - 'url': window.location.href - }) - }).then(() => { - this.vnApp.showSuccess(this.$t('Invoice sent')); - }); - } - return this.$http.post(`Tickets/invoiceTickets`, {ticketsIds: [this.id]}) .then(() => this.reload()) - .then(() => this.vnApp.showSuccess(this.$t('Ticket invoiced'))); + .then(() => { + const client = this.ticket.client; + + if (client.hasElectronicInvoice) { + const notificationData = { + name: client.name, + email: client.email, + ticketId: this.id, + url: window.location.href + }; + + this.$http.post(`NotificationQueues`, { + notificationFk: 'invoice-electronic', + authorFk: client.id, + params: JSON.stringify(notificationData) + }).then(() => { + this.vnApp.showSuccess(this.$t('Invoice sent')); + }); + } + + this.vnApp.showSuccess(this.$t('Ticket invoiced')); + }); } createPdfInvoice() { From 509d5cea14c8912dde579cf1f663ef77687016f4 Mon Sep 17 00:00:00 2001 From: carlossa Date: Tue, 30 Jan 2024 15:54:03 +0100 Subject: [PATCH 4/7] refs #6270 fix back --- .../ticket/back/methods/ticket/makeInvoice.js | 26 +++++++++++++------ modules/ticket/front/descriptor-menu/index.js | 23 +--------------- .../invoice-electronic/invoice-electronic.js | 2 +- 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/modules/ticket/back/methods/ticket/makeInvoice.js b/modules/ticket/back/methods/ticket/makeInvoice.js index 1fcbd4130..706da6f39 100644 --- a/modules/ticket/back/methods/ticket/makeInvoice.js +++ b/modules/ticket/back/methods/ticket/makeInvoice.js @@ -108,16 +108,26 @@ module.exports = function(Self) { await Self.rawSql('CALL invoiceOutBooking(?)', [resultInvoice.id], myOptions); + const client = await models.Client.findById(clientId, + {fields: ['hasElectronicInvoice', 'name', 'email']}, myOptions); + if (client.hasElectronicInvoice) { + const url = await models.Url.getUrl(); + await models.NotificationQueue.create({ + notificationFk: 'invoice-electronic', + authorFk: client.id, + params: JSON.stringify( + { + 'name': client.name, + 'email': client.email, + 'ticketId': ticketsIds.join(','), + 'url': url + 'ticket/index?q=' + encodeURIComponent(JSON.stringify({clientFk: clientId})) + }) + }, myOptions); + } + if (tx) await tx.commit(); - const notificationInfo = { - clientName: firstTicket.clientFk.name, - clientEmail: firstTicket.clientFk.email, - ticketId: resultInvoice.id, - url: ctx.req.headers.referer - }; - - return {invoiceId: resultInvoice.id, notificationInfo}; + return resultInvoice.id; } catch (e) { if (tx) await tx.rollback(); throw e; diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js index 4e33d2c43..c254900cc 100644 --- a/modules/ticket/front/descriptor-menu/index.js +++ b/modules/ticket/front/descriptor-menu/index.js @@ -250,28 +250,7 @@ class Controller extends Section { return this.$http.post(`Tickets/invoiceTickets`, {ticketsIds: [this.id]}) .then(() => this.reload()) - .then(() => { - const client = this.ticket.client; - - if (client.hasElectronicInvoice) { - const notificationData = { - name: client.name, - email: client.email, - ticketId: this.id, - url: window.location.href - }; - - this.$http.post(`NotificationQueues`, { - notificationFk: 'invoice-electronic', - authorFk: client.id, - params: JSON.stringify(notificationData) - }).then(() => { - this.vnApp.showSuccess(this.$t('Invoice sent')); - }); - } - - this.vnApp.showSuccess(this.$t('Ticket invoiced')); - }); + .then(() => this.vnApp.showSuccess(this.$t('Ticket invoiced'))); } createPdfInvoice() { diff --git a/print/templates/email/invoice-electronic/invoice-electronic.js b/print/templates/email/invoice-electronic/invoice-electronic.js index 2e1e739ac..1ec6d1374 100644 --- a/print/templates/email/invoice-electronic/invoice-electronic.js +++ b/print/templates/email/invoice-electronic/invoice-electronic.js @@ -10,7 +10,7 @@ module.exports = { required: true }, ticketId: { - type: [Number], + type: [String], required: true }, url: { From a6ea4ed0485db8d5257bfe07e5c493294379d05d Mon Sep 17 00:00:00 2001 From: carlossa Date: Tue, 30 Jan 2024 16:42:11 +0100 Subject: [PATCH 5/7] Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 6270-electronicInvoiceBack --- loopback/locale/en.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 568916bef..059da6356 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -203,5 +203,7 @@ "Cannot past travels with entries": "Cannot past travels with entries", "It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}", "Incorrect pin": "Incorrect pin.", - "The notification subscription of this worker cant be modified": "The notification subscription of this worker cant be modified" + "The notification subscription of this worker cant be modified": "The notification subscription of this worker cant be modified", + "Fecha fuera de rango": "Fecha fuera de rango", + "There is no zone for these parameters 34": "There is no zone for these parameters 34" } \ No newline at end of file From c136395d1e65edf1bd81c5cff5e570c961e539da Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 31 Jan 2024 09:16:38 +0100 Subject: [PATCH 6/7] fix: refs #6703 fix conflicts --- .../{10832-purpleAralia => 10856-greenAralia}/00-cloneAcl.sql | 0 modules/ticket/front/sale/index.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename db/versions/{10832-purpleAralia => 10856-greenAralia}/00-cloneAcl.sql (100%) diff --git a/db/versions/10832-purpleAralia/00-cloneAcl.sql b/db/versions/10856-greenAralia/00-cloneAcl.sql similarity index 100% rename from db/versions/10832-purpleAralia/00-cloneAcl.sql rename to db/versions/10856-greenAralia/00-cloneAcl.sql diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js index ce6aad5ed..f295efae9 100644 --- a/modules/ticket/front/sale/index.js +++ b/modules/ticket/front/sale/index.js @@ -523,7 +523,7 @@ class Controller extends Section { if (!sales) return; const salesIds = sales.map(sale => sale.id); - const params = {salesIds: salesIds, withWarehouse: withWarehouse}; + const params = {salesIds: salesIds, withWarehouse: withWarehouse,}; const query = 'Sales/clone'; this.$http.post(query, params).then(res => { const [refundTicket] = res.data; From e6eac5470934f90ee7ba2055e1969a33336db98d Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 31 Jan 2024 09:59:32 +0100 Subject: [PATCH 7/7] fix: refs #6703 tests & front --- .../back/methods/sale/specs/clone.spec.js | 38 +++++++++++++++++++ modules/ticket/front/sale/index.js | 2 +- modules/ticket/front/sale/index.spec.js | 1 + modules/ticket/front/services/index.js | 4 +- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/modules/ticket/back/methods/sale/specs/clone.spec.js b/modules/ticket/back/methods/sale/specs/clone.spec.js index 26506485a..f52f7ba38 100644 --- a/modules/ticket/back/methods/sale/specs/clone.spec.js +++ b/modules/ticket/back/methods/sale/specs/clone.spec.js @@ -67,4 +67,42 @@ describe('Ticket cloning - clone function', () => { expect(services.length).toBeGreaterThan(0); } }); + + it('should create a ticket without sales', async() => { + const servicesIds = [4]; + const tx = await models.Sale.beginTransaction({}); + const options = {transaction: tx}; + try { + const tickets = await models.Sale.clone(ctx, null, servicesIds, false, options); + const refundedTicket = await getTicketRefund(tickets[0].id, options); + + expect(refundedTicket).toBeDefined(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); }); + +async function getTicketRefund(id, options) { + return models.Ticket.findOne({ + where: { + id + }, + include: [ + { + relation: 'ticketSales', + scope: { + include: { + relation: 'components' + } + } + }, + { + relation: 'ticketServices', + } + ] + }, options); +} diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js index f295efae9..1cd5560a4 100644 --- a/modules/ticket/front/sale/index.js +++ b/modules/ticket/front/sale/index.js @@ -523,7 +523,7 @@ class Controller extends Section { if (!sales) return; const salesIds = sales.map(sale => sale.id); - const params = {salesIds: salesIds, withWarehouse: withWarehouse,}; + const params = {salesIds: salesIds, withWarehouse: withWarehouse, negative: true}; const query = 'Sales/clone'; this.$http.post(query, params).then(res => { const [refundTicket] = res.data; diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js index 6b1da108e..fb1c925d4 100644 --- a/modules/ticket/front/sale/index.spec.js +++ b/modules/ticket/front/sale/index.spec.js @@ -727,6 +727,7 @@ describe('Ticket', () => { jest.spyOn(controller.$state, 'go'); const params = { salesIds: [1, 4], + negative: true }; const refundTicket = {id: 99}; $httpBackend.expect('POST', 'Sales/clone', params).respond(200, [refundTicket]); diff --git a/modules/ticket/front/services/index.js b/modules/ticket/front/services/index.js index 08a76f9ba..fadf2ad4f 100644 --- a/modules/ticket/front/services/index.js +++ b/modules/ticket/front/services/index.js @@ -55,10 +55,10 @@ class Controller extends Section { createRefund() { if (!this.checkeds.length) return; - const params = {servicesIds: this.checkeds, withWarehouse: false}; + const params = {servicesIds: this.checkeds, withWarehouse: false, negative: true}; const query = 'Sales/clone'; this.$http.post(query, params).then(res => { - const refundTicket = res.data; + const [refundTicket] = res.data; this.vnApp.showSuccess(this.$t('The following refund ticket have been created', { ticketId: refundTicket.id }));