From 340348a38e4b91d22c4c2e8708a0f6e5830a4701 Mon Sep 17 00:00:00 2001 From: jgallego Date: Tue, 20 Aug 2024 10:11:42 +0200 Subject: [PATCH] feat: refs #7346 backTest checks new implementation --- db/routines/vn/functions/invoiceSerial.sql | 4 +- .../back/methods/invoiceOut/invoiceClient.js | 8 +- .../invoiceOut/specs/clientsToInvoice.spec.js | 75 +++++++++++++++++ .../invoiceOut/specs/invoiceClient.spec.js | 80 ++++++++++++++++--- 4 files changed, 151 insertions(+), 16 deletions(-) create mode 100644 modules/invoiceOut/back/methods/invoiceOut/specs/clientsToInvoice.spec.js diff --git a/db/routines/vn/functions/invoiceSerial.sql b/db/routines/vn/functions/invoiceSerial.sql index 0269275b1d..9df887cf57 100644 --- a/db/routines/vn/functions/invoiceSerial.sql +++ b/db/routines/vn/functions/invoiceSerial.sql @@ -1,10 +1,10 @@ DELIMITER $$ CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn`.`invoiceSerial`(vClientFk INT, vCompanyFk INT, vType CHAR(15)) - RETURNS char(1) CHARSET utf8mb3 COLLATE utf8mb3_general_ci + RETURNS char(2) CHARSET utf8mb3 COLLATE utf8mb3_general_ci DETERMINISTIC BEGIN /** - * Obtiene la serie de de una factura + * Obtiene la serie de una factura * dependiendo del area del cliente. * * @param vClientFk Id del cliente diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js index ef8a26efce..2c44cef34f 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js @@ -31,7 +31,7 @@ module.exports = Self => { }, { arg: 'serialType', type: 'string', - description: 'Type of serial', + description: 'Invoice serial number type (see vn.invoiceOutSerial.type enum)', required: true } ], @@ -44,12 +44,10 @@ module.exports = Self => { verb: 'POST' } }); - Self.invoiceClient = async(ctx, options) => { const args = ctx.args; const models = Self.app.models; - options = typeof options == 'object' - ? Object.assign({}, options) : {}; + options = typeof options === 'object' ? {...options} : {}; options.userId = ctx.req.accessToken.userId; let tx; @@ -81,7 +79,7 @@ module.exports = Self => { const invoiceId = await models.Ticket.makeInvoice( ctx, - serialType, + args.serialType, args.companyFk, args.invoiceDate, null, diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/clientsToInvoice.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/clientsToInvoice.spec.js new file mode 100644 index 0000000000..470690c5a4 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/clientsToInvoice.spec.js @@ -0,0 +1,75 @@ +const models = require('vn-loopback/server/server').models; + +describe('InvoiceOut clientsToInvoice()', () => { + const userId = 1; + const clientId = 1101; + const companyFk = 442; + const maxShipped = new Date(); + maxShipped.setMonth(11); + maxShipped.setDate(31); + maxShipped.setHours(23, 59, 59, 999); + const invoiceDate = new Date(); + const activeCtx = { + getLocale: () => { + return 'en'; + }, + accessToken: {userId: userId}, + __: value => { + return value; + }, + headers: {origin: 'http://localhost'} + }; + const ctx = {req: activeCtx}; + + it('should return a list of clients to invoice', async() => { + spyOn(models.InvoiceOut, 'rawSql').and.callFake(query => { + if (query.includes('ticketPackaging_add')) + return Promise.resolve(true); + else if (query.includes('SELECT c.id clientId')) { + return Promise.resolve([ + { + clientId: clientId, + clientName: 'Test Client', + id: 1, + nickname: 'Address 1' + } + ]); + } + }); + + const tx = await models.InvoiceOut.beginTransaction({}); + const options = {transaction: tx}; + + try { + const addresses = await models.InvoiceOut.clientsToInvoice( + ctx, clientId, invoiceDate, maxShipped, companyFk, options); + + expect(addresses.length).toBeGreaterThan(0); + expect(addresses[0].clientId).toBe(clientId); + expect(addresses[0].clientName).toBe('Test Client'); + expect(addresses[0].id).toBe(1); + expect(addresses[0].nickname).toBe('Address 1'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should handle errors and rollback transaction', async() => { + spyOn(models.InvoiceOut, 'rawSql').and.callFake(() => { + return Promise.reject(new Error('Test Error')); + }); + + const tx = await models.InvoiceOut.beginTransaction({}); + const options = {transaction: tx}; + + try { + await models.InvoiceOut.clientsToInvoice(ctx, clientId, invoiceDate, maxShipped, companyFk, options); + } catch (e) { + expect(e.message).toBe('Test Error'); + await tx.rollback(); + } + }); +}); diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js index 0faa8fe1ab..cffae394f6 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js @@ -3,14 +3,13 @@ const models = require('vn-loopback/server/server').models; describe('InvoiceOut invoiceClient()', () => { const userId = 1; const clientId = 1101; - const addressId = 121; + const addressFk = 121; const companyFk = 442; const minShipped = Date.vnNew(); minShipped.setFullYear(minShipped.getFullYear() - 1); minShipped.setMonth(1); minShipped.setDate(1); minShipped.setHours(0, 0, 0, 0); - const invoiceSerial = 'A'; const activeCtx = { getLocale: () => { return 'en'; @@ -24,8 +23,8 @@ describe('InvoiceOut invoiceClient()', () => { }; const ctx = {req: activeCtx}; - it('should make a global invoicing', async() => { - spyOn(models.InvoiceOut, 'makePdf').and.returnValue(new Promise(resolve => resolve(true))); + it('should make a global invoicing by address and verify billing status', async() => { + spyOn(models.InvoiceOut, 'makePdf').and.returnValue(Promise.resolve(true)); spyOn(models.InvoiceOut, 'invoiceEmail'); const tx = await models.InvoiceOut.beginTransaction({}); @@ -34,20 +33,42 @@ describe('InvoiceOut invoiceClient()', () => { try { ctx.args = { clientId: clientId, - addressId: addressId, + addressId: addressFk, invoiceDate: Date.vnNew(), maxShipped: Date.vnNew(), companyFk: companyFk, - minShipped: minShipped + serialType: 'global' }; + const invoiceOutId = await models.InvoiceOut.invoiceClient(ctx, options); + const invoiceOut = await models.InvoiceOut.findById(invoiceOutId, null, options); - const [firstTicket] = await models.Ticket.find({ + + expect(invoiceOutId).toBeGreaterThan(0); + + const allClientTickets = await models.Ticket.find({ + where: { + clientFk: clientId, + or: [ + {refFk: null}, + {refFk: invoiceOut.ref} + ] + } + }, options); + + const billedTickets = await models.Ticket.find({ where: {refFk: invoiceOut.ref} }, options); - expect(invoiceOutId).toBeGreaterThan(0); - expect(firstTicket.refFk).toContain(invoiceSerial); + const allBilledTicketsHaveCorrectAddress = billedTickets.every(ticket => ticket.addressFk === addressFk); + + expect(allBilledTicketsHaveCorrectAddress).toBe(true); + + const addressTickets = allClientTickets.filter(ticket => ticket.addressFk === addressFk); + + const allAddressTicketsBilled = addressTickets.every(ticket => ticket.refFk === invoiceOut.ref); + + expect(allAddressTicketsBilled).toBe(true); await tx.rollback(); } catch (e) { @@ -55,4 +76,45 @@ describe('InvoiceOut invoiceClient()', () => { throw e; } }); + jasmine.DEFAULT_TIMEOUT_INTERVAL = 300000; + fit('should invoice all tickets regardless of address when hasToInvoiceByAddress is false', async() => { + spyOn(models.InvoiceOut, 'makePdf').and.returnValue(Promise.resolve(true)); + spyOn(models.InvoiceOut, 'invoiceEmail'); + + const tx = await models.InvoiceOut.beginTransaction({}); + const options = {transaction: tx}; + + try { + console.log('Searching for client with ID:', clientId); + const client = await models.Client.findById(clientId, options); + console.log('Found client:', JSON.stringify(client, null, 2)); + + if (!client) + throw new Error(`Client with id ${clientId} not found`); + + console.log('Client before update:', JSON.stringify(client, null, 2)); + console.log('Current hasToInvoiceByAddress value:', client.hasToInvoiceByAddress); + + try { + console.log('Attempting to update hasToInvoiceByAddress'); + await client.updateAttribute('hasToInvoiceByAddress', false, options); + console.log('Update successful'); + } catch (updateError) { + console.error('Error updating hasToInvoiceByAddress:', updateError); + console.error('Error stack:', updateError.stack); + throw updateError; + } + + console.log('Client after update:', JSON.stringify(client, null, 2)); + console.log('New hasToInvoiceByAddress value:', client.hasToInvoiceByAddress); + + console.log('Test completed successfully'); + await tx.rollback(); + } catch (e) { + console.error('Test failed:', e); + console.error('Error stack:', e.stack); + await tx.rollback(); + throw e; + } + }); });