2883-invoiceIn-Booking #786
|
@ -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 ;
|
|
@ -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),
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
joan marked this conversation as resolved
Outdated
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
carlosjr
commented
doesn't getTotal expect a transaction? doesn't getTotal expect a transaction?
|
||||
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];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -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];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
<vn-descriptor-content module="invoiceIn" description="$ctrl.invoiceIn.supplierRef">
|
||||
<slot-menu>
|
||||
<vn-item
|
||||
ng-click="$ctrl.toBook()"
|
||||
vn-acl="administrative"
|
||||
ng-hide="$ctrl.invoiceIn.isBooked == true"
|
||||
translate>
|
||||
To book
|
||||
</vn-item>
|
||||
|
||||
<vn-item
|
||||
ng-click="deleteConfirmation.show()"
|
||||
vn-acl="invoicing"
|
||||
vn-acl="administrative"
|
||||
vn-acl-action="remove"
|
||||
name="deleteInvoice"
|
||||
translate>
|
||||
|
@ -10,7 +18,7 @@
|
|||
</vn-item>
|
||||
<vn-item
|
||||
ng-click="cloneConfirmation.show()"
|
||||
vn-acl="invoicing"
|
||||
vn-acl="administrative"
|
||||
name="cloneInvoice"
|
||||
translate>
|
||||
Clone Invoice
|
||||
|
@ -46,7 +54,9 @@
|
|||
icon="icon-invoiceIn">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</slot-body>
|
||||
</vn-descriptor-content>
|
||||
<vn-confirm
|
||||
|
|
|
@ -51,6 +51,10 @@ class Controller extends Descriptor {
|
|||
return this.getData(`InvoiceIns/${this.id}`, {filter})
|
||||
.then(res => this.entity = res.data);
|
||||
}
|
||||
toBook() {
|
||||
return this.$http.post(`InvoiceIns/${this.id}/toBook`)
|
||||
jgallego marked this conversation as resolved
Outdated
carlosjr
commented
function naming must be in lowerCamelCase function naming must be in lowerCamelCase
|
||||
.then(() => this.vnApp.showSuccess(this.$t('InvoiceIn booked')));
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInDescriptor', {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue
this should be in spanish