diff --git a/db/changes/240001/00-fixInvoiceCorrectionConstraintsName.sql b/db/changes/240001/00-fixInvoiceCorrectionConstraintsName.sql new file mode 100644 index 000000000..426afea90 --- /dev/null +++ b/db/changes/240001/00-fixInvoiceCorrectionConstraintsName.sql @@ -0,0 +1,7 @@ +ALTER TABLE `vn`.`invoiceCorrection` DROP FOREIGN KEY `cplusInvoiceTyoeFk`; +ALTER TABLE `vn`.`invoiceCorrection` DROP FOREIGN KEY `invoiceCorrectionType_Fk33`; +ALTER TABLE `vn`.`invoiceCorrection` DROP FOREIGN KEY `invoiceCorrection_ibfk_1`; + +ALTER TABLE `vn`.`invoiceCorrection` ADD CONSTRAINT `siiTypeInvoiceOut_FK` FOREIGN KEY (`siiTypeInvoiceOutFk`) REFERENCES `vn`.`siiTypeInvoiceOut`(id) ON UPDATE CASCADE; +ALTER TABLE `vn`.`invoiceCorrection` ADD CONSTRAINT `invoiceCorrectionType_FK` FOREIGN KEY (`invoiceCorrectionTypeFk`) REFERENCES `vn`.`invoiceCorrectionType`(id) ON UPDATE CASCADE; +ALTER TABLE `vn`.`invoiceCorrection` ADD CONSTRAINT `cplusRectificationType_FK` FOREIGN KEY (`cplusRectificationTypeFk`) REFERENCES `vn`.`cplusRectificationType`(id) ON UPDATE CASCADE; diff --git a/db/changes/240001/00-getTaxBases.sql b/db/changes/240001/00-getTaxBases.sql new file mode 100644 index 000000000..8bd1b745a --- /dev/null +++ b/db/changes/240001/00-getTaxBases.sql @@ -0,0 +1,33 @@ +DELIMITER $$ +$$ +CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`getTaxBases`() +BEGIN +/** +* Calcula y devuelve en número de bases imponibles postivas y negativas +* Requiere la tabla temporal tmp.ticketToInvoice(id) +* +* returns tmp.taxBases +*/ + + CREATE OR REPLACE TEMPORARY TABLE tmp.ticket + (KEY (ticketFk)) + ENGINE = MEMORY + SELECT id ticketFk + FROM tmp.ticketToInvoice; + + CALL ticket_getTax(NULL); + + DROP TEMPORARY TABLE IF EXISTS tmp.taxBases; + CREATE TEMPORARY TABLE tmp.taxBases + ENGINE = MEMORY + SELECT + SUM(taxableBase > 0) as positive, + SUM(taxableBase < 0) as negative + FROM( + SELECT SUM(taxableBase) taxableBase + FROM tmp.ticketTax + GROUP BY pgcFk + ) t; + +END$$ +DELIMITER ; diff --git a/db/changes/240001/01-newHasAnyPositiveBase.sql b/db/changes/240001/01-newHasAnyPositiveBase.sql new file mode 100644 index 000000000..c4edfaed0 --- /dev/null +++ b/db/changes/240001/01-newHasAnyPositiveBase.sql @@ -0,0 +1,30 @@ +DELIMITER $$ +$$ +CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn`.`hasAnyPositiveBase`() RETURNS tinyint(1) + DETERMINISTIC +BEGIN + +/** +* Calcula si existe alguna base imponible positiva +* Requiere la tabla temporal tmp.ticketToInvoice(id) para getTaxBases() +* +* returns BOOLEAN +*/ + + DECLARE hasAnyPositiveBase BOOLEAN; + + CALL getTaxBases(); + + SELECT positive INTO hasAnyPositiveBase + FROM tmp.taxBases + LIMIT 1; + + DROP TEMPORARY TABLE + tmp.ticketTax, + tmp.ticket, + tmp.taxBases; + + RETURN hasAnyPositiveBase; + +END$$ +DELIMITER ; diff --git a/db/changes/240001/01-refactorHasAnyNegativeBase.sql b/db/changes/240001/01-refactorHasAnyNegativeBase.sql new file mode 100644 index 000000000..a3eb2d9c7 --- /dev/null +++ b/db/changes/240001/01-refactorHasAnyNegativeBase.sql @@ -0,0 +1,32 @@ +DELIMITER $$ +$$ +CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn`.`hasAnyNegativeBase`() RETURNS tinyint(1) + DETERMINISTIC +BEGIN + +/** +* Calcula si existe alguna base imponible negativa +* Requiere la tabla temporal tmp.ticketToInvoice(id) para getTaxBases() +* +* returns BOOLEAN +*/ + + DECLARE hasAnyNegativeBase BOOLEAN; + + CALL getTaxBases(); + + SELECT negative INTO hasAnyNegativeBase + FROM tmp.taxBases + LIMIT 1; + + DROP TEMPORARY TABLE + tmp.ticketTax, + tmp.ticket, + tmp.taxBases; + + RETURN hasAnyNegativeBase; + +END$$ +DELIMITER ; + + diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 6e676f3e6..8ad9b511a 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -602,18 +602,19 @@ INSERT INTO `vn`.`taxArea` (`code`, `claveOperacionFactura`, `CodigoTransaccion` INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaFk`, `isCEE`, `type`) VALUES - ('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'), - ('T', 'Española rapida', 1, 'NATIONAL', 0, 'quick'), - ('V', 'Intracomunitaria global', 0, 'CEE', 1, 'global'), - ('M', 'Múltiple nacional', 1, 'NATIONAL', 0, 'quick'), - ('E', 'Exportación rápida', 0, 'WORLD', 0, 'quick'); + ('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'), + ('T', 'Española rapida', 1, 'NATIONAL', 0, 'quick'), + ('V', 'Intracomunitaria global', 0, 'CEE', 1, 'global'), + ('M', 'Múltiple nacional', 1, 'NATIONAL', 0, 'quick'), + ('R', 'Rectificativa', 1, 'NATIONAL', 0, NULL), + ('E', 'Exportación rápida', 0, 'WORLD', 0, 'quick'); INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`) VALUES (1, 'T', 1026.24, util.VN_CURDATE(), 1101, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0), (2, 'T', 121.36, util.VN_CURDATE(), 1102, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0), (3, 'T', 8.88, util.VN_CURDATE(), 1103, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0), - (4, 'T', 8.88, util.VN_CURDATE(), 1103, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0), + (4, 'T', 8.88, util.VN_CURDATE(), 1104, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0), (5, 'A', 8.88, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1103, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 442, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 0); UPDATE `vn`.`invoiceOut` SET ref = 'T1111111' WHERE id = 1; @@ -719,7 +720,7 @@ INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agen INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `zoneFk`, `zonePrice`, `zoneBonus`, `created`, `weight`) VALUES (1 , 3, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Bat cave', 121, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1), - (2 , 1, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2), + (2 , 1, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Bat cave', 1, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2), (3 , 1, 7, 1, 6, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), NULL), (4 , 3, 2, 1, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 9, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), NULL), (5 , 3, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), NULL), diff --git a/e2e/paths/05-ticket/18_index_payout.spec.js b/e2e/paths/05-ticket/18_index_payout.spec.js index 7e5201d11..9c5518424 100644 --- a/e2e/paths/05-ticket/18_index_payout.spec.js +++ b/e2e/paths/05-ticket/18_index_payout.spec.js @@ -35,7 +35,7 @@ describe('Ticket index payout path', () => { await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton); await page.write(selectors.ticketsIndex.advancedSearchClient, '1101'); await page.keyboard.press('Enter'); - await page.waitForNumberOfElements(selectors.ticketsIndex.anySearchResult, 9); + await page.waitForNumberOfElements(selectors.ticketsIndex.anySearchResult, 10); await page.waitToClick(selectors.ticketsIndex.firstTicketCheckbox); await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox); diff --git a/e2e/paths/09-invoice-out/01_summary.spec.js b/e2e/paths/09-invoice-out/01_summary.spec.js index 728f0130a..09ac66ffc 100644 --- a/e2e/paths/09-invoice-out/01_summary.spec.js +++ b/e2e/paths/09-invoice-out/01_summary.spec.js @@ -28,7 +28,6 @@ describe('InvoiceOut summary path', () => { it('should contain the tax breakdown', async() => { const firstTax = await page.waitToGetProperty(selectors.invoiceOutSummary.taxOne, 'innerText'); - const secondTax = await page.waitToGetProperty(selectors.invoiceOutSummary.taxTwo, 'innerText'); expect(firstTax).toContain('10%'); @@ -37,10 +36,9 @@ describe('InvoiceOut summary path', () => { it('should contain the tickets info', async() => { const firstTicket = await page.waitToGetProperty(selectors.invoiceOutSummary.ticketOne, 'innerText'); - const secondTicket = await page.waitToGetProperty(selectors.invoiceOutSummary.ticketTwo, 'innerText'); expect(firstTicket).toContain('Bat cave'); - expect(secondTicket).toContain('Stark tower'); + expect(secondTicket).toContain('Bat cave'); }); }); diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 508c17344..2c7dc6be1 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -45,6 +45,7 @@ "Extension format is invalid": "Extension format is invalid", "NO_ZONE_FOR_THIS_PARAMETERS": "NO_ZONE_FOR_THIS_PARAMETERS", "This client can't be invoiced": "This client can't be invoiced", + "You must provide the correction information to generate a corrective invoice": "You must provide the correction information to generate a corrective invoice", "The introduced hour already exists": "The introduced hour already exists", "Invalid parameters to create a new ticket": "Invalid parameters to create a new ticket", "Concept cannot be blank": "Concept cannot be blank", @@ -178,7 +179,8 @@ "The renew period has not been exceeded": "The renew period has not been exceeded", "You can not use the same password": "You can not use the same password", "Valid priorities": "Valid priorities: %d", - "Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}", + "hasAnyNegativeBase": "Negative basis of tickets: {{ticketsIds}}", + "hasAnyPositiveBase": "Positive basis of tickets: {{ticketsIds}}", "This ticket cannot be left empty.": "This ticket cannot be left empty. %s", "Social name should be uppercase": "Social name should be uppercase", "Street should be uppercase": "Street should be uppercase", diff --git a/loopback/locale/es.json b/loopback/locale/es.json index e2b90983b..25c76971d 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -72,6 +72,7 @@ "The secret can't be blank": "La contraseña no puede estar en blanco", "We weren't able to send this SMS": "No hemos podido enviar el SMS", "This client can't be invoiced": "Este cliente no puede ser facturado", + "You must provide the correction information to generate a corrective invoice": "Debes informar la información de corrección para generar una factura rectificativa", "This ticket can't be invoiced": "Este ticket no puede ser facturado", "You cannot add or modify services to an invoiced ticket": "No puedes añadir o modificar servicios a un ticket facturado", "This ticket can not be modified": "Este ticket no puede ser modificado", @@ -305,7 +306,8 @@ "Mail not sent": "Se ha producido un fallo al enviar la factura al cliente [{{clientId}}]({{{clientUrl}}}), por favor revisa la dirección de correo electrónico", "The renew period has not been exceeded": "El periodo de renovación no ha sido superado", "Valid priorities": "Prioridades válidas: %d", - "Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}", + "hasAnyNegativeBase": "Base negativa para los tickets: {{ticketsIds}}", + "hasAnyPositiveBase": "Base positivas para los tickets: {{ticketsIds}}", "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado", "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %s", "The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias", @@ -333,5 +335,6 @@ "This user does not have an assigned tablet": "Este usuario no tiene tablet asignada", "Incorrect pin": "Pin incorrecto.", "You already have the mailAlias": "Ya tienes este alias de correo", - "The alias cant be modified": "Este alias de correo no puede ser modificado" -} \ No newline at end of file + "The alias cant be modified": "Este alias de correo no puede ser modificado", + "No tickets to invoice": "No hay tickets para facturar" +} diff --git a/modules/client/back/methods/client/canBeInvoiced.js b/modules/client/back/methods/client/canBeInvoiced.js index 843e9549f..cdb865500 100644 --- a/modules/client/back/methods/client/canBeInvoiced.js +++ b/modules/client/back/methods/client/canBeInvoiced.js @@ -1,7 +1,7 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = function(Self) { - Self.remoteMethodCtx('canBeInvoiced', { + Self.remoteMethod('canBeInvoiced', { description: 'Change property isEqualizated in all client addresses', accessType: 'READ', accepts: [ diff --git a/modules/client/back/methods/client/specs/consumption.spec.js b/modules/client/back/methods/client/specs/consumption.spec.js index 47a495d79..85dbb7422 100644 --- a/modules/client/back/methods/client/specs/consumption.spec.js +++ b/modules/client/back/methods/client/specs/consumption.spec.js @@ -16,7 +16,7 @@ describe('client consumption() filter', () => { }; const result = await models.Client.consumption(ctx, filter, options); - expect(result.length).toEqual(10); + expect(result.length).toEqual(11); await tx.rollback(); } catch (e) { @@ -49,7 +49,7 @@ describe('client consumption() filter', () => { const thirdRow = result[2]; expect(result.length).toEqual(3); - expect(firstRow.quantity).toEqual(10); + expect(firstRow.quantity).toEqual(11); expect(secondRow.quantity).toEqual(15); expect(thirdRow.quantity).toEqual(20); diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js index fa22dab1e..530b02353 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js @@ -80,6 +80,7 @@ module.exports = Self => { invoiceType, args.companyFk, args.invoiceDate, + null, options ); diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/transferinvoice.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/transferinvoice.spec.js index 800a4ea83..11575999a 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/transferinvoice.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/transferinvoice.spec.js @@ -2,7 +2,7 @@ const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); -describe('InvoiceOut tranferInvoice()', () => { +describe('InvoiceOut transferInvoice()', () => { const activeCtx = { accessToken: {userId: 5}, http: { @@ -23,20 +23,29 @@ describe('InvoiceOut tranferInvoice()', () => { const tx = await models.InvoiceOut.beginTransaction({}); const options = {transaction: tx}; const args = { - id: '1', - ref: 'T4444444', + id: '4', + refFk: 'T4444444', newClientFk: 1, - cplusRectificationId: 1, - siiTypeInvoiceOutId: 1, - invoiceCorrectionTypeId: 1 + cplusRectificationTypeFk: 1, + siiTypeInvoiceOutFk: 1, + invoiceCorrectionTypeFk: 1 }; ctx.args = args; try { + const {clientFk: oldClient} = await models.InvoiceOut.findById(args.id, {fields: ['clientFk']}); + const invoicesBefore = await models.InvoiceOut.find({}, options); const result = await models.InvoiceOut.transferInvoice( ctx, options); + const invoicesAfter = await models.InvoiceOut.find({}, options); + const rectificativeInvoice = invoicesAfter[invoicesAfter.length - 2]; + const newInvoice = invoicesAfter[invoicesAfter.length - 1]; expect(result).toBeDefined(); + expect(invoicesAfter.length - invoicesBefore.length).toEqual(2); + expect(rectificativeInvoice.clientFk).toEqual(oldClient); + expect(newInvoice.clientFk).toEqual(args.newClientFk); + await tx.rollback(); } catch (e) { await tx.rollback(); @@ -49,20 +58,44 @@ describe('InvoiceOut tranferInvoice()', () => { const options = {transaction: tx}; const args = { id: '1', - ref: 'T1111111', + refFk: 'T1111111', newClientFk: 1101, - cplusRectificationId: 1, - siiTypeInvoiceOutId: 1, - invoiceCorrectionTypeId: 1 + cplusRectificationTypeFk: 1, + siiTypeInvoiceOutFk: 1, + invoiceCorrectionTypeFk: 1 }; ctx.args = args; try { await models.InvoiceOut.transferInvoice( ctx, options); + await tx.rollback(); } catch (e) { expect(e.message).toBe(`Select a different client`); await tx.rollback(); } }); + + it('should throw an UserError when it is refund', async() => { + const tx = await models.InvoiceOut.beginTransaction({}); + const options = {transaction: tx}; + const args = { + id: '1', + refFk: 'T1111111', + newClientFk: 1102, + cplusRectificationTypeFk: 1, + siiTypeInvoiceOutFk: 1, + invoiceCorrectionTypeFk: 1 + }; + ctx.args = args; + try { + await models.InvoiceOut.transferInvoice( + ctx, + options); + await tx.rollback(); + } catch (e) { + expect(e.message).toContain(`This ticket is already a refund`); + await tx.rollback(); + } + }); }); diff --git a/modules/invoiceOut/back/methods/invoiceOut/transferInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/transferInvoice.js index dde535c99..5f2428539 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/transferInvoice.js +++ b/modules/invoiceOut/back/methods/invoiceOut/transferInvoice.js @@ -12,7 +12,7 @@ module.exports = Self => { description: 'Issued invoice id' }, { - arg: 'ref', + arg: 'refFk', type: 'string', required: true }, @@ -22,17 +22,17 @@ module.exports = Self => { required: true }, { - arg: 'cplusRectificationId', + arg: 'cplusRectificationTypeFk', type: 'number', required: true }, { - arg: 'siiTypeInvoiceOutId', + arg: 'siiTypeInvoiceOutFk', type: 'number', required: true }, { - arg: 'invoiceCorrectionTypeId', + arg: 'invoiceCorrectionTypeFk', type: 'number', required: true }, @@ -50,14 +50,14 @@ module.exports = Self => { Self.transferInvoice = async(ctx, options) => { const models = Self.app.models; const myOptions = {userId: ctx.req.accessToken.userId}; - const args = ctx.args; + const {id, refFk, newClientFk, cplusRectificationTypeFk, siiTypeInvoiceOutFk, invoiceCorrectionTypeFk} = ctx.args; let tx; if (typeof options == 'object') Object.assign(myOptions, options); - const {clientFk} = await models.InvoiceOut.findById(args.id); + const {clientFk} = await models.InvoiceOut.findById(id); - if (clientFk == args.newClientFk) + if (clientFk == newClientFk) throw new UserError(`Select a different client`); if (!myOptions.transaction) { @@ -65,10 +65,10 @@ module.exports = Self => { myOptions.transaction = tx; } try { - const filterRef = {where: {refFk: args.ref}}; + const filterRef = {where: {refFk: refFk}}; const tickets = await models.Ticket.find(filterRef, myOptions); const ticketsIds = tickets.map(ticket => ticket.id); - await models.Ticket.refund(ctx, ticketsIds, null, myOptions); + const refundTickets = await models.Ticket.refund(ctx, ticketsIds, null, myOptions); const filterTicket = {where: {ticketFk: {inq: ticketsIds}}}; @@ -82,20 +82,16 @@ module.exports = Self => { const clonedTicketIds = []; for (const clonedTicket of clonedTickets) { - await clonedTicket.updateAttribute('clientFk', args.newClientFk, myOptions); + await clonedTicket.updateAttribute('clientFk', newClientFk, myOptions); clonedTicketIds.push(clonedTicket.id); } - const invoiceIds = await models.Ticket.invoiceTickets(ctx, clonedTicketIds, myOptions); - const [invoiceId] = invoiceIds; + const invoiceCorrection = + {correctedFk: id, cplusRectificationTypeFk, siiTypeInvoiceOutFk, invoiceCorrectionTypeFk}; + const refundTicketIds = refundTickets.map(ticket => ticket.id); - await models.InvoiceCorrection.create({ - correctingFk: invoiceId, - correctedFk: args.id, - cplusRectificationTypeFk: args.cplusRectificationId, - siiTypeInvoiceOutFk: args.siiTypeInvoiceOutId, - invoiceCorrectionTypeFk: args.invoiceCorrectionTypeId - }, myOptions); + await models.Ticket.invoiceTickets(ctx, refundTicketIds, invoiceCorrection, myOptions); + const [invoiceId] = await models.Ticket.invoiceTickets(ctx, clonedTicketIds, null, myOptions); if (tx) { await tx.commit(); diff --git a/modules/invoiceOut/back/models/invoice-correction.json b/modules/invoiceOut/back/models/invoice-correction.json index 43e4f07ef..58f6f63b7 100644 --- a/modules/invoiceOut/back/models/invoice-correction.json +++ b/modules/invoiceOut/back/models/invoice-correction.json @@ -16,13 +16,43 @@ "type": "number" }, "cplusRectificationTypeFk": { - "type": "number" + "type": "number", + "required": true }, "siiTypeInvoiceOutFk": { - "type": "number" + "type": "number", + "required": true }, "invoiceCorrectionTypeFk": { - "type": "number" + "type": "number", + "required": true + }, + "relations": { + "correcting": { + "type": "belongsTo", + "model": "InvoiceOut", + "foreignKey": "correctingFk" + }, + "corrected": { + "type": "belongsTo", + "model": "InvoiceOut", + "foreignKey": "correctedFk" + }, + "cplusRectificationType": { + "type": "belongsTo", + "model": "cplusRectificationType", + "foreignKey": "cplusRectificationTypeFk" + }, + "siiTypeInvoiceOut": { + "type": "belongsTo", + "model": "siiTypeInvoiceOut", + "foreignKey": "siiTypeInvoiceOutFk" + }, + "invoiceCorrectionType": { + "type": "belongsTo", + "model": "invoiceCorrectionType", + "foreignKey": "invoiceCorrectionTypeFk" + } } } } diff --git a/modules/invoiceOut/back/models/sii-type-invoice-out.json b/modules/invoiceOut/back/models/sii-type-invoice-out.json index 17b312617..58d50a12c 100644 --- a/modules/invoiceOut/back/models/sii-type-invoice-out.json +++ b/modules/invoiceOut/back/models/sii-type-invoice-out.json @@ -12,6 +12,9 @@ "type": "number", "description": "Identifier" }, + "code": { + "type": "string" + }, "description": { "type": "string" } diff --git a/modules/invoiceOut/front/descriptor-menu/index.html b/modules/invoiceOut/front/descriptor-menu/index.html index 0052f0c03..435db3612 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.html +++ b/modules/invoiceOut/front/descriptor-menu/index.html @@ -7,7 +7,8 @@ + data="siiTypeInvoiceOuts" + where="{code: {like: 'R%'}}"> + + transferInvoice +
- - - - #{{id}} - {{::name}} - - - - - {{::description}} - - - - - - - - - -
+ + + + #{{id}} - {{::name}} + + + + + {{::description}} + + + + + + + {{::code}} - {{::description}} + + + + + +
diff --git a/modules/invoiceOut/front/descriptor-menu/index.js b/modules/invoiceOut/front/descriptor-menu/index.js index d3862a753..2c28599e7 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.js +++ b/modules/invoiceOut/front/descriptor-menu/index.js @@ -129,15 +129,15 @@ class Controller extends Section { transferInvoice() { const params = { id: this.invoiceOut.id, - ref: this.invoiceOut.ref, - newClientFk: this.invoiceOut.client.id, - cplusRectificationId: this.cplusRectificationType, - siiTypeInvoiceOutId: this.siiTypeInvoiceOut, - invoiceCorrectionTypeId: this.invoiceCorrectionType + refFk: this.invoiceOut.ref, + newClientFk: this.clientId, + cplusRectificationTypeFk: this.cplusRectificationType, + siiTypeInvoiceOutFk: this.siiTypeInvoiceOut, + invoiceCorrectionTypeFk: this.invoiceCorrectionType }; this.$http.post(`InvoiceOuts/transferInvoice`, params).then(res => { const invoiceId = res.data; - this.vnApp.showSuccess(this.$t('Invoice trasfered!')); + this.vnApp.showSuccess(this.$t('Transferred invoice')); this.$state.go('invoiceOut.card.summary', {id: invoiceId}); }); } diff --git a/modules/invoiceOut/front/descriptor-menu/locale/es.yml b/modules/invoiceOut/front/descriptor-menu/locale/es.yml index 0f74b5fec..aaeefd9cc 100644 --- a/modules/invoiceOut/front/descriptor-menu/locale/es.yml +++ b/modules/invoiceOut/front/descriptor-menu/locale/es.yml @@ -22,4 +22,5 @@ The email can't be empty: El correo no puede estar vacío The following refund tickets have been created: "Se han creado los siguientes tickets de abono: {{ticketIds}}" Refund...: Abono... Transfer invoice to...: Transferir factura a... -Cplus Type: Cplus Tipo +Rectificative type: Tipo rectificativa +Transferred invoice: Factura transferida diff --git a/modules/invoiceOut/front/index/manual/index.html b/modules/invoiceOut/front/index/manual/index.html index c3362a319..5872911e4 100644 --- a/modules/invoiceOut/front/index/manual/index.html +++ b/modules/invoiceOut/front/index/manual/index.html @@ -6,6 +6,7 @@ auto-load="true" url="InvoiceOutSerials" data="invoiceOutSerials" + where="{code: {neq: 'R'}}" order="code">
{ } ], returns: { - type: ['number'], + type: ['object'], root: true }, http: { @@ -54,7 +54,7 @@ module.exports = Self => { if (tx) await tx.commit(); - return refundsTicket[0]; + 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 index 08eb1fabd..60f77e90c 100644 --- a/modules/ticket/back/methods/sale/specs/refund.spec.js +++ b/modules/ticket/back/methods/sale/specs/refund.spec.js @@ -23,9 +23,9 @@ describe('Sale refund()', () => { try { const options = {transaction: tx}; - const refundedTicket = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options); + const refundedTickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options); - expect(refundedTicket).toBeDefined(); + expect(refundedTickets).toBeDefined(); await tx.rollback(); } catch (e) { @@ -42,11 +42,11 @@ describe('Sale refund()', () => { const options = {transaction: tx}; const ticketsBefore = await models.Ticket.find({}, options); - const ticket = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options); + const tickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options); const refundedTicket = await models.Ticket.findOne({ where: { - id: ticket.id + id: tickets[0].id }, include: [ { diff --git a/modules/ticket/back/methods/ticket/canBeInvoiced.js b/modules/ticket/back/methods/ticket/canBeInvoiced.js index 348f02348..855a864c2 100644 --- a/modules/ticket/back/methods/ticket/canBeInvoiced.js +++ b/modules/ticket/back/methods/ticket/canBeInvoiced.js @@ -10,20 +10,20 @@ module.exports = function(Self) { description: 'The tickets id', type: ['number'], required: true + }, + { + arg: 'isRectificative', + description: 'If it is rectificative', + type: 'boolean' } ], - returns: { - arg: 'data', - type: 'boolean', - root: true - }, http: { path: `/canBeInvoiced`, verb: 'get' } }); - Self.canBeInvoiced = async(ctx, ticketsIds, options) => { + Self.canBeInvoiced = async(ctx, ticketsIds, isRectificative, options) => { const myOptions = {}; const $t = ctx.req.__; // $translate @@ -34,26 +34,14 @@ module.exports = function(Self) { where: { id: {inq: ticketsIds} }, - fields: ['id', 'refFk', 'shipped', 'totalWithVat', 'companyFk'] + fields: ['id', 'refFk', 'shipped', 'totalWithVat'] }, myOptions); - const [firstTicket] = tickets; - const companyFk = firstTicket.companyFk; - - const query = - `SELECT COUNT(*) isSpanishCompany - FROM supplier s - JOIN country c ON c.id = s.countryFk - AND c.code = 'ES' - WHERE s.id = ?`; - const [supplierCompany] = await Self.rawSql(query, [companyFk], options); - - const isSpanishCompany = supplierCompany?.isSpanishCompany; - - const [result] = await Self.rawSql('SELECT hasAnyNegativeBase() AS base', null, options); - const hasAnyNegativeBase = result?.base && isSpanishCompany; - if (hasAnyNegativeBase) - throw new UserError($t('Negative basis of tickets', {ticketsIds: ticketsIds})); + const taxBaseFunction = isRectificative ? 'hasAnyPositiveBase' : 'hasAnyNegativeBase'; + const [hasAnyIncorrectBase] = + await Self.rawSql(`SELECT ${taxBaseFunction}() AS hasBasesProblem`, null, options); + if (hasAnyIncorrectBase?.hasBasesProblem) + throw new UserError($t(taxBaseFunction, {ticketsIds: ticketsIds})); const today = Date.vnNew(); tickets.some(ticket => { @@ -70,7 +58,5 @@ module.exports = function(Self) { if (ticketsIds.length == 1 && priceZero) throw new UserError(`A ticket with an amount of zero can't be invoiced`); }); - - return true; }; }; diff --git a/modules/ticket/back/methods/ticket/invoiceTickets.js b/modules/ticket/back/methods/ticket/invoiceTickets.js index fa3ee93af..06429836e 100644 --- a/modules/ticket/back/methods/ticket/invoiceTickets.js +++ b/modules/ticket/back/methods/ticket/invoiceTickets.js @@ -10,7 +10,13 @@ module.exports = function(Self) { description: 'The tickets id', type: ['number'], required: true + }, + { + arg: 'invoiceCorrection', + description: 'The invoice correction', + type: 'object', } + ], returns: { type: ['object'], @@ -22,7 +28,7 @@ module.exports = function(Self) { } }); - Self.invoiceTickets = async(ctx, ticketsIds, options) => { + Self.invoiceTickets = async(ctx, ticketsIds, invoiceCorrection, options) => { const models = Self.app.models; const date = Date.vnNew(); date.setHours(0, 0, 0, 0); @@ -41,10 +47,10 @@ module.exports = function(Self) { let invoicesIds = []; try { const tickets = await models.Ticket.find({ + fields: ['id', 'clientFk', 'companyFk', 'addressFk'], where: { id: {inq: ticketsIds} - }, - fields: ['id', 'clientFk', 'companyFk'] + } }, myOptions); const [firstTicket] = tickets; @@ -55,22 +61,20 @@ module.exports = function(Self) { if (!isSameClient) throw new UserError(`You can't invoice tickets from multiple clients`); - const client = await models.Client.findById(clientId, { - fields: ['id', 'hasToInvoiceByAddress'] + const {hasToInvoiceByAddress} = await models.Client.findById(clientId, { + fields: ['hasToInvoiceByAddress'] }, myOptions); - if (client.hasToInvoiceByAddress) { - const query = ` - SELECT DISTINCT addressFk - FROM ticket t - WHERE id IN (?)`; - const result = await Self.rawSql(query, [ticketsIds], myOptions); + let ticketsByAddress = hasToInvoiceByAddress + ? Object.values(tickets.reduce((group, {id, addressFk}) => { + group[addressFk] = group[addressFk] ?? []; + group[addressFk].push(id); + return group; + }, {})) + : [ticketsIds]; - const addressIds = result.map(address => address.addressFk); - for (const address of addressIds) - await createInvoice(ctx, companyId, ticketsIds, address, invoicesIds, myOptions); - } else - await createInvoice(ctx, companyId, ticketsIds, null, invoicesIds, myOptions); + for (const ticketIds of ticketsByAddress) + invoicesIds.push(await createInvoice(ctx, companyId, ticketIds, invoiceCorrection, myOptions)); if (tx) await tx.commit(); } catch (e) { @@ -85,9 +89,8 @@ module.exports = function(Self) { return invoicesIds; }; - async function createInvoice(ctx, companyId, ticketsIds, address, invoicesIds, myOptions) { + async function createInvoice(ctx, companyId, ticketsIds, invoiceCorrection, myOptions) { const models = Self.app.models; - await models.Ticket.rawSql(` CREATE OR REPLACE TEMPORARY TABLE tmp.ticketToInvoice (PRIMARY KEY (id)) @@ -95,11 +98,8 @@ module.exports = function(Self) { SELECT id FROM vn.ticket WHERE id IN (?) - ${address ? `AND addressFk = ${address}` : ''} `, [ticketsIds], myOptions); - - const invoiceId = await models.Ticket.makeInvoice(ctx, 'R', companyId, Date.vnNew(), myOptions); - invoicesIds.push(invoiceId); + return models.Ticket.makeInvoice(ctx, 'R', companyId, Date.vnNew(), invoiceCorrection, myOptions); } }; diff --git a/modules/ticket/back/methods/ticket/makeInvoice.js b/modules/ticket/back/methods/ticket/makeInvoice.js index e7ee806c7..83222a4ee 100644 --- a/modules/ticket/back/methods/ticket/makeInvoice.js +++ b/modules/ticket/back/methods/ticket/makeInvoice.js @@ -22,6 +22,11 @@ module.exports = function(Self) { description: 'The invoice date', type: 'date', required: true + }, + { + arg: 'invoiceCorrection', + description: 'The invoice correction', + type: 'object', } ], returns: { @@ -34,7 +39,7 @@ module.exports = function(Self) { } }); - Self.makeInvoice = async(ctx, invoiceType, companyFk, invoiceDate, options) => { + Self.makeInvoice = async(ctx, invoiceType, companyFk, invoiceDate, invoiceCorrection, options) => { const models = Self.app.models; invoiceDate.setHours(0, 0, 0, 0); @@ -62,20 +67,24 @@ module.exports = function(Self) { fields: ['id', 'clientFk', 'addressFk'] }, myOptions); - await models.Ticket.canBeInvoiced(ctx, ticketsIds, myOptions); + await models.Ticket.canBeInvoiced(ctx, ticketsIds, !!invoiceCorrection, myOptions); const [firstTicket] = tickets; const clientId = firstTicket.clientFk; - const clientCanBeInvoiced = await models.Client.canBeInvoiced(clientId, companyFk, myOptions); + const clientCanBeInvoiced = + await models.Client.canBeInvoiced(clientId, companyFk, myOptions); + if (!clientCanBeInvoiced) throw new UserError(`This client can't be invoiced`); - const query = `SELECT vn.invoiceSerial(?, ?, ?) AS serial`; - const [{serial}] = await Self.rawSql(query, [ - clientId, - companyFk, - invoiceType, - ], myOptions); + const [{serial}] = invoiceCorrection ? [{serial: 'R'}] : await Self.rawSql( + `SELECT vn.invoiceSerial(?, ?, ?) AS serial`, + [ + clientId, + companyFk, + invoiceType + ], + myOptions); const invoiceOutSerial = await models.InvoiceOutSerial.findById(serial); if (invoiceOutSerial?.taxAreaFk == 'WORLD') { @@ -87,11 +96,17 @@ module.exports = function(Self) { await Self.rawSql('CALL invoiceOut_new(?, ?, null, @invoiceId)', [serial, invoiceDate], myOptions); const [resultInvoice] = await Self.rawSql('SELECT @invoiceId id', [], myOptions); - if (!resultInvoice) + if (!resultInvoice?.id) throw new UserError('No tickets to invoice', 'notInvoiced'); - if (serial != 'R' && resultInvoice.id) - await Self.rawSql('CALL invoiceOutBooking(?)', [resultInvoice.id], myOptions); + if (invoiceCorrection) { + await models.InvoiceCorrection.create( + Object.assign(invoiceCorrection, {correctingFk: resultInvoice.id}), + myOptions + ); + } + + await Self.rawSql('CALL invoiceOutBooking(?)', [resultInvoice.id], myOptions); if (tx) await tx.commit(); diff --git a/modules/ticket/back/methods/ticket/refund.js b/modules/ticket/back/methods/ticket/refund.js index 758384ae2..4fed02260 100644 --- a/modules/ticket/back/methods/ticket/refund.js +++ b/modules/ticket/back/methods/ticket/refund.js @@ -15,7 +15,7 @@ module.exports = Self => { } ], returns: { - type: ['number'], + type: ['object'], root: true }, http: { diff --git a/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js b/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js index 538dbc49f..78973e040 100644 --- a/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js +++ b/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js @@ -27,10 +27,7 @@ describe('ticket canBeInvoiced()', () => { WHERE id IN (?) `, [ticketId], options); - const canBeInvoiced = await models.Ticket.canBeInvoiced(ctx, [ticketId], options); - - expect(canBeInvoiced).toEqual(false); - + await models.Ticket.canBeInvoiced(ctx, [ticketId], false, options); await tx.rollback(); } catch (e) { error = e; @@ -59,10 +56,7 @@ describe('ticket canBeInvoiced()', () => { WHERE id IN (?) `, [ticketId], options); - const canBeInvoiced = await models.Ticket.canBeInvoiced(ctx, [ticketId], options); - - expect(canBeInvoiced).toEqual(false); - + await models.Ticket.canBeInvoiced(ctx, [ticketId], false, options); await tx.rollback(); } catch (e) { error = e; @@ -95,10 +89,7 @@ describe('ticket canBeInvoiced()', () => { WHERE id IN (?) `, [ticketId], options); - const canBeInvoiced = await models.Ticket.canBeInvoiced(ctx, [ticketId], options); - - expect(canBeInvoiced).toEqual(false); - + await models.Ticket.canBeInvoiced(ctx, [ticketId], false, options); await tx.rollback(); } catch (e) { error = e; @@ -123,14 +114,36 @@ describe('ticket canBeInvoiced()', () => { WHERE id IN (?) `, [ticketId], options); - const canBeInvoiced = await models.Ticket.canBeInvoiced(ctx, [ticketId], options); - - expect(canBeInvoiced).toEqual(true); - + await models.Ticket.canBeInvoiced(ctx, [ticketId], false, options); await tx.rollback(); } catch (e) { await tx.rollback(); throw e; } }); + + it('should return falsy for a ticket has positiveBase', async() => { + const tx = await models.Ticket.beginTransaction({}); + + try { + const options = {transaction: tx}; + + await models.Ticket.rawSql(` + CREATE OR REPLACE TEMPORARY TABLE tmp.ticketToInvoice + (PRIMARY KEY (id)) + ENGINE = MEMORY + SELECT id + FROM vn.ticket + WHERE id IN (?) + `, [ticketId], options); + + await models.Ticket.canBeInvoiced(ctx, [ticketId], true, options); + await tx.rollback(); + } catch (e) { + error = e; + await tx.rollback(); + } + + expect(error.message).toEqual(`hasAnyPositiveBase`); + }); }); diff --git a/modules/ticket/back/methods/ticket/specs/invoiceTickets.spec.js b/modules/ticket/back/methods/ticket/specs/invoiceTickets.spec.js index 8971fb24a..162dc066a 100644 --- a/modules/ticket/back/methods/ticket/specs/invoiceTickets.spec.js +++ b/modules/ticket/back/methods/ticket/specs/invoiceTickets.spec.js @@ -31,7 +31,7 @@ describe('ticket invoiceTickets()', () => { const options = {transaction: tx}; const ticketsIds = [11, 16]; - await models.Ticket.invoiceTickets(ctx, ticketsIds, options); + await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options); await tx.rollback(); } catch (e) { @@ -57,7 +57,7 @@ describe('ticket invoiceTickets()', () => { await client.updateAttribute('isTaxDataChecked', false, options); const ticketsIds = [11]; - await models.Ticket.invoiceTickets(ctx, ticketsIds, options); + await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options); await tx.rollback(); } catch (e) { @@ -80,8 +80,8 @@ describe('ticket invoiceTickets()', () => { const options = {transaction: tx}; const ticketsIds = [11]; - await models.Ticket.invoiceTickets(ctx, ticketsIds, options); - await models.Ticket.invoiceTickets(ctx, ticketsIds, options); + await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options); + await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options); await tx.rollback(); } catch (e) { @@ -102,7 +102,7 @@ describe('ticket invoiceTickets()', () => { const options = {transaction: tx}; const ticketsIds = [11]; - const invoicesIds = await models.Ticket.invoiceTickets(ctx, ticketsIds, options); + const invoicesIds = await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options); expect(invoicesIds.length).toBeGreaterThan(0); diff --git a/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js b/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js index 9b1fd8f6f..456303602 100644 --- a/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js +++ b/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js @@ -42,7 +42,7 @@ describe('ticket makeInvoice()', () => { WHERE id IN (?) `, [ticketsIds], options); - const invoiceId = await models.Ticket.makeInvoice(ctx, invoiceType, companyFk, invoiceDate, options); + const invoiceId = await models.Ticket.makeInvoice(ctx, invoiceType, companyFk, invoiceDate, null, options); expect(invoiceId).toBeDefined(); @@ -70,7 +70,7 @@ describe('ticket makeInvoice()', () => { WHERE id IN (?) `, [ticketsId], options); - await models.Ticket.makeInvoice(ctx, invoiceType, companyFk, invoiceDate, options); + await models.Ticket.makeInvoice(ctx, invoiceType, companyFk, invoiceDate, null, options); await tx.rollback(); } catch (e) { error = e; diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js index 18db8c147..cd819e623 100644 --- a/modules/ticket/front/descriptor-menu/index.js +++ b/modules/ticket/front/descriptor-menu/index.js @@ -292,7 +292,7 @@ class Controller extends Section { const query = 'Tickets/refund'; return 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 })); diff --git a/modules/ticket/front/descriptor-menu/index.spec.js b/modules/ticket/front/descriptor-menu/index.spec.js index 1bb270165..c755b14c3 100644 --- a/modules/ticket/front/descriptor-menu/index.spec.js +++ b/modules/ticket/front/descriptor-menu/index.spec.js @@ -262,11 +262,12 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { const params = { ticketsIds: [16] }; - $httpBackend.expectPOST('Tickets/refund', params).respond({id: 99}); + const response = {id: 99}; + $httpBackend.expectPOST('Tickets/refund', params).respond([response]); controller.refund(); $httpBackend.flush(); - expect(controller.$state.go).toHaveBeenCalledWith('ticket.card.sale', {id: 99}); + expect(controller.$state.go).toHaveBeenCalledWith('ticket.card.sale', response); }); }); diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js index 4f6a9e757..ed6d9b10a 100644 --- a/modules/ticket/front/sale/index.js +++ b/modules/ticket/front/sale/index.js @@ -526,7 +526,7 @@ class Controller extends Section { const params = {salesIds: salesIds, withWarehouse: withWarehouse}; const query = 'Sales/refund'; 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 })); diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js index 70781eb58..36be32f52 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/refund', params).respond(200, [refundTicket]); controller.createRefund(); $httpBackend.flush();