2883-invoiceIn-Booking #786
|
@ -0,0 +1,2 @@
|
|||
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||
VALUES('InvoiceInDueDay', '*', '*', 'ALLOW', 'ROLE', 'administrative');
|
|
@ -0,0 +1,248 @@
|
|||
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 ;
|
|
@ -2353,7 +2353,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),
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
{
|
||||
"name": "salix-front",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@uirouter/angularjs": {
|
||||
"version": "1.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.29.tgz",
|
||||
"integrity": "sha512-RImWnBarNixkMto0o8stEaGwZmvhv5cnuOLXyMU2pY8MP2rgEF74ZNJTLeJCW14LR7XDUxVH8Mk8bPI6lxedmQ==",
|
||||
"requires": {
|
||||
"@uirouter/core": "6.0.7"
|
||||
}
|
||||
},
|
||||
"@uirouter/core": {
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.0.7.tgz",
|
||||
"integrity": "sha512-KUTJxL+6q0PiBnFx4/Z+Hsyg0pSGiaW5yZQeJmUxknecjpTbnXkLU8H2EqRn9N2B+qDRa7Jg8RcgeNDPY72O1w=="
|
||||
},
|
||||
"angular": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/angular/-/angular-1.8.2.tgz",
|
||||
"integrity": "sha512-IauMOej2xEe7/7Ennahkbb5qd/HFADiNuLSESz9Q27inmi32zB0lnAsFeLEWcox3Gd1F6YhNd1CP7/9IukJ0Gw=="
|
||||
},
|
||||
"angular-animate": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.8.2.tgz",
|
||||
"integrity": "sha512-Jbr9+grNMs9Kj57xuBU3Ju3NOPAjS1+g2UAwwDv7su1lt0/PLDy+9zEwDiu8C8xJceoTbmBNKiWGPJGBdCQLlA=="
|
||||
},
|
||||
"angular-moment": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-moment/-/angular-moment-1.3.0.tgz",
|
||||
"integrity": "sha512-KG8rvO9MoaBLwtGnxTeUveSyNtrL+RNgGl1zqWN36+HDCCVGk2DGWOzqKWB6o+eTTbO3Opn4hupWKIElc8XETA==",
|
||||
"requires": {
|
||||
"moment": ">=2.8.0 <3.0.0"
|
||||
}
|
||||
},
|
||||
"angular-translate": {
|
||||
"version": "2.18.4",
|
||||
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.18.4.tgz",
|
||||
"integrity": "sha512-KohNrkH6J9PK+VW0L/nsRTcg5Fw70Ajwwe3Jbfm54Pf9u9Fd+wuingoKv+h45mKf38eT+Ouu51FPua8VmZNoCw==",
|
||||
"requires": {
|
||||
"angular": "^1.8.0"
|
||||
}
|
||||
},
|
||||
"angular-translate-loader-partial": {
|
||||
"version": "2.18.4",
|
||||
"resolved": "https://registry.npmjs.org/angular-translate-loader-partial/-/angular-translate-loader-partial-2.18.4.tgz",
|
||||
"integrity": "sha512-bsjR+FbB0sdA2528E/ugwKdlPPQhA1looxLxI3otayBTFXBpED33besfSZhYAISLgNMSL038vSssfRUen9qD8w==",
|
||||
"requires": {
|
||||
"angular-translate": "~2.18.4"
|
||||
}
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"requires": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"croppie": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/croppie/-/croppie-2.6.5.tgz",
|
||||
"integrity": "sha512-IlChnVUGG5T3w2gRZIaQgBtlvyuYnlUWs2YZIXXR3H9KrlO1PtBT3j+ykxvy9eZIWhk+V5SpBmhCQz5UXKrEKQ=="
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"mg-crud": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/mg-crud/-/mg-crud-1.1.2.tgz",
|
||||
"integrity": "sha1-p6AWGzWSPK7/8ZpIBpS2V1vDggw=",
|
||||
"requires": {
|
||||
"angular": "^1.6.1"
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
|
||||
},
|
||||
"oclazyload": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/oclazyload/-/oclazyload-0.6.3.tgz",
|
||||
"integrity": "sha1-Kjirv/QJDAihEBZxkZRbWfLoJ5w="
|
||||
},
|
||||
"require-yaml": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/require-yaml/-/require-yaml-0.0.1.tgz",
|
||||
"integrity": "sha1-LhsY2RPDuqcqWk03O28Tjd0sMr0=",
|
||||
"requires": {
|
||||
"js-yaml": "^4.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"requires": {
|
||||
"argparse": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||
},
|
||||
"validator": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-6.3.0.tgz",
|
||||
"integrity": "sha1-R84j7Y1Ord+p1LjvAHG2zxB418g="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -210,6 +210,7 @@
|
|||
"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",
|
||||
"Amounts do not match": "Las cantidades no coinciden",
|
||||
"The PDF document does not exists": "El documento PDF no existe. Prueba a regenerarlo desde la opción 'Regenerar PDF factura'",
|
||||
joan marked this conversation as resolved
Outdated
|
||||
"The type of business must be filled in basic data": "El tipo de negocio debe estar rellenado en datos básicos",
|
||||
"You can't create a claim from a ticket delivered more than seven days ago": "No puedes crear una reclamación de un ticket entregado hace más de siete días",
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('getTotals', {
|
||||
description: 'Return totals for an invoiceIn',
|
||||
accessType: 'READ',
|
||||
accepts: {
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'invoiceIn id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: '/:id/getTotals',
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getTotals = async(id, options) => {
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const [result] = await Self.rawSql(`
|
||||
SELECT iit.*,
|
||||
jgallego marked this conversation as resolved
carlosjr
commented
creating transaction on a read methods is required. creating transaction on a read methods is required.
carlosjr
commented
is not* required is not* required
|
||||
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
|
||||
jgallego marked this conversation as resolved
carlosjr
commented
It is easier for code maintenance to extract values to constants or variables It is easier for code maintenance to extract values to constants or variables
|
||||
WHERE iit.invoiceInFk = ?) iit ON TRUE
|
||||
LEFT JOIN vn.invoiceInDueDay iidd ON iidd.invoiceInFk = ii.id
|
||||
WHERE
|
||||
ii.id = ?`, [id, id]);
|
||||
|
||||
return result;
|
||||
jgallego marked this conversation as resolved
Outdated
carlosjr
commented
remove the () remove the ()
|
||||
};
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('invoiceIn getTotals()', () => {
|
||||
it('should check that returns invoiceIn totals', async() => {
|
||||
const invoiceInId = 1;
|
||||
const tx = await models.InvoiceIn.beginTransaction({});
|
||||
const options = {transaction: tx};
|
||||
|
||||
try {
|
||||
const invoiceIntotals = await models.InvoiceIn.getTotals(invoiceInId, options);
|
||||
|
||||
expect(typeof invoiceIntotals.totalTaxableBase).toBe('number');
|
||||
carlosjr
commented
will this fail if both properties are undefined? will this fail if both properties are undefined?
|
||||
expect(invoiceIntotals.totalTaxableBase).toEqual(invoiceIntotals.totalDueDay);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('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;
|
||||
const 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, myOptions);
|
||||
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,42 @@
|
|||
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) => {
|
||||
let tx;
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
if (!myOptions.transaction) {
|
||||
tx = await Self.beginTransaction({});
|
||||
myOptions.transaction = tx;
|
||||
}
|
||||
|
||||
try {
|
||||
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,6 @@ 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);
|
||||
require('../methods/invoice-in/getTotals')(Self);
|
||||
};
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
<vn-descriptor-content module="invoiceIn" description="$ctrl.invoiceIn.supplierRef">
|
||||
<slot-menu>
|
||||
<vn-item
|
||||
ng-click="$ctrl.checkToBook()"
|
||||
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
|
||||
|
@ -26,7 +34,7 @@
|
|||
</vn-label-value>
|
||||
<vn-label-value label="Supplier">
|
||||
<span ng-click="supplierDescriptor.show($event, $ctrl.invoiceIn.supplier.id)" class="link">
|
||||
{{$ctrl.invoiceIn.supplier.nickname}}
|
||||
{{$ctrl.invoiceIn.supplier.nickname}}
|
||||
</span>
|
||||
</vn-label-value>
|
||||
</div>
|
||||
|
@ -46,7 +54,9 @@
|
|||
icon="icon-invoice-in">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</slot-body>
|
||||
</vn-descriptor-content>
|
||||
<vn-confirm
|
||||
|
@ -62,3 +72,8 @@
|
|||
<vn-supplier-descriptor-popover
|
||||
vn-id="supplierDescriptor">
|
||||
</vn-supplier-descriptor-popover>
|
||||
<vn-confirm
|
||||
vn-id="confirm-toBookAnyway"
|
||||
message="Are you sure you want to book this invoice?"
|
||||
on-accept="$ctrl.onAcceptToBook()">
|
||||
</vn-confirm>
|
|
@ -51,6 +51,43 @@ class Controller extends Descriptor {
|
|||
return this.getData(`InvoiceIns/${this.id}`, {filter})
|
||||
.then(res => this.entity = res.data);
|
||||
}
|
||||
|
||||
checkToBook() {
|
||||
jgallego marked this conversation as resolved
Outdated
carlosjr
commented
function naming must be in lowerCamelCase function naming must be in lowerCamelCase
|
||||
let message = '';
|
||||
const id = this.invoiceIn.id;
|
||||
this.$q.all([
|
||||
this.$http.get(`InvoiceIns/${this.id}/getTotals`)
|
||||
.then(res => {
|
||||
const taxableBaseNotEqualDueDay = res.data.totalDueDay != res.data.totalTaxableBase;
|
||||
const vatNotEqualDueDay = res.data.totalDueDay != res.data.totalVat;
|
||||
if (taxableBaseNotEqualDueDay && vatNotEqualDueDay)
|
||||
message += 'amountsDoNotMatch';
|
||||
}),
|
||||
this.$http.get('InvoiceInDueDays/count', {
|
||||
filter: {
|
||||
where: {
|
||||
invoiceInFk: id,
|
||||
dueDated: {gte: new Date()}
|
||||
}
|
||||
}})
|
||||
.then(res => {
|
||||
if (res.data)
|
||||
message += 'future payments';
|
||||
})
|
||||
|
||||
]).finally(() => {
|
||||
if (message.length)
|
||||
this.$.confirmToBookAnyway.show();
|
||||
else
|
||||
this.onAcceptToBook();
|
||||
});
|
||||
}
|
||||
|
||||
onAcceptToBook() {
|
||||
this.$http.post(`InvoiceIns/${this.id}/toBook`)
|
||||
.then(() => this.$state.reload())
|
||||
.then(() => this.vnApp.showSuccess(this.$t('InvoiceIn booked')));
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInDescriptor', {
|
||||
|
|
|
@ -8,19 +8,70 @@ describe('vnInvoiceInDescriptor', () => {
|
|||
|
||||
beforeEach(inject(($componentController, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
controller = $componentController('vnInvoiceInDescriptor', {$element: null});
|
||||
const $element = angular.element('<vn-invoice-in-descriptor></vn-invoice-in-descriptor>');
|
||||
|
||||
controller = $componentController('vnInvoiceInDescriptor', {$element});
|
||||
controller.invoiceIn = {id: 1};
|
||||
$httpBackend.when('GET', `InvoiceIns/${controller.invoiceIn.id}`).respond({id: 1});
|
||||
}));
|
||||
|
||||
describe('loadData()', () => {
|
||||
it(`should perform a get query to store the invoice in data into the controller`, () => {
|
||||
const id = 1;
|
||||
const response = {id: 1};
|
||||
expect(controller.invoiceIn).toEqual({id: 1});
|
||||
});
|
||||
});
|
||||
|
||||
$httpBackend.expectGET(`InvoiceIns/${id}`).respond(response);
|
||||
controller.id = id;
|
||||
describe('onAcceptToBook()', () => {
|
||||
it(`should perform a post query to book the invoice`, () => {
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
controller.$state.reload = jest.fn();
|
||||
|
||||
const id = 1;
|
||||
|
||||
$httpBackend.expectPOST(`InvoiceIns/${id}/toBook`).respond();
|
||||
controller.onAcceptToBook();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.invoiceIn).toEqual(response);
|
||||
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('InvoiceIn booked');
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkToBook()', () => {
|
||||
it(`should show a warning before book`, () => {
|
||||
jgallego marked this conversation as resolved
Outdated
carlosjr
commented
the description of the test states two warning messages will be shown but the test doesn't check that the description of the test states two warning messages will be shown but the test doesn't check that
|
||||
controller.$.confirmToBookAnyway = {show: () => {}};
|
||||
jest.spyOn(controller.$.confirmToBookAnyway, 'show');
|
||||
|
||||
const invoceInId = 1;
|
||||
const data = {
|
||||
totalDueDay: 'an amount',
|
||||
totalTaxableBase: 'distinct amount'
|
||||
};
|
||||
|
||||
$httpBackend.expectGET(`InvoiceIns/${invoceInId}/getTotals`).respond(data);
|
||||
$httpBackend.expectGET(`InvoiceInDueDays/count`).respond();
|
||||
|
||||
controller.checkToBook();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$.confirmToBookAnyway.show).toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
it(`should call onAcceptToBook`, () => {
|
||||
controller.onAcceptToBook = jest.fn();
|
||||
|
||||
const invoceInId = 1;
|
||||
const data = {
|
||||
totalDueDay: 'same amount',
|
||||
totalTaxableBase: 'same amount'
|
||||
};
|
||||
|
||||
$httpBackend.expectGET(`InvoiceIns/${invoceInId}/getTotals`).respond(data);
|
||||
$httpBackend.expectGET(`InvoiceInDueDays/count`).respond();
|
||||
|
||||
controller.checkToBook();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.onAcceptToBook).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
InvoiceIn: Facturas recibidas
|
||||
Search invoices in by reference: Buscar facturas recibidas por referencia
|
||||
Entries list: Listado de entradas
|
||||
InvoiceIn deleted: Factura eliminada
|
||||
Remove tax: Quitar iva
|
||||
Add tax: Añadir iva
|
||||
Amounts do not match: La BI no coincide con el vencimiento ni con el total
|
||||
Due day: Vencimiento
|
||||
Entries list: Listado de entradas
|
||||
Foreign value: Divisa
|
||||
InvoiceIn: Facturas recibidas
|
||||
InvoiceIn cloned: Factura clonada
|
||||
InvoiceIn deleted: Factura eliminada
|
||||
Invoice list: Listado de facturas recibidas
|
||||
InvoiceIn booked: Factura contabilizada
|
||||
Remove tax: Quitar iva
|
||||
Sage tax: Sage iva
|
||||
Sage transaction: Sage transaccion
|
||||
Foreign value: Divisa
|
||||
Due day: Vencimiento
|
||||
Invoice list: Listado de facturas recibidas
|
||||
InvoiceIn cloned: Factura clonada
|
||||
Search invoices in by reference: Buscar facturas recibidas por referencia
|
||||
To book: Contabilizar
|
||||
|
||||
|
|
|
@ -14,4 +14,4 @@ InvoiceOut booked: Factura asentada
|
|||
Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura?
|
||||
Regenerate PDF invoice: Regenerar PDF factura
|
||||
The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado
|
||||
The email can't be empty: El correo no puede estar vacío
|
||||
The email can't be empty: El correo no puede estar vacío
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
this should be in spanish