From e5c9ea850bfdf150e662c022af6715078f2722c2 Mon Sep 17 00:00:00 2001 From: jgallego Date: Fri, 24 Sep 2021 08:24:34 +0200 Subject: [PATCH] testback done --- db/changes/10370-cucumber/00-booking.sql | 246 ++++++++++++++++++ db/dump/fixtures.sql | 2 +- loopback/locale/es.json | 3 +- .../methods/invoice-in/specs/toBook.spec.js | 34 +++ .../back/methods/invoice-in/summary.js | 21 +- .../back/methods/invoice-in/toBook.js | 56 ++++ modules/invoiceIn/back/models/invoice-in.js | 16 ++ modules/invoiceIn/front/descriptor/index.html | 16 +- modules/invoiceIn/front/descriptor/index.js | 4 + .../invoiceIn/front/descriptor/index.spec.js | 13 + modules/invoiceIn/front/locale/es.yml | 2 + 11 files changed, 390 insertions(+), 23 deletions(-) create mode 100644 db/changes/10370-cucumber/00-booking.sql create mode 100644 modules/invoiceIn/back/methods/invoice-in/specs/toBook.spec.js create mode 100644 modules/invoiceIn/back/methods/invoice-in/toBook.js diff --git a/db/changes/10370-cucumber/00-booking.sql b/db/changes/10370-cucumber/00-booking.sql new file mode 100644 index 0000000000..2e86198cf5 --- /dev/null +++ b/db/changes/10370-cucumber/00-booking.sql @@ -0,0 +1,246 @@ +DROP PROCEDURE IF EXISTS vn.invoiceInBookingMain; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`invoiceInBookingMain`(vInvoiceInId INT) +BEGIN + DECLARE vTotalAmount,vTotalAmountDivisa DECIMAL(10,2); + DECLARE vBookNumber,vSerialNumber INT; + DECLARE vRate DECIMAL(10,4); + + CALL invoiceInBookingCommon(vInvoiceInId,vSerialNumber); + + SELECT SUM(iit.taxableBase * IF( i.serial= 'R' AND ti.Iva <> 'HP DEVENGADO 21 ISP', 1 +(ti.PorcentajeIva/100),1)), + SUM(iit.foreignValue * IF( i.serial= 'R', 1 + (ti.PorcentajeIva/100),1)), + iit.taxableBase/iit.foreignValue + INTO vTotalAmount, vTotalAmountDivisa, vRate + FROM newInvoiceIn i + JOIN invoiceInTax iit ON iit.invoiceInFk = i.id + LEFT JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk; + + CALL vn.ledger_next(vBookNumber); + + -- Apunte del proveedor + + INSERT INTO XDiario(ASIEN, + FECHA, + SUBCTA, + EUROHABER, + CONCEPTO, + CAMBIO, + HABERME, + NFACTICK, + CLAVE, + empresa_id + ) + SELECT + vBookNumber, + n.bookEntried, + s.supplierAccount, + vTotalAmount EUROHABER, + n.conceptWithSupplier, + vRate, + vTotalAmountDivisa, + n.invoicesCount, + vInvoiceInId, + n.companyFk + FROM newInvoiceIn n + JOIN newSupplier s; + + -- Línea de Gastos + INSERT INTO XDiario ( ASIEN, + FECHA, + SUBCTA, + CONTRA, + EURODEBE, + EUROHABER, + CONCEPTO, + CAMBIO, + DEBEME, + HABERME, + NFACTICK, + empresa_id + ) + SELECT vBookNumber ASIEN, + n.bookEntried FECHA, + IF(e.isWithheld , LPAD(RIGHT(s.supplierAccount,5),10,iit.expenceFk),iit.expenceFk) SUBCTA, + s.supplierAccount CONTRA, + IF(e.isWithheld AND iit.taxableBase < 0, NULL, ROUND(SUM(iit.taxableBase),2)) EURODEBE, + IF(e.isWithheld AND iit.taxableBase < 0,ROUND(SUM(-iit.taxableBase),2),NULL) EUROHABER, + n.conceptWithSupplier CONCEPTO, + vRate, + IF(e.isWithheld,NULL,ABS(ROUND(SUM(iit.foreignValue),2))) DEBEME, + IF(e.isWithheld,ABS(ROUND(SUM(iit.foreignValue),2)),NULL) HABERME, + n.invoicesCount NFACTICK, + n.companyFk empresa_id + FROM newInvoiceIn n + JOIN newSupplier s + JOIN invoiceInTax iit ON iit.invoiceInFk = n.id + JOIN (SELECT * FROM expence e GROUP BY e.id)e ON e.id = iit.expenceFk + WHERE e.name != 'Suplidos Transitarios nacionales' + GROUP BY iit.expenceFk; + + -- Líneas de IVA + + INSERT INTO XDiario( ASIEN, + FECHA, + SUBCTA, + CONTRA, + EURODEBE, + BASEEURO, + CONCEPTO, + FACTURA, + IVA, + AUXILIAR, + SERIE, + TIPOOPE, + FECHA_EX, + FECHA_OP, + NFACTICK, + FACTURAEX, + L340, + LRECT349, + TIPOCLAVE, + TIPOEXENCI, + TIPONOSUJE, + TIPOFACT, + TIPORECTIF, + TERIDNIF, + TERNIF, + TERNOM, + FECREGCON, + empresa_id + ) + SELECT vBookNumber ASIEN, + n.bookEntried FECHA, + IF(n.expenceFkDeductible>0, n.expenceFkDeductible, ti.CuentaIvaSoportado) SUBCTA, + s.supplierAccount CONTRA, + SUM(ROUND(ti.PorcentajeIva * it.taxableBase / 100 /* + 0.0001*/ , 2)) EURODEBE, + SUM(it.taxableBase) BASEEURO, + GROUP_CONCAT(DISTINCT e.`name` SEPARATOR ', ') CONCEPTO, + vSerialNumber FACTURA, + ti.PorcentajeIva IVA, + IF(isUeeMember AND eWithheld.id IS NULL,'','*') AUXILIAR, + n.serial SERIE, + ttr.ClaveOperacionDefecto, + n.issued FECHA_EX, + n.operated FECHA_OP, + n.invoicesCount NFACTICK, + n.supplierRef FACTURAEX, + TRUE L340, + (isSameCountry OR NOT isUeeMember) LRECT349, + n.cplusTrascendency472Fk TIPOCLAVE, + n.cplusTaxBreakFk TIPOEXENCI, + n.cplusSubjectOpFk TIPONOSUJE, + n.cplusInvoiceType472Fk TIPOFACT, + n.cplusRectificationTypeFk TIPORECTIF, + iis.cplusTerIdNifFk TERIDNIF, + s.nif AS TERNIF, + s.name AS TERNOM, + n.booked FECREGCON, + n.companyFk + FROM newInvoiceIn n + JOIN newSupplier s + JOIN invoiceInTax it ON n.id = it.invoiceInFk + JOIN sage.TiposIva ti ON ti.CodigoIva = it.taxTypeSageFk + JOIN sage.TiposTransacciones ttr ON ttr.CodigoTransaccion = it.transactionTypeSageFk + JOIN invoiceInSerial iis ON iis.code = n.serial + JOIN (SELECT * FROM expence e GROUP BY e.id)e ON e.id = it.expenceFk + LEFT JOIN (SELECT eWithheld.id + FROM invoiceInTax hold + JOIN expence eWithheld ON eWithheld.id = hold.expenceFk AND eWithheld.isWithheld + WHERE hold.invoiceInFk = vInvoiceInId LIMIT 1 + ) eWithheld ON TRUE + WHERE it.taxTypeSageFk IS NOT NULL + AND it.taxTypeSageFk NOT IN (22, 90) + GROUP BY ti.PorcentajeIva, e.id; + + -- Línea iva inversor sujeto pasivo + + INSERT INTO XDiario( ASIEN, + FECHA, + SUBCTA, + CONTRA, + EUROHABER, + BASEEURO, + CONCEPTO, + FACTURA, + IVA, + AUXILIAR, + SERIE, + TIPOOPE, + FECHA_EX, + FECHA_OP, + NFACTICK, + FACTURAEX, + L340, + LRECT349, + TIPOCLAVE, + TIPOEXENCI, + TIPONOSUJE, + TIPOFACT, + TIPORECTIF, + TERIDNIF, + TERNIF, + TERNOM, + empresa_id + ) + SELECT vBookNumber ASIEN, + n.bookEntried FECHA, + ti.CuentaIvaRepercutido SUBCTA, + s.supplierAccount CONTRA, + SUM(ROUND(ti.PorcentajeIva * it.taxableBase / 100,2)) EUROHABER, + ROUND(SUM(it.taxableBase),2) BASEEURO, + GROUP_CONCAT(DISTINCT e.`name` SEPARATOR ', ') CONCEPTO, + vSerialNumber FACTURA, + ti.PorcentajeIva IVA, + '*' AUXILIAR, + n.serial SERIE, + ttr.ClaveOperacionDefecto, + n.issued FECHA_EX, + n.operated FECHA_OP, + n.invoicesCount NFACTICK, + n.supplierRef FACTURAEX, + FALSE L340, + (isSameCountry OR NOT isUeeMember) LRECT349, + 1 TIPOCLAVE, + n.cplusTaxBreakFk TIPOEXENCI, + n.cplusSubjectOpFk TIPONOSUJE, + n.cplusInvoiceType472Fk TIPOFACT, + n.cplusRectificationTypeFk TIPORECTIF, + iis.cplusTerIdNifFk TERIDNIF, + s.nif AS TERNIF, + s.name AS TERNOM, + n.companyFk + FROM newInvoiceIn n + JOIN newSupplier s + JOIN invoiceInTax it ON n.id = it.invoiceInFk + JOIN sage.TiposIva ti ON ti.CodigoIva = it.taxTypeSageFk + JOIN sage.TiposTransacciones ttr ON ttr.CodigoTransaccion = it.transactionTypeSageFk + JOIN invoiceInSerial iis ON iis.code = n.serial + JOIN (SELECT * FROM expence e GROUP BY e.id)e ON e.id = it.expenceFk + WHERE ti.Iva = 'HP DEVENGADO 21 ISP' OR MID(s.account, 4, 1) = '1' + GROUP BY ti.PorcentajeIva, e.id; + + -- Actualización del registro original + UPDATE invoiceIn ii + JOIN newInvoiceIn ni ON ii.id = ni.id + SET ii.serialNumber = vSerialNumber, + ii.isBooked = TRUE; + + -- Problemas derivados de la precisión en los decimales al calcular los impuestos + UPDATE XDiario + SET EURODEBE = EURODEBE - + (SELECT IF(ABS(sub.difference) = 0.01, sub.difference, 0) + FROM(SELECT SUM(IFNULL(ROUND(EURODEBE, 2),0)) - SUM(IFNULL(ROUND(EUROHABER, 2), 0)) difference + FROM XDiario + WHERE ASIEN = vBookNumber + )sub + ) + WHERE ASIEN = vBookNumber + AND EURODEBE <> 0 + ORDER BY id DESC + LIMIT 1; + +END$$ +DELIMITER ; diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 2b65efbc10..b949027a22 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2340,7 +2340,7 @@ REPLACE INTO `vn`.`invoiceIn`(`id`, `serialNumber`,`serial`, `supplierFk`, `issu INSERT INTO `vn`.`invoiceInDueDay`(`invoiceInFk`, `dueDated`, `bankFk`, `amount`) VALUES - (1, CURDATE(), 1, 237), + (1, CURDATE(), 1, 336.99), (1, CURDATE(), 1, 15.25), (2, CURDATE(), 1, 168), (2, CURDATE(), 1, 55.17), diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 7a670d2edd..0d94c21f8f 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -209,5 +209,6 @@ "Wasn't able to invoice the following clients": "No se han podido facturar los siguientes clientes", "Can't verify data unless the client has a business type": "No se puede verificar datos de un cliente que no tiene tipo de negocio", "You don't have enough privileges to set this credit amount": "No tienes suficientes privilegios para establecer esta cantidad de crédito", - "You can't change the credit set to zero from a manager": "No puedes cambiar el cŕedito establecido a cero por un gerente" + "You can't change the credit set to zero from a manager": "No puedes cambiar el cŕedito establecido a cero por un gerente", + "Amounts do not match": "Amounts do not match" } \ No newline at end of file diff --git a/modules/invoiceIn/back/methods/invoice-in/specs/toBook.spec.js b/modules/invoiceIn/back/methods/invoice-in/specs/toBook.spec.js new file mode 100644 index 0000000000..43c1b96590 --- /dev/null +++ b/modules/invoiceIn/back/methods/invoice-in/specs/toBook.spec.js @@ -0,0 +1,34 @@ +const models = require('vn-loopback/server/server').models; + +fdescribe('invoiceIn toBook()', () => { + it('should check that invoiceIn is booked', async() => { + const userId = 1; + const ctx = { + req: { + + accessToken: {userId: userId}, + headers: {origin: 'http://localhost:5000'}, + } + }; + const invoiceInId = 1; + const tx = await models.InvoiceIn.beginTransaction({}); + const options = {transaction: tx}; + + try { + const invoiceInBefore = await models.InvoiceIn.findById(invoiceInId, null, options); + + expect(invoiceInBefore.isBooked).toEqual(false); + + await models.InvoiceIn.toBook(ctx, invoiceInId, options); + + const invoiceIn = await models.InvoiceIn.findById(invoiceInId, null, options); + + expect(invoiceIn.isBooked).toEqual(true); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/invoiceIn/back/methods/invoice-in/summary.js b/modules/invoiceIn/back/methods/invoice-in/summary.js index f09be4add1..80dc2331b2 100644 --- a/modules/invoiceIn/back/methods/invoice-in/summary.js +++ b/modules/invoiceIn/back/methods/invoice-in/summary.js @@ -20,6 +20,7 @@ module.exports = Self => { }); Self.summary = async(id, options) => { + const models = Self.app.models; let myOptions = {}; if (typeof options == 'object') @@ -85,25 +86,9 @@ module.exports = Self => { } ] }; + let summaryObj = await models.InvoiceIn.findById(id, filter, myOptions); - let summaryObj = await Self.app.models.InvoiceIn.findById(id, filter, myOptions); - - summaryObj.totals = await getTotals(id); + summaryObj.totals = await models.InvoiceIn.getTotals(id); return summaryObj; }; - - async function getTotals(invoiceInFk) { - return (await Self.rawSql(` - SELECT iit.*, - SUM(iidd.amount) totalDueDay - FROM vn.invoiceIn ii - LEFT JOIN (SELECT SUM(iit.taxableBase) totalTaxableBase, - SUM(iit.taxableBase * (1 + (ti.PorcentajeIva / 100))) totalVat - FROM vn.invoiceInTax iit - LEFT JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk - WHERE iit.invoiceInFk = ?) iit ON TRUE - LEFT JOIN vn.invoiceInDueDay iidd ON iidd.invoiceInFk = ii.id - WHERE - ii.id = ?`, [invoiceInFk, invoiceInFk]))[0]; - } }; diff --git a/modules/invoiceIn/back/methods/invoice-in/toBook.js b/modules/invoiceIn/back/methods/invoice-in/toBook.js new file mode 100644 index 0000000000..1444df63ec --- /dev/null +++ b/modules/invoiceIn/back/methods/invoice-in/toBook.js @@ -0,0 +1,56 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethodCtx('toBook', { + description: 'To book the invoiceIn', + accessType: 'WRITE', + accepts: { + arg: 'id', + type: 'number', + required: true, + description: 'The invoiceIn id', + http: {source: 'path'} + }, + returns: { + type: 'object', + root: true + }, + http: { + path: '/:id/toBook', + verb: 'POST' + } + }); + + Self.toBook = async(ctx, id, options) => { + const models = Self.app.models; + let tx; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const totals = await models.InvoiceIn.getTotals(id); + if (totals.totalDueDay != totals.totalTaxableBase && totals.totalDueDay != totals.totalVal) + throw new UserError(`Amounts do not match`); + + /* const now = new Date(); + const hasFuturePayments = await models.InvoiceInDueDay.findOne({ + where: { + invoiceInFk: id, + dueDated: {gte: now} + } + });*/ + await Self.rawSql(`CALL vn.invoiceInBookingMain(?)`, [id], myOptions); + if (tx) await tx.commit(); + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/invoiceIn/back/models/invoice-in.js b/modules/invoiceIn/back/models/invoice-in.js index 7754890cad..eb57b079f2 100644 --- a/modules/invoiceIn/back/models/invoice-in.js +++ b/modules/invoiceIn/back/models/invoice-in.js @@ -2,4 +2,20 @@ module.exports = Self => { require('../methods/invoice-in/filter')(Self); require('../methods/invoice-in/summary')(Self); require('../methods/invoice-in/clone')(Self); + require('../methods/invoice-in/toBook')(Self); + + Self.getTotals = async function getTotals(invoiceInFk) { + return (await Self.rawSql(` + SELECT iit.*, + SUM(iidd.amount) totalDueDay + FROM vn.invoiceIn ii + LEFT JOIN (SELECT SUM(iit.taxableBase) totalTaxableBase, + SUM(iit.taxableBase * (1 + (ti.PorcentajeIva / 100))) totalVat + FROM vn.invoiceInTax iit + LEFT JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk + WHERE iit.invoiceInFk = ?) iit ON TRUE + LEFT JOIN vn.invoiceInDueDay iidd ON iidd.invoiceInFk = ii.id + WHERE + ii.id = ?`, [invoiceInFk, invoiceInFk]))[0]; + }; }; diff --git a/modules/invoiceIn/front/descriptor/index.html b/modules/invoiceIn/front/descriptor/index.html index 6829a0daf4..50efec2d53 100644 --- a/modules/invoiceIn/front/descriptor/index.html +++ b/modules/invoiceIn/front/descriptor/index.html @@ -1,8 +1,16 @@ + + To book + + @@ -10,7 +18,7 @@ Clone Invoice @@ -26,7 +34,7 @@ - {{$ctrl.invoiceIn.supplier.nickname}} + {{$ctrl.invoiceIn.supplier.nickname}} @@ -46,7 +54,9 @@ icon="icon-invoiceIn"> + + this.entity = res.data); } + toBook() { + return this.$http.post(`InvoiceIns/${this.id}/toBook`) + .then(() => this.vnApp.showSuccess(this.$t('InvoiceIn booked'))); + } } ngModule.vnComponent('vnInvoiceInDescriptor', { diff --git a/modules/invoiceIn/front/descriptor/index.spec.js b/modules/invoiceIn/front/descriptor/index.spec.js index df72f5b45e..235d04a43c 100644 --- a/modules/invoiceIn/front/descriptor/index.spec.js +++ b/modules/invoiceIn/front/descriptor/index.spec.js @@ -23,4 +23,17 @@ describe('vnInvoiceInDescriptor', () => { expect(controller.invoiceIn).toEqual(response); }); }); + + describe('toBook()', () => { + it(`should perform a post query to book the invoiSce`, () => { + const id = 1; + const response = {id: 1}; + + $httpBackend.expectPOST(`InvoiceIns/${id}/toBook`).respond(response); + controller.id = id; + $httpBackend.flush(); + + expect(controller.invoiceIn).toEqual(response); + }); + }); }); diff --git a/modules/invoiceIn/front/locale/es.yml b/modules/invoiceIn/front/locale/es.yml index f837c834b0..af86d099b8 100644 --- a/modules/invoiceIn/front/locale/es.yml +++ b/modules/invoiceIn/front/locale/es.yml @@ -10,4 +10,6 @@ Foreign value: Divisa Due day: Vencimiento Invoice list: Listado de facturas recibidas InvoiceIn cloned: Factura clonada +To book: Contabilizar +Amounts do not match: La BI no coincide con el vencimiento ni con el total